# This is a BitKeeper generated patch for the following project: # Project Name: Linux 2.4 # This patch format is intended for GNU patch command version 2.5 or higher. # This patch includes the following deltas: # ChangeSet v2.4.5-pre1 -> 1.154 # arch/ppc/kernel/ppc4xx_pic.h 1.1 -> 1.3 # drivers/char/tty_io.c 1.1.1.4 -> 1.6 # arch/sparc64/kernel/pci.c 1.5 -> 1.6 # include/asm-ppc/system.h 1.1.1.1 -> 1.7 # arch/ppc/kernel/head_8xx.S 1.1.1.1 -> 1.6 # arch/ppc/lib/locks.c 1.1.1.1 -> 1.5 # include/asm-ppc/ptrace.h 1.1 -> 1.3 # include/asm-ppc/unaligned.h 1.1 -> 1.3 # arch/ppc/chrpboot/main.c 1.1 -> 1.5 arch/ppc/boot/chrp/main.c (moved) # arch/ppc/math-emu/fsqrt.c 1.1 -> 1.3 # arch/ppc/math-emu/mtfsf.c 1.1 -> 1.3 # CREDITS 1.1.1.11 -> 1.15 # arch/sparc64/kernel/ioctl32.c 1.4.1.3 -> 1.8 # drivers/scsi/aic7xxx/aic7xxx_pci.c 1.1 -> 1.2 # arch/ppc/kernel/pci.h 1.1.1.1 -> 1.6 # include/asm-ppc/traps.h 1.1 -> 1.3 # arch/ppc/coffboot/zlib.c 1.1 -> 1.5 arch/ppc/boot/lib/zlib.c (moved) # net/ipv4/icmp.c 1.3 -> 1.4 # BitKeeper/etc/COPYING 1.1 -> (deleted) # arch/ppc/kernel/chrp_pci.c 1.1.1.2 -> 1.13 # include/asm-ppc/mc146818rtc.h 1.1 -> 1.3 # arch/ppc/kernel/i8259.h 1.1 -> 1.3 # arch/ppc/mbxboot/head_8260.S 1.1 -> 1.5 arch/ppc/boot/mbx/head_8260.S (moved) # arch/ppc/math-emu/fneg.c 1.1 -> 1.3 # drivers/ide/ide-features.c 1.1.1.1 -> 1.3 # drivers/video/controlfb.c 1.1.1.1 -> 1.3 # arch/ppc/configs/mbx_defconfig 1.1.1.1 -> 1.6 # include/asm-ppc/dbdma.h 1.1 -> 1.3 # include/asm-ppc/bootinfo.h 1.1 -> 1.4 # include/asm-ppc/m48t35.h 1.1 -> 1.3 # arch/ppc/kernel/pmac_pic.h 1.1 -> 1.3 # arch/ppc/kernel/sleep.S 1.1 -> 1.4 # arch/ppc/chrpboot/addnote.c 1.1 -> 1.5 arch/ppc/boot/utils/addnote.c (moved) # arch/ppc/xmon/subr_prf.c 1.1 -> 1.3 # arch/ppc/math-emu/fnmsub.c 1.1 -> 1.3 # arch/ppc/configs/apus_defconfig 1.1.1.1 -> 1.5 # include/asm-ppc/param.h 1.1 -> 1.3 # arch/ppc/amiga/config.c 1.1 -> 1.3 # include/asm-ppc/poll.h 1.1 -> 1.3 # include/asm-ppc/msgbuf.h 1.1 -> 1.3 # arch/ppc/xmon/nonstdio.h 1.1 -> 1.3 # arch/ppc/kernel/time.c 1.1.1.2 -> 1.11 # include/asm-ppc/pgtable.h 1.1.1.1 -> 1.6 # arch/ppc/xmon/xmon.c 1.1.1.1 -> 1.6 # include/asm-ppc/est8260.h 1.1 -> 1.3 # drivers/macintosh/mac_hid.c 1.1 -> 1.4 # arch/ppc/treeboot/ld.script 1.1 -> 1.2 arch/ppc/boot/tree/ld.script (moved) # net/ipv6/addrconf.c 1.4 -> 1.5 # arch/sparc/prom/console.c 1.2 -> 1.3 # arch/ppc/treeboot/mkevimg 1.1.1.1 -> 1.7 arch/ppc/boot/utils/mkevimg (moved) # drivers/char/keyboard.c 1.1 -> 1.2 # arch/sparc64/kernel/pci_schizo.c 1.6 -> 1.7 # drivers/scsi/Makefile 1.4 -> 1.5 # include/asm-ppc/ioctls.h 1.1.1.1 -> 1.5 # arch/ppc/configs/bseip_defconfig 1.1.1.1 -> 1.6 # drivers/net/3c515.c 1.3.1.3 -> 1.7 # arch/ppc/8260_io/enet.c 1.1.1.2 -> 1.4 # drivers/sound/dmasound/dmasound_atari.c 1.1 -> 1.2 # arch/i386/mm/fault.c 1.4 -> 1.5 # arch/alpha/defconfig 1.2 -> 1.3 # include/asm-ppc/mmu_context.h 1.1.1.1 -> 1.6 # include/asm-ppc/machdep.h 1.1.1.1 -> 1.9 # arch/ppc/kernel/mk_defs.c 1.1 -> 1.3 # arch/ppc/boot/misc.c 1.1 -> 1.6 arch/ppc/boot/prep/misc.c (moved) # drivers/scsi/aic7xxx/aic7xxx_reg.h 1.1 -> 1.2 # drivers/ide/ide-pmac.c 1.1.1.1 -> 1.4 # include/asm-ppc/ohare.h 1.1 -> 1.3 # net/ipv4/protocol.c 1.1 -> 1.2 # net/ipv4/fib_frontend.c 1.1 -> 1.2 # arch/ppc/kernel/mol.h 1.1 -> (deleted) # drivers/scsi/aic7xxx/aic7xxx_osm.h 1.3 -> 1.4 # include/asm-ppc/raven.h 1.1.1.1 -> 1.5 # arch/ppc/kernel/indirect_pci.c 1.1.1.1 -> 1.5 # include/asm-ppc/8xx_immap.h 1.1 -> 1.3 # include/asm-ppc/vc_ioctl.h 1.1 -> 1.3 # include/asm-ppc/immap_8260.h 1.1 -> 1.3 # arch/ppc/mm/mem_pieces.c 1.1 -> 1.3 # arch/ppc/math-emu/fmsub.c 1.1 -> 1.3 # include/linux/skbuff.h 1.4 -> 1.5 # arch/ppc/mm/init.c 1.1.2.4 -> 1.22 # arch/ppc/kernel/proc_rtas.c 1.1 -> (deleted) # include/asm-ppc/scatterlist.h 1.1 -> 1.3 # include/asm-ppc/div64.h 1.1 -> 1.3 # arch/ppc/boot/head.S 1.1 -> 1.5 arch/ppc/boot/prep/head.S (moved) # arch/ppc/coffboot/zlib.h 1.1 -> 1.5 arch/ppc/boot/include/zlib.h (moved) # include/asm-ppc/pgalloc.h 1.1.1.3 -> 1.7 # include/asm-ppc/termbits.h 1.1 -> 1.3 # drivers/sgi/char/linux_logo.h 1.1 -> (deleted) # arch/ppc/coffboot/nonstdio.h 1.1 -> 1.5 arch/ppc/boot/include/nonstdio.h (moved) # arch/ppc/math-emu/mcrfs.c 1.1 -> 1.3 # arch/i386/kernel/pci-irq.c 1.4 -> 1.5 # include/asm-ppc/vga.h 1.1 -> 1.3 # include/asm-ppc/hdreg.h 1.1 -> 1.3 # include/asm-ppc/heathrow.h 1.1 -> 1.4 # arch/ppc/math-emu/mtfsb1.c 1.1 -> 1.3 # include/asm-ppc/irq.h 1.1.1.2 -> 1.7 # arch/ppc/kernel/oak_setup.c 1.1 -> 1.3 # arch/ppc/amiga/bootinfo.c 1.1 -> 1.3 # arch/ppc/config.in 1.1.2.3 -> 1.23 # include/linux/blkdev.h 1.2.1.2 -> 1.5 # fs/proc/base.c 1.2 -> 1.3 # drivers/scsi/aic7xxx/aic7770.c 1.1 -> 1.2 # include/asm-ppc/elf.h 1.1.1.1 -> 1.7 # include/asm-ppc/timex.h 1.1 -> 1.3 # arch/ppc/kernel/align.c 1.1 -> 1.3 # arch/ppc/math-emu/fnmadd.c 1.1 -> 1.3 # drivers/scsi/fdomain.c 1.2 -> 1.3 # drivers/scsi/aic7xxx/aic7xxx_linux.c 1.3 -> 1.4 # arch/sparc/kernel/irq.c 1.6 -> 1.7 # include/linux/proc_fs.h 1.1.1.3 -> 1.5 # arch/ppc/defconfig 1.1.1.2 -> 1.8 # arch/ppc/8xx_io/fec.c 1.1.1.4 -> 1.9 # arch/ppc/kernel/prep_nvram.c 1.1.1.2 -> 1.7 # arch/ppc/chrpboot/start.c 1.1 -> 1.4 arch/ppc/boot/chrp/start.c (moved) # include/asm-ppc/mbx.h 1.1 -> 1.5 # include/asm-ppc/resource.h 1.1 -> 1.3 # include/asm-ppc/mk48t59.h 1.1 -> 1.3 # fs/dcache.c 1.5.1.4 -> 1.10 # net/ipv4/arp.c 1.3 -> 1.4 # include/asm-ppc/serial.h 1.1.1.1 -> 1.12 # arch/ppc/mbxboot/embed_config.c 1.1 -> 1.4 arch/ppc/boot/mbx/embed_config.c (moved) # arch/ppc/mbxboot/rdimage.c 1.1 -> 1.4 arch/ppc/boot/mbx/rdimage.c (moved) # drivers/net/pcmcia/hermes.c 1.4 -> 1.5 drivers/net/wireless/hermes.c (moved) # include/asm-ppc/init.h 1.1 -> 1.3 # include/asm-ppc/amigayle.h 1.1 -> 1.3 # drivers/net/ncr885e.c 1.1 -> (deleted) # arch/ppc/boot/mkprep.c 1.1 -> 1.5 arch/ppc/boot/utils/mkprep.c (moved) # mm/oom_kill.c 1.1 -> 1.2 # include/asm-ppc/posix_types.h 1.1 -> 1.3 # include/asm-ppc/amigappc.h 1.1 -> 1.3 # arch/ppc/kernel/chrp_time.c 1.1 -> 1.4 # arch/ppc/math-emu/fcmpo.c 1.1 -> 1.3 # arch/ppc/kernel/pmac_setup.c 1.1.1.4 -> 1.18 # include/asm-ppc/amipcmcia.h 1.1 -> 1.3 # include/linux/dcache.h 1.3.1.2 -> 1.6 # drivers/input/keybdev.c 1.1.1.4 -> 1.10 # arch/ppc/kernel/smp.c 1.1.2.2 -> 1.20 # arch/ppc/8xx_io/uart.c 1.2.1.1 -> 1.7 # arch/ppc/kernel/pmac_pic.c 1.1.1.2 -> 1.11 # arch/ppc/xmon/start.c 1.1.1.1 -> 1.8 # include/asm-ppc/backlight.h 1.1 -> 1.3 # drivers/block/swim3.c 1.1 -> 1.3 # arch/ppc/boot/ns16550.c 1.1 -> 1.6 arch/ppc/boot/common/ns16550.c (moved) # drivers/ide/ide-pnp.c 1.1.1.1 -> 1.10 # fs/smbfs/cache.c 1.3.1.2 -> 1.6 # include/asm-ppc/linux_logo.h 1.1.1.1 -> 1.5 # arch/ppc/xmon/ppc-dis.c 1.1 -> 1.3 # arch/ppc/math-emu/stfiwx.c 1.1 -> 1.3 # drivers/char/serial.c 1.1.1.5 -> 1.8 # include/asm-ppc/uninorth.h 1.1 -> 1.4 # arch/ppc/coffboot/mknote.c 1.1 -> (deleted) # include/asm-ppc/mpc8xx.h 1.1.1.1 -> 1.7 # drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c 1.1 -> 1.2 # include/asm-ppc/pci-bridge.h 1.1.1.1 -> 1.7 # include/asm-ppc/gg2.h 1.1 -> 1.3 # drivers/scsi/aic7xxx/aic7xxx_proc.c 1.1 -> 1.2 # arch/ppc/kernel/ppc8xx_pic.c 1.1.1.1 -> 1.7 # drivers/macintosh/via-pmu.c 1.1.1.2 -> 1.4 # arch/ppc/kernel/apus_setup.c 1.1.1.1 -> 1.8 # arch/sparc/kernel/head.S 1.2 -> 1.3 # drivers/video/aty128.h 1.1 -> 1.2 # arch/ppc/amiga/amiga_ksyms.c 1.1 -> 1.3 # fs/nls/nls_koi8-u.c 1.1 -> 1.2 # arch/i386/kernel/traps.c 1.5 -> 1.6 # include/asm-ppc/prep_nvram.h 1.1.1.1 -> 1.5 # include/asm-ppc/page.h 1.1 -> 1.3 # include/asm-ppc/sembuf.h 1.1 -> 1.3 # arch/ppc/kernel/bitops.c 1.1 -> 1.4 # arch/ppc/amiga/chipram.c 1.1 -> 1.3 # BitKeeper/etc/ignore 1.1 -> 1.6 # arch/sparc64/defconfig 1.10 -> 1.11 # drivers/net/Config.in 1.1.1.8 -> 1.16 # arch/ppc/configs/SM850_defconfig 1.1 -> (deleted) # arch/ppc/kernel/i8259.c 1.1.1.1 -> 1.5 # arch/ppc/chrpboot/crt0.S 1.1 -> 1.9 arch/ppc/boot/common/crt0.S (moved) # Documentation/sysrq.txt 1.2 -> 1.3 # drivers/ide/Config.in 1.1.1.1 -> 1.3 # arch/ppc/treeboot/main.c 1.1 -> 1.5 arch/ppc/boot/tree/main.c (moved) # drivers/net/pcmcia/orinoco_cs.c 1.3 -> 1.4 drivers/net/wireless/orinoco_cs.c (moved) # drivers/scsi/aic7xxx/aicasm/Makefile 1.1.1.1 -> 1.5 # drivers/scsi/aic7xxx/Config.in 1.1 -> 1.2 # include/asm-ppc/semaphore-helper.h 1.1 -> (deleted) # arch/ppc/mm/4xx_tlb.h 1.1 -> 1.3 # include/asm-ppc/feature.h 1.1.1.1 -> 1.6 # arch/ppc/math-emu/types.c 1.1 -> 1.3 # drivers/video/sis/sis_main.c 1.2 -> 1.3 # arch/ppc/boot/offset 1.1 -> 1.2 arch/ppc/boot/utils/offset (moved) # drivers/scsi/aic7xxx/aic7xxx.c 1.1 -> 1.2 # arch/ppc/kernel/error_log.h 1.1 -> (deleted) # include/asm-ppc/setup.h 1.1 -> 1.3 # arch/ppc/math-emu/fadds.c 1.1 -> 1.3 # arch/ppc/configs/rpxcllf_defconfig 1.1.1.1 -> 1.6 # include/video/macmodes.h 1.1 -> 1.2 # arch/ppc/kernel/pmac_backlight.c 1.1 -> 1.3 # arch/ppc/coffboot/misc.S 1.1 -> 1.4 arch/ppc/boot/pmac/misc.S (moved) # arch/ppc/coffboot/coffcrt0.S 1.1 -> (deleted) # arch/ppc/kernel/open_pic.h 1.1.1.2 -> 1.6 # include/asm-ppc/ipcbuf.h 1.1 -> 1.3 # include/asm-ppc/mpc8260.h 1.1 -> 1.3 # arch/ppc/mbxboot/size 1.1 -> (deleted) # arch/ppc/configs/common_defconfig 1.1.1.2 -> 1.7 # include/asm-ppc/siginfo.h 1.1 -> 1.3 # arch/ppc/amiga/time.c 1.1 -> 1.3 # drivers/net/ne2k-pci.c 1.1.1.3 -> 1.5 # arch/ppc/kernel/setup.c 1.1.2.3 -> 1.20 # drivers/net/bmac.c 1.1.1.1 -> 1.9 # drivers/video/chipsfb.c 1.1.1.1 -> 1.5 # MAINTAINERS 1.1.1.10 -> 1.14 # init/main.c 1.7 -> 1.8 # arch/ppc/coffboot/coffmain.c 1.1.1.1 -> 1.7 arch/ppc/boot/pmac/coffmain.c (moved) # include/asm-ppc/shmparam.h 1.1 -> 1.3 # arch/ppc/mbxboot/gzimage.c 1.1 -> 1.4 arch/ppc/boot/mbx/gzimage.c (moved) # arch/ppc/math-emu/fcmpu.c 1.1 -> 1.3 # arch/ppc/math-emu/fsubs.c 1.1 -> 1.3 # arch/i386/defconfig 1.15 -> 1.16 # include/asm-ppc/pci.h 1.1.1.2 -> 1.7 # include/asm-ppc/atomic.h 1.1 -> 1.6 # include/asm-ppc/shmbuf.h 1.1 -> 1.3 # arch/ppc/kernel/oak_setup.h 1.1 -> 1.3 # arch/sparc64/kernel/sys_sunos32.c 1.7 -> 1.8 # arch/ppc/kernel/idle.c 1.1.1.2 -> 1.7 # include/asm-ppc/smplock.h 1.1.1.1 -> 1.5 # arch/ppc/configs/rpxlite_defconfig 1.1.1.1 -> 1.6 # arch/ppc/kernel/walnut_setup.c 1.1 -> 1.3 # arch/sparc/kernel/sys_sunos.c 1.7 -> 1.8 # drivers/video/macmodes.c 1.2 -> 1.3 # include/asm-ppc/unistd.h 1.1.1.1 -> 1.5 # drivers/macintosh/mac_keyb.c 1.1 -> 1.2 # drivers/md/md.c 1.5.1.2 -> 1.8 # fs/nfsd/nfsproc.c 1.2.1.1 -> 1.4 # include/asm-ppc/processor.h 1.1.2.2 -> 1.20 # arch/ppc/kernel/signal.c 1.1.1.1 -> 1.5 # arch/ppc/kernel/pci-dma.c 1.1 -> 1.3 # arch/ppc/math-emu/fmuls.c 1.1 -> 1.3 # arch/ppc/8xx_io/commproc.c 1.1.1.1 -> 1.5 # scripts/mkdep.c 1.1.1.1 -> 1.3 # kernel/exit.c 1.2 -> 1.3 # include/asm-ppc/mediabay.h 1.1 -> 1.3 # arch/ppc/configs/IVMS8_defconfig 1.1 -> (deleted) # include/asm-ppc/nvram.h 1.1 -> 1.3 # drivers/net/ncr885_debug.h 1.1 -> (deleted) # arch/ppc/math-emu/frsp.c 1.1 -> 1.3 # include/asm-ppc/termios.h 1.1.1.2 -> 1.6 # include/asm-ppc/checksum.h 1.1 -> 1.4 # arch/ppc/xmon/ppc-opc.c 1.1 -> 1.3 # arch/ppc/math-emu/fmul.c 1.1 -> 1.3 # arch/ppc/math-emu/lfd.c 1.1 -> 1.3 # arch/i386/kernel/pci-pc.c 1.3.1.4 -> 1.8 # drivers/scsi/aic7xxx/aic7770_linux.c 1.1 -> 1.2 # include/asm-ppc/socket.h 1.2 -> 1.4 # include/asm-ppc/io.h 1.1.1.1 -> 1.5 # drivers/sbus/char/su.c 1.6 -> 1.7 # arch/ppc/kernel/process.c 1.1.1.2 -> 1.11 # include/asm-ppc/smp.h 1.1.1.1 -> 1.6 # Documentation/powerpc/00-INDEX 1.1 -> 1.2 # drivers/sbus/char/zs.c 1.3 -> 1.4 # include/asm-ppc/ipc.h 1.1 -> 1.3 # arch/ppc/math-emu/op-common.h 1.1 -> 1.3 # Documentation/powerpc/ppc_htab.txt 1.1.1.1 -> 1.3 # include/asm-ppc/ide.h 1.1.1.1 -> 1.7 # arch/ppc/lib/Makefile 1.1.1.1 -> 1.4 # arch/ppc/treeboot/misc.S 1.1 -> 1.5 arch/ppc/boot/tree/misc.S (moved) # arch/ppc/amiga/cia.c 1.1 -> 1.3 # arch/sparc64/kernel/pci_sabre.c 1.7 -> 1.8 # arch/ppc/kernel/open_pic_defs.h 1.1.1.1 -> (deleted) # fs/proc/procfs_syms.c 1.1 -> (deleted) # include/net/ipconfig.h 1.1 -> 1.2 # include/asm-ppc/bootx.h 1.1 -> 1.3 # arch/ppc/boot/of1275.h 1.1 -> 1.4 arch/ppc/boot/prep/of1275.h (moved) # drivers/scsi/aic7xxx/Makefile 1.1 -> 1.2 # include/asm-ppc/amigahw.h 1.1 -> 1.3 # arch/ppc/chrpboot/no_initrd.c 1.1 -> 1.5 arch/ppc/boot/common/no_initrd.c (moved) # arch/ppc/math-emu/mtfsfi.c 1.1 -> 1.3 # arch/i386/kernel/setup.c 1.11 -> 1.12 # Documentation/Configure.help 1.1.2.7 -> 1.27 # arch/ppc/kernel/semaphore.c 1.1.1.1 -> 1.9 # include/asm-ppc/walnut.h 1.1 -> 1.4 # arch/ppc/xmon/start_8xx.c 1.1 -> 1.4 # Documentation/DocBook/Makefile 1.3 -> 1.4 # fs/nfsd/vfs.c 1.2.1.1 -> 1.4 # drivers/scsi/aic7xxx/aic7xxx.reg 1.2 -> 1.3 # drivers/scsi/aic7xxx/aic7xxx.seq 1.2 -> 1.3 # arch/ppc/amiga/amiints.c 1.2 -> 1.4 # arch/ppc/mbxboot/misc.c 1.1 -> 1.5 arch/ppc/boot/mbx/misc.c (moved) # include/asm-ppc/time.h 1.1.1.1 -> 1.7 # fs/proc/root.c 1.1 -> 1.3 # arch/ppc/mbxboot/offset 1.1 -> (deleted) # drivers/cdrom/cdrom.c 1.5 -> 1.6 # drivers/net/gmac.c 1.1.1.1 -> 1.11 # include/asm-ppc/mmu.h 1.1.1.1 -> 1.5 # arch/ppc/chrpboot/piggyback.c 1.1 -> 1.5 arch/ppc/boot/utils/piggyback.c (moved) # fs/proc/array.c 1.3 -> 1.4 # arch/ppc/kernel/local_irq.h 1.1.1.1 -> 1.5 # include/asm-ppc/fads.h 1.1 -> 1.5 # arch/ppc/treeboot/Makefile 1.1 -> 1.4 arch/ppc/boot/tree/Makefile (moved) # arch/ppc/amiga/pcmcia.c 1.1 -> 1.3 # Makefile 1.19.1.15 -> 1.38 # drivers/scsi/aic7xxx/aic7xxx_linux_host.h 1.1 -> 1.2 # arch/ppc/kernel/irq.c 1.1.1.3 -> 1.19 # arch/ppc/8xx_io/enet.c 1.1.1.3 -> 1.8 # include/asm-ppc/uaccess.h 1.1 -> 1.3 # arch/ppc/kernel/prep_time.c 1.1 -> 1.4 # drivers/net/8139too.c 1.7 -> 1.8 # arch/ppc/mm/fault.c 1.1.1.3 -> 1.8 # arch/ppc/kernel/Makefile 1.1.2.2 -> 1.15 # include/asm-ppc/kgdb.h 1.1 -> 1.3 # arch/ppc/8260_io/commproc.c 1.1 -> 1.3 # arch/ppc/mbxboot/head.S 1.1 -> 1.5 arch/ppc/boot/mbx/head.S (moved) # arch/ppc/math-emu/mffs.c 1.1 -> 1.3 # arch/ppc/kernel/chrp_setup.c 1.1.1.5 -> 1.14 # drivers/net/Makefile 1.1.1.5 -> 1.12 # include/asm-ppc/semaphore.h 1.1.1.3 -> 1.13 # arch/ppc/kernel/misc.S 1.1.1.1 -> 1.14 # arch/ppc/math-emu/fnmadds.c 1.1 -> 1.3 # arch/ppc/kernel/prep_setup.c 1.1.1.4 -> 1.16 # drivers/net/3c509.c 1.3.1.3 -> 1.7 # drivers/net/acenic_firmware.h 1.2 -> 1.3 # arch/ppc/kernel/entry.S 1.1.1.1 -> 1.7 # drivers/sound/dmasound/dmasound.h 1.1 -> 1.2 # arch/ppc/kernel/xics.h 1.1 -> 1.3 # arch/ppc/boot/of1275.c 1.1 -> 1.4 arch/ppc/boot/prep/of1275.c (moved) # arch/ppc/mbxboot/Makefile 1.1 -> 1.3 arch/ppc/boot/mbx/Makefile (moved) # arch/ppc/math-emu/math.c 1.1 -> 1.3 # drivers/video/aty128fb.c 1.1.1.1 -> 1.5 # include/asm-ppc/stat.h 1.1 -> 1.3 # arch/ppc/mbxboot/pci.c 1.1 -> 1.4 arch/ppc/boot/mbx/pci.c (moved) # arch/ppc/math-emu/fdiv.c 1.1 -> 1.3 # arch/ppc/math-emu/fres.c 1.1 -> 1.3 # fs/buffer.c 1.9 -> 1.10 # arch/ppc/xmon/ansidecl.h 1.1 -> 1.3 # arch/ppc/math-emu/op-1.h 1.1 -> 1.3 # arch/ppc/math-emu/fdivs.c 1.1 -> 1.3 # include/asm-ppc/prom.h 1.1.1.1 -> 1.8 # include/asm-ppc/keylargo.h 1.1.1.1 -> 1.6 # arch/ppc/math-emu/fmadd.c 1.1 -> 1.3 # drivers/scsi/aic7xxx/aic7xxx_linux_pci.c 1.2 -> 1.3 # include/asm-ppc/spd8xx.h 1.1 -> (deleted) # drivers/video/offb.c 1.1.1.1 -> 1.4 # arch/ppc/boot/vreset.c 1.1.1.1 -> 1.7 arch/ppc/boot/prep/vreset.c (moved) # net/ipv4/fib_rules.c 1.1 -> 1.2 # arch/ppc/coffboot/crt0.S 1.1 -> (deleted) # arch/ppc/kernel/ppc_ksyms.c 1.1.1.3 -> 1.27 # fs/proc/Makefile 1.1 -> 1.2 # include/asm-ppc/floppy.h 1.1 -> 1.3 # arch/ppc/boot/kbd.c 1.1 -> 1.5 arch/ppc/boot/prep/kbd.c (moved) # drivers/video/clgenfb.c 1.1.1.2 -> 1.5 # include/asm-ppc/fcntl.h 1.1 -> 1.3 # arch/ppc/coffboot/rs6000.h 1.1 -> 1.5 arch/ppc/boot/include/rs6000.h (moved) # arch/ppc/xmon/setjmp.c 1.1 -> 1.3 # drivers/video/atyfb.c 1.1.1.2 -> 1.4 # drivers/scsi/aic7xxx/aic7xxx.h 1.1 -> 1.2 # arch/ppc/mbxboot/m8260_tty.c 1.1 -> 1.5 arch/ppc/boot/mbx/m8260_tty.c (moved) # arch/ppc/kernel/open_pic.c 1.1.2.2 -> 1.17 # arch/ppc/kernel/error_log.c 1.1 -> (deleted) # arch/ppc/math-emu/fmsubs.c 1.1 -> 1.3 # arch/ppc/math-emu/soft-fp.h 1.1 -> 1.3 # arch/ppc/8xx_io/commproc.h 1.2.1.1 -> 1.6 # arch/ppc/treeboot/elf.pl 1.1 -> 1.4 arch/ppc/boot/utils/elf.pl (moved) # arch/ppc/math-emu/fctiw.c 1.1 -> 1.3 # include/asm-ppc/amigaints.h 1.1 -> 1.3 # include/asm-ppc/md.h 1.1 -> 1.3 # arch/ppc/kernel/find_name.c 1.1 -> 1.3 # arch/ppc/math-emu/mtfsb0.c 1.1 -> 1.3 # arch/ppc/configs/TQM850L_defconfig 1.1 -> (deleted) # include/asm-ppc/bitops.h 1.1 -> 1.4 # include/asm-ppc/sockios.h 1.1 -> 1.3 # arch/ppc/lib/string.S 1.1 -> 1.3 # arch/ppc/coffboot/ld.script 1.1 -> 1.2 arch/ppc/boot/pmac/ld.script (moved) # drivers/net/dmfe.c 1.8 -> 1.9 # drivers/scsi/sym53c8xx_defs.h 1.2 -> 1.3 # arch/ppc/configs/TQM860L_defconfig 1.1 -> (deleted) # include/asm-ppc/hw_irq.h 1.1.1.1 -> 1.7 # include/asm-ppc/signal.h 1.1 -> 1.3 # arch/ppc/lib/strcase.c 1.1 -> 1.3 # drivers/usb/hid.c 1.1.1.2 -> 1.4 # include/asm-i386/system.h 1.3 -> 1.4 # arch/ppc/kernel/ppc8xx_pic.h 1.1 -> 1.4 # arch/ppc/lib/checksum.S 1.1 -> 1.3 # arch/ppc/coffboot/hack-coff.c 1.1 -> 1.6 arch/ppc/boot/utils/hack-coff.c (moved) # arch/ppc/coffboot/chrpmain.c 1.1 -> 1.6 arch/ppc/boot/pmac/chrpmain.c (moved) # arch/ppc/math-emu/sfp-machine.h 1.1 -> 1.3 # include/asm-ppc/board.h 1.1 -> 1.3 # arch/ppc/kernel/ptrace.c 1.1 -> 1.3 # arch/ppc/math-emu/fsqrts.c 1.1 -> 1.3 # arch/ppc/kernel/head.S 1.1.2.2 -> 1.13 # arch/ppc/configs/oak_defconfig 1.1.1.1 -> 1.5 # include/asm-ppc/hydra.h 1.1 -> 1.3 # arch/ppc/mbxboot/m8xx_tty.c 1.1 -> 1.5 arch/ppc/boot/mbx/m8xx_tty.c (moved) # fs/binfmt_elf.c 1.4 -> 1.6 # arch/ppc/kernel/pmac_time.c 1.1.1.1 -> 1.6 # arch/ppc/math-emu/fmadds.c 1.1 -> 1.3 # arch/ppc/kernel/prom.c 1.1.2.2 -> 1.13 # arch/ppc/kernel/hashtable.S 1.1.1.1 -> 1.7 # arch/ppc/math-emu/fnabs.c 1.1 -> 1.3 # arch/ppc/8260_io/uart.c 1.2 -> 1.4 # drivers/sound/ymfpci.c 1.9 -> 1.10 # drivers/macintosh/macserial.c 1.1.1.1 -> 1.4 # net/ipv4/Config.in 1.1 -> 1.2 # arch/ppc/kernel/ppc4xx_pic.c 1.1 -> 1.3 # arch/ppc/coffboot/dummy.c 1.1 -> 1.4 arch/ppc/boot/pmac/dummy.c (moved) # include/asm-ppc/statfs.h 1.1 -> 1.3 # arch/ppc/chrpboot/mknote.c 1.1 -> 1.5 arch/ppc/boot/utils/mknote.c (moved) # arch/ppc/math-emu/fsub.c 1.1 -> 1.3 # arch/ppc/math-emu/single.h 1.1 -> 1.3 # drivers/scsi/sym53c8xx.c 1.1.1.5 -> 1.9 # drivers/net/mace.c 1.1.1.3 -> 1.7 # drivers/pci/pci.ids 1.2.1.1 -> 1.4 # Documentation/powerpc/zImage_layout.txt 1.1.1.1 -> 1.4 # drivers/net/gmac.h 1.1 -> 1.5 # arch/ppc/math-emu/fmr.c 1.1 -> 1.3 # arch/ppc/chrpboot/Makefile 1.1.1.1 -> 1.7 arch/ppc/boot/chrp/Makefile (moved) # drivers/net/pcmcia/hermes.h 1.3 -> 1.4 drivers/net/wireless/hermes.h (moved) # Documentation/DocBook/kernel-api.tmpl 1.3 -> 1.4 # arch/ppc/kernel/checks.c 1.2 -> 1.4 # include/linux/pci_ids.h 1.1.1.4 -> 1.10 # arch/ppc/kernel/residual.c 1.2 -> 1.4 # arch/ppc/coffboot/Makefile 1.1.1.1 -> 1.6 arch/ppc/boot/pmac/Makefile (moved) # arch/ppc/amiga/amisound.c 1.1 -> 1.3 # arch/ppc/math-emu/stfs.c 1.1 -> 1.3 # net/ipv4/tcp.c 1.6 -> 1.7 # net/sunrpc/svcsock.c 1.2.1.3 -> 1.6 # BitKeeper/etc/logging_ok 1.1.1.6 -> 1.25 # include/asm-ppc/tqm8xx.h 1.1.1.1 -> (deleted) # include/asm-ppc/bugs.h 1.1 -> 1.3 # arch/ppc/treeboot/irSect.h 1.1 -> 1.4 arch/ppc/boot/tree/irSect.h (moved) # include/asm-ppc/dma.h 1.1.2.1 -> 1.6 # include/asm-ppc/softirq.h 1.1 -> 1.3 # arch/ppc/coffboot/no_initrd.c 1.1 -> (deleted) # arch/ppc/kernel/m8260_setup.c 1.1.1.4 -> 1.13 # include/asm-ppc/kmap_types.h 1.1.1.1 -> 1.4 # include/asm-i386/pci.h 1.2 -> 1.3 # include/asm-ppc/module.h 1.1 -> 1.3 # drivers/Makefile 1.1 -> 1.2 # include/linux/rwsem.h 1.4.1.1 -> 1.6 # kernel/ptrace.c 1.1.1.1 -> 1.3 # arch/ppc/kernel/traps.c 1.1.1.3 -> 1.9 # Documentation/powerpc/sound.txt 1.1.1.1 -> 1.3 # arch/ppc/configs/ibmchrp_defconfig 1.1 -> (deleted) # include/asm-ppc/sigcontext.h 1.1 -> 1.3 # arch/ppc/configs/walnut_defconfig 1.1.1.1 -> 1.5 # arch/ppc/kernel/ppc-stub.c 1.1 -> 1.3 # arch/ppc/kernel/qspan_pci.c 1.1 -> 1.3 # drivers/block/ll_rw_blk.c 1.1.1.12 -> 1.15 # arch/ppc/8260_io/fcc_enet.c 1.1.1.3 -> 1.5 # include/asm-ppc/errno.h 1.1 -> 1.5 # include/asm-ppc/string.h 1.1 -> 1.3 # arch/ppc/math-emu/frsqrte.c 1.1 -> 1.3 # drivers/pci/Makefile 1.1.1.1 -> 1.4 # mm/vmscan.c 1.7 -> 1.8 # drivers/scsi/aic7xxx/aic7xxx_inline.h 1.1 -> 1.2 # fs/ncpfs/dir.c 1.3.1.1 -> 1.5 # drivers/macintosh/Makefile 1.1.1.1 -> 1.4 # arch/ppc/math-emu/lfs.c 1.1 -> 1.3 # include/asm-ppc/parport.h 1.1 -> (deleted) # arch/ppc/kernel/ppc_asm.h 1.1.1.1 -> 1.7 # arch/ppc/kernel/feature.c 1.1.1.1 -> 1.7 # include/asm-ppc/bseip.h 1.1 -> 1.4 # arch/ppc/kernel/ppc8260_pic.c 1.1 -> 1.3 # arch/ppc/math-emu/fsel.c 1.1 -> 1.3 # drivers/scsi/scsi_lib.c 1.4 -> 1.5 # include/asm-ppc/segment.h 1.1.1.1 -> 1.5 # arch/ppc/kernel/pmac_nvram.c 1.1 -> 1.3 # arch/ppc/xmon/ppc.h 1.1 -> 1.3 # arch/ppc/kernel/pci.c 1.1.1.3 -> 1.16 # include/asm-ppc/byteorder.h 1.1 -> 1.3 # include/asm-ppc/namei.h 1.1 -> 1.3 # include/asm-ppc/xor.h 1.1 -> 1.3 # arch/ppc/treeboot/irSect.c 1.1 -> 1.4 arch/ppc/boot/tree/irSect.c (moved) # arch/ppc/math-emu/double.h 1.1 -> 1.3 # drivers/net/ncr885e.h 1.1 -> (deleted) # arch/ppc/math-emu/fnmsubs.c 1.1 -> 1.3 # drivers/net/pcmcia/Config.in 1.3 -> 1.4 # arch/ppc/mm/mem_pieces.h 1.1 -> 1.3 # arch/ppc/boot/ns16550.h 1.1 -> (deleted) # arch/ppc/coffboot/string.S 1.1 -> 1.6 arch/ppc/boot/common/string.S (moved) # arch/ppc/treeboot/mkirimg 1.1 -> 1.5 arch/ppc/boot/utils/mkirimg (moved) # drivers/sound/dmasound/dmasound_awacs.c 1.1.1.1 -> 1.6 # include/asm-ppc/hardirq.h 1.1.1.1 -> 1.5 # arch/ppc/kernel/galaxy_pci.c 1.1.1.1 -> 1.5 # arch/ppc/configs/est8260_defconfig 1.1.1.1 -> 1.5 # arch/ppc/coffboot/piggyback.c 1.1 -> (deleted) # arch/ppc/math-emu/stfd.c 1.1 -> 1.3 # arch/ppc/8xx_io/Config.in 1.1.1.1 -> 1.4 # arch/ppc/amiga/ints.c 1.1 -> 1.3 # arch/ppc/xmon/privinst.h 1.1 -> 1.3 # include/asm-ppc/cpm_8260.h 1.1.1.1 -> 1.5 # include/asm-ppc/mman.h 1.1.1.1 -> 1.5 # include/asm-ppc/keyboard.h 1.1 -> 1.4 # arch/ppc/mbxboot/qspan_pci.c 1.1 -> 1.4 arch/ppc/boot/mbx/qspan_pci.c (moved) # arch/ppc/mm/4xx_tlb.c 1.1 -> 1.3 # arch/ppc/boot/iso_font.h 1.1 -> 1.4 arch/ppc/boot/prep/iso_font.h (moved) # drivers/net/pcnet32.c 1.1.1.6 -> 1.9 # arch/ppc/Makefile 1.1.1.1 -> 1.13 # arch/ppc/chrpboot/misc.S 1.1 -> 1.4 arch/ppc/boot/chrp/misc.S (moved) # arch/sparc64/kernel/pci_psycho.c 1.6 -> 1.7 # drivers/scsi/aic7xxx/aic7xxx_seq.h 1.1 -> 1.2 # include/asm-ppc/cache.h 1.1 -> 1.3 # drivers/sound/dmasound/Makefile 1.1 -> 1.2 # arch/ppc/math-emu/op-4.h 1.1 -> 1.3 # drivers/scsi/sr.c 1.3.1.2 -> 1.6 # arch/ppc/kernel/ppc_htab.c 1.1.1.1 -> 1.5 # arch/ppc/math-emu/op-2.h 1.1 -> 1.3 # Documentation/networking/8139too.txt 1.4 -> 1.5 # drivers/net/pcmcia/Makefile 1.3 -> 1.4 # Documentation/powerpc/smp.txt 1.1.1.1 -> 1.3 # drivers/char/mxser.c 1.2 -> 1.3 # drivers/sound/dmasound/dmasound_core.c 1.1.1.1 -> 1.5 # net/ipv4/ipconfig.c 1.2 -> 1.3 # include/asm-ppc/ioctl.h 1.1 -> 1.3 # arch/ppc/mm/extable.c 1.1 -> 1.3 # arch/ppc/kernel/head_4xx.S 1.1 -> 1.3 # arch/ppc/treeboot/crt0.S 1.1 -> (deleted) # include/asm-ppc/ivms8.h 1.1 -> (deleted) # arch/ppc/kernel/prep_pci.c 1.1.1.3 -> 1.14 # include/asm-ppc/a.out.h 1.1 -> 1.3 # include/asm-ppc/pnp.h 1.1 -> 1.3 # arch/ppc/math-emu/fabs.c 1.1 -> 1.3 # arch/ppc/configs/power3_defconfig 1.1 -> (deleted) # include/asm-ppc/residual.h 1.1 -> 1.3 # include/asm-ppc/rpxlite.h 1.1 -> 1.5 # arch/ppc/kernel/ppc8260_pic.h 1.1 -> 1.4 # arch/ppc/boot/size 1.1 -> 1.2 arch/ppc/boot/utils/size (moved) # arch/ppc/math-emu/udivmodti4.c 1.1 -> 1.3 # arch/ppc/kernel/m8xx_setup.c 1.1.1.4 -> 1.14 # net/ipv4/af_inet.c 1.2 -> 1.3 # include/asm-ppc/tlb.h 1.1 -> (deleted) # arch/ppc/kernel/pmac_pci.c 1.1.1.2 -> 1.11 # arch/ppc/configs/SPD823TS_defconfig 1.1 -> (deleted) # arch/ppc/configs/TQM823L_defconfig 1.1 -> (deleted) # include/asm-ppc/spinlock.h 1.1 -> 1.3 # arch/ppc/math-emu/fadd.c 1.1 -> 1.3 # arch/ppc/math-emu/fctiwz.c 1.1 -> 1.3 # drivers/net/eql.c 1.4 -> 1.5 # arch/ppc/boot/Makefile 1.1.2.1 -> 1.12 arch/ppc/boot/prep/Makefile (moved) # include/asm-ppc/current.h 1.1 -> 1.3 # arch/ppc/kernel/xics.c 1.1 -> 1.3 # arch/ppc/kernel/walnut_setup.h 1.1 -> 1.3 # arch/ppc/mbxboot/iic.c 1.1 -> 1.5 arch/ppc/boot/mbx/iic.c (moved) # arch/ppc/xmon/adb.c 1.1 -> 1.3 # include/linux/mmzone.h 1.1.1.1 -> 1.3 # include/asm-ppc/highmem.h 1.1.1.1 -> 1.5 # include/asm-ppc/user.h 1.1 -> 1.3 # arch/ppc/kernel/syscalls.c 1.2 -> 1.5 # arch/ppc/kernel/softemu8xx.c 1.1.1.2 -> 1.6 # include/asm-ppc/ucontext.h 1.1 -> 1.3 # include/asm-ppc/oak.h 1.1 -> 1.4 # drivers/macintosh/macserial.h 1.1.1.1 -> 1.4 # include/asm-ppc/delay.h 1.1.1.1 -> 1.5 # include/asm-ppc/types.h 1.1 -> 1.3 # include/asm-ppc/rpxclassic.h 1.1 -> 1.5 # drivers/net/bmac.h 1.1 -> 1.3 # arch/ppc/coffboot/start.c 1.1 -> 1.5 arch/ppc/boot/pmac/start.c (moved) # (new) -> 1.1 drivers/net/wireless/Makefile # (new) -> 1.2 arch/ppc/boot/utils/sioffset # (new) -> 1.1 arch/ppc/kernel/pci_auto.c # (new) -> 1.3 include/asm-ppc/tlb.h # (new) -> 1.1 arch/ppc/boot/images/Makefile # (new) -> 1.2 arch/ppc/configs/gemini_defconfig # (new) -> 1.1 drivers/net/wireless/orinoco.h # (new) -> 1.1 arch/ppc/kernel/mvme5100_pci.c # (new) -> 1.1 arch/ppc/kernel/prpmc750_pci.c # (new) -> 1.2 arch/ppc/configs/power3_defconfig # (new) -> 1.1 arch/ppc/boot/spruce/Makefile # (new) -> 1.1 BitKeeper/etc/COPYING # (new) -> 1.1 arch/ppc/boot/utils/mkpmon.c # (new) -> 1.1 arch/ppc/boot/utils/mkbugboot.c # (new) -> 1.1 include/asm-ppc/spruce.h # (new) -> 1.1 arch/ppc/kernel/cpc710.h # (new) -> 1.2 arch/ppc/configs/ibmchrp_defconfig # (new) -> 1.3 drivers/net/ncr885e.h # (new) -> 1.1 arch/ppc/kernel/cpc700.h # (new) -> 1.3 arch/ppc/configs/SPD823TS_defconfig # (new) -> 1.1 drivers/net/wireless/airport.c # (new) -> 1.1 arch/ppc/boot/pp3/Makefile # (new) -> 1.1 arch/ppc/configs/k2_defconfig # (new) -> 1.1 arch/ppc/kernel/prpmc750_setup.c # (new) -> 1.1 Documentation/powerpc/todc.txt # (new) -> 1.2 arch/ppc/boot/utils/sisize # (new) -> 1.5 BitKeeper/triggers/post-incoming # (new) -> 1.1 arch/ppc/configs/prpmc750_defconfig # (new) -> 1.1 arch/ppc/configs/mvme5100_defconfig # (new) -> 1.2 BitKeeper/etc/gone # (new) -> 1.3 include/asm-ppc/spd8xx.h # (new) -> 1.1 arch/ppc/configs/spruce_defconfig # (new) -> 1.3 arch/ppc/kernel/gemini_prom.S # (new) -> 1.1 include/asm-ppc/mvme5100_serial.h # (new) -> 1.3 arch/ppc/configs/TQM860L_defconfig # (new) -> 1.1 arch/ppc/boot/pp3/head.S # (new) -> 1.1 arch/ppc/kernel/spruce_pci.c # (new) -> 1.1 arch/ppc/boot/spruce/head.S # (new) -> 1.2 arch/ppc/kernel/spruce_setup.c # (new) -> 1.1 arch/ppc/kernel/todc_time.c # (new) -> 1.2 arch/ppc/boot/common/misc-common.c # (new) -> 1.1 arch/ppc/kernel/m1543c.h # (new) -> 1.1 drivers/net/wireless/Config.in # (new) -> 1.1 arch/ppc/kernel/prpmc750.h # (new) -> 1.1 linux/i2c-algo-8xx.h # (new) -> 1.1 include/asm-ppc/prpmc750_serial.h # (new) -> 1.3 arch/ppc/configs/SM850_defconfig # (new) -> 1.1 include/asm-ppc/ppc4xx.h # (new) -> 1.1 arch/ppc/kernel/spruce_pic.c # (new) -> 1.3 include/asm-ppc/gemini_serial.h # (new) -> 1.3 drivers/net/ncr885e.c # (new) -> 1.3 include/asm-ppc/parport.h # (new) -> 1.1 arch/ppc/boot/lib/Makefile # (new) -> 1.3 include/asm-ppc/gemini.h # (new) -> 1.3 arch/ppc/kernel/error_log.h # (new) -> 1.3 arch/ppc/configs/TQM823L_defconfig # (new) -> 1.1 arch/ppc/boot/spruce/misc.c # (new) -> 1.1 include/asm-ppc/spruce_serial.h # (new) -> 1.3 arch/ppc/boot/utils/Makefile # (new) -> 1.1 arch/ppc/kernel/mvme5100.h # (new) -> 1.1 drivers/net/wireless/orinoco.c # (new) -> 1.2 arch/ppc/configs/IVMS8_defconfig # (new) -> 1.4 arch/ppc/boot/utils/mksimage.c # (new) -> 1.3 drivers/net/ncr885_debug.h # (new) -> 1.1 arch/ppc/kernel/ppc_stubs.c # (new) -> 1.2 arch/ppc/boot/common/Makefile # (new) -> 1.4 arch/ppc/kernel/error_log.c # (new) -> 1.3 include/asm-ppc/ivms8.h # (new) -> 1.5 arch/ppc/boot/Makefile # (new) -> 1.1 arch/ppc/kernel/mvme5100_setup.c # (new) -> 1.4 include/asm-ppc/rwsem.h # (new) -> 1.1 arch/ppc/kernel/k2_pic.c # (new) -> 1.1 include/asm-ppc/ppc4xx_serial.h # (new) -> 1.3 arch/ppc/kernel/proc_rtas.c # (new) -> 1.1 arch/ppc/kernel/pplus.h # (new) -> 1.3 arch/ppc/kernel/gemini_pci.c # (new) -> 1.1 arch/ppc/kernel/k2.h # (new) -> 1.1 arch/ppc/kernel/k2_pci.c # (new) -> 1.1 arch/ppc/kernel/pci_auto.h # (new) -> 1.1 arch/ppc/kernel/todc.h # (new) -> 1.1 arch/ppc/kernel/pplus_common.c # (new) -> 1.4 include/asm-ppc/tqm8xx.h # (new) -> 1.1 drivers/net/wireless/README # (new) -> 1.1 arch/ppc/boot/pmon/head.S # (new) -> 1.1 include/asm-ppc/rpxhiox.h # (new) -> 1.1 arch/ppc/boot/common/misc-one.c # (new) -> 1.5 arch/ppc/kernel/gemini_setup.c # (new) -> 1.5 arch/ppc/kernel/open_pic_defs.h # (new) -> 1.1 drivers/net/wireless/todo.txt # (new) -> 1.3 arch/ppc/configs/TQM850L_defconfig # (new) -> 1.1 arch/ppc/boot/pmon/Makefile # (new) -> 1.1 arch/ppc/kernel/k2_setup.c # # The following is the BitKeeper ChangeSet Log # -------------------------------------------- # 01/05/03 cort@cort.fsmlabs.com 1.2.2.16 # bk-work-patch-patch-2.4.5-pre1.28559.new # -------------------------------------------- # 01/05/03 cort@cort.fsmlabs.com 1.123.1.5 # Merge cort.fsmlabs.com:/home/sys/linux_2_4 # into cort.fsmlabs.com:/home/sys/linuxppc_2_4 # -------------------------------------------- # 01/05/03 cort@cort.fsmlabs.com 1.128.1.1 # Merge cort.fsmlabs.com:/home/sys/linuxppc_2_4 # into cort.fsmlabs.com:/home/sys/linuxppc_2_4_devel # -------------------------------------------- # 01/05/03 cort@cort.fsmlabs.com 1.132 # Merge hq:/home/bk/linuxppc_2_4_devel # into cort.fsmlabs.com:/home/sys/linuxppc_2_4_devel # -------------------------------------------- # 01/05/04 cort@cort.fsmlabs.com 1.133 # Change permissions on the scripts in the boot/utils/ directory # -------------------------------------------- # 01/05/04 cort@cort.fsmlabs.com 1.134 # PReP boot serial changes from Tom. # -------------------------------------------- # 01/05/04 cort@cort.fsmlabs.com 1.135 # Move spruce board support over from _2_5 tree. # -------------------------------------------- # 01/05/04 cort@cort.fsmlabs.com 1.136 # New files to go along with the spruce merge. # -------------------------------------------- # 01/05/05 benh@zion.wanadoo.fr 1.123.1.6 # PowerMac updates (better Titanium powerbook support, fix BootX booting,...) # -------------------------------------------- # 01/05/06 benh@zion.wanadoo.fr 1.123.1.7 # gcc3 updates & mmap2 implementation (Franz Sirl) # -------------------------------------------- # 01/05/07 cort@cort.fsmlabs.com 1.137 # Merge recent _2_4 changes into _2_4_devel # -------------------------------------------- # 01/05/07 cort@ftsoj.fsmlabs.com 1.123.2.1 # Set do_get_fast_time = do_gettimeofday # -------------------------------------------- # 01/05/07 cort@ftsoj.fsmlabs.com 1.123.2.2 # Fix gemini build - from Val. # -------------------------------------------- # 01/05/08 cort@ftsoj.fsmlabs.com 1.123.1.8 # Merge hq:/home/bk/linuxppc_2_4 into ftsoj.fsmlabs.com:/sys/linuxppc_2_4 # -------------------------------------------- # 01/05/08 cort@ftsoj.fsmlabs.com 1.131.1.1 # Merge ftsoj.fsmlabs.com:/sys/linuxppc_2_4 # into ftsoj.fsmlabs.com:/sys/linuxppc_2_4_devel # -------------------------------------------- # 01/05/08 cort@ftsoj.fsmlabs.com 1.138 # Merge hq.fsmlabs.com:/home/bk/linuxppc_2_4_devel # into ftsoj.fsmlabs.com:/sys/linuxppc_2_4_devel # -------------------------------------------- # 01/05/09 trini@opus.bloom.county 1.123.1.9 # Update the ignore file so it really does ignore the new aic7xxx files. # -------------------------------------------- # 01/05/09 trini@opus.bloom.county 1.123.1.10 # Update all of the defconfigs. # -------------------------------------------- # 01/05/09 trini@bill-the-cat.bloom.county 1.139 # Merge bill-the-cat.bloom.county:/home/trini/work/kernel/pristine/linuxppc_2_4 # into bill-the-cat.bloom.county:/home/trini/work/kernel/pristine/linuxppc_2_4_devel # -------------------------------------------- # 01/05/09 trini@opus.bloom.county 1.140 # Add BI_CMD_LINE to PowerMac stand-alone images. Fix code in # identify_machine to not try and overwrite it. # -------------------------------------------- # 01/05/09 cort@ftsoj.fsmlabs.com 1.141 # Mvista copyright notice in the spruce boot messages. # -------------------------------------------- # 01/05/09 cort@ftsoj.fsmlabs.com 1.142 # Boot fixups. # -------------------------------------------- # 01/05/09 cort@ftsoj.fsmlabs.com 1.143 # Add SBS K2 board port. # -------------------------------------------- # 01/05/09 cort@ftsoj.fsmlabs.com 1.123.1.11 # Changes to add support for RTC from Tom. # -------------------------------------------- # 01/05/09 cort@ftsoj.fsmlabs.com 1.144 # Add todc.txt and # -------------------------------------------- # 01/05/09 cort@ftsoj.fsmlabs.com 1.145 # New files for the k2 and todc changes # -------------------------------------------- # 01/05/09 cort@ftsoj.fsmlabs.com 1.146 # 2_4_devel-i2c.patch # -------------------------------------------- # 01/05/09 cort@ftsoj.fsmlabs.com 1.147 # 1-mvme5100.patch # -------------------------------------------- # 01/05/09 cort@ftsoj.fsmlabs.com 1.148 # 2-prpmc750.patch # -------------------------------------------- # 01/05/09 cort@ftsoj.fsmlabs.com 1.149 # 3-machspec.patch # -------------------------------------------- # 01/05/09 cort@ftsoj.fsmlabs.com 1.150 # 4-sprucecons.patch # -------------------------------------------- # 01/05/10 trini@opus.bloom.county 1.151 # Update the ignore file wrt the new boot reorg. # -------------------------------------------- # 01/05/11 trini@opus.bloom.county 1.123.1.12 # Add devfs support to the swim3 driver, from Christiaan Welvaart # # -------------------------------------------- # 01/05/14 trini@opus.bloom.county 1.123.1.13 # Redo the xxx_config rules. Now to add another one, only the file has # to be added. Thanks to Dan Jacobowitz for help. # -------------------------------------------- # 01/05/14 trini@opus.bloom.county 1.123.1.14 # Ignore mksimage. # -------------------------------------------- # 01/05/15 paulus@tango.linuxcare.com.au 1.123.1.15 # small fix for chrpboot startup # -------------------------------------------- # 01/05/15 trini@opus.bloom.county 1.152 # Paulus recent fix, done by hand as chrpboot/crt0.S is gone. # -------------------------------------------- # 01/05/15 trini@opus.bloom.county 1.151.1.1 # Ooops. This shouldn't have been commited. # -------------------------------------------- # 01/05/15 trini@opus.bloom.county 1.153 # Merge opus.bloom.county:/home/trini/work/kernel/testing/linuxppc_2_4_devel # into opus.bloom.county:/home/trini/work/kernel/pristine/linuxppc_2_4_devel # -------------------------------------------- # 01/05/15 cort@ftsoj.fsmlabs.com 1.2.2.17 # bk-work-patch-patch-2.4.5-pre2.2883.new # -------------------------------------------- # 01/05/15 cort@ftsoj.fsmlabs.com 1.123.1.16 # Merge to 2.4.5-pre2 # -------------------------------------------- # 01/05/15 cort@ftsoj.fsmlabs.com 1.154 # Merge to 2.4.5-pre2 # -------------------------------------------- # diff -Nru a/BitKeeper/etc/gone b/BitKeeper/etc/gone --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/BitKeeper/etc/gone Wed May 16 06:00:33 2001 @@ -0,0 +1,2 @@ +include/linux/openpic.h +arch/ppc/coffboot/main.c diff -Nru a/BitKeeper/etc/ignore b/BitKeeper/etc/ignore --- a/BitKeeper/etc/ignore Wed May 16 06:00:18 2001 +++ b/BitKeeper/etc/ignore Wed May 16 06:00:18 2001 @@ -1 +1,76 @@ -BitKeeper/*/* +*.a +*.o +*.stamp +*.ver +.*.a.flags +.*.o.flags +.config +.config.old +.depend +.hdepend +.version +BitKeeper/etc/.cached_proxy +BitKeeper/etc/csets-in +BitKeeper/etc/csets-out +PENDING/* +System.map +arch/ppc/boot/images/miboot.image +arch/ppc/boot/images/sImage +arch/ppc/boot/images/vmlinux.* +arch/ppc/boot/images/zImage.* +arch/ppc/boot/images/zvmlinux* +arch/ppc/boot/mkprep +arch/ppc/boot/mksimage +arch/ppc/boot/sImage +arch/ppc/boot/utils/addnote +arch/ppc/boot/utils/coffboot +arch/ppc/boot/utils/hack-coff +arch/ppc/boot/utils/mkbugboot +arch/ppc/boot/utils/mknote +arch/ppc/boot/utils/mkprep +arch/ppc/boot/utils/piggyback +arch/ppc/boot/zImage +arch/ppc/boot/zvmlinux +arch/ppc/chrpboot/addnote +arch/ppc/chrpboot/piggyback +arch/ppc/chrpboot/zImage +arch/ppc/chrpboot/zImage.rs6k +arch/ppc/coffboot/coffboot +arch/ppc/coffboot/hack-coff +arch/ppc/coffboot/miboot.image +arch/ppc/coffboot/mknote +arch/ppc/coffboot/note +arch/ppc/coffboot/piggyback +arch/ppc/coffboot/vmlinux.coff +arch/ppc/coffboot/vmlinux.elf +arch/ppc/coffboot/vmlinux.gz +arch/ppc/coffboot/zImage +arch/ppc/kernel/checks +arch/ppc/kernel/ppc_defs.h +drivers/char/conmakehash +drivers/char/consolemap_deftbl.c +drivers/net/hamradio/soundmodem/gentbl +drivers/net/hamradio/soundmodem/sm_tbl_afsk1200.h +drivers/net/hamradio/soundmodem/sm_tbl_afsk2400_7.h +drivers/net/hamradio/soundmodem/sm_tbl_afsk2400_8.h +drivers/net/hamradio/soundmodem/sm_tbl_afsk2666.h +drivers/net/hamradio/soundmodem/sm_tbl_fsk9600.h +drivers/net/hamradio/soundmodem/sm_tbl_hapn4800.h +drivers/net/hamradio/soundmodem/sm_tbl_psk4800.h +drivers/pci/classlist.h +drivers/pci/devlist.h +drivers/pci/gen-devlist +drivers/scsi/aic7xxx/aicasm/aicasm +drivers/scsi/aic7xxx/aicasm/aicasm_gram.c +drivers/scsi/aic7xxx/aicasm/aicasm_scan.c +drivers/scsi/aic7xxx/aicasm/y.tab.h +include/asm +include/config/* +include/linux/autoconf.h +include/linux/compile.h +include/linux/modversions.h +include/linux/version.h +scripts/lxdialog/lxdialog +scripts/mkdep +scripts/split-include +vmlinux diff -Nru a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok --- a/BitKeeper/etc/logging_ok Wed May 16 06:00:24 2001 +++ b/BitKeeper/etc/logging_ok Wed May 16 06:00:24 2001 @@ -1,7 +1,22 @@ +benh@sawtooth.wanadoo.fr +benh@streumon.mipsys.com +benh@zion.wanadoo.fr +cort@cort.fsmlabs.com cort@ftsoj.fsmlabs.com -paulus@diego.linuxcare.com.au -paulus@argo.linuxcare.com.au -paulus@tango.linuxcare.com.au cort@hq.fsmlabs.com +danc@phong.az.mvista.com +dmalek@dp500.netx4.com +geert@callisto.of.borg +geert@tux.of.borg +geert@tux.sonytel.be +hozer@narn.drgw.net +mporter@beef.az.mvista.com +paulus@argo.canberra.net.au +paulus@argo.linuxcare.com.au paulus@argo.ozlabs.ibm.com.au -cort@cort.fsmlabs.com +paulus@diego.linuxcare.com.au +paulus@tango.linuxcare.com.au +tgall@vorlon.rchland.ibm.com +trini@entropy.crashing.org +trini@opus.bloom.county +trini@bill-the-cat.bloom.county diff -Nru a/BitKeeper/triggers/post-incoming b/BitKeeper/triggers/post-incoming --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/BitKeeper/triggers/post-incoming Wed May 16 06:00:33 2001 @@ -0,0 +1,12 @@ +#!/bin/sh + +REPO=`bk gethost`:`pwd` +if [ "$BK_STATUS" = OK -a -f BitKeeper/etc/csets-in -a `hostname` = "hq.fsmlabs.com" ] +then ( + echo ${USER}@"$@" + echo "" + bk changes -r`cat BitKeeper/etc/csets-in` -v + bk prs -d ":KEY:\n" -r+ ChangeSet + ) | mail -s "Incoming to $REPO" linuxppc-commit@fsmlabs.com +fi + diff -Nru a/CREDITS b/CREDITS --- a/CREDITS Wed May 16 06:00:16 2001 +++ b/CREDITS Wed May 16 06:00:16 2001 @@ -1126,13 +1126,11 @@ S: USA N: Benjamin Herrenschmidt -E: bh40@calva.net +E: benh@kernel.crashing.org E: benh@mipsys.com -D: PowerMac booter (BootX) -D: Additional PowerBook support -D: Apple "Core99" machines support (ibook,g4,...) -S: 22, rue des Marguettes -S: 75012 Paris +D: Various parts of PPC & PowerMac +S: 122, boulevard Baille +S: 13005 Marseille S: France N: Sebastian Hetze @@ -1731,6 +1729,8 @@ N: Paul Mackerras E: paulus@samba.org +D: PPP driver +D: Linux for PowerPC D: Linux port for PCI Power Macintosh N: Pat Mackinlay diff -Nru a/Documentation/Configure.help b/Documentation/Configure.help --- a/Documentation/Configure.help Wed May 16 06:00:20 2001 +++ b/Documentation/Configure.help Wed May 16 06:00:20 2001 @@ -5635,7 +5635,7 @@ Default: 253 Initial Bus Reset Settle Delay -CONFIG_AIC7XXX_RESET_DELAY +CONFIG_AIC7XXX_RESET_DELAY_MS The number of milliseconds to delay after an initial bus reset. The bus settle delay following all error recovery actions is dictated by the SCSI layer and is not affected by this value. @@ -11489,6 +11489,16 @@ (the one containing the directory /) cannot be a module, so saying M could be dangerous. If unsure, say N. +PReP residual data support +CONFIG_PREP_RESIDUAL + Some PReP systems have residual data passed to the kernel by the + firmware. This allows detection of memory size, devices present and + other useful pieces of information. Sometimes this information is not + present or incorrect. + + Unless you expect to boot on a PReP system, there is not need to select + yes. + /proc file system support CONFIG_PROC_FS This is a virtual file system providing information about the status @@ -12691,6 +12701,15 @@ If unsure, say N. +Use a non standard baud rate on serial console +CONFIG_SERIAL_CONSOLE_NONSTD + By default the serial console code assumes that all of the registers + for setting up the baud rate are set. In some cases, such as the IBM + Spruce boards, this is not the case. If you answer Y here, you can fill + in the desired baud rate to use at console (eg 9600). + + If unsure, say N. + Support for PowerMac serial ports CONFIG_MAC_SERIAL If you have Macintosh style serial ports (8 pin mini-DIN), say Y @@ -13204,6 +13223,14 @@ say M here and read Documentation/modules.txt. The module will be called msbusmouse.o. +Apple Desktop Bus support +CONFIG_ADB + Apple Desktop Bus (ADB) support is for support of devices which + are connected to the to an ADB port. ADB devices tend to have + 4 pins. If you have an Apple Macintosh prior to the iMac, or a + "Blue and White G3", you probably want to say Y here. Otherwise + say N. + Apple Desktop Bus mouse support CONFIG_ADBMOUSE Say Y here if you have this type of bus mouse (4 pin connector) as @@ -16249,22 +16276,57 @@ Processor Type CONFIG_6xx There are four types of PowerPC chips supported. The more common - types (601, 603, 604, 740, 750), the Motorola embedded versions - (821, 823, 850, 855, 860), the IBM embedded versions (403 and + types (601, 603, 604, 740, 750, 7400), the Motorola embedded versions + (821, 823, 850, 855, 860, 8260), the IBM embedded versions (403 and 405) and the high end 64 bit Power processors (Power 3, Power 4). - Unless you are building a kernel for one of the embedded - processor systems, or a 64 bit IBM RS/6000, choose 6xx. Note that - the kernel runs in 32-bit mode even on 64-bit chips. + Unless you are building a kernel for one of the embedded processor + systems, or a 64 bit IBM RS/6000, choose 6xx. Note that the kernel + runs in 32-bit mode even on 64-bit chips. Also note that because + the 82xx family has a 603e core, specific support for that chipset + is asked later on. + +Motorola MPC8260 CPM support +CONFIG_8260 + The MPC8260 CPM (Communications Processor Module) is a typically + embedded CPU made by Motorola. Selecting this option means that + you wish to build a kernel for a machine with specifically an 8260 + for a CPU. + + If in doubt, say N. + +Workarounds for PPC601 bugs +CONFIG_PPC601_SYNC_FIX + Some versions of the PPC601 (the first PowerPC chip) have bugs which + mean that extra synchronization instructions are required near certain + instructions, typically those that make major changes to the CPU state. + These extra instructions reduce performance slightly. If you say N + here, these extra instructions will not be included, resulting in a + kernel which will run faster but may not run at all on some systems + with the PPC601 chip. + + If in doubt, say Y here. Machine Type -CONFIG_PMAC +CONFIG_ALL_PPC Linux currently supports several different kinds of PowerPC-based machines: Apple Power Macintoshes and clones (such as the Motorola Starmax series), PReP (PowerPC Reference Platform) machines such as - the Motorola PowerStack, Amiga Power-Up systems (APUS), CHRP and the - embedded MBX boards from Motorola. Currently, a single kernel binary - only supports one type or the other. However, there is very early - work on support for CHRP, PReP and PowerMac's from a single binary. + the Motorola PowerStack, CHRP (Common Hardware Reference Platform), + the embedded MBX boards from Motorola and many others. Currently, + the default option is to build a kernel which works on the first + three. Support for other machines is currently incomplete. + +MVME5100 configured with an IPMC761 +CONFIG_MVME5100_IPMC761_PRESENT + The MVME5100 supports a special IPMC761 PMC module in PMC site 1. + This option enables the use of the onboard i8259 PIC and ISA I/O + to support the legacy peripherals on the module. + +Carrier Type +CONFIG_PRPMC_BASE + The PrPMC750 PPMC module is only a complete system if placed in + an appropriate PPMC carrier. This option selects one of two + COTS carriers offered for PPMCs. Power management support for PowerBooks CONFIG_PMAC_PBOOK @@ -16324,6 +16386,37 @@ an image of the device tree that the kernel copies from Open Firmware. If unsure, say Y here. +RTAS proc interface +CONFIG_PPC_RTAS + When you use this option, you will be able to use RTAS from + userspace. + + RTAS stands for RunTime Abstraction Services and should + provide a portable way to access and set system information. This is + commonly used on RS/6000 (pSeries) computers. + + You can access RTAS via the special proc filesystem entry rtas. + Don't confuse this rtas entry with the one in /proc/device-tree/rtas + which is readonly. + + If you don't know if you can use RTAS look into + /proc/device-tree/rtas. If there are some entries, it is very likely + that you will be able to use RTAS. + + You can do cool things with rtas. To print out information about + various sensors in the system, just do a + + $ cat /proc/rtas/sensors + + or if you power off your machine at night but want it running when + you enter your office at 7:45 am, do a + + # date -d 'tomorrow 7:30' +%s > /proc/rtas/poweron + + and shutdown. + + If unsure, say Y + MESH (Power Mac internal SCSI) support CONFIG_SCSI_MESH Many Power Macintoshes and clones have a MESH (Macintosh Enhanced @@ -16367,6 +16460,16 @@ which can be inserted in and removed from the running kernel whenever you want). If you want to compile it as a module, say M here and read Documentation/modules.txt. + +Use AAUI port instead of TP by default +CONFIG_MACE_AAUI_PORT + Some Apple machines (notably the Apple Network Server) which use the + MACE ethernet chip have an Apple AUI port (small 15-pin connector), + instead of an 8-pin RJ45 connector for twisted-pair ethernet. Say + Y here if you have such a machine. If unsure, say N. + The driver will default to AAUI on ANS anyway, and if you use it as + a module, you can provide the port_aaui=0|1 to force the driver + setting. BMAC (G3 ethernet) support CONFIG_BMAC diff -Nru a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile --- a/Documentation/DocBook/Makefile Wed May 16 06:00:20 2001 +++ b/Documentation/DocBook/Makefile Wed May 16 06:00:20 2001 @@ -95,6 +95,7 @@ $(TOPDIR)/kernel/pm.c \ $(TOPDIR)/kernel/ksyms.c \ $(TOPDIR)/kernel/kmod.c \ + $(TOPDIR)/kernel/module.c \ $(TOPDIR)/kernel/printk.c \ $(TOPDIR)/kernel/sched.c \ $(TOPDIR)/kernel/sysctl.c \ diff -Nru a/Documentation/DocBook/kernel-api.tmpl b/Documentation/DocBook/kernel-api.tmpl --- a/Documentation/DocBook/kernel-api.tmpl Wed May 16 06:00:23 2001 +++ b/Documentation/DocBook/kernel-api.tmpl Wed May 16 06:00:23 2001 @@ -140,8 +140,13 @@ - Module Loading + Module Support + Module Loading !Ekernel/kmod.c + + Inter Module support +!Ekernel/module.c + diff -Nru a/Documentation/networking/8139too.txt b/Documentation/networking/8139too.txt --- a/Documentation/networking/8139too.txt Wed May 16 06:00:25 2001 +++ b/Documentation/networking/8139too.txt Wed May 16 06:00:25 2001 @@ -185,6 +185,13 @@ Change History -------------- +Version 0.9.17 - May 7, 2001 + +* Fix chipset wakeup bug which prevent media connection for 8139B +* Print out "media is unconnected..." instead of + "partner ability 0000" + + Version 0.9.16 - April 14, 2001 * Complete MMIO audit, disable read-after-every-write diff -Nru a/Documentation/powerpc/00-INDEX b/Documentation/powerpc/00-INDEX --- a/Documentation/powerpc/00-INDEX Wed May 16 06:00:20 2001 +++ b/Documentation/powerpc/00-INDEX Wed May 16 06:00:20 2001 @@ -13,5 +13,8 @@ - EST SBC8260 board info sound.txt - info on sound support under Linux/PPC +todc.txt + - documentation for common support of mk48txx and mc146818 family of + realtime clocks zImage_layout.txt - info on the kernel images for Linux/PPC diff -Nru a/Documentation/powerpc/todc.txt b/Documentation/powerpc/todc.txt --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/Documentation/powerpc/todc.txt Wed May 16 06:00:33 2001 @@ -0,0 +1,53 @@ + Documentation for arch/ppc/kernel/todc_time.c + ============================================= + +Author: Mark A. Greer (mgreer@mvista.com) +Date: 3.5.2001 + +Last Change: 3.5.2001 + +arch/ppc/kernel/todc_time.c supports the mk48txx and mc146818 family of +Time-of-Day (todc)/RealTime Clocks (rtc). Its intent is to replace most or all +of the *_time.c files in arch/ppc/kernel that have very similar code. + +To hook into the routines of this file, do the following: + +- Add '#include "todc.h"' to your *_setup.c file. +- In your *_init() routine, set the 'todc_info' global to the address of the + 'todc_info_t' structure that matches your RTC chip. +- Set 'todc_info->nvram_as0', 'todc_info->nvram_as1' to the address of the + address strobe registers. If you have an MC146818 RTC on an ISA bus, the + default values should work fine. +- Set 'todc_info->nvram_data' to the address of the RTC data register. If you + have an MC146818 RTC on an ISA bus, the default value should work fine. +- Set 'ppc_md.time_init', 'ppc_md.set_rtc_time', and 'ppc_md.get_rtc_time' to + 'todc_time_init', 'todc_set_rtc_time', and 'todc_get_rtc_time', respectively. +- If you want to use the RTC to calibrate you decrementer, set + 'ppc_md.calibrate_decr' to 'todc_calibrate_decr'. + +There are 3 sets of pre-defined todc access register routines: +- 'todc_direct_read_val' and 'todc_direct_write_val' for direct access + (e.g., mk48txx whose NVRAM & RTC registers are directly mapped into the + physical address space of the processor); +- 'todc_m48txx_read_val' and 'todc_m48txx_write_val' for an mk48txx whose NVRAM + & RTC registers are accessed via address strobe & data registers; +- 'todc_mc146818_read_val' and 'todc_mc146818_write_val' for mc146818 RTC whose + registers are accessed via an address/data registers pair. + +To use one of these sets of access routines, set 'ppc_md.nvram_read_val' and +'ppc_md.nvram_write_val' to the appropriate values for your RTC and board +combination. + +For an example using a mk48txx, look at arch/ppc/kernel/mcpn765_setup.c; +for an example using a mc146818, look at arch/ppc/kernel/sandpoint_setup.c. + +If your board doesn't have a full 8 bits wired to AS0, you can change the +'as0_bits' in the 'todc_info_t' structure. See arch/ppc/kernel/menf1_setup.c +for an example. + +Adding support for other closely related RTC chips should be easy. To do so, +you simply add another 'todc_info_t' structure to the the beginning of +arch/ppc/kernel/todc_time.c and add another TODC_TYPE_xxx in +arch/ppc/kernel/todc.h. + +If you encounter problems, please email me at mgreer@mvista.com diff -Nru a/Documentation/sysrq.txt b/Documentation/sysrq.txt --- a/Documentation/sysrq.txt Wed May 16 06:00:18 2001 +++ b/Documentation/sysrq.txt Wed May 16 06:00:18 2001 @@ -29,7 +29,8 @@ You send a BREAK, then within 5 seconds a command key. Sending BREAK twice is interpreted as a normal BREAK. -On Mac - Press 'Keypad+-F13-' +On PowerPC - Press 'ALT - Print Screen (or F13) - , + Print Screen (or F13) - may suffice. On other - If you know of the key combos for other architectures, please let me know so I can add them to this section. diff -Nru a/MAINTAINERS b/MAINTAINERS --- a/MAINTAINERS Wed May 16 06:00:19 2001 +++ b/MAINTAINERS Wed May 16 06:00:19 2001 @@ -596,6 +596,11 @@ W: http://www.uni-mainz.de/~langm000/linux.html S: Maintained +IBM RS/6000 LINUX +P: Paul Mackerras +M: paulus@samba.org +S: Supported + IBM ServeRAID RAID DRIVER P: Keith Mitchell M: ipslinux@us.ibm.com @@ -780,12 +785,14 @@ LINUX FOR POWERPC P: Cort Dougan M: cort@fsmlabs.com +P: Paul Mackerras +M: paulus@samba.org W: http://www.fsmlabs.com/linuxppcbk.html -S: Maintained +S: Supported LINUX FOR POWER MACINTOSH -P: Paul Mackerras -M: paulus@samba.org +P: Benjamin Herrenschmidt +M: benh@kernel.crashing.org W: http://www.linuxppc.org/ L: linuxppc-dev@lists.linuxppc.org S: Maintained @@ -1052,7 +1059,7 @@ P: Paul Mackerras M: paulus@samba.org L: linux-ppp@vger.kernel.org -S: Maintained +S: Supported PPP OVER ETHERNET P: Michal Ostrowski diff -Nru a/Makefile b/Makefile --- a/Makefile Wed May 16 06:00:21 2001 +++ b/Makefile Wed May 16 06:00:21 2001 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 4 SUBLEVEL = 5 -EXTRAVERSION =-pre1 +EXTRAVERSION =-pre2 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) @@ -144,7 +144,6 @@ DRIVERS-$(CONFIG_ATM) += drivers/atm/atm.o DRIVERS-$(CONFIG_IDE) += drivers/ide/idedriver.o DRIVERS-$(CONFIG_SCSI) += drivers/scsi/scsidrv.o -DRIVERS-$(CONFIG_SCSI_AIC7XXX) += drivers/scsi/aic7xxx/aic7xxx_drv.o DRIVERS-$(CONFIG_IEEE1394) += drivers/ieee1394/ieee1394drv.o ifneq ($(CONFIG_CD_NO_IDESCSI)$(CONFIG_BLK_DEV_IDECD)$(CONFIG_BLK_DEV_SR)$(CONFIG_PARIDE_PCD),) @@ -161,7 +160,7 @@ DRIVERS-$(CONFIG_SBUS) += drivers/sbus/sbus_all.o DRIVERS-$(CONFIG_ZORRO) += drivers/zorro/driver.o DRIVERS-$(CONFIG_FC4) += drivers/fc4/fc4.a -DRIVERS-$(CONFIG_ALL_PPC) += drivers/macintosh/macintosh.o +DRIVERS-$(CONFIG_PPC) += drivers/macintosh/macintosh.o DRIVERS-$(CONFIG_MAC) += drivers/macintosh/macintosh.o DRIVERS-$(CONFIG_ISAPNP) += drivers/pnp/pnp.o DRIVERS-$(CONFIG_SGI_IP22) += drivers/sgi/sgi.a diff -Nru a/arch/alpha/defconfig b/arch/alpha/defconfig --- a/arch/alpha/defconfig Wed May 16 06:00:17 2001 +++ b/arch/alpha/defconfig Wed May 16 06:00:17 2001 @@ -286,7 +286,7 @@ # CONFIG_SCSI_AHA1740 is not set CONFIG_SCSI_AIC7XXX=y CONFIG_AIC7XXX_CMDS_PER_DEVICE=253 -CONFIG_AIC7XXX_RESET_DELAY=5000 +CONFIG_AIC7XXX_RESET_DELAY_MS=5000 # CONFIG_SCSI_ADVANSYS is not set # CONFIG_SCSI_IN2000 is not set # CONFIG_SCSI_AM53C974 is not set diff -Nru a/arch/i386/defconfig b/arch/i386/defconfig --- a/arch/i386/defconfig Wed May 16 06:00:19 2001 +++ b/arch/i386/defconfig Wed May 16 06:00:19 2001 @@ -441,7 +441,6 @@ # CONFIG_PCMCIA_XIRTULIP is not set CONFIG_NET_PCMCIA_RADIO=y CONFIG_PCMCIA_RAYCS=y -# CONFIG_PCMCIA_HERMES is not set # CONFIG_PCMCIA_NETWAVE is not set # CONFIG_PCMCIA_WAVELAN is not set # CONFIG_AIRONET4500_CS is not set diff -Nru a/arch/i386/kernel/pci-irq.c b/arch/i386/kernel/pci-irq.c --- a/arch/i386/kernel/pci-irq.c Wed May 16 06:00:17 2001 +++ b/arch/i386/kernel/pci-irq.c Wed May 16 06:00:17 2001 @@ -411,6 +411,7 @@ { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0, pirq_piix_get, pirq_piix_set }, { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371MX, pirq_piix_get, pirq_piix_set }, { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_0, pirq_piix_get, pirq_piix_set }, + { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82820FW_0, pirq_piix_get, pirq_piix_set }, { "ALI", PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, pirq_ali_get, pirq_ali_set }, diff -Nru a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c --- a/arch/i386/kernel/setup.c Wed May 16 06:00:20 2001 +++ b/arch/i386/kernel/setup.c Wed May 16 06:00:20 2001 @@ -127,6 +127,9 @@ unsigned int BIOS_revision; unsigned int mca_pentium_flag; +/* For PCI or other memory-mapped resources */ +unsigned long pci_mem_start = 0x10000000; + /* * Setup options */ @@ -1008,6 +1011,9 @@ /* request I/O space for devices used on all i[345]86 PCs */ for (i = 0; i < STANDARD_IO_RESOURCES; i++) request_resource(&ioport_resource, standard_io_resources+i); + + /* Tell the PCI layer not to allocate too close to the RAM area.. */ + pci_mem_start = ((max_low_pfn << PAGE_SHIFT) + 0xfffff) & ~0xfffff; #ifdef CONFIG_VT #if defined(CONFIG_VGA_CONSOLE) diff -Nru a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c --- a/arch/i386/kernel/traps.c Wed May 16 06:00:18 2001 +++ b/arch/i386/kernel/traps.c Wed May 16 06:00:18 2001 @@ -973,7 +973,7 @@ set_trap_gate(11,&segment_not_present); set_trap_gate(12,&stack_segment); set_trap_gate(13,&general_protection); - set_trap_gate(14,&page_fault); + set_intr_gate(14,&page_fault); set_trap_gate(15,&spurious_interrupt_bug); set_trap_gate(16,&coprocessor_error); set_trap_gate(17,&alignment_check); diff -Nru a/arch/i386/mm/fault.c b/arch/i386/mm/fault.c --- a/arch/i386/mm/fault.c Wed May 16 06:00:17 2001 +++ b/arch/i386/mm/fault.c Wed May 16 06:00:17 2001 @@ -117,6 +117,10 @@ /* get the address */ __asm__("movl %%cr2,%0":"=r" (address)); + /* It's safe to allow irq's after cr2 has been saved */ + if (regs->eflags & X86_EFLAGS_IF) + local_irq_enable(); + tsk = current; /* @@ -127,8 +131,12 @@ * be in an interrupt or a critical region, and should * only copy the information from the master page table, * nothing more. + * + * This verifies that the fault happens in kernel space + * (error_code & 4) == 0, and that the fault was not a + * protection error (error_code & 1) == 0. */ - if (address >= TASK_SIZE) + if (address >= TASK_SIZE && !(error_code & 5)) goto vmalloc_fault; mm = tsk->mm; @@ -224,7 +232,6 @@ bad_area: up_read(&mm->mmap_sem); -bad_area_nosemaphore: /* User mode accesses just cause a SIGSEGV */ if (error_code & 4) { tsk->thread.cr2 = address; @@ -329,24 +336,25 @@ int offset = __pgd_offset(address); pgd_t *pgd, *pgd_k; pmd_t *pmd, *pmd_k; + pte_t *pte_k; asm("movl %%cr3,%0":"=r" (pgd)); pgd = offset + (pgd_t *)__va(pgd); pgd_k = init_mm.pgd + offset; - if (!pgd_present(*pgd)) { - if (!pgd_present(*pgd_k)) - goto bad_area_nosemaphore; - set_pgd(pgd, *pgd_k); - return; - } - + if (!pgd_present(*pgd_k)) + goto no_context; + set_pgd(pgd, *pgd_k); + pmd = pmd_offset(pgd, address); pmd_k = pmd_offset(pgd_k, address); - - if (pmd_present(*pmd) || !pmd_present(*pmd_k)) - goto bad_area_nosemaphore; + if (!pmd_present(*pmd_k)) + goto no_context; set_pmd(pmd, *pmd_k); + + pte_k = pte_offset(pmd_k, address); + if (!pte_present(*pte_k)) + goto no_context; return; } } diff -Nru a/arch/ppc/8xx_io/Config.in b/arch/ppc/8xx_io/Config.in --- a/arch/ppc/8xx_io/Config.in Wed May 16 06:00:25 2001 +++ b/arch/ppc/8xx_io/Config.in Wed May 16 06:00:25 2001 @@ -18,12 +18,12 @@ fi bool 'Use Big CPM Ethernet Buffers' CONFIG_ENET_BIG_BUFFERS fi -bool 'Use SMC2 for UART' CONFIG_8xxSMC2 -if [ "$CONFIG_8xxSMC2" = "y" ]; then - bool 'Use Alternate SMC2 I/O (823/850)' CONFIG_8xx_ALTSMC2 - bool 'Use SMC2 for Console' CONFIG_8xx_CONS_SMC2 +bool 'Use SMC2 for UART' CONFIG_SMC2_UART +if [ "$CONFIG_SMC2_UART" = "y" ]; then + bool 'Use Alternate SMC2 I/O (823/850)' CONFIG_ALTSMC2 + bool 'Use SMC2 for Console' CONFIG_CONS_SMC2 fi -bool 'Enable SCC2 and SCC3 for UART' CONFIG_8xxSCC +bool 'Enable SCC2 and SCC3 for UART' CONFIG_USE_SCC_IO # This doesn't really belong here, but it is convenient to ask # 8xx specific questions. diff -Nru a/arch/ppc/8xx_io/uart.c b/arch/ppc/8xx_io/uart.c --- a/arch/ppc/8xx_io/uart.c Wed May 16 06:00:18 2001 +++ b/arch/ppc/8xx_io/uart.c Wed May 16 06:00:18 2001 @@ -55,17 +55,17 @@ */ # ifndef CONFIG_SERIAL_CONSOLE_PORT # ifdef CONFIG_SCC3_ENET -# ifdef CONFIG_8xx_CONS_SMC2 +# ifdef CONFIG_CONS_SMC2 # define CONFIG_SERIAL_CONSOLE_PORT 0 /* Console on SMC2 is 1st port */ # else # error "Can't use SMC1 for console with Ethernet on SCC3" # endif # else /* ! CONFIG_SCC3_ENET */ -# ifdef CONFIG_8xx_CONS_SMC2 /* Console on SMC2 */ +# ifdef CONFIG_CONS_SMC2 /* Console on SMC2 */ # define CONFIG_SERIAL_CONSOLE_PORT 1 # else /* Console on SMC1 */ # define CONFIG_SERIAL_CONSOLE_PORT 0 -# endif /* CONFIG_8xx_CONS_SMC2 */ +# endif /* CONFIG_CONS_SMC2 */ # endif /* CONFIG_SCC3_ENET */ # endif /* CONFIG_SERIAL_CONSOLE_PORT */ #endif /* CONFIG_SERIAL_CONSOLE */ @@ -134,15 +134,15 @@ { 0, 0, PROFF_SMC1, CPMVEC_SMC1, 0, 0 }, /* SMC1 ttyS0 */ #endif #if !defined(CONFIG_USB_MPC8xx) && !defined(CONFIG_USB_CLIENT_MPC8xx) -# ifdef CONFIG_8xxSMC2 +# ifdef CONFIG_SMC2_UART { 0, 0, PROFF_SMC2, CPMVEC_SMC2, 0, 1 }, /* SMC2 ttyS1 */ # endif -# ifdef CONFIG_8xxSCC +# ifdef CONFIG_USE_SCC_IO { 0, 0, PROFF_SCC2, CPMVEC_SCC2, 0, (NUM_IS_SCC | 1) }, /* SCC2 ttyS2 */ { 0, 0, PROFF_SCC3, CPMVEC_SCC3, 0, (NUM_IS_SCC | 2) }, /* SCC3 ttyS3 */ # endif #else /* CONFIG_USB_xxx */ -# ifdef CONFIG_8xxSCC +# ifdef CONFIG_USE_SCC_IO { 0, 0, PROFF_SCC3, CPMVEC_SCC3, 0, (NUM_IS_SCC | 2) }, /* SCC3 ttyS3 */ # endif #endif /* CONFIG_USB_xxx */ @@ -2533,7 +2533,7 @@ /* Configure SCC2, SCC3, and SCC4 instead of port A parallel I/O. */ -#ifdef CONFIG_8xxSCC +#ifdef CONFIG_USE_SCC_IO #ifndef CONFIG_MBX /* The "standard" configuration through the 860. */ @@ -2747,7 +2747,7 @@ * parallel I/O. On 823/850 these are on * port A for SMC2. */ -#ifndef CONFIG_8xx_ALTSMC2 +#ifndef CONFIG_ALTSMC2 iobits = 0xc0 << (idx * 4); cp->cp_pbpar |= iobits; cp->cp_pbdir &= ~iobits; diff -Nru a/arch/ppc/Makefile b/arch/ppc/Makefile --- a/arch/ppc/Makefile Wed May 16 06:00:25 2001 +++ b/arch/ppc/Makefile Wed May 16 06:00:25 2001 @@ -31,7 +31,7 @@ endif ifdef CONFIG_8xx -CFLAGS := $(CFLAGS) -mcpu=860 -I../8xx_io +CFLAGS := $(CFLAGS) -mcpu=860 endif ifdef CONFIG_PPC64BRIDGE @@ -65,10 +65,6 @@ endif MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot -MAKECOFFBOOT = $(MAKE) -C arch/$(ARCH)/coffboot -MAKECHRPBOOT = $(MAKE) -C arch/$(ARCH)/chrpboot -MAKEMBXBOOT = $(MAKE) -C arch/$(ARCH)/mbxboot -MAKETREEBOOT = $(MAKE) -C arch/$(ARCH)/treeboot ifdef CONFIG_8xx SUBDIRS += arch/ppc/8xx_io @@ -89,108 +85,24 @@ checks: @$(MAKE) -C arch/$(ARCH)/kernel checks -BOOT_TARGETS = zImage znetboot.initrd zImage.initrd +BOOT_TARGETS = zImage zImage.initrd znetboot znetboot.initrd -ifdef CONFIG_4xx -$(BOOT_TARGETS): $(CHECKS) vmlinux - @$(MAKETREEBOOT) $@ -endif - -ifdef CONFIG_8xx -$(BOOT_TARGETS): $(CHECKS) vmlinux - @$(MAKECOFFBOOT) $@ - @$(MAKEMBXBOOT) $@ -endif - -ifdef CONFIG_6xx -ifndef CONFIG_8260 -$(BOOT_TARGETS): $(CHECKS) vmlinux - @$(MAKECOFFBOOT) $@ - @$(MAKEBOOT) $@ - @$(MAKECHRPBOOT) $@ - -znetboot: $(CHECKS) vmlinux -ifdef CONFIG_ALL_PPC -ifdef CONFIG_SMP - cp -f vmlinux /tftpboot/vmlinux.smp -else - cp -f vmlinux /tftpboot/vmlinux -endif -endif - @$(MAKECOFFBOOT) $@ - @$(MAKEBOOT) $@ - @$(MAKECHRPBOOT) $@ -else -# 8260 is custom 6xx -$(BOOT_TARGETS): $(CHECKS) vmlinux - @$(MAKECOFFBOOT) $@ - @$(MAKEMBXBOOT) $@ -endif -endif - -ifdef CONFIG_PPC64BRIDGE $(BOOT_TARGETS): $(CHECKS) vmlinux - @$(MAKECOFFBOOT) $@ @$(MAKEBOOT) $@ - @$(MAKECHRPBOOT) $@ - -znetboot: $(CHECKS) vmlinux - cp -f vmlinux /tftpboot/vmlinux.64 - @$(MAKECOFFBOOT) $@ - @$(MAKEBOOT) $@ - @$(MAKECHRPBOOT) $@ -endif .PHONY: clean_config clean_config: rm -f .config arch/ppc/defconfig -pmac_config: clean_config - cp -f arch/ppc/configs/pmac_defconfig arch/ppc/defconfig - -prep_config: clean_config - cp -f arch/ppc/configs/prep_defconfig arch/ppc/defconfig - -chrp_config: clean_config - cp -f arch/ppc/configs/chrp_defconfig arch/ppc/defconfig - -common_config: clean_config - cp -f arch/ppc/configs/common_defconfig arch/ppc/defconfig - -mbx_config: clean_config - cp -f arch/ppc/configs/mbx_defconfig arch/ppc/defconfig - -apus_config: clean_config - cp -f arch/ppc/configs/apus_defconfig arch/ppc/defconfig - -oak_config: clean_config - cp -f arch/ppc/configs/oak_defconfig arch/ppc/defconfig - -walnut_config: clean_config - cp -f arch/ppc/configs/walnut_defconfig arch/ppc/defconfig - -rpxlite_config: clean_config - cp -f arch/ppc/configs/rpxlite_defconfig arch/ppc/defconfig - -rpxcllf_config: clean_config - cp -f arch/ppc/configs/rpxcllf_defconfig arch/ppc/defconfig - -bseip_config: clean_config - cp -f arch/ppc/configs/bseip_defconfig arch/ppc/defconfig - -est8260_config: clean_config - cp -f arch/ppc/configs/est8260_defconfig arch/ppc/defconfig +%_config: arch/ppc/configs/%_defconfig + rm -f .config arch/ppc/defconfig + cp -f arch/ppc/configs/$(@:config=defconfig) arch/ppc/defconfig archclean: rm -f arch/ppc/kernel/{mk_defs,ppc_defs.h,find_name,checks} - @$(MAKECOFFBOOT) clean @$(MAKEBOOT) clean - @$(MAKECHRPBOOT) clean - @$(MAKEMBXBOOT) clean - @$(MAKETREEBOOT) clean archmrproper: archdep: - $(MAKEBOOT) fastdep - $(MAKECHRPBOOT) fastdep + $(MAKEBOOT) dep diff -Nru a/arch/ppc/boot/Makefile b/arch/ppc/boot/Makefile --- a/arch/ppc/boot/Makefile Wed May 16 06:00:25 2001 +++ b/arch/ppc/boot/Makefile Wed May 16 06:00:34 2001 @@ -9,127 +9,96 @@ # Adapted for PowerPC by Gary Thomas # modified by Cort (cort@cs.nmt.edu) # + .c.s: $(CC) $(CFLAGS) -S -o $*.s $< .s.o: $(AS) -o $*.o $< .c.o: - $(CC) $(CFLAGS) -DINITRD_OFFSET=$(IOFF) -DINITRD_SIZE=$(ISZ) -DZIMAGE_OFFSET=$(ZOFF) -DZIMAGE_SIZE=$(ZSZ) -D__BOOTER__ -c -o $*.o $< + $(CC) $(CFLAGS) -c -o $*.o $< .S.s: $(CPP) $(AFLAGS) -traditional -o $*.o $< .S.o: $(CC) $(AFLAGS) -traditional -c -o $*.o $< -ZOFF = 0 -ZSZ = 0 -IOFF = 0 -ISZ = 0 +GZIP_FLAGS = -v9f + +CFLAGS := $(CPPFLAGS) -O2 -DSTDC_HEADERS -fno-builtin -D__BOOTER__ \ + -I$(TOPDIR)/arch/$(ARCH)/boot/include +AFLAGS += -D__BOOTER__ +OBJCOPY_ARGS = -O elf32-powerpc ifeq ($(CONFIG_SMP),y) -TFTPIMAGE=/tftpboot/zImage.prep.smp$(MSIZE) +TFTPSIMAGE=/tftpboot/sImage.smp else -TFTPIMAGE=/tftpboot/zImage.prep$(MSIZE) +TFTPSIMAGE=/tftpboot/sImage endif -ifeq ($(CONFIG_PPC64BRIDGE),y) -MSIZE=.64 -else -MSIZE= -endif -ZLINKFLAGS = -T ../vmlinux.lds -Ttext 0x00800000 +lib/zlib.a: + $(MAKE) -C lib -GZIP_FLAGS = -v9f +images/vmlinux.gz: $(TOPDIR)/vmlinux + $(MAKE) -C images vmlinux.gz -OBJECTS := head.o misc.o ../coffboot/zlib.o -CFLAGS = $(CPPFLAGS) -O2 -DSTDC_HEADERS -fno-builtin -OBJCOPY_ARGS = -O elf32-powerpc - -OBJECTS += vreset.o kbd.o of1275.o -ifeq ($(CONFIG_SERIAL_CONSOLE),y) -OBJECTS += ns16550.o -endif - -all: zImage - -zvmlinux.initrd: zvmlinux - $(LD) $(ZLINKFLAGS) -o zvmlinux.initrd.tmp $(OBJECTS) - $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ - --add-section=initrd=ramdisk.image.gz \ - --add-section=image=../coffboot/vmlinux.gz \ - zvmlinux.initrd.tmp zvmlinux.initrd - $(CC) $(CFLAGS) -DINITRD_OFFSET=`sh offset $(OBJDUMP) zvmlinux.initrd initrd` \ - -DINITRD_SIZE=`sh size $(OBJDUMP) zvmlinux.initrd initrd` \ - -DZIMAGE_OFFSET=`sh offset $(OBJDUMP) zvmlinux.initrd image` \ - -DZIMAGE_SIZE=`sh size $(OBJDUMP) zvmlinux.initrd image` \ - -D__BOOTER__ \ - -c -o misc.o misc.c - $(LD) $(ZLINKFLAGS) -o zvmlinux.initrd.tmp $(OBJECTS) - $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ - --add-section=initrd=ramdisk.image.gz \ - --add-section=image=../coffboot/vmlinux.gz \ - zvmlinux.initrd.tmp $@ - rm zvmlinux.initrd.tmp +# Since gemini doesn't need/have it's own directory, we do znetboot* here +ifdef CONFIG_GEMINI +BOOT_TARGETS = zImage zImage.initrd +else +BOOT_TARGETS = zImage zImage.initrd znetboot znetboot.initrd +endif -zImage: zvmlinux mkprep +# We go into the utils dir by hand to ensure HOSTCC builds +$(BOOT_TARGETS): sImage vmapus lib/zlib.a images/vmlinux.gz +ifdef CONFIG_8260 + $(MAKE) -C mbx $@ +endif ifdef CONFIG_ALL_PPC - ./mkprep -pbp zvmlinux zImage + $(MAKE) -C utils addnote piggyback mknote hack-coff mkprep + $(MAKE) -C chrp $@ + $(MAKE) -C pmac $@ + $(MAKE) -C prep $@ endif -ifdef CONFIG_APUS - $(STRIP) ../../../vmlinux -o vmapus - gzip $(GZIP_FLAGS) vmapus +ifdef CONFIG_4xx + $(MAKE) -C tree $@ endif - -zImage.initrd: zvmlinux.initrd mkprep -ifdef CONFIG_ALL_PPC - ./mkprep -pbp zvmlinux.initrd zImage.initrd +ifdef CONFIG_8xx + $(MAKE) -C mbx $@ +endif +ifdef CONFIG_K2 + $(MAKE) -C pmon $@ +endif +ifneq ("xx$(CONFIG_MVME5100)$(CONFIG_PRPMC750)","xx") + $(MAKE) -C utils mkbugboot mkprep + $(MAKE) -C pp3 $@ +endif +ifdef CONFIG_SPRUCE + $(MAKE) -C spruce $@ endif -zvmlinux: $(OBJECTS) ../coffboot/vmlinux.gz -# -# build the boot loader image and then compute the offset into it -# for the kernel image -# - $(LD) $(ZLINKFLAGS) -o zvmlinux.tmp $(OBJECTS) - $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment --add-section=image=../coffboot/vmlinux.gz \ - zvmlinux.tmp $@ -# -# then with the offset rebuild the bootloader so we know where the kernel is -# - $(CC) $(CFLAGS) -DINITRD_OFFSET=0 -DINITRD_SIZE=0 \ - -DZIMAGE_OFFSET=`sh offset $(OBJDUMP) zvmlinux image` \ - -DZIMAGE_SIZE=`sh size $(OBJDUMP) zvmlinux image` \ - -D__BOOTER__ \ - -c -o misc.o misc.c - $(LD) $(ZLINKFLAGS) -o zvmlinux.tmp $(OBJECTS) - $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment --add-section=image=../coffboot/vmlinux.gz \ - zvmlinux.tmp $@ - rm zvmlinux.tmp - -floppy: $(TOPDIR)/vmlinux zImage - dd if=zImage of=/dev/fd0H1440 bs=64b +sImage: $(TOPDIR)/vmlinux +ifdef CONFIG_GEMINI + $(OBJCOPY) -I elf32-powerpc -O binary $(TOPDIR)/vmlinux images/sImage +endif -mkprep : mkprep.c - $(HOSTCC) -o mkprep mkprep.c +vmapus: $(TOPDIR)/vmlinux +ifdef CONFIG_APUS + $(STRIP) $(TOPDIR)/vmlinux -o images/vmapus + gzip $(GZIP_FLAGS) images/vmapus +endif +ifdef CONFIG_GEMINI znetboot : zImage -ifdef CONFIG_ALL_PPC - cp zImage $(TFTPIMAGE) + cp images/sImage $(TFTPSIMAGE) endif -znetboot.initrd : zImage.initrd - cp zImage.initrd $(TFTPIMAGE) - +# Do the dirs clean: - rm -f vmlinux* zvmlinux* mkprep zImage* - -fastdep: - $(TOPDIR)/scripts/mkdep *.[Sch] > .depend + $(MAKE) -C images clean + $(MAKE) -C spruce clean + $(MAKE) -C tree clean + $(MAKE) -C utils clean dep: - $(CPP) $(CPPFLAGS) -M *.S *.c > .depend - -# just here to match coffboot/Makefile -vmlinux.coff: -vmlinux.coff.initrd: +include $(TOPDIR)/Rules.make diff -Nru a/arch/ppc/boot/chrp/Makefile b/arch/ppc/boot/chrp/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/chrp/Makefile Wed May 16 06:00:23 2001 @@ -0,0 +1,71 @@ +# Makefile for making ELF bootable images for booting on CHRP-style machines +# using Open Firmware. +# +# Geert Uytterhoeven September 1997 +# +# Based on coffboot by Paul Mackerras + +ifeq ($(CONFIG_PPC64BRIDGE),y) +MSIZE=.64 +AFLAGS += -Wa,-mppc64bridge +else +MSIZE= +endif + +.c.o: + $(CC) $(CFLAGS) -DKERNELBASE=$(KERNELBASE) -c -o $*.o $< +.S.o: + $(CC) $(AFLAGS) -traditional -c -o $*.o $< + +LD_ARGS = -Ttext 0x00400000 + +OBJS = ../common/crt0.o start.o main.o misc.o ../common/string.o image.o +LIBS = $(TOPDIR)/lib/lib.a ../lib/zlib.a +ADDNOTE = ../utils/addnote +PIGGYBACK = ../utils/piggyback + +ifeq ($(CONFIG_SMP),y) +TFTPIMAGE=/tftpboot/zImage.chrp.smp$(MSIZE) +else +TFTPIMAGE=/tftpboot/zImage.chrp$(MSIZE) +endif + +all: zImage + +znetboot: zImage +ifdef CONFIG_SMP + cp -f $(TOPDIR)/vmlinux /tftpboot/vmlinux.smp +else + cp -f $(TOPDIR)/vmlinux /tftpboot/vmlinux +endif +ifdef CONFIG_PPC64BRIDGE + cp -f $(TOPDIR)/vmlinux /tftpboot/vmlinux.64 +endif + cp ../images/zImage.chrp $(TFTPIMAGE) + +znetboot.initrd: zImage.initrd + cp ../images/zImage.initrd.chrp $(TFTPIMAGE) + +floppy: zImage + mcopy zImage a:zImage + +image.o: $(PIGGYBACK) ../images/vmlinux.gz + $(PIGGYBACK) image < ../images/vmlinux.gz | $(AS) -o $@ + +sysmap.o: $(PIGGYBACK) $(TOPDIR)/System.map + $(PIGGYBACK) sysmap < $(TOPDIR)/System.map | $(AS) -o $@ + +initrd.o: ../images/ramdisk.image.gz $(PIGGYBACK) + $(PIGGYBACK) initrd < ../images/ramdisk.image.gz | $(AS) -o $@ + +zImage: $(OBJS) $(LIBS) ../common/no_initrd.o $(ADDNOTE) ../images/vmlinux.gz + $(LD) $(LD_ARGS) -o ../images/$@.chrp $(OBJS) ../common/no_initrd.o $(LIBS) + cp ../images/$@.chrp ../images/$@.chrp-rs6k + $(ADDNOTE) ../images/$@.chrp-rs6k + +zImage.initrd: $(OBJS) $(LIBS) initrd.o $(ADDNOTE) ../images/vmlinux.gz + $(LD) $(LD_ARGS) -o ../images/$@.chrp $(OBJS) initrd.o $(LIBS) + cp ../images/$@.chrp ../images/$@.chrp-rs6k + $(ADDNOTE) ../images/$@.chrp-rs6k + +include $(TOPDIR)/Rules.make diff -Nru a/arch/ppc/boot/chrp/main.c b/arch/ppc/boot/chrp/main.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/chrp/main.c Wed May 16 06:00:16 2001 @@ -0,0 +1,195 @@ +/* + * 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 "zlib.h" +#include +#include +#include + +extern void *finddevice(const char *); +extern int getprop(void *, const char *, void *, int); +void gunzip(void *, int, unsigned char *, int *); + +#define RAM_START 0x00000000 +#define RAM_END (64<<20) + +#define BOOT_START ((unsigned long)_start) +#define BOOT_END ((unsigned long)(_end + 0xFFF) & ~0xFFF) + +#define RAM_FREE ((unsigned long)(_end+0x1000)&~0xFFF) +#define PROG_START 0x00010000 + +char *avail_ram; +char *end_avail; + +extern char _end[]; +extern char image_data[]; +extern int image_len; +extern char initrd_data[]; +extern int initrd_len; +extern char sysmap_data[]; +extern int sysmap_len; + +static char scratch[1024<<10]; /* 1MB of scratch space for gunzip */ + +chrpboot(int a1, int a2, void *prom) +{ + int ns, oh, i; + unsigned sa, len; + void *dst; + unsigned char *im; + unsigned initrd_start, initrd_size; + extern char _start; + + printf("chrpboot starting: loaded at 0x%x\n\r", &_start); + + if (initrd_len) { + initrd_size = initrd_len; + initrd_start = (RAM_END - initrd_size) & ~0xFFF; + a1 = initrd_start; + a2 = initrd_size; + claim(initrd_start, RAM_END - initrd_start, 0); + printf("initial ramdisk moving 0x%x <- 0x%x (%x bytes)\n\r", + initrd_start, initrd_data, initrd_size); + memcpy((char *)initrd_start, initrd_data, initrd_size); + } + + im = image_data; + len = image_len; + /* claim 4MB starting at PROG_START */ + claim(PROG_START, (4<<20) - PROG_START, 0); + dst = (void *) PROG_START; + if (im[0] == 0x1f && im[1] == 0x8b) { + avail_ram = scratch; + end_avail = scratch + sizeof(scratch); + printf("gunzipping (0x%x <- 0x%x:0x%0x)...", dst, im, im+len); + gunzip(dst, 0x400000, im, &len); + printf("done %u bytes\n\r", len); + } else { + memmove(dst, im, len); + } + + flush_cache(dst, len); + + sa = (unsigned long)PROG_START; + printf("start address = 0x%x\n\r", sa); + + { + struct bi_record *rec; + + rec = (struct bi_record *)_ALIGN((unsigned long)dst+len+(1<<20)-1,(1<<20)); + + rec->tag = BI_FIRST; + rec->size = sizeof(struct bi_record); + rec = (struct bi_record *)((unsigned long)rec + rec->size); + + rec->tag = BI_BOOTLOADER_ID; + sprintf( (char *)rec->data, "chrpboot"); + rec->size = sizeof(struct bi_record) + strlen("chrpboot") + 1; + rec = (struct bi_record *)((unsigned long)rec + rec->size); + + rec->tag = BI_MACHTYPE; + rec->data[0] = _MACH_chrp; + rec->data[1] = 1; + rec->size = sizeof(struct bi_record) + sizeof(unsigned long); + rec = (struct bi_record *)((unsigned long)rec + rec->size); +#if 0 + rec->tag = BI_SYSMAP; + rec->data[0] = (unsigned long)sysmap_data; + rec->data[1] = sysmap_len; + rec->size = sizeof(struct bi_record) + sizeof(unsigned long); + rec = (struct bi_record *)((unsigned long)rec + rec->size); +#endif + rec->tag = BI_LAST; + rec->size = sizeof(struct bi_record); + rec = (struct bi_record *)((unsigned long)rec + rec->size); + } + (*(void (*)())sa)(a1, a2, prom); + + printf("returned?\n\r"); + + 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\r"); + pause(); + } + return p; +} + +void zfree(void *x, void *addr, unsigned nb) +{ + nb = (nb + 7) & -8; + if (addr == (avail_ram - nb)) { + avail_ram -= 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\r"); + 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\r"); + exit(); + } + + s.zalloc = zalloc; + s.zfree = zfree; + r = inflateInit2(&s, -MAX_WBITS); + if (r != Z_OK) { + printf("inflateInit2 returned %d\n\r", 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 msg: %s\n\r", r, s.msg); + exit(); + } + *lenp = s.next_out - (unsigned char *) dst; + inflateEnd(&s); +} diff -Nru a/arch/ppc/boot/chrp/misc.S b/arch/ppc/boot/chrp/misc.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/chrp/misc.S Wed May 16 06:00:25 2001 @@ -0,0 +1,50 @@ +/* + * 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 0x90000000. + */ + .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,0x9000 + 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 3,4 + mtdbatl 3,5 +5: mtibatu 3,4 + mtibatl 3,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 diff -Nru a/arch/ppc/boot/chrp/start.c b/arch/ppc/boot/chrp/start.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/chrp/start.c Wed May 16 06:00:18 2001 @@ -0,0 +1,305 @@ +/* + * 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 + +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 printk(char *fmt, ...); + +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(); + + chrpboot(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; +} + +void * +claim(unsigned int virt, unsigned int size, unsigned int align) +{ + struct prom_args { + char *service; + int nargs; + int nret; + unsigned int virt; + unsigned int size; + unsigned int align; + void *ret; + } args; + + args.service = "claim"; + args.nargs = 3; + args.nret = 1; + args.virt = virt; + args.size = size; + args.align = align; + (*prom)(&args); + return args.ret; +} + +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; +} diff -Nru a/arch/ppc/boot/common/Makefile b/arch/ppc/boot/common/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/common/Makefile Wed May 16 06:00:34 2001 @@ -0,0 +1,27 @@ +# +# arch/ppc/boot/common/Makefile +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. +# +# Tom Rini January 2001 +# + +.c.s: + $(CC) $(CFLAGS) -S -o $*.s $< +.s.o: + $(AS) -o $*.o $< +.c.o: + $(CC) $(CFLAGS) -c -o $*.o $< +.S.s: + $(CPP) $(AFLAGS) -traditional -o $*.o $< +.S.o: + $(CC) $(AFLAGS) -traditional -c -o $*.o $< + +OBJCOPY_ARGS = -O elf32-powerpc + +coffcrt0.o: + $(CC) $(AFLAGS) -DXCOFF -traditional -c -o coffcrt0.o crt0.S + +include $(TOPDIR)/Rules.make diff -Nru a/arch/ppc/boot/common/crt0.S b/arch/ppc/boot/common/crt0.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/common/crt0.S Wed May 16 06:00:18 2001 @@ -0,0 +1,83 @@ +/* + * Copyright (c) 1997 Paul Mackerras + * Initial Power Macintosh COFF version. + * Copyright (c) 1999 Grant Erickson + * Modifications for IBM PowerPC 400-class processor evaluation + * boards. + * + * Module name: crt0.S + * + * Description: + * Boot loader execution entry point. Clears out .bss section as per + * ANSI C requirements. Invalidates and flushes the caches over the + * range covered by the boot loader's .text section. Sets up a stack + * below the .text section entry point. + * + * 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 +#include "../../kernel/ppc_asm.tmpl" + + .text + + .globl _start +_start: +#ifdef XCOFF + .long __start,0,0 + + .globl __start +__start: +#endif +#ifdef CONFIG_4xx + ## Clear out the BSS as per ANSI C requirements + + lis r7,_end@ha + addi r7,r7,_end@l # r7 = &_end + lis r8,__bss_start@ha # + addi r8,r8,__bss_start@l # r8 = &_bss_start + + ## Determine how large an area, in number of words, to clear + + subf r7,r8,r7 # r7 = &_end - &_bss_start + 1 + addi r7,r7,3 # r7 += 3 + srwi. r7,r7,2 # r7 = size in words. + beq 2f # If the size is zero, do not bother + addi r8,r8,-4 # r8 -= 4 + mtctr r7 # SPRN_CTR = number of words to clear + li r0,0 # r0 = 0 +1: stwu r0,4(r8) # Clear out a word + bdnz 1b # If we are not done yet, keep clearing +#endif + + ## Flush and invalidate the caches for the range in memory covering + ## the .text section of the boot loader + +2: lis r9,_start@h # r9 = &_start + lis r8,_etext@ha # + addi r8,r8,_etext@l # r8 = &_etext +3: dcbf r0,r9 # Flush the data cache + icbi r0,r9 # Invalidate the instruction cache + addi r9,r9,0x10 # Increment by one cache line + cmplw cr0,r9,r8 # Are we at the end yet? + blt 3b # No, keep flushing and invalidating + sync # sync ; isync after flushing the icache + isync + +#ifdef CONFIG_4xx + ## Set up the stack + + lis r9,_start@h # r9 = &_start (text section entry) + addi r9,r9,_start@l + subi r1,r9,64 # Start the stack 64 bytes below _start + clrrwi r1,r1,4 # Make sure it is aligned on 16 bytes. + li r0,0 + stwu r0,-16(r1) + mtlr r9 +#endif + + b start # All done, start the real work. diff -Nru a/arch/ppc/boot/common/misc-common.c b/arch/ppc/boot/common/misc-common.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/common/misc-common.c Wed May 16 06:00:33 2001 @@ -0,0 +1,539 @@ +/* + * arch/ppc/boot/common/misc-common.c + * + * Misc. bootloader code (almost) all platforms can use + * + * Author: Johnnie Peters + * Editor: Tom Rini + * + * Derived from arch/ppc/boot/prep/misc.c + * + * Copyright 2000-2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include "zlib.h" +#include + +/* If we're on a ALL_PPC, assume we have a keyboard controller + * Also note, if we're not ALL_PPC, we assume you are a serial + * console - Tom */ +#ifdef CONFIG_ALL_PPC +extern void cursor(int x, int y); +extern void scroll(void); +extern char *vidmem; +extern int lines, cols; +extern int orig_x, orig_y; +extern int keyb_present; +extern int CRT_tstc(void); +extern int CRT_getc(void); +#else +int cursor(int x, int y) {return 0;} +void scroll(void) {} +char vidmem[1]; +#define lines 0 +#define cols 0 +int orig_x = 0; +int orig_y = 0; +#define keyb_present 0 +int CRT_tstc(void) {return 0;} +int CRT_getc(void) {return 0;} +#endif + +extern char *avail_ram; +extern char *end_avail; +extern char _end[]; + +void puts(const char *); +void putc(const char c); +void puthex(unsigned long val); +void _bcopy(char *src, char *dst, int len); +void gunzip(void *, int, unsigned char *, int *); +static int _cvt(unsigned long val, char *buf, long radix, char *digits); + +void _vprintk(void(*)(const char), const char *, va_list); + +#if defined(CONFIG_SERIAL_CONSOLE) +struct NS16550 *com_port; + +int serial_tstc(volatile struct NS16550 *); +unsigned char serial_getc(volatile struct NS16550 *); +void serial_putc(volatile struct NS16550 *, unsigned char); +#endif + +void pause(void) +{ + puts("pause\n"); +} + +void exit(void) +{ + puts("exit\n"); + while(1); +} + +int tstc(void) +{ +#if defined(CONFIG_SERIAL_CONSOLE) + if(keyb_present) + return (CRT_tstc() || serial_tstc(com_port)); + else + return (serial_tstc(com_port)); +#else + return CRT_tstc(); +#endif +} + +int getc(void) +{ + while (1) { +#if defined(CONFIG_SERIAL_CONSOLE) + if (serial_tstc(com_port)) + return (serial_getc(com_port)); +#endif /* CONFIG_SERIAL_CONSOLE */ + if (keyb_present) + if(CRT_tstc()) + return (CRT_getc()); + } +} + +void +putc(const char c) +{ + int x,y; + +#if defined(CONFIG_SERIAL_CONSOLE) + serial_putc(com_port, c); + if ( c == '\n' ) + serial_putc(com_port, '\r'); +#endif /* CONFIG_SERIAL_CONSOLE */ + + x = orig_x; + y = orig_y; + + if ( c == '\n' ) { + x = 0; + if ( ++y >= lines ) { + scroll(); + y--; + } + } else if (c == '\r') { + x = 0; + } 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) +{ + int x,y; + char c; + + x = orig_x; + y = orig_y; + + while ( ( c = *s++ ) != '\0' ) { +#if defined(CONFIG_SERIAL_CONSOLE) + serial_putc(com_port, c); + if ( c == '\n' ) serial_putc(com_port, '\r'); +#endif /* CONFIG_SERIAL_CONSOLE */ + + 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 error(char *x) +{ + puts("\n\n"); + puts(x); + puts("\n\n -- System halted"); + + while(1); /* Halt */ +} + +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) { + puts("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) { + puts("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) { + puts("gunzip: ran out of data in header\n"); + exit(); + } + + s.zalloc = zalloc; + s.zfree = zfree; + r = inflateInit2(&s, -MAX_WBITS); + if (r != Z_OK) { + puts("inflateInit2 returned %d\n"); + 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) { + puts("inflate returned %d\n"); + exit(); + } + *lenp = s.next_out - (unsigned char *) dst; + inflateEnd(&s); +} + +void +puthex(unsigned long val) +{ + + unsigned char buf[10]; + int i; + for (i = 7; i >= 0; i--) + { + buf[i] = "0123456789ABCDEF"[val & 0x0F]; + val >>= 4; + } + buf[8] = '\0'; + puts(buf); +} + +#define FALSE 0 +#define TRUE 1 +#include + +void +_printk(char const *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + _vprintk(putc, fmt, ap); + va_end(ap); + return; +} + +#define is_digit(c) ((c >= '0') && (c <= '9')) + +void +_vprintk(void(*putc)(const char), const char *fmt0, va_list ap) +{ + char c, sign, *cp = 0; + int left_prec, right_prec, zero_fill, length = 0, pad, pad_on_right; + char buf[32]; + long val; + while ((c = *fmt0++)) + { + if (c == '%') + { + c = *fmt0++; + left_prec = right_prec = pad_on_right = 0; + if (c == '-') + { + c = *fmt0++; + pad_on_right++; + } + if (c == '0') + { + zero_fill = TRUE; + c = *fmt0++; + } else + { + zero_fill = FALSE; + } + while (is_digit(c)) + { + left_prec = (left_prec * 10) + (c - '0'); + c = *fmt0++; + } + if (c == '.') + { + c = *fmt0++; + zero_fill++; + while (is_digit(c)) + { + right_prec = (right_prec * 10) + (c - '0'); + c = *fmt0++; + } + } else + { + right_prec = left_prec; + } + sign = '\0'; + switch (c) + { + case 'd': + case 'x': + case 'X': + val = va_arg(ap, long); + switch (c) + { + case 'd': + if (val < 0) + { + sign = '-'; + val = -val; + } + length = _cvt(val, buf, 10, "0123456789"); + break; + case 'x': + length = _cvt(val, buf, 16, "0123456789abcdef"); + break; + case 'X': + length = _cvt(val, buf, 16, "0123456789ABCDEF"); + break; + } + cp = buf; + break; + case 's': + cp = va_arg(ap, char *); + length = strlen(cp); + break; + case 'c': + c = va_arg(ap, long /*char*/); + (*putc)(c); + continue; + default: + (*putc)('?'); + } + pad = left_prec - length; + if (sign != '\0') + { + pad--; + } + if (zero_fill) + { + c = '0'; + if (sign != '\0') + { + (*putc)(sign); + sign = '\0'; + } + } else + { + c = ' '; + } + if (!pad_on_right) + { + while (pad-- > 0) + { + (*putc)(c); + } + } + if (sign != '\0') + { + (*putc)(sign); + } + while (length-- > 0) + { + (*putc)(c = *cp++); + if (c == '\n') + { + (*putc)('\r'); + } + } + if (pad_on_right) + { + while (pad-- > 0) + { + (*putc)(c); + } + } + } else + { + (*putc)(c); + if (c == '\n') + { + (*putc)('\r'); + } + } + } +} + +int +_cvt(unsigned long val, char *buf, long radix, char *digits) +{ + char temp[80]; + char *cp = temp; + int length = 0; + if (val == 0) + { /* Special case */ + *cp++ = '0'; + } else + while (val) + { + *cp++ = digits[val % radix]; + val /= radix; + } + while (cp != temp) + { + *buf++ = *--cp; + length++; + } + *buf = '\0'; + return (length); +} + +void +_dump_buf_with_offset(unsigned char *p, int s, unsigned char *base) +{ + int i, c; + if ((unsigned int)s > (unsigned int)p) + { + s = (unsigned int)s - (unsigned int)p; + } + while (s > 0) + { + if (base) + { + _printk("%06X: ", (int)p - (int)base); + } else + { + _printk("%06X: ", p); + } + for (i = 0; i < 16; i++) + { + if (i < s) + { + _printk("%02X", p[i] & 0xFF); + } else + { + _printk(" "); + } + if ((i % 2) == 1) _printk(" "); + if ((i % 8) == 7) _printk(" "); + } + _printk(" |"); + for (i = 0; i < 16; i++) + { + if (i < s) + { + c = p[i] & 0xFF; + if ((c < 0x20) || (c >= 0x7F)) c = '.'; + } else + { + c = ' '; + } + _printk("%c", c); + } + _printk("|\n"); + s -= 16; + p += 16; + } +} + +void +_dump_buf(unsigned char *p, int s) +{ + _printk("\n"); + _dump_buf_with_offset(p, s, 0); +} + +/* + * Local variables: + * c-indent-level: 8 + * c-basic-offset: 8 + * tab-width: 8 + * End: + */ diff -Nru a/arch/ppc/boot/common/misc-one.c b/arch/ppc/boot/common/misc-one.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/common/misc-one.c Wed May 16 06:00:34 2001 @@ -0,0 +1,180 @@ +/* + * arch/ppc/common/misc-one.c + * + * Misc. bootloader code for the PrPMC750 + * Misc. bootloader code for the PMON equiped machines as well + * + * This file will be merged into the other misc*.c files at some point + * soon. For now PMON and PrPMC750 share the same file. - Tom Rini + * + * Author: Matt Porter + * Derived from arch/ppc/boot/prep/misc.c + * + * Copyright 2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include + +#include +#include +#include + +#include "zlib.h" + +unsigned long com_port; + +char *avail_ram; +char *end_avail; +extern char _end[]; + +#ifdef CONFIG_CMDLINE +#define CMDLINE CONFIG_CMDLINE +#else +#define CMDLINE "" +#endif +char cmd_preset[] = CMDLINE; +char cmd_buf[256]; +char *cmd_line = cmd_buf; + +unsigned long initrd_start = 0, initrd_end = 0; +char *zimage_start; +int zimage_size; + +extern void puts(const char *); +extern void putc(const char c); +extern void puthex(unsigned long val); +extern void *memcpy(void * __dest, __const void * __src, + __kernel_size_t __n); +extern void gunzip(void *, int, unsigned char *, int *); + +unsigned long +decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum) +{ + + int timer; + extern unsigned long start; + char *cp, ch; + unsigned long i; + unsigned long TotalMemory; + unsigned long orig_MSR; + + com_port = /*(unsigned long *)*/serial_init(0); + + /* Assume 128MB on the SBS K2 */ + TotalMemory = 0x08000000; + + /* assume the chunk below 8M is free */ + end_avail = (char *)0x00800000; + + /* + * Reveal where we were loaded at and where we + * were relocated to. + */ + puts("loaded at: "); puthex(load_addr); + puts(" "); puthex((unsigned long)(load_addr + (4*num_words))); puts("\n"); + if ( (unsigned long)load_addr != (unsigned long)&start ) + { + puts("relocated to: "); puthex((unsigned long)&start); + puts(" "); + puthex((unsigned long)((unsigned long)&start + (4*num_words))); + puts("\n"); + } + + /* we have to subtract 0x10000 here to correct for objdump including + the size of the elf header which we strip -- Cort */ + zimage_start = (char *)(load_addr - 0x10000 + ZIMAGE_OFFSET); + zimage_size = ZIMAGE_SIZE; + + if ( INITRD_OFFSET ) + initrd_start = load_addr - 0x10000 + INITRD_OFFSET; + else + initrd_start = 0; + initrd_end = INITRD_SIZE + initrd_start; + + /* + * Find a place to stick the zimage and initrd and + * relocate them if we have to. -- Cort + */ + avail_ram = (char *)PAGE_ALIGN((unsigned long)_end); + puts("zimage at: "); puthex((unsigned long)zimage_start); + puts(" "); puthex((unsigned long)(zimage_size+zimage_start)); puts("\n"); + if ( (unsigned long)zimage_start <= 0x00800000 ) + { + memcpy( (void *)avail_ram, (void *)zimage_start, zimage_size ); + zimage_start = (char *)avail_ram; + puts("relocated to: "); puthex((unsigned long)zimage_start); + puts(" "); + puthex((unsigned long)zimage_size+(unsigned long)zimage_start); + puts("\n"); + + /* relocate initrd */ + if ( initrd_start ) + { + puts("initrd at: "); puthex(initrd_start); + puts(" "); puthex(initrd_end); puts("\n"); + avail_ram = (char *)PAGE_ALIGN( + (unsigned long)zimage_size+(unsigned long)zimage_start); + memcpy ((void *)avail_ram, (void *)initrd_start, INITRD_SIZE ); + initrd_start = (unsigned long)avail_ram; + initrd_end = initrd_start + INITRD_SIZE; + puts("relocated to: "); puthex(initrd_start); + puts(" "); puthex(initrd_end); puts("\n"); + } + } else if ( initrd_start ) { + puts("initrd at: "); puthex(initrd_start); + puts(" "); puthex(initrd_end); puts("\n"); + } + + avail_ram = (char *)0x00400000; + end_avail = (char *)0x00800000; + puts("avail ram: "); puthex((unsigned long)avail_ram); puts(" "); + puthex((unsigned long)end_avail); puts("\n"); + + /* Display standard Linux/PPC boot prompt for kernel args */ + puts("\nLinux/PPC load: "); + timer = 0; + cp = cmd_line; + memcpy (cmd_line, cmd_preset, sizeof(cmd_preset)); + while ( *cp ) putc(*cp++); + while (timer++ < 5*1000) { + if (tstc()) { + while ((ch = getc()) != '\n' && ch != '\r') { + if (ch == '\b') { + if (cp != cmd_line) { + cp--; + puts("\b \b"); + } + } else { + *cp++ = ch; + putc(ch); + } + } + break; /* Exit 'timer' loop */ + } + udelay(1000); /* 1 msec */ + } + *cp = 0; + puts("\n"); + + /* mappings on early boot can only handle 16M */ + if ( (int)(cmd_line[0]) > (16<<20)) + puts("cmd_line located > 16M\n"); + if ( initrd_start > (16<<20)) + puts("initrd_start located > 16M\n"); + + puts("Uncompressing Linux..."); + + gunzip(0, 0x400000, zimage_start, &zimage_size); + puts("done.\n"); + + puts("Now booting the kernel\n"); +} + + diff -Nru a/arch/ppc/boot/common/no_initrd.c b/arch/ppc/boot/common/no_initrd.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/common/no_initrd.c Wed May 16 06:00:20 2001 @@ -0,0 +1,2 @@ +char initrd_data[1]; +int initrd_len = 0; diff -Nru a/arch/ppc/boot/common/ns16550.c b/arch/ppc/boot/common/ns16550.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/common/ns16550.c Wed May 16 06:00:18 2001 @@ -0,0 +1,77 @@ +/* + * COM1 NS16550 support + */ + +#include +#include +#include +#include + +/* Some machines, such as ones with a PReP memory map, initally have + * their serial port at an offset of 0x80000000 from where they are + * in . This tries to take that into account. */ +#ifndef IOOFFSET +#define IOOFFSET 0 +#endif + +static struct serial_state rs_table[RS_TABLE_SIZE] = { + SERIAL_PORT_DFNS /* Defined in */ +}; + +static int shift; + +volatile unsigned long serial_init(int chan) { + unsigned long com_port; + + /* Get the base, and add any offset we need to deal with. */ + com_port = rs_table[chan].port + IOOFFSET; + + /* How far apart the registers are. */ + shift = rs_table[chan].iomem_reg_shift; + + /* See if port is present */ + *((unsigned char *)com_port + (UART_LCR << shift)) = 0x00; + *((unsigned char *)com_port + (UART_IER << shift)) = 0x00; + /* Access baud rate */ + *((unsigned char *)com_port + (UART_LCR << shift)) = 0x00; +#ifdef CONFIG_SERIAL_CONSOLE_NONSTD + /* Input clock. */ + *((unsigned char *)com_port + (UART_DLL << shift)) = + (BASE_BAUD / CONFIG_SERIAL_CONSOLE_BAUD); + *((unsigned char *)com_port + (UART_DLM << shift)) = + (BASE_BAUD / CONFIG_SERIAL_CONSOLE_BAUD) >> 8; +#endif + /* 8 data, 1 stop, no parity */ + *((unsigned char *)com_port + (UART_LCR << shift)) = 0x03; + /* RTS/DTR */ + *((unsigned char *)com_port + (UART_MCR << shift)) = 0x03; + /* Clear & enable FIFOs */ + *((unsigned char *)com_port + (UART_FCR << shift)) = 0x07; + + return (com_port); +} + +void +serial_putc(volatile unsigned long com_port, unsigned char c) +{ + while ((*((volatile unsigned char *)com_port + (UART_LSR << shift)) & + UART_LSR_THRE) == 0) + ; + *(volatile unsigned char *)com_port = c; +} + +unsigned char +serial_getc(volatile unsigned long com_port) +{ + while ((*((volatile unsigned char *)com_port + (UART_LSR << shift)) + & UART_LSR_DR) == 0) + ; + return (*(volatile unsigned char *)com_port); +} + +int +serial_tstc(volatile unsigned long com_port) +{ + return ((*((volatile unsigned char *)com_port + (UART_LSR << shift)) + & UART_LSR_DR) != 0); +} diff -Nru a/arch/ppc/boot/common/string.S b/arch/ppc/boot/common/string.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/common/string.S Wed May 16 06:00:25 2001 @@ -0,0 +1,150 @@ +/* + * 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 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 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 diff -Nru a/arch/ppc/boot/head.S b/arch/ppc/boot/head.S --- a/arch/ppc/boot/head.S Wed May 16 06:00:17 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,238 +0,0 @@ -#include "../kernel/ppc_defs.h" -#include "../kernel/ppc_asm.tmpl" -#include -#include - - .text - -/* - * $Id: head.S,v 1.33 1999/09/08 01:06:58 cort Exp $ - * - * Boot loader philosophy: - * ROM loads us to some arbitrary location - * Move the boot code to the link address (8M) - * Call decompress_kernel() - * Relocate the initrd, zimage and residual data to 8M - * Decompress the kernel to 0 - * Jump to the kernel entry - * -- Cort - */ - .globl start -start: - bl start_ -start_: - mr r11,r3 /* Save pointer to residual/board data */ - mr r25,r5 /* Save OFW pointer */ - li r3,MSR_IP /* Establish default MSR value */ - mtmsr r3 - -/* check if we need to relocate ourselves to the link addr or were we - loaded there to begin with -- Cort */ - lis r4,start@h - ori r4,r4,start@l - mflr r3 - subi r3,r3,4 /* we get the nip, not the ip of the branch */ - mr r8,r3 - cmp 0,r3,r4 - bne 1010f -/* compute size of whole image in words. this should be moved to - * start_ldr() -- Cort - */ - lis r4,start@h - ori r4,r4,start@l - lis r5,end@h - ori r5,r5,end@l - addi r5,r5,3 /* round up */ - sub r5,r5,r4 - srwi r5,r5,2 - mr r7,r5 - b start_ldr -1010: -/* - * no matter where we're loaded, move ourselves to -Ttext address - */ -relocate: - mflr r3 /* Compute code bias */ - subi r3,r3,4 - mr r8,r3 - lis r4,start@h - ori r4,r4,start@l - lis r5,end@h - ori r5,r5,end@l - addi r5,r5,3 /* Round up - just in case */ - sub r5,r5,r4 /* Compute # longwords to move */ - srwi r5,r5,2 - mtctr r5 - mr r7,r5 - li r6,0 - subi r3,r3,4 /* Set up for loop */ - subi r4,r4,4 -00: lwzu r5,4(r3) - stwu r5,4(r4) - xor r6,r6,r5 - bdnz 00b - lis r3,start_ldr@h - ori r3,r3,start_ldr@l - mtlr r3 /* Easiest way to do an absolute jump */ - blr -start_ldr: -/* Clear all of BSS */ - lis r3,edata@h - ori r3,r3,edata@l - lis r4,end@h - ori r4,r4,end@l - subi r3,r3,4 - subi r4,r4,4 - li r0,0 -50: stwu r0,4(r3) - cmp 0,r3,r4 - bne 50b -90: mr r9,r1 /* Save old stack pointer (in case it matters) */ - lis r1,.stack@h - ori r1,r1,.stack@l - addi r1,r1,4096*2 - subi r1,r1,256 - li r2,0x000F /* Mask pointer to 16-byte boundary */ - andc r1,r1,r2 -/* Run loader */ - mr r3,r8 /* Load point */ - mr r4,r7 /* Program length */ - mr r5,r6 /* Checksum */ - mr r6,r11 /* Residual data */ - mr r7,r25 /* OFW interfaces */ - bl decompress_kernel - - /* changed to use r3 (as firmware does) for kernel - as ptr to residual -- Cort*/ - lis r6,cmd_line@h - ori r6,r6,cmd_line@l - lwz r6, 0(r6) - subi r7,r6,1 -00: lbzu r2,1(r7) - cmpi 0,r2,0 - bne 00b - - /* tell kernel we're prep */ - /* - * get start address of kernel code which is stored as a coff - * entry. see boot/head.S -- Cort - */ - li r9,0x4 - mtlr r9 - lis r10,0xdeadc0de@h - ori r10,r10,0xdeadc0de@l - li r9,0 - stw r10,0(r9) -/* - * The Radstone firmware maps PCI memory at 0xc0000000 using BAT2 - * so disable BATs before setting this to avoid a clash - */ - li r8,0 - mtspr DBAT0U,r8 - mtspr DBAT1U,r8 - mtspr DBAT2U,r8 - mtspr DBAT3U,r8 - mtspr IBAT0U,r8 - mtspr IBAT1U,r8 - mtspr IBAT2U,r8 - mtspr IBAT3U,r8 - - blr -hang: - b hang - -/* - * 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 - -.globl _get_HID0 -_get_HID0: - mfspr r3,HID0 - blr - -.globl _put_HID0 -_put_HID0: - mtspr HID0,r3 - blr - -.globl _get_MSR -_get_MSR: - mfmsr r3 - blr - -.globl _put_MSR -_put_MSR: - mtmsr r3 - blr - -/* - * Flush instruction cache - * *** I'm really paranoid here! - */ -_GLOBAL(flush_instruction_cache) - mflr r5 - bl flush_data_cache - mfspr r3,HID0 /* Caches are controlled by this register */ - li r4,0 - ori r4,r4,(HID0_ICE|HID0_ICFI) - or r3,r3,r4 /* Need to enable+invalidate to clear */ - mtspr HID0,r3 - andc r3,r3,r4 - ori r3,r3,HID0_ICE /* Enable cache */ - mtspr HID0,r3 - mtlr r5 - blr - -#define NUM_CACHE_LINES 128*8 -#define CACHE_LINE_SIZE 32 -#define cache_flush_buffer 0x1000 - -/* - * Flush data cache - * *** I'm really paranoid here! - */ -_GLOBAL(flush_data_cache) - lis r3,cache_flush_buffer@h - ori r3,r3,cache_flush_buffer@l - li r4,NUM_CACHE_LINES - mtctr r4 -00: lwz r4,0(r3) - addi r3,r3,CACHE_LINE_SIZE /* Next line, please */ - bdnz 00b -10: blr - .comm .stack,4096*2,4 diff -Nru a/arch/ppc/boot/images/Makefile b/arch/ppc/boot/images/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/images/Makefile Wed May 16 06:00:33 2001 @@ -0,0 +1,12 @@ +# +# This dir holds all of the images for PPC machines. +# Tom Rini January 2001 + +include $(TOPDIR)/Rules.make + +vmlinux.gz: $(TOPDIR)/vmlinux + $(OBJCOPY) -S -O binary $(TOPDIR)/vmlinux vmlinux + gzip -vf9 vmlinux + +clean: + rm -f sImage vmapus vmlinux.* miboot.image* zImage* zvmlinux.* diff -Nru a/arch/ppc/boot/include/nonstdio.h b/arch/ppc/boot/include/nonstdio.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/include/nonstdio.h Wed May 16 06:00:17 2001 @@ -0,0 +1,18 @@ +/* + * 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)) diff -Nru a/arch/ppc/boot/include/rs6000.h b/arch/ppc/boot/include/rs6000.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/include/rs6000.h Wed May 16 06:00:22 2001 @@ -0,0 +1,243 @@ +/* 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 diff -Nru a/arch/ppc/boot/include/zlib.h b/arch/ppc/boot/include/zlib.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/include/zlib.h Wed May 16 06:00:17 2001 @@ -0,0 +1,432 @@ +/* $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 +#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< - -#include <../drivers/char/defkeymap.c> /* yeah I know it's bad -- Cort */ - - -unsigned char shfts, ctls, alts, caps; - -#define KBDATAP 0x60 /* kbd data port */ -#define KBSTATUSPORT 0x61 /* kbd status */ -#define KBSTATP 0x64 /* kbd status port */ -#define KBINRDY 0x01 -#define KBOUTRDY 0x02 - - -static int kbd(int noblock) -{ - unsigned char dt, brk, val; - unsigned code; -loop: - if (noblock) { - if ((inb(KBSTATP) & KBINRDY) == 0) - return (-1); - } else while((inb(KBSTATP) & KBINRDY) == 0) ; - - dt = inb(KBDATAP); - - brk = dt & 0x80; /* brk == 1 on key release */ - dt = dt & 0x7f; /* keycode */ - - if (shfts) - code = shift_map[dt]; - else if (ctls) - code = ctrl_map[dt]; - else - code = plain_map[dt]; - - val = KVAL(code); - switch (KTYP(code) & 0x0f) { - case KT_LATIN: - if (brk) - break; - if (alts) - val |= 0x80; - if (val == 0x7f) /* map delete to backspace */ - val = '\b'; - return val; - - case KT_LETTER: - if (brk) - break; - if (caps) - val -= 'a'-'A'; - return val; - - case KT_SPEC: - if (brk) - break; - if (val == KVAL(K_CAPS)) - caps = !caps; - else if (val == KVAL(K_ENTER)) { -enter: /* Wait for key up */ - while (1) { - while((inb(KBSTATP) & KBINRDY) == 0) ; - dt = inb(KBDATAP); - if (dt & 0x80) /* key up */ break; - } - return 10; - } - break; - - case KT_PAD: - if (brk) - break; - if (val < 10) - return val; - if (val == KVAL(K_PENTER)) - goto enter; - break; - - case KT_SHIFT: - switch (val) { - case KG_SHIFT: - case KG_SHIFTL: - case KG_SHIFTR: - shfts = brk ? 0 : 1; - break; - case KG_ALT: - case KG_ALTGR: - alts = brk ? 0 : 1; - break; - case KG_CTRL: - case KG_CTRLL: - case KG_CTRLR: - ctls = brk ? 0 : 1; - break; - } - break; - - case KT_LOCK: - switch (val) { - case KG_SHIFT: - case KG_SHIFTL: - case KG_SHIFTR: - if (brk) - shfts = !shfts; - break; - case KG_ALT: - case KG_ALTGR: - if (brk) - alts = !alts; - break; - case KG_CTRL: - case KG_CTRLL: - case KG_CTRLR: - if (brk) - ctls = !ctls; - break; - } - break; - } - if (brk) return (-1); /* Ignore initial 'key up' codes */ - goto loop; -} - -static void kbdreset(void) -{ - unsigned char c; - int i; - - /* flush input queue */ - while ((inb(KBSTATP) & KBINRDY)) - { - (void)inb(KBDATAP); - } - /* Send self-test */ - while (inb(KBSTATP) & KBOUTRDY) ; - outb(KBSTATP,0xAA); - while ((inb(KBSTATP) & KBINRDY) == 0) ; /* wait input ready */ - if ((c = inb(KBDATAP)) != 0x55) - { - puts("Keyboard self test failed - result:"); - puthex(c); - puts("\n"); - } - /* Enable interrupts and keyboard controller */ - while (inb(KBSTATP) & KBOUTRDY) ; - outb(KBSTATP,0x60); - while (inb(KBSTATP) & KBOUTRDY) ; - outb(KBDATAP,0x45); - for (i = 0; i < 10000; i++) udelay(1); - - while (inb(KBSTATP) & KBOUTRDY) ; - outb(KBSTATP,0x20); - while ((inb(KBSTATP) & KBINRDY) == 0) ; /* wait input ready */ - if (! (inb(KBDATAP) & 0x40)) { - /* - * Quote from PS/2 System Reference Manual: - * - * "Address hex 0060 and address hex 0064 should be - * written only when the input-buffer-full bit and - * output-buffer-full bit in the Controller Status - * register are set 0." (KBINRDY and KBOUTRDY) - */ - - while (inb(KBSTATP) & (KBINRDY | KBOUTRDY)) ; - outb(KBDATAP,0xF0); - while (inb(KBSTATP) & (KBINRDY | KBOUTRDY)) ; - outb(KBDATAP,0x01); - } - - while (inb(KBSTATP) & KBOUTRDY) ; - outb(KBSTATP,0xAE); -} - -/* We have to actually read the keyboard when CRT_tstc is called, - * since the pending data might be a key release code, and therefore - * not valid data. In this case, kbd() will return -1, even though there's - * data to be read. Of course, we might actually read a valid key press, - * in which case it gets queued into key_pending for use by CRT_getc. - */ - -static int kbd_reset = 0; - -static int key_pending = -1; - -int CRT_getc(void) -{ - int c; - if (!kbd_reset) {kbdreset(); kbd_reset++; } - - if (key_pending != -1) { - c = key_pending; - key_pending = -1; - return c; - } else { - while ((c = kbd(0)) == 0) ; - return c; - } -} - -int CRT_tstc(void) -{ - if (!kbd_reset) {kbdreset(); kbd_reset++; } - - while (key_pending == -1 && ((inb(KBSTATP) & KBINRDY) != 0)) { - key_pending = kbd(1); - } - - return (key_pending != -1); -} diff -Nru a/arch/ppc/boot/lib/Makefile b/arch/ppc/boot/lib/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/lib/Makefile Wed May 16 06:00:34 2001 @@ -0,0 +1,9 @@ +# +# Makefile for some libs needed by zImage. +# + +L_TARGET := zlib.a + +obj-y := zlib.o + +include $(TOPDIR)/Rules.make diff -Nru a/arch/ppc/boot/lib/zlib.c b/arch/ppc/boot/lib/zlib.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/lib/zlib.c Wed May 16 06:00:16 2001 @@ -0,0 +1,2148 @@ +/* + * 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.3 1999/05/27 22:22:54 cort 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 +#define zmemcpy memcpy +#define zmemzero(dest, len) memset(dest, 0, len) + +/* Diagnostic functions */ +#ifdef DEBUG_ZLIB +# include +# 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)<>=(j);k-=(j);} +/* output bytes */ +#define WAVAIL (qread?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} + +/* + * The IBM 150 firmware munges the data right after _etext[]. This + * protects it. -- Cort + */ +local uInt protect_mask[] = {0, 0, 0, 0, 0, 0, 0, 0, 0 ,0 ,0 ,0}; +/* 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)<>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; +} diff -Nru a/arch/ppc/boot/mbx/Makefile b/arch/ppc/boot/mbx/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/mbx/Makefile Wed May 16 06:00:21 2001 @@ -0,0 +1,121 @@ +# +# arch/ppc/mbxboot/Makefile +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. +# +# Copyright (C) 1994 by Linus Torvalds +# Adapted for PowerPC by Gary Thomas +# modified by Cort (cort@cs.nmt.edu) +# +.c.s: + $(CC) $(CFLAGS) -S -o $*.s $< +.s.o: + $(AS) -o $*.o $< +.c.o: + $(CC) $(CFLAGS) -c -o $*.o $< +.S.s: + $(CPP) $(AFLAGS) -traditional -o $*.o $< +.S.o: + $(CC) $(AFLAGS) -traditional -c -o $*.o $< + +TFTPIMAGE := /tftpboot/zImage.embedded + +OFFSET := ../utils/offset +SIZE := ../utils/size + +OBJECTS := ../common/misc-common.o misc.o ../common/string.o +LIBS := ../lib/zlib.a +OBJCOPY_ARGS := -O elf32-powerpc + +ifdef CONFIG_8xx +ZLINKFLAGS := -T $(TOPDIR)/arch/$(ARCH)/vmlinux.lds -Ttext 0x00180000 +OBJECTS += head.o m8xx_tty.o +CFLAGS += -DCONFIG_8xx +endif + +ifdef CONFIG_8260 +ZLINKFLAGS := -T $(TOPDIR)/arch/$(ARCH)/vmlinux.lds -Ttext 0x00400000 +OBJECTS += head_8260.o m8260_tty.o embed_config.o +CFLAGS += -DCONFIG_8260 +endif + +OBJCOPY_ARGS = -O elf32-powerpc + +ifeq ($(CONFIG_MBX),y) +OBJECTS += pci.o qspan_pci.o +CFLAGS += -DCONFIG_MBX +endif +ifeq ($(CONFIG_RPXLITE),y) +CFLAGS += -DCONFIG_RPXLITE +OBJECTS += iic.o embed_config.o +endif +ifeq ($(CONFIG_RPXCLASSIC),y) +CFLAGS += -DCONFIG_RPXCLASSIC +OBJECTS += iic.o embed_config.o pci.o qspan_pci.o +endif +ifeq ($(CONFIG_BSEIP),y) +CFLAGS += -DCONFIG_BSEIP +OBJECTS += iic.o embed_config.o +endif + +all: zImage + +misc.o: + $(CC) $(CFLAGS) -DINITRD_OFFSET=0 -DINITRD_SIZE=0 -DZIMAGE_OFFSET=0 \ + -DZIMAGE_SIZE=0 -c -o $@ $*.c + +zvmlinux.initrd: $(OBJECTS) $(LIBS) ../images/vmlinux.gz + $(LD) $(ZLINKFLAGS) -o $@.tmp $(OBJECTS) $(LIBS) + $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ + --add-section=initrd=../images/ramdisk.image.gz \ + --add-section=image=../images/vmlinux.gz \ + $@.tmp $@ + $(CC) $(CFLAGS) -DINITRD_OFFSET=`sh $(OFFSET) $(OBJDUMP) $@ initrd` \ + -DINITRD_SIZE=`sh $(SIZE) $(OBJDUMP) $@ initrd` \ + -DZIMAGE_OFFSET=`sh $(OFFSET) $(OBJDUMP) $@ image` \ + -DZIMAGE_SIZE=`sh $(SIZE) $(OBJDUMP) $@ image` \ + -c -o misc.o misc.c + $(LD) $(ZLINKFLAGS) -o $@.tmp $(OBJECTS) $(LIBS) + $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ + --add-section=initrd=../images/ramdisk.image.gz \ + --add-section=image=../images/vmlinux.gz \ + $@.tmp ../images/$@.mbx + +zImage: zvmlinux + ln -sf zvmlinux.mbx ../images/zImage.mbx + +zImage.initrd: zvmlinux.initrd + ln -sf zvmlinux.initrd.mbx ../images/zImage.initrd.mbx + +zvmlinux: $(OBJECTS) $(LIBS) ../images/vmlinux.gz +# +# build the boot loader image and then compute the offset into it +# for the kernel image +# + $(LD) $(ZLINKFLAGS) -o $@.tmp $(OBJECTS) $(LIBS) + $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ + --add-section=image=../images/vmlinux.gz \ + $@.tmp $@ +# +# then with the offset rebuild the bootloader so we know where the kernel is +# + $(CC) $(CFLAGS) -DINITRD_OFFSET=0 -DINITRD_SIZE=0 \ + -DZIMAGE_OFFSET=`sh $(OFFSET) $(OBJDUMP) $@ image` \ + -DZIMAGE_SIZE=`sh $(SIZE) $(OBJDUMP) $@ image` \ + -c -o misc.o misc.c + $(LD) $(ZLINKFLAGS) -o $@.tmp $(OBJECTS) $(LIBS) + $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ + --add-section=image=../images/vmlinux.gz \ + $@.tmp ../images/$@.mbx +# Remove zvmlinux and zvmlinux.temp, we have ../images/zvmlinux.mbx + rm -f $@.tmp $@ + +znetboot : zImage + cp ../images/zImage.mbx $(TFTPIMAGE) + +znetboot.initrd : zImage.initrd + cp ../images/zImage.initrd.mbx $(TFTPIMAGE) + +include $(TOPDIR)/Rules.make diff -Nru a/arch/ppc/boot/mbx/embed_config.c b/arch/ppc/boot/mbx/embed_config.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/mbx/embed_config.c Wed May 16 06:00:18 2001 @@ -0,0 +1,253 @@ + +/* Board specific functions for those embedded 8xx boards that do + * not have boot monitor support for board information. + */ +#include +#include +#ifdef CONFIG_8xx +#include +#endif +#ifdef CONFIG_8260 +#include +#endif + + +/* IIC functions. + * These are just the basic master read/write operations so we can + * examine serial EEPROM. + */ +extern void iic_read(uint devaddr, u_char *buf, uint offset, uint count); +extern u_char aschex_to_byte(u_char *cp); + +/* Supply a default Ethernet address for those eval boards that don't + * ship with one. This is an address from the MBX board I have, so + * it is unlikely you will find it on your network. + */ +static ushort def_enet_addr[] = { 0x0800, 0x3e26, 0x1559 }; + +#if defined(CONFIG_RPXLITE) || defined(CONFIG_RPXCLASSIC) + +static void rpx_eth(bd_t *bd, u_char *cp); +static void rpx_brate(bd_t *bd, u_char *cp); +static void rpx_memsize(bd_t *bd, u_char *cp); +static void rpx_cpuspeed(bd_t *bd, u_char *cp); + +/* Read the EEPROM on the RPX-Lite board. +*/ +void +rpx_cfg(bd_t *bd) +{ + u_char eebuf[256], *cp; + + /* Read the first 256 bytes of the EEPROM. I think this + * is really all there is, and I hope if it gets bigger the + * info we want is still up front. + */ +#if 1 + iic_read(0xa8, eebuf, 0, 128); + iic_read(0xa8, &eebuf[128], 128, 128); + { + int i; + cp = (u_char *)0xfa000000; + + for (i=0; i<256; i++) + *cp++ = eebuf[i]; + } + + /* We look for two things, the Ethernet address and the + * serial baud rate. The records are separated by + * newlines. + */ + cp = eebuf; + for (;;) { + if (*cp == 'E') { + cp++; + if (*cp == 'A') { + cp += 2; + rpx_eth(bd, cp); + } + } + if (*cp == 'S') { + cp++; + if (*cp == 'B') { + cp += 2; + rpx_brate(bd, cp); + } + } + if (*cp == 'D') { + cp++; + if (*cp == '1') { + cp += 2; + rpx_memsize(bd, cp); + } + } + if (*cp == 'H') { + cp++; + if (*cp == 'Z') { + cp += 2; + rpx_cpuspeed(bd, cp); + } + } + + /* Scan to the end of the record. + */ + while ((*cp != '\n') && (*cp != 0xff)) + cp++; + + /* If the next character is a 0 or ff, we are done. + */ + cp++; + if ((*cp == 0) || (*cp == 0xff)) + break; + } + bd->bi_memstart = 0; + +#else + /* For boards without initialized EEPROM. + */ + bd->bi_memstart = 0; + bd->bi_memsize = (8 * 1024 * 1024); + bd->bi_intfreq = 48; + bd->bi_busfreq = 48; + bd->bi_baudrate = 9600; +#endif +} + +static void +rpx_eth(bd_t *bd, u_char *cp) +{ + int i; + + for (i=0; i<6; i++) { + bd->bi_enetaddr[i] = aschex_to_byte(cp); + cp += 2; + } +} + +static void +rpx_brate(bd_t *bd, u_char *cp) +{ + uint rate; + + rate = 0; + + while (*cp != '\n') { + rate *= 10; + rate += (*cp) - '0'; + cp++; + } + + bd->bi_baudrate = rate * 100; +} + +static void +rpx_memsize(bd_t *bd, u_char *cp) +{ + uint size; + + size = 0; + + while (*cp != '\n') { + size *= 10; + size += (*cp) - '0'; + cp++; + } + + bd->bi_memsize = size * 1024 * 1024; +} + +static void +rpx_cpuspeed(bd_t *bd, u_char *cp) +{ + uint num, den; + + num = den = 0; + + while (*cp != '\n') { + num *= 10; + num += (*cp) - '0'; + cp++; + if (*cp == '/') { + cp++; + den = (*cp) - '0'; + break; + } + } + + /* I don't know why the RPX just can't state the actual + * CPU speed..... + */ + if (den) { + num /= den; + num *= den; + } + bd->bi_intfreq = bd->bi_busfreq = num; + + /* The 8xx can only run a maximum 50 MHz bus speed (until + * Motorola changes this :-). Greater than 50 MHz parts + * run internal/2 for bus speed. + */ + if (num > 50) + bd->bi_busfreq /= 2; +} +#endif /* RPXLITE || RPXCLASSIC */ + +#ifdef CONFIG_BSEIP +/* Build a board information structure for the BSE ip-Engine. + * There is more to come since we will add some environment + * variables and a function to read them. + */ +void +bseip_cfg(bd_t *bd) +{ + u_char *cp; + int i; + + /* Baud rate and processor speed will eventually come + * from the environment variables. + */ + bd->bi_baudrate = 9600; + + /* Get the Ethernet station address from the Flash ROM. + */ + cp = (u_char *)0xfe003ffa; + for (i=0; i<6; i++) { + bd->bi_enetaddr[i] = *cp++; + } + + /* The rest of this should come from the environment as well. + */ + bd->bi_memstart = 0; + bd->bi_memsize = (16 * 1024 * 1024); + bd->bi_intfreq = 48; + bd->bi_busfreq = 48; +} +#endif /* BSEIP */ + +#ifdef CONFIG_EST8260 +void +embed_config(bd_t *bd) +{ + u_char *cp; + int i; + +#if 0 + /* This is actually provided by my boot rom. I have it + * here for those people that may load the kernel with + * a JTAG/COP tool and not the rom monitor. + */ + bd->bi_baudrate = 115200; + bd->bi_intfreq = 200; + bd->bi_busfreq = 66; + bd->bi_cpmfreq = 66; + bd->bi_brgfreq = 33; + bd->bi_memsize = 16 * 1024 * 1024; +#endif + + cp = (u_char *)def_enet_addr; + for (i=0; i<6; i++) { + bd->bi_enetaddr[i] = *cp++; + } +} +#endif /* EST8260 */ + diff -Nru a/arch/ppc/boot/mbx/gzimage.c b/arch/ppc/boot/mbx/gzimage.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/mbx/gzimage.c Wed May 16 06:00:19 2001 @@ -0,0 +1,8 @@ +/* + * gzimage.c + * + * Dummy file to allow a compressed zImage to be added + * into a linker section, accessed by the boot coode + */ + +char dummy_for_gzimage; diff -Nru a/arch/ppc/boot/mbx/head.S b/arch/ppc/boot/mbx/head.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/mbx/head.S Wed May 16 06:00:21 2001 @@ -0,0 +1,249 @@ +#include +#include "../../kernel/ppc_defs.h" +#include "../../kernel/ppc_asm.tmpl" +#include +#include + + .text + +/* + * $Id: head.S,v 1.6 1999/09/15 00:02:25 dmalek Exp $ + * + * This code is loaded by the ROM loader at some arbitrary location. + * Move it to high memory so that it can load the kernel at 0x0000. + * + * This is a three step process that will also work when booting from + * a Flash PROM normally located in high memory. + * + * First, the entire image is loaded into some high memory address. + * This is usually at or above 0x02000000. This is done by a network + * boot function supported by the board or a debugger over BDM port. + * + * Second, the start up function here will relocate the decompress + * function to run at the link address of 0x01000000. + * + * Last, the decompression function will reloate the initrd, zImage, and + * the residual data to locations under 8 Meg. This is necessary because + * the embedded kernel start up uses 8 Meg translations to access physical + * space before the MMU is enabled. Finally, the zImage is uncompressed + * to location 0 and we jump to it. + * + * On the MBX, + * R1 - Stack pointer at a high memory address. + * R3 - Pointer to Board Information Block. + * R4 - Pointer to argument string. + * Interrupts masked, cache and MMU disabled. + * + * ...and the first and second functions listed above are + * done for us (it knows ELF images). + * + * For other embedded boards we build the Board Information Block. + */ + + .globl start +start: + bl start_ +start_: +#ifndef CONFIG_MBX + lis r11, local_bd_info@h + ori r11, r11, local_bd_info@l +#else + mr r11, r3 +#endif + + mfmsr r3 /* Turn off interrupts */ + li r4,0 + ori r4,r4,MSR_EE + andc r3,r3,r4 + mtmsr r3 + +/* check if we need to relocate ourselves to the link addr or were we + loaded there to begin with -- Cort */ + lis r4,start@h + ori r4,r4,start@l + mflr r3 + subi r3,r3,4 /* we get the nip, not the ip of the branch */ + mr r8,r3 +#if 0 + cmp 0,r3,r4 + beq start_ldr /* Branch if loaded OK */ +#endif + +/* + * no matter where we're loaded, move ourselves to -Ttext address + * This computes the sizes we need to determine other things. + */ + lis r5,end@h + ori r5,r5,end@l + addi r5,r5,3 /* Round up - just in case */ + sub r5,r5,r4 /* Compute # longwords to move */ + srwi r5,r5,2 + mtctr r5 + mr r7,r5 + li r6,0 + subi r3,r3,4 /* Set up for loop */ + subi r4,r4,4 +00: lwzu r5,4(r3) + stwu r5,4(r4) + xor r6,r6,r5 + bdnz 00b + + lis r3,start_ldr@h + ori r3,r3,start_ldr@l + mtlr r3 /* Easiest way to do an absolute jump */ + blr + +start_ldr: +/* Most 8xx boards don't boot up with the I-cache enabled. Do that + * now because the decompress runs much faster that way. + */ + lis r3, IDC_INVALL@h + mtspr IC_CST, r3 + lis r3, IDC_ENABLE@h + mtspr IC_CST, r3 + +/* Clear all of BSS */ + lis r3,edata@h + ori r3,r3,edata@l + lis r4,end@h + ori r4,r4,end@l + subi r3,r3,4 + subi r4,r4,4 + li r0,0 +50: stwu r0,4(r3) + cmp 0,r3,r4 + bne 50b + + lis r1,.stack@h + ori r1,r1,.stack@l + addi r1,r1,4096*2 + subi r1,r1,256 + li r2,0x000F /* Mask pointer to 16-byte boundary */ + andc r1,r1,r2 + + /* Perform configuration of the various boards. This is done + * by reading some configuration data from EEPROM and building + * the board information structure. + */ + mr r3, r11 + mr r21, r11 + mr r22, r8 + mr r23, r7 + mr r24, r6 + +#if defined(CONFIG_RPXLITE) || defined(CONFIG_RPXCLASSIC) + bl rpx_cfg + mr r3, r21 +#endif +#ifdef CONFIG_BSEIP + bl bseip_cfg + mr r3, r21 +#endif + bl serial_init /* Init MBX serial port */ + + mr r11, r21 + mr r8, r22 + mr r7, r23 + mr r6, r24 + +#ifdef CONFIG_MBX + lis r18, 0xfa200000@h /* Disable Ethernet SCC */ + li r0, 0 + stw r0, 0x0a00(r18) + + /* On the MBX (or anything that will TFTP load an ELF image), + * we have to find the intermediate address. The ELF loader + * only moves the Linux boostrap/decompress, not the zImage. + */ +#define ILAP_ADDRESS 0xfa000020 + lis r8, ILAP_ADDRESS@h + lwz r8, ILAP_ADDRESS@l(r8) + addis r8, r8, 1 /* Add 64K */ +#endif + + mr r3,r8 /* Load point */ + mr r4,r7 /* Program length */ + mr r5,r6 /* Checksum */ + mr r6,r11 /* Residual data */ + bl decompress_kernel + + /* changed to use r3 (as firmware does) for kernel + as ptr to residual -- Cort*/ + lis r6,cmd_line@h + ori r6,r6,cmd_line@l + lwz r6, 0(r6) + subi r7,r6,1 +00: lbzu r2,1(r7) + 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) + + /* The world starts from the beginning. + */ + li r9,0x0 + mtlr r9 + + /* Invalidate the instruction cache because we just copied a + * bunch of kernel instructions. + */ + lis r9, IDC_INVALL@h + mtspr IC_CST, r9 + + blr +hang: + b hang + +/* + * Delay for a number of microseconds + * -- Use the BUS timer (assumes 66MHz) + */ + .globl udelay +udelay: + 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 + +.globl _get_MSR +_get_MSR: + mfmsr r3 + blr + +.globl _put_MSR +_put_MSR: + mtmsr r3 + blr + + .comm .stack,4096*2,4 +#ifndef CONFIG_MBX +local_bd_info: + .long 0 + .long 0x01000000 + .long 64 + .long 64 + .long 0 + .long 0 + .long 0 +#endif diff -Nru a/arch/ppc/boot/mbx/head_8260.S b/arch/ppc/boot/mbx/head_8260.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/mbx/head_8260.S Wed May 16 06:00:16 2001 @@ -0,0 +1,258 @@ +#include "../../kernel/ppc_defs.h" +#include "../../kernel/ppc_asm.tmpl" +#include +#include + + .text + +/* + * $Id: head.S,v 1.33 1999/09/08 01:06:58 cort Exp $ + * + * Boot loader philosophy: + * + * ROM loads us to some arbitrary location + * ROM loads these registers: + * + * R3 = Pointer to the board configuration data + * R5 = Pointer to Open Firmware data + * + * ROM jumps to start/start_ + * Move the boot code to the link address (4 MB) + * Call decompress_kernel() + * Relocate the initrd, zimage and residual data to 4 MB + * Decompress the kernel to 0 + * Jump to the kernel entry + * -- Cort + */ + .globl start +start: + bl start_ +start_: + mr r11,r3 /* Save pointer to residual/board data */ + mr r25,r5 /* Save OFW pointer */ + li r3,MSR_IP /* Establish default MSR value */ + mtmsr r3 + +/* check if we need to relocate ourselves to the link addr or were we + loaded there to begin with -- Cort */ + lis r4,start@h + ori r4,r4,start@l + mflr r3 + subi r3,r3,4 /* we get the nip, not the ip of the branch */ + mr r8,r3 + cmp 0,r3,r4 + bne 1010f +/* compute size of whole image in words. this should be moved to + * start_ldr() -- Cort + */ + lis r4,start@h + ori r4,r4,start@l + lis r5,end@h + ori r5,r5,end@l + addi r5,r5,3 /* round up */ + sub r5,r5,r4 + srwi r5,r5,2 + mr r7,r5 + b start_ldr +1010: +/* + * no matter where we're loaded, move ourselves to -Ttext address + */ +relocate: + mflr r3 /* Compute code bias */ + subi r3,r3,4 + mr r8,r3 + lis r4,start@h + ori r4,r4,start@l + lis r5,end@h + ori r5,r5,end@l + addi r5,r5,3 /* Round up - just in case */ + sub r5,r5,r4 /* Compute # longwords to move */ + srwi r5,r5,2 + mtctr r5 + mr r7,r5 + li r6,0 + subi r3,r3,4 /* Set up for loop */ + subi r4,r4,4 +00: lwzu r5,4(r3) + stwu r5,4(r4) + xor r6,r6,r5 + bdnz 00b + lis r3,start_ldr@h + ori r3,r3,start_ldr@l + mtlr r3 /* Easiest way to do an absolute jump */ + blr +start_ldr: +/* Clear all of BSS */ + lis r3,edata@h + ori r3,r3,edata@l + lis r4,end@h + ori r4,r4,end@l + subi r3,r3,4 + subi r4,r4,4 + li r0,0 +50: stwu r0,4(r3) + cmp 0,r3,r4 + bne 50b +90: mr r9,r1 /* Save old stack pointer (in case it matters) */ + lis r1,.stack@h + ori r1,r1,.stack@l + addi r1,r1,4096*2 + subi r1,r1,256 + li r2,0x000F /* Mask pointer to 16-byte boundary */ + andc r1,r1,r2 + + /* Speed us up a little. + */ + bl flush_instruction_cache + +/* Run loader */ + mr r3,r8 /* Load point */ + mr r4,r7 /* Program length */ + mr r5,r6 /* Checksum */ + mr r6,r11 /* Residual data */ + mr r7,r25 /* OFW interfaces */ + bl decompress_kernel + + /* changed to use r3 (as firmware does) for kernel + as ptr to residual -- Cort*/ + lis r6,cmd_line@h + ori r6,r6,cmd_line@l + lwz r6, 0(r6) + subi r7,r6,1 +00: lbzu r2,1(r7) + 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) + + /* tell kernel we're prep */ + /* + * get start address of kernel code which is stored as a coff + * entry. see boot/head.S -- Cort + */ + li r9,0x4 + mtlr r9 + lis r10,0xdeadc0de@h + ori r10,r10,0xdeadc0de@l + li r9,0 + stw r10,0(r9) +/* + * The Radstone firmware maps PCI memory at 0xc0000000 using BAT2 + * so disable BATs before setting this to avoid a clash + */ + li r8,0 + mtspr DBAT0U,r8 + mtspr DBAT1U,r8 + mtspr DBAT2U,r8 + mtspr DBAT3U,r8 + mtspr IBAT0U,r8 + mtspr IBAT1U,r8 + mtspr IBAT2U,r8 + mtspr IBAT3U,r8 + + blr +hang: + b hang + +/* + * 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 + +.globl _get_HID0 +_get_HID0: + mfspr r3,HID0 + blr + +.globl _put_HID0 +_put_HID0: + mtspr HID0,r3 + blr + +.globl _get_MSR +_get_MSR: + mfmsr r3 + blr + +.globl _put_MSR +_put_MSR: + mtmsr r3 + blr + +/* + * Flush instruction cache + * *** I'm really paranoid here! + */ +_GLOBAL(flush_instruction_cache) + mflr r5 + bl flush_data_cache + mfspr r3,HID0 /* Caches are controlled by this register */ + li r4,0 + ori r4,r4,(HID0_ICE|HID0_ICFI) + or r3,r3,r4 /* Need to enable+invalidate to clear */ + mtspr HID0,r3 + andc r3,r3,r4 + ori r3,r3,HID0_ICE /* Enable cache */ + mtspr HID0,r3 + mtlr r5 + blr + +#define NUM_CACHE_LINES 128*8 +#define CACHE_LINE_SIZE 32 +#define cache_flush_buffer 0x1000 + +/* + * Flush data cache + * *** I'm really paranoid here! + */ +_GLOBAL(flush_data_cache) + lis r3,cache_flush_buffer@h + ori r3,r3,cache_flush_buffer@l + li r4,NUM_CACHE_LINES + mtctr r4 +00: lwz r4,0(r3) + addi r3,r3,CACHE_LINE_SIZE /* Next line, please */ + bdnz 00b +10: blr + .comm .stack,4096*2,4 diff -Nru a/arch/ppc/boot/mbx/iic.c b/arch/ppc/boot/mbx/iic.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/mbx/iic.c Wed May 16 06:00:25 2001 @@ -0,0 +1,258 @@ + +/* Minimal support functions to read configuration from IIC EEPROMS + * on MPC8xx boards. Originally written for RPGC RPX-Lite. + * Dan Malek (dmalek@jlc.net). + */ +#include +#include +#include +#include "../../8xx_io/commproc.h" + + +/* IIC functions. + * These are just the basic master read/write operations so we can + * examine serial EEPROM. + */ +void iic_read(uint devaddr, u_char *buf, uint offset, uint count); +u_char aschex_to_byte(u_char *cp); + +static int iic_init_done; + +static void +iic_init() +{ + volatile iic_t *iip; + volatile i2c8xx_t *i2c; + volatile cpm8xx_t *cp; + volatile immap_t *immap; + uint dpaddr; + + immap = (immap_t *)IMAP_ADDR; + cp = (cpm8xx_t *)&(immap->im_cpm); + + /* Reset the CPM. This is necessary on the 860 processors + * that may have started the SCC1 ethernet without relocating + * the IIC. + * This also stops the Ethernet in case we were loaded by a + * BOOTP rom monitor. + */ + cp->cp_cpcr = (CPM_CR_RST | CPM_CR_FLG); + + /* Wait for it. + */ + while (cp->cp_cpcr & (CPM_CR_RST | CPM_CR_FLG)); + + /* Remove any microcode patches. We will install our own + * later. + */ + cp->cp_cpmcr1 = 0; + cp->cp_cpmcr2 = 0; + cp->cp_cpmcr3 = 0; + cp->cp_cpmcr4 = 0; + cp->cp_rccr = 0; + + iip = (iic_t *)&cp->cp_dparam[PROFF_IIC]; + i2c = (i2c8xx_t *)&(immap->im_i2c); + + /* Initialize Port B IIC pins. + */ + cp->cp_pbpar |= 0x00000030; + cp->cp_pbdir |= 0x00000030; + cp->cp_pbodr |= 0x00000030; + + /* Initialize the parameter ram. + */ + + /* Allocate space for a two transmit and one receive buffer + * descriptor in the DP ram. + * For now, this address seems OK, but it may have to + * change with newer versions of the firmware. + */ + dpaddr = 0x0840; + + /* Set up the IIC parameters in the parameter ram. + */ + iip->iic_tbase = dpaddr; + iip->iic_rbase = dpaddr + (2 * sizeof(cbd_t)); + + iip->iic_tfcr = SMC_EB; + iip->iic_rfcr = SMC_EB; + + /* This should really be done by the reader/writer. + */ + iip->iic_mrblr = 128; + + /* Initialize Tx/Rx parameters. + */ + cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_I2C, CPM_CR_INIT_TRX) | CPM_CR_FLG; + while (cp->cp_cpcr & CPM_CR_FLG); + + /* Select an arbitrary address. Just make sure it is unique. + */ + i2c->i2c_i2add = 0x34; + + /* Make clock run maximum slow. + */ + i2c->i2c_i2brg = 7; + + /* Disable interrupts. + */ + i2c->i2c_i2cmr = 0; + i2c->i2c_i2cer = 0xff; + + /* Enable SDMA. + */ + immap->im_siu_conf.sc_sdcr = 1; + + iic_init_done = 1; +} + +/* Read from IIC. + * Caller provides device address, memory buffer, and byte count. + */ +static u_char iitemp[32]; + +void +iic_read(uint devaddr, u_char *buf, uint offset, uint count) +{ + volatile iic_t *iip; + volatile i2c8xx_t *i2c; + volatile cbd_t *tbdf, *rbdf; + volatile cpm8xx_t *cp; + volatile immap_t *immap; + u_char *tb; + uint temp; + + /* If the interface has not been initialized, do that now. + */ + if (!iic_init_done) + iic_init(); + + immap = (immap_t *)IMAP_ADDR; + cp = (cpm8xx_t *)&(immap->im_cpm); + + iip = (iic_t *)&cp->cp_dparam[PROFF_IIC]; + i2c = (i2c8xx_t *)&(immap->im_i2c); + + tbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_tbase]; + rbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_rbase]; + + /* Send a "dummy write" operation. This is a write request with + * only the offset sent, followed by another start condition. + * This will ensure we start reading from the first location + * of the EEPROM. + */ + tb = iitemp; + tb = (u_char *)(((uint)tb + 15) & ~15); + tbdf->cbd_bufaddr = (int)tb; + *tb = devaddr & 0xfe; /* Device address */ + *(tb+1) = offset; /* Offset */ + tbdf->cbd_datlen = 2; /* Length */ + tbdf->cbd_sc = + BD_SC_READY | BD_SC_LAST | BD_SC_WRAP | BD_IIC_START; + + i2c->i2c_i2mod = 1; /* Enable */ + i2c->i2c_i2cer = 0xff; + i2c->i2c_i2com = 0x81; /* Start master */ + + /* Wait for IIC transfer. + */ +#if 0 + while ((i2c->i2c_i2cer & 3) == 0); + + if (tbdf->cbd_sc & BD_SC_READY) + printf("IIC ra complete but tbuf ready\n"); +#else + temp = 10000000; + while ((tbdf->cbd_sc & BD_SC_READY) && (temp != 0)) + temp--; +#if 0 + /* We can't do this...there is no serial port yet! + */ + if (temp == 0) { + printf("Timeout reading EEPROM\n"); + return; + } +#endif +#endif + + /* Chip errata, clear enable. + */ + i2c->i2c_i2mod = 0; + + /* To read, we need an empty buffer of the proper length. + * All that is used is the first byte for address, the remainder + * is just used for timing (and doesn't really have to exist). + */ + tbdf->cbd_bufaddr = (int)tb; + *tb = devaddr | 1; /* Device address */ + rbdf->cbd_bufaddr = (uint)buf; /* Desination buffer */ + tbdf->cbd_datlen = rbdf->cbd_datlen = count + 1; /* Length */ + tbdf->cbd_sc = BD_SC_READY | BD_SC_LAST | BD_SC_WRAP | BD_IIC_START; + rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP; + + /* Chip bug, set enable here. + */ + i2c->i2c_i2mod = 1; /* Enable */ + i2c->i2c_i2cer = 0xff; + i2c->i2c_i2com = 0x81; /* Start master */ + + /* Wait for IIC transfer. + */ +#if 0 + while ((i2c->i2c_i2cer & 1) == 0); + + if (rbdf->cbd_sc & BD_SC_EMPTY) + printf("IIC read complete but rbuf empty\n"); +#else + temp = 10000000; + while ((tbdf->cbd_sc & BD_SC_READY) && (temp != 0)) + temp--; +#endif + + /* Chip errata, clear enable. + */ + i2c->i2c_i2mod = 0; +} + +/* Because I didn't find anything that would do this....... +*/ +u_char +aschex_to_byte(u_char *cp) +{ + u_char byte, c; + + c = *cp++; + + if ((c >= 'A') && (c <= 'F')) { + c -= 'A'; + c += 10; + } + else if ((c >= 'a') && (c <= 'f')) { + c -= 'a'; + c += 10; + } + else { + c -= '0'; + } + + byte = c * 16; + + c = *cp; + + if ((c >= 'A') && (c <= 'F')) { + c -= 'A'; + c += 10; + } + else if ((c >= 'a') && (c <= 'f')) { + c -= 'a'; + c += 10; + } + else { + c -= '0'; + } + + byte += c; + + return(byte); +} diff -Nru a/arch/ppc/boot/mbx/m8260_tty.c b/arch/ppc/boot/mbx/m8260_tty.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/mbx/m8260_tty.c Wed May 16 06:00:22 2001 @@ -0,0 +1,292 @@ + + +/* Minimal serial functions needed to send messages out the serial + * port on SMC1. + */ +#include +#include +#include + +uint no_print; +extern char *params[]; +extern int nparams; +static u_char cons_hold[128], *sgptr; +static int cons_hold_cnt; + +/* If defined, enables serial console. The value (1 through 4) + * should designate which SCC is used, but this isn't complete. Only + * SCC1 is known to work at this time. + */ +#define SCC_CONSOLE 1 + +void +serial_init(bd_t *bd) +{ + volatile smc_t *sp; + volatile smc_uart_t *up; + volatile scc_t *sccp; + volatile scc_uart_t *sup; + volatile cbd_t *tbdf, *rbdf; + volatile immap_t *ip; + volatile iop8260_t *io; + volatile cpm8260_t *cp; + uint dpaddr, memaddr; + + ip = (immap_t *)IMAP_ADDR; + cp = &ip->im_cpm; + io = &ip->im_ioport; + +#ifdef SCC_CONSOLE + sccp = (scc_t *)&(ip->im_scc[SCC_CONSOLE-1]); + sup = (scc_uart_t *)&ip->im_dprambase[PROFF_SCC1 + ((SCC_CONSOLE-1) << 8)]; + sccp->scc_sccm &= ~(UART_SCCM_TX | UART_SCCM_RX); + sccp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); + + /* Use Port D for SCC1 instead of other functions. + */ + io->iop_ppard |= 0x00000003; + io->iop_psord &= ~0x00000001; /* Rx */ + io->iop_psord |= 0x00000002; /* Tx */ + io->iop_pdird &= ~0x00000001; /* Rx */ + io->iop_pdird |= 0x00000002; /* Tx */ + +#else + sp = (smc_t*)&(ip->im_smc[0]); + *(ushort *)(&ip->im_dprambase[PROFF_SMC1_BASE]) = PROFF_SMC1; + up = (smc_uart_t *)&ip->im_dprambase[PROFF_SMC1]; + + /* Disable transmitter/receiver. + */ + sp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); + + /* Use Port D for SMC1 instead of other functions. + */ + io->iop_ppard |= 0x00c00000; + io->iop_pdird |= 0x00400000; + io->iop_pdird &= ~0x00800000; + io->iop_psord &= ~0x00c00000; +#endif + + /* Allocate space for two buffer descriptors in the DP ram. + * For now, this address seems OK, but it may have to + * change with newer versions of the firmware. + */ + dpaddr = 0x0800; + + /* Grab a few bytes from the top of memory. + */ + memaddr = (bd->bi_memsize - 256) & ~15; + + /* Set the physical address of the host memory buffers in + * the buffer descriptors. + */ + rbdf = (cbd_t *)&ip->im_dprambase[dpaddr]; + rbdf->cbd_bufaddr = memaddr; + rbdf->cbd_sc = 0; + tbdf = rbdf + 1; + tbdf->cbd_bufaddr = memaddr+128; + tbdf->cbd_sc = 0; + + /* Set up the uart parameters in the parameter ram. + */ +#ifdef SCC_CONSOLE + sup->scc_genscc.scc_rbase = dpaddr; + sup->scc_genscc.scc_tbase = dpaddr + sizeof(cbd_t); + + /* Set up the uart parameters in the + * parameter ram. + */ + sup->scc_genscc.scc_rfcr = CPMFCR_GBL | CPMFCR_EB; + sup->scc_genscc.scc_tfcr = CPMFCR_GBL | CPMFCR_EB; + + sup->scc_genscc.scc_mrblr = 128; + sup->scc_maxidl = 8; + sup->scc_brkcr = 1; + sup->scc_parec = 0; + sup->scc_frmec = 0; + sup->scc_nosec = 0; + sup->scc_brkec = 0; + sup->scc_uaddr1 = 0; + sup->scc_uaddr2 = 0; + sup->scc_toseq = 0; + sup->scc_char1 = 0x8000; + sup->scc_char2 = 0x8000; + sup->scc_char3 = 0x8000; + sup->scc_char4 = 0x8000; + sup->scc_char5 = 0x8000; + sup->scc_char6 = 0x8000; + sup->scc_char7 = 0x8000; + sup->scc_char8 = 0x8000; + sup->scc_rccm = 0xc0ff; + + /* Send the CPM an initialize command. + */ + cp->cp_cpcr = mk_cr_cmd(CPM_CR_SCC1_PAGE, CPM_CR_SCC1_SBLOCK, 0, + CPM_CR_INIT_TRX) | CPM_CR_FLG; + while (cp->cp_cpcr & CPM_CR_FLG); + + /* Set UART mode, 8 bit, no parity, one stop. + * Enable receive and transmit. + */ + sccp->scc_gsmrh = 0; + sccp->scc_gsmrl = + (SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16); + + /* Disable all interrupts and clear all pending + * events. + */ + sccp->scc_sccm = 0; + sccp->scc_scce = 0xffff; + sccp->scc_dsr = 0x7e7e; + sccp->scc_pmsr = 0x3000; + + /* Wire BRG1 to SCC1. The console driver will take care of + * others. + */ + ip->im_cpmux.cmx_scr = 0; +#else + up->smc_rbase = dpaddr; + up->smc_tbase = dpaddr+sizeof(cbd_t); + up->smc_rfcr = CPMFCR_EB; + up->smc_tfcr = CPMFCR_EB; + up->smc_brklen = 0; + up->smc_brkec = 0; + up->smc_brkcr = 0; + up->smc_mrblr = 128; + up->smc_maxidl = 8; + + /* Set UART mode, 8 bit, no parity, one stop. + * Enable receive and transmit. + */ + sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART; + + /* Mask all interrupts and remove anything pending. + */ + sp->smc_smcm = 0; + sp->smc_smce = 0xff; + + /* Set up the baud rate generator. + */ + ip->im_cpmux.cmx_smr = 0; +#endif + + /* The baud rate divisor needs to be coordinated with clk_8260(). + */ + ip->im_brgc1 = + ((((bd->bi_brgfreq * 1000000)/16) / bd->bi_baudrate) << 1) | + CPM_BRG_EN; + + /* Make the first buffer the only buffer. + */ + tbdf->cbd_sc |= BD_SC_WRAP; + rbdf->cbd_sc |= BD_SC_EMPTY | BD_SC_WRAP; + + /* Initialize Tx/Rx parameters. + */ +#ifdef SCC_CONSOLE + sccp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT); +#else + cp->cp_cpcr = mk_cr_cmd(CPM_CR_SMC1_PAGE, CPM_CR_SMC1_SBLOCK, 0, CPM_CR_INIT_TRX) | CPM_CR_FLG; + while (cp->cp_cpcr & CPM_CR_FLG); + + /* Enable transmitter/receiver. + */ + sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN; +#endif +} + +void +serial_putc(const char c) +{ + volatile cbd_t *tbdf; + volatile char *buf; + volatile smc_uart_t *up; + volatile scc_uart_t *sup; + volatile immap_t *ip; + extern bd_t *board_info; + + ip = (immap_t *)IMAP_ADDR; +#ifdef SCC_CONSOLE + sup = (scc_uart_t *)&ip->im_dprambase[PROFF_SCC1 + ((SCC_CONSOLE-1) << 8)]; + tbdf = (cbd_t *)&ip->im_dprambase[sup->scc_genscc.scc_tbase]; +#else + up = (smc_uart_t *)&(ip->im_dprambase[PROFF_SMC1]); + tbdf = (cbd_t *)&ip->im_dprambase[up->smc_tbase]; +#endif + + /* Wait for last character to go. + */ + buf = (char *)tbdf->cbd_bufaddr; + while (tbdf->cbd_sc & BD_SC_READY); + + *buf = c; + tbdf->cbd_datlen = 1; + tbdf->cbd_sc |= BD_SC_READY; +} + +char +serial_getc() +{ + char c; + + if (cons_hold_cnt <= 0) { + cons_hold_cnt = serial_readbuf(cons_hold); + sgptr = cons_hold; + } + c = *sgptr++; + cons_hold_cnt--; + + return(c); +} + +int +serial_readbuf(u_char *cbuf) +{ + volatile cbd_t *rbdf; + volatile char *buf; + volatile smc_uart_t *up; + volatile scc_uart_t *sup; + volatile immap_t *ip; + int i, nc; + + ip = (immap_t *)IMAP_ADDR; + +#ifdef SCC_CONSOLE + sup = (scc_uart_t *)&ip->im_dprambase[PROFF_SCC1 + ((SCC_CONSOLE-1) << 8)]; + rbdf = (cbd_t *)&ip->im_dprambase[sup->scc_genscc.scc_rbase]; +#else + up = (smc_uart_t *)&(ip->im_dprambase[PROFF_SMC1]); + rbdf = (cbd_t *)&ip->im_dprambase[up->smc_rbase]; +#endif + + /* Wait for character to show up. + */ + buf = (char *)rbdf->cbd_bufaddr; + while (rbdf->cbd_sc & BD_SC_EMPTY); + nc = rbdf->cbd_datlen; + for (i=0; icbd_sc |= BD_SC_EMPTY; + + return(nc); +} + +int +serial_tstc() +{ + volatile cbd_t *rbdf; + volatile smc_uart_t *up; + volatile scc_uart_t *sup; + volatile immap_t *ip; + + ip = (immap_t *)IMAP_ADDR; +#ifdef SCC_CONSOLE + sup = (scc_uart_t *)&ip->im_dprambase[PROFF_SCC1 + ((SCC_CONSOLE-1) << 8)]; + rbdf = (cbd_t *)&ip->im_dprambase[sup->scc_genscc.scc_rbase]; +#else + up = (smc_uart_t *)&(ip->im_dprambase[PROFF_SMC1]); + rbdf = (cbd_t *)&ip->im_dprambase[up->smc_rbase]; +#endif + + return(!(rbdf->cbd_sc & BD_SC_EMPTY)); +} diff -Nru a/arch/ppc/boot/mbx/m8xx_tty.c b/arch/ppc/boot/mbx/m8xx_tty.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/mbx/m8xx_tty.c Wed May 16 06:00:23 2001 @@ -0,0 +1,276 @@ + + +/* Minimal serial functions needed to send messages out the serial + * port on the MBX console. + * + * The MBX uxes SMC1 for the serial port. We reset the port and use + * only the first BD that EPPC-Bug set up as a character FIFO. + * + * Later versions (at least 1.4, maybe earlier) of the MBX EPPC-Bug + * use COM1 instead of SMC1 as the console port. This kinda sucks + * for the rest of the kernel, so here we force the use of SMC1 again. + */ +#include +#include +#include +#include +#include "../../8xx_io/commproc.h" + +#ifdef CONFIG_MBX +#define MBX_CSR1 ((volatile u_char *)0xfa100000) +#define CSR1_COMEN (u_char)0x02 +#endif + +#ifdef TQM_SMC2_CONSOLE +#define PROFF_CONS PROFF_SMC2 +#define CPM_CR_CH_CONS CPM_CR_CH_SMC2 +#define SMC_INDEX 1 +static volatile iop8xx_t *iopp = (iop8xx_t *)&(((immap_t *)IMAP_ADDR)->im_ioport); +#else +#define PROFF_CONS PROFF_SMC1 +#define CPM_CR_CH_CONS CPM_CR_CH_SMC1 +#define SMC_INDEX 0 +#endif + +static cpm8xx_t *cpmp = (cpm8xx_t *)&(((immap_t *)IMAP_ADDR)->im_cpm); + +void +serial_init(bd_t *bd) +{ + volatile smc_t *sp; + volatile smc_uart_t *up; + volatile cbd_t *tbdf, *rbdf; + volatile cpm8xx_t *cp; + uint dpaddr, memaddr; + + cp = cpmp; + sp = (smc_t*)&(cp->cp_smc[SMC_INDEX]); + up = (smc_uart_t *)&cp->cp_dparam[PROFF_CONS]; + + /* Disable transmitter/receiver. + */ + sp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); + +#ifndef CONFIG_MBX + { + /* Initialize SMCx and use it for the console port. + */ + + /* Enable SDMA. + */ + ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sdcr = 1; + +#ifdef TQM_SMC2_CONSOLE + /* Use Port A for SMC2 instead of other functions. + */ + iopp->iop_papar |= 0x00c0; + iopp->iop_padir &= ~0x00c0; + iopp->iop_paodr &= ~0x00c0; +#else + /* Use Port B for SMCs instead of other functions. + */ + cp->cp_pbpar |= 0x00000cc0; + cp->cp_pbdir &= ~0x00000cc0; + cp->cp_pbodr &= ~0x00000cc0; +#endif + + /* Allocate space for two buffer descriptors in the DP ram. + * For now, this address seems OK, but it may have to + * change with newer versions of the firmware. + */ + dpaddr = 0x0800; + + /* Grab a few bytes from the top of memory for SMC FIFOs. + */ + memaddr = (bd->bi_memsize - 32) & ~15; + + /* Set the physical address of the host memory buffers in + * the buffer descriptors. + */ + rbdf = (cbd_t *)&cp->cp_dpmem[dpaddr]; + rbdf->cbd_bufaddr = memaddr; + rbdf->cbd_sc = 0; + tbdf = rbdf + 1; + tbdf->cbd_bufaddr = memaddr+4; + tbdf->cbd_sc = 0; + + /* Set up the uart parameters in the parameter ram. + */ + up->smc_rbase = dpaddr; + up->smc_tbase = dpaddr+sizeof(cbd_t); + up->smc_rfcr = SMC_EB; + up->smc_tfcr = SMC_EB; + + /* Set UART mode, 8 bit, no parity, one stop. + * Enable receive and transmit. + */ + sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART; + + /* Mask all interrupts and remove anything pending. + */ + sp->smc_smcm = 0; + sp->smc_smce = 0xff; + + /* Set up the baud rate generator. + * See 8xx_io/commproc.c for details. + * This wires BRG1 to SMC1 and BRG2 to SMC2; + */ + cp->cp_simode = 0x10000000; +#ifdef TQM_SMC2_CONSOLE + cp->cp_brgc2 = +#else + cp->cp_brgc1 = +#endif + ((((bd->bi_intfreq * 1000000)/16) / bd->bi_baudrate) << 1) | CPM_BRG_EN; + +#else /* CONFIG_MBX */ + if (*MBX_CSR1 & CSR1_COMEN) { + /* COM1 is enabled. Initialize SMC1 and use it for + * the console port. + */ + + /* Enable SDMA. + */ + ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sdcr = 1; + + /* Use Port B for SMCs instead of other functions. + */ + cp->cp_pbpar |= 0x00000cc0; + cp->cp_pbdir &= ~0x00000cc0; + cp->cp_pbodr &= ~0x00000cc0; + + /* Allocate space for two buffer descriptors in the DP ram. + * For now, this address seems OK, but it may have to + * change with newer versions of the firmware. + */ + dpaddr = 0x0800; + + /* Grab a few bytes from the top of memory. EPPC-Bug isn't + * running any more, so we can do this. + */ + memaddr = (bd->bi_memsize - 32) & ~15; + + /* Set the physical address of the host memory buffers in + * the buffer descriptors. + */ + rbdf = (cbd_t *)&cp->cp_dpmem[dpaddr]; + rbdf->cbd_bufaddr = memaddr; + rbdf->cbd_sc = 0; + tbdf = rbdf + 1; + tbdf->cbd_bufaddr = memaddr+4; + tbdf->cbd_sc = 0; + + /* Set up the uart parameters in the parameter ram. + */ + up->smc_rbase = dpaddr; + up->smc_tbase = dpaddr+sizeof(cbd_t); + up->smc_rfcr = SMC_EB; + up->smc_tfcr = SMC_EB; + + /* Set UART mode, 8 bit, no parity, one stop. + * Enable receive and transmit. + */ + sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART; + + /* Mask all interrupts and remove anything pending. + */ + sp->smc_smcm = 0; + sp->smc_smce = 0xff; + + /* Set up the baud rate generator. + * See 8xx_io/commproc.c for details. + */ + cp->cp_simode = 0x10000000; + cp->cp_brgc1 = + ((((bd->bi_intfreq * 1000000)/16) / 9600) << 1) | CPM_BRG_EN; + + /* Enable SMC1 for console output. + */ + *MBX_CSR1 &= ~CSR1_COMEN; + } + else { +#endif /* ndef CONFIG_MBX */ + /* SMCx is used as console port. + */ + tbdf = (cbd_t *)&cp->cp_dpmem[up->smc_tbase]; + rbdf = (cbd_t *)&cp->cp_dpmem[up->smc_rbase]; + + /* Issue a stop transmit, and wait for it. + */ + cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_CONS, + CPM_CR_STOP_TX) | CPM_CR_FLG; + while (cp->cp_cpcr & CPM_CR_FLG); + } + + /* Make the first buffer the only buffer. + */ + tbdf->cbd_sc |= BD_SC_WRAP; + rbdf->cbd_sc |= BD_SC_EMPTY | BD_SC_WRAP; + + /* Single character receive. + */ + up->smc_mrblr = 1; + up->smc_maxidl = 0; + + /* Initialize Tx/Rx parameters. + */ + cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_CONS, CPM_CR_INIT_TRX) | CPM_CR_FLG; + while (cp->cp_cpcr & CPM_CR_FLG); + + /* Enable transmitter/receiver. + */ + sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN; +} + +void +serial_putc(const char c) +{ + volatile cbd_t *tbdf; + volatile char *buf; + volatile smc_uart_t *up; + + up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_CONS]; + tbdf = (cbd_t *)&cpmp->cp_dpmem[up->smc_tbase]; + + /* Wait for last character to go. + */ + buf = (char *)tbdf->cbd_bufaddr; + while (tbdf->cbd_sc & BD_SC_READY); + + *buf = c; + tbdf->cbd_datlen = 1; + tbdf->cbd_sc |= BD_SC_READY; +} + +char +serial_getc() +{ + volatile cbd_t *rbdf; + volatile char *buf; + volatile smc_uart_t *up; + char c; + + up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_CONS]; + rbdf = (cbd_t *)&cpmp->cp_dpmem[up->smc_rbase]; + + /* Wait for character to show up. + */ + buf = (char *)rbdf->cbd_bufaddr; + while (rbdf->cbd_sc & BD_SC_EMPTY); + c = *buf; + rbdf->cbd_sc |= BD_SC_EMPTY; + + return(c); +} + +int +serial_tstc() +{ + volatile cbd_t *rbdf; + volatile smc_uart_t *up; + + up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_CONS]; + rbdf = (cbd_t *)&cpmp->cp_dpmem[up->smc_rbase]; + + return(!(rbdf->cbd_sc & BD_SC_EMPTY)); +} diff -Nru a/arch/ppc/boot/mbx/misc.c b/arch/ppc/boot/mbx/misc.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/mbx/misc.c Wed May 16 06:00:20 2001 @@ -0,0 +1,304 @@ +/* + * misc.c + * + * $Id: misc.c,v 1.2 1999/09/14 05:55:29 dmalek Exp $ + * + * Adapted for PowerPC by Gary Thomas + * + * Rewritten by Cort Dougan (cort@cs.nmt.edu) + * One day to be replaced by a single bootloader for chrp/prep/pmac. -- Cort + */ + +#include +#include "zlib.h" +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_8xx +#include +#endif +#ifdef CONFIG_8260 +#include +#endif + +/* + * The following references are needed to cause the linker to pull in the + * gzimage.o and rdimage.o files. These object files are special, + * since they get placed into the .gzimage and .rdimage ELF sections + * of the zvmlinux and zvmlinux.initrd files. + */ +extern char dummy_for_gzimage; +extern char dummy_for_rdimage; + +/* + * Please send me load/board info and such data for hardware not + * listed here so I can keep track since things are getting tricky + * with the different load addrs with different firmware. This will + * help to avoid breaking the load/boot process. + * -- Cort + */ +char *avail_ram; +char *end_avail; + +/* See comment below..... +*/ +unsigned int initrd_offset, initrd_size; + +/* Because of the limited amount of memory on embedded, it presents + * loading problems. The biggest is that we load this boot program + * into a relatively low memory address, and the Linux kernel Bss often + * extends into this space when it get loaded. When the kernel starts + * and zeros the BSS space, it also writes over the information we + * save here and pass to the kernel (command line and board info). + * On these boards, we grab some known memory holes to hold this information. + */ +char cmd_buf[256]; +char *cmd_line = cmd_buf; + +char *root_string = "root=/dev/nfs rw"; +char *nfsaddrs_string = "nfsaddrs="; +char *nfsroot_string = "nfsroot="; +char *defroot_string = "/sys/mbxroot"; +char *ramroot_string = "root=/dev/ram"; +int do_ipaddrs(char **cmd_cp, int echo); +void do_nfsroot(char **cmd_cp, char *dp); +int strncmp(const char * cs,const char * ct,size_t count); +char *strrchr(const char * s, int c); + +bd_t hold_resid_buf; +bd_t *hold_residual = &hold_resid_buf; +unsigned long initrd_start = 0, initrd_end = 0; +char *zimage_start; +int zimage_size; + +extern void puts(const char *); +extern void putc(const char c); +extern void udelay(long x); +extern void puthex(unsigned long val); +extern void * memcpy(void * __dest, __const void * __src, __kernel_size_t __n); +extern void gunzip(void *, int, unsigned char *, int *); +extern int tstc(void); +extern int getc(void); + +unsigned char sanity[0x2000]; + +unsigned long +decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, bd_t *bp) +{ + int timer; + extern unsigned long start; + char *cp, ch; + char *dp; + +#ifdef CONFIG_8260 + /* I don't know why I didn't do it this way on the 8xx....... + */ + embed_config(&bp); + serial_init(bp); +#endif + + /* These values must be variables. If not, the compiler optimizer + * will remove some code, causing the size of the code to vary + * when these values are zero. This is bad because we first + * compile with these zero to determine the size and offsets + * in an image, than compile again with these set to the proper + * discovered value.....Ya know, we used to read these from the + * header a long time ago..... + */ + initrd_offset = INITRD_OFFSET; + initrd_size = INITRD_SIZE; + + /* Grab some space for the command line and board info. Since + * we no longer use the ELF header, but it was loaded, grab + * that space. + */ +#ifdef CONFIG_MBX + cmd_line = (char *)(load_addr - 0x10000); + + /* To be like everyone else, we need one too, although this + * board information is passed from the boot rom. + */ + bp->bi_baudrate = 9600; +#else + cmd_line = (char *)(0x200000); +#endif + hold_residual = (bd_t *)(cmd_line + sizeof(cmd_buf)); + /* copy board data */ + if (bp) + memcpy(hold_residual,bp,sizeof(bd_t)); + + /* Set end of memory available to us. It is always the highest + * memory address provided by the board information. + */ + end_avail = (char *)(bp->bi_memsize); + + puts("loaded at: "); puthex(load_addr); + puts(" "); puthex((unsigned long)(load_addr + (4*num_words))); puts("\n"); + if ( (unsigned long)load_addr != (unsigned long)&start ) + { + puts("relocated to: "); puthex((unsigned long)&start); + puts(" "); + puthex((unsigned long)((unsigned long)&start + (4*num_words))); + puts("\n"); + } + + if ( bp ) + { + puts("board data at: "); puthex((unsigned long)bp); + puts(" "); + puthex((unsigned long)((unsigned long)bp + sizeof(bd_t))); + puts("\n"); + puts("relocated to: "); + puthex((unsigned long)hold_residual); + puts(" "); + puthex((unsigned long)((unsigned long)hold_residual + sizeof(bd_t))); + puts("\n"); + } + + /* we have to subtract 0x10000 here to correct for objdump including the + size of the elf header which we strip -- Cort */ + zimage_start = (char *)(load_addr - 0x10000 + ZIMAGE_OFFSET); + zimage_size = ZIMAGE_SIZE; + + if ( initrd_offset ) + initrd_start = load_addr - 0x10000 + initrd_offset; + else + initrd_start = 0; + initrd_end = initrd_size + initrd_start; + + /* + * setup avail_ram - this is the first part of ram usable + * by the uncompress code. -- Cort + */ + avail_ram = (char *)PAGE_ALIGN((unsigned long)zimage_start+zimage_size); + if ( ((load_addr+(num_words*4)) > (unsigned long) avail_ram) + && (load_addr <= 0x01000000) ) + avail_ram = (char *)(load_addr+(num_words*4)); + if ( (((unsigned long)&start+(num_words*4)) > (unsigned long) avail_ram) + && (load_addr <= 0x01000000) ) + avail_ram = (char *)((unsigned long)&start+(num_words*4)); + + /* relocate zimage */ + puts("zimage at: "); puthex((unsigned long)zimage_start); + puts(" "); puthex((unsigned long)(zimage_size+zimage_start)); puts("\n"); + /* + * There is no reason (yet) to relocate zImage for embedded boards. + * To support boot from flash rom on 8xx embedded boards, I + * assume if zimage start is over 16M we are booting from flash. + * In this case, avilable ram will start just above the space we + * have allocated for the command buffer and board information. + */ + if ((unsigned long)zimage_start > 0x01000000) + avail_ram = (char *)PAGE_ALIGN((unsigned long)hold_residual + sizeof(bd_t)); + + /* relocate initrd */ + if ( initrd_start ) + { + puts("initrd at: "); puthex(initrd_start); + puts(" "); puthex(initrd_end); puts("\n"); + + /* We only have to relocate initrd if we find it is in Flash + * rom. This is because the kernel thinks it can toss the + * pages into the free memory pool after it is done. Use + * the same 16M test. + */ + if ((unsigned long)initrd_start > 0x01000000) { + memcpy ((void *)PAGE_ALIGN(-PAGE_SIZE+(unsigned long)end_avail-INITRD_SIZE), + (void *)initrd_start, + initrd_size ); + initrd_start = PAGE_ALIGN(-PAGE_SIZE+(unsigned long)end_avail-INITRD_SIZE); + initrd_end = initrd_start + initrd_size; + end_avail = (char *)initrd_start; + puts("relocated to: "); puthex(initrd_start); + puts(" "); puthex(initrd_end); puts("\n"); + } + else { + avail_ram = (char *)PAGE_ALIGN((unsigned long)initrd_end); + } + } + + + puts("avail ram: "); puthex((unsigned long)avail_ram); puts(" "); + puthex((unsigned long)end_avail); puts("\n"); + + puts("\nLinux/PPC load: "); + timer = 0; + cp = cmd_line; + + while (timer++ < 5*1000) { + if (tstc()) { + while ((ch = getc()) != '\n' && ch != '\r') { + if (ch == '\b') { + if (cp != cmd_line) { + cp--; + puts("\b \b"); + } + } else { + *cp++ = ch; + putc(ch); + } + } + break; /* Exit 'timer' loop */ + } + udelay(1000); /* 1 msec */ + } + *cp = 0; + + /* If the command line is not filled in, we will automatically + * create the default boot. + */ + if (cmd_line[0] == 0) { + + /* An initrd on these boards means we booted from Flash + * ROM and want to use the ramdisk as the root file system. + * Otherwise, we perform a diskless NFS boot. + */ + if (!initrd_start) { + dp = root_string; + while (*dp != 0) + *cp++ = *dp++; + *cp = 0; + } + } + + puts("\n"); + + puts("Uncompressing Linux..."); + + gunzip(0, 0x400000, zimage_start, &zimage_size); + puts("done.\n"); + puts("Now booting the kernel\n"); + return (unsigned long)hold_residual; +} + +/* + * PCI/ISA I/O support + */ + +volatile unsigned char *ISA_io = (unsigned char *)0x80000000; +volatile unsigned char *ISA_mem = (unsigned char *)0xC0000000; + +void +outb(int port, char val) +{ + /* Ensure I/O operations complete */ + __asm__ volatile("eieio"); + ISA_io[port] = val; +} + +unsigned char +inb(int port) +{ + /* Ensure I/O operations complete */ + __asm__ volatile("eieio"); + return (ISA_io[port]); +} + +unsigned long +local_to_PCI(unsigned long addr) +{ + return ((addr & 0x7FFFFFFF) | 0x80000000); +} diff -Nru a/arch/ppc/boot/mbx/pci.c b/arch/ppc/boot/mbx/pci.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/mbx/pci.c Wed May 16 06:00:22 2001 @@ -0,0 +1,252 @@ +/* Stand alone funtions for QSpan Tundra support. + */ +#include +#include +#include +#include + +/* To map PCI devices, you first write 0xffffffff into the device + * base address registers. When the register is read back, the + * number of most significant '1' bits describes the amount of address + * space needed for mapping. If the most significant bit is not set, + * either the device does not use that address register, or it has + * a fixed address that we can't change. After the address is assigned, + * the command register has to be written to enable the card. + */ +typedef struct { + u_char pci_bus; + u_char pci_devfn; + ushort pci_command; + uint pci_addrs[6]; +} pci_map_t; + +/* We should probably dynamically allocate these structures. +*/ +#define MAX_PCI_DEVS 32 +int pci_dev_cnt; +pci_map_t pci_map[MAX_PCI_DEVS]; + +void pci_conf_write(int bus, int device, int func, int reg, uint writeval); +void pci_conf_read(int bus, int device, int func, int reg, void *readval); +void probe_addresses(int bus, int devfn); +void map_pci_addrs(void); + +/* This is a really stripped version of PCI bus scan. All we are + * looking for are devices that exist. + */ +pci_scanner(int addr_probe) +{ + unsigned int devfn, l, max, class, bus_number; + unsigned char cmd, irq, tmp, hdr_type, is_multi; + int reg; + + is_multi = 0; + bus_number = 0; + for (devfn = 0; devfn < 0xff; ++devfn) { + /* The device numbers are comprised of upper 5 bits of + * device number and lower 3 bits of multi-function number. + */ + if ((devfn & 7) && !is_multi) { + /* Don't scan multifunction addresses if this is + * not a multifunction device. + */ + continue; + } + + /* Read the header to determine card type. + */ + qs_pci_read_config_byte(bus_number, devfn, PCI_HEADER_TYPE, + &hdr_type); + + /* If this is a base device number, check the header to + * determine if it is mulifunction. + */ + if ((devfn & 7) == 0) + is_multi = hdr_type & 0x80; + + /* Check to see if the board is really in the slot. + */ + qs_pci_read_config_dword(bus_number, devfn, PCI_VENDOR_ID, &l); + /* some broken boards return 0 if a slot is empty: */ + if (l == 0xffffffff || l == 0x00000000 || l == 0x0000ffff || + l == 0xffff0000) { + /* Nothing there. + */ + is_multi = 0; + continue; + } + + /* If we are not performing an address probe, + * just simply print out some information. + */ + if (!addr_probe) { + qs_pci_read_config_dword(bus_number, devfn, + PCI_CLASS_REVISION, &class); + + class >>= 8; /* upper 3 bytes */ + +#if 0 + printf("Found (%3d:%d): vendor 0x%04x, device 0x%04x, class 0x%06x\n", + (devfn >> 3), (devfn & 7), + (l & 0xffff), (l >> 16) & 0xffff, class); +#else + puts("Found ("); puthex(devfn >> 3); + puts(":"); puthex(devfn & 7); + puts("): vendor "); puthex(l & 0xffff); + puts(", device "); puthex((l >> 16) & 0xffff); + puts(", class "); puthex(class); puts("\n"); +#endif + } + else { + /* If this is a "normal" device, build address list. + */ + if ((hdr_type & 0x7f) == PCI_HEADER_TYPE_NORMAL) + probe_addresses(bus_number, devfn); + } + } + + /* Now map the boards. + */ + if (addr_probe) + map_pci_addrs(); +} + +/* Probe addresses for the specified device. This is a destructive + * operation because it writes the registers. + */ +void +probe_addresses(bus, devfn) +{ + int i; + uint pciaddr; + ushort pcicmd; + pci_map_t *pm; + + if (pci_dev_cnt >= MAX_PCI_DEVS) { + puts("Too many PCI devices\n"); + return; + } + + pm = &pci_map[pci_dev_cnt++]; + + pm->pci_bus = bus; + pm->pci_devfn = devfn; + + for (i=0; i<6; i++) { + qs_pci_write_config_dword(bus, devfn, PCI_BASE_ADDRESS_0 + (i * 4), -1); + qs_pci_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0 + (i * 4), + &pciaddr); + pm->pci_addrs[i] = pciaddr; + qs_pci_read_config_word(bus, devfn, PCI_COMMAND, &pcicmd); + pm->pci_command = pcicmd; + } +} + +/* Map the cards into the PCI space. The PCI has separate memory + * and I/O spaces. In addition, some memory devices require mapping + * below 1M. The least significant 4 bits of the address register + * provide information. If this is an I/O device, only the LS bit + * is used to indicate that, so I/O devices can be mapped to a two byte + * boundard. Memory addresses can be mapped to a 32 byte boundary. + * The QSpan implementations usually have a 1Gbyte space for each + * memory and I/O spaces. + * + * This isn't a terribly fancy algorithm. I just map the spaces from + * the top starting with the largest address space. When finished, + * the registers are written and the card enabled. + * + * While the Tundra can map a large address space on most boards, we + * need to be careful because it may overlap other devices (like IMMR). + */ +#define MEMORY_SPACE_SIZE 0x20000000 +#define IO_SPACE_SIZE 0x20000000 + +void +map_pci_addrs() +{ + uint pci_mem_top, pci_mem_low; + uint pci_io_top; + uint addr_mask, reg_addr, space; + int i, j; + pci_map_t *pm; + + pci_mem_top = MEMORY_SPACE_SIZE; + pci_io_top = IO_SPACE_SIZE; + pci_mem_low = (1 * 1024 * 1024); /* Below one meg addresses */ + + /* We can't map anything more than the maximum space, but test + * for it anyway to catch devices out of range. + */ + addr_mask = 0x80000000; + + do { + space = (~addr_mask) + 1; /* Size of the space */ + for (i=0; ipci_addrs[j]; + if ((reg_addr & 0x80000000) == 0) + continue; + if (reg_addr & PCI_BASE_ADDRESS_SPACE_IO) { + if ((reg_addr & PCI_BASE_ADDRESS_IO_MASK) != addr_mask) + continue; + if (pci_io_top < space) { + puts("Out of PCI I/O space\n"); + } + else { + pci_io_top -= space; + pm->pci_addrs[j] = pci_io_top; + pm->pci_command |= PCI_COMMAND_IO; + } + } + else { + if ((reg_addr & PCI_BASE_ADDRESS_MEM_MASK) != addr_mask) + continue; + + /* Memory space. Test if below 1M. + */ + if (reg_addr & PCI_BASE_ADDRESS_MEM_TYPE_1M) { + if (pci_mem_low < space) { + puts("Out of PCI 1M space\n"); + } + else { + pci_mem_low -= space; + pm->pci_addrs[j] = pci_mem_low; + } + } + else { + if (pci_mem_top < space) { + puts("Out of PCI Mem space\n"); + } + else { + pci_mem_top -= space; + pm->pci_addrs[j] = pci_mem_top; + } + } + pm->pci_command |= PCI_COMMAND_MEMORY; + } + } + } + addr_mask >>= 1; + addr_mask |= 0x80000000; + } while (addr_mask != 0xfffffffe); + + /* Now, run the list one more time and map everything. + */ + for (i=0; ipci_bus, pm->pci_devfn, + PCI_BASE_ADDRESS_0 + (j * 4), pm->pci_addrs[j]); + } + + /* Enable memory or address mapping. + */ + qs_pci_write_config_word(pm->pci_bus, pm->pci_devfn, PCI_COMMAND, + pm->pci_command); + } +} + diff -Nru a/arch/ppc/boot/mbx/qspan_pci.c b/arch/ppc/boot/mbx/qspan_pci.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/mbx/qspan_pci.c Wed May 16 06:00:25 2001 @@ -0,0 +1,268 @@ +/* + * LinuxPPC arch/ppc/kernel/qspan_pci.c Dan Malek (dmalek@jlc.net) + * + * QSpan Motorola bus to PCI bridge. The config address register + * is located 0x500 from the base of the bridge control/status registers. + * The data register is located at 0x504. + * This is a two step operation. First, the address register is written, + * then the data register is read/written as required. + * I don't know what to do about interrupts (yet). + */ + +#include +#include +#include +#include + +/* + * When reading the configuration space, if something does not respond + * the bus times out and we get a machine check interrupt. So, the + * good ol' exception tables come to mind to trap it and return some + * value. + * + * On an error we just return a -1, since that is what the caller wants + * returned if nothing is present. I copied this from __get_user_asm, + * with the only difference of returning -1 instead of EFAULT. + * There is an associated hack in the machine check trap code. + * + * The QSPAN is also a big endian device, that is it makes the PCI + * look big endian to us. This presents a problem for the Linux PCI + * functions, which assume little endian. For example, we see the + * first 32-bit word like this: + * ------------------------ + * | Device ID | Vendor ID | + * ------------------------ + * If we read/write as a double word, that's OK. But in our world, + * when read as a word, device ID is at location 0, not location 2 as + * the little endian PCI would believe. We have to switch bits in + * the PCI addresses given to us to get the data to/from the correct + * byte lanes. + * + * The QSPAN only supports 4 bits of "slot" in the dev_fn instead of 5. + * It always forces the MS bit to zero. Therefore, dev_fn values + * greater than 128 are returned as "no device found" errors. + * + * The QSPAN can only perform long word (32-bit) configuration cycles. + * The "offset" must have the two LS bits set to zero. Read operations + * require we read the entire word and then sort out what should be + * returned. Write operations other than long word require that we + * read the long word, update the proper word or byte, then write the + * entire long word back. + * + * PCI Bridge hack. We assume (correctly) that bus 0 is the primary + * PCI bus from the QSPAN. If we are called with a bus number other + * than zero, we create a Type 1 configuration access that a downstream + * PCI bridge will interpret. + */ + +#define __get_pci_config(x, addr, op) \ + __asm__ __volatile__( \ + "1: "op" %0,0(%1)\n" \ + " eieio\n" \ + "2:\n" \ + ".section .fixup,\"ax\"\n" \ + "3: li %0,-1\n" \ + " b 2b\n" \ + ".section __ex_table,\"a\"\n" \ + " .align 2\n" \ + " .long 1b,3b\n" \ + ".text" \ + : "=r"(x) : "r"(addr)) + +#define QS_CONFIG_ADDR ((volatile uint *)(PCI_CSR_ADDR + 0x500)) +#define QS_CONFIG_DATA ((volatile uint *)(PCI_CSR_ADDR + 0x504)) + +#define mk_config_addr(bus, dev, offset) \ + (((bus)<<16) | ((dev)<<8) | (offset & 0xfc)) + +#define mk_config_type1(bus, dev, offset) \ + mk_config_addr(bus, dev, offset) | 1; + +/* Initialize the QSpan device registers after power up. +*/ +qspan_init() +{ + uint *qptr; + + + + qptr = (uint *)PCI_CSR_ADDR; + + /* PCI Configuration/status. Upper bits written to clear + * pending interrupt or status. Lower bits enable QSPAN as + * PCI master, enable memory and I/O cycles, and enable PCI + * parity error checking. + * IMPORTANT: The last two bits of this word enable PCI + * master cycles into the QBus. The QSpan is broken and can't + * meet the timing specs of the PQ bus for this to work. Therefore, + * if you don't have external bus arbitration, you can't use + * this function. + */ +#ifdef EXTERNAL_PQ_ARB + qptr[1] = 0xf9000147; +#else + qptr[1] = 0xf9000144; +#endif + + /* PCI Misc configuration. Set PCI latency timer resolution + * of 8 cycles, set cache size to 4 x 32. + */ + qptr[3] = 0; + + /* Set up PCI Target address mapping. Enable, Posted writes, + * 2Gbyte space (processor memory controller determines actual size). + */ + qptr[64] = 0x8f000080; + + /* Map processor 0x80000000 to PCI 0x00000000. + * Processor address bit 1 determines I/O type access (0x80000000) + * or memory type access (0xc0000000). + */ + qptr[65] = 0x80000000; + + /* Enable error logging and clear any pending error status. + */ + qptr[80] = 0x90000000; + + qptr[512] = 0x000c0003; + + /* Set up Qbus slave image. + */ + qptr[960] = 0x01000000; + qptr[961] = 0x000000d1; + qptr[964] = 0x00000000; + qptr[965] = 0x000000d1; + +} + +/* Functions to support PCI bios-like features to read/write configuration + * space. If the function fails for any reason, a -1 (0xffffffff) value + * must be returned. + */ +#define DEVICE_NOT_FOUND (-1) +#define SUCCESSFUL 0 + +int qs_pci_read_config_byte(unsigned char bus, unsigned char dev_fn, + unsigned char offset, unsigned char *val) +{ + uint temp; + u_char *cp; + + if ((bus > 7) || (dev_fn > 127)) { + *val = 0xff; + return DEVICE_NOT_FOUND; + } + + if (bus == 0) + *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset); + else + *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset); + __get_pci_config(temp, QS_CONFIG_DATA, "lwz"); + + offset ^= 0x03; + cp = ((u_char *)&temp) + (offset & 0x03); + *val = *cp; + return SUCCESSFUL; +} + +int qs_pci_read_config_word(unsigned char bus, unsigned char dev_fn, + unsigned char offset, unsigned short *val) +{ + uint temp; + ushort *sp; + + if ((bus > 7) || (dev_fn > 127)) { + *val = 0xffff; + return DEVICE_NOT_FOUND; + } + + if (bus == 0) + *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset); + else + *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset); + __get_pci_config(temp, QS_CONFIG_DATA, "lwz"); + offset ^= 0x02; + + sp = ((ushort *)&temp) + ((offset >> 1) & 1); + *val = *sp; + return SUCCESSFUL; +} + +int qs_pci_read_config_dword(unsigned char bus, unsigned char dev_fn, + unsigned char offset, unsigned int *val) +{ + if ((bus > 7) || (dev_fn > 127)) { + *val = 0xffffffff; + return DEVICE_NOT_FOUND; + } + if (bus == 0) + *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset); + else + *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset); + __get_pci_config(*val, QS_CONFIG_DATA, "lwz"); + return SUCCESSFUL; +} + +int qs_pci_write_config_byte(unsigned char bus, unsigned char dev_fn, + unsigned char offset, unsigned char val) +{ + uint temp; + u_char *cp; + + if ((bus > 7) || (dev_fn > 127)) + return DEVICE_NOT_FOUND; + + qs_pci_read_config_dword(bus, dev_fn, offset, &temp); + + offset ^= 0x03; + cp = ((u_char *)&temp) + (offset & 0x03); + *cp = val; + + if (bus == 0) + *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset); + else + *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset); + *QS_CONFIG_DATA = temp; + + return SUCCESSFUL; +} + +int qs_pci_write_config_word(unsigned char bus, unsigned char dev_fn, + unsigned char offset, unsigned short val) +{ + uint temp; + ushort *sp; + + if ((bus > 7) || (dev_fn > 127)) + return DEVICE_NOT_FOUND; + + qs_pci_read_config_dword(bus, dev_fn, offset, &temp); + + offset ^= 0x02; + sp = ((ushort *)&temp) + ((offset >> 1) & 1); + *sp = val; + + if (bus == 0) + *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset); + else + *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset); + *QS_CONFIG_DATA = temp; + + return SUCCESSFUL; +} + +int qs_pci_write_config_dword(unsigned char bus, unsigned char dev_fn, + unsigned char offset, unsigned int val) +{ + if ((bus > 7) || (dev_fn > 127)) + return DEVICE_NOT_FOUND; + + if (bus == 0) + *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset); + else + *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset); + *(unsigned int *)QS_CONFIG_DATA = val; + + return SUCCESSFUL; +} + diff -Nru a/arch/ppc/boot/mbx/rdimage.c b/arch/ppc/boot/mbx/rdimage.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/mbx/rdimage.c Wed May 16 06:00:18 2001 @@ -0,0 +1,8 @@ +/* + * rdimage.c + * + * Dummy file to allow a compressed initrd to be added + * into a linker section, accessed by the boot coode + */ + +char dummy_for_rdimage; diff -Nru a/arch/ppc/boot/misc.c b/arch/ppc/boot/misc.c --- a/arch/ppc/boot/misc.c Wed May 16 06:00:17 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,845 +0,0 @@ -/* - * misc.c - * - * $Id: misc.c,v 1.68 1999/10/20 22:08:08 cort Exp $ - * - * Adapted for PowerPC by Gary Thomas - * - * Rewritten by Cort Dougan (cort@cs.nmt.edu) - * One day to be replaced by a single bootloader for chrp/prep/pmac. -- Cort - */ - -#include -#include "../coffboot/zlib.h" -#include "asm/residual.h" -#include -#include -#include -#include -#include -#include -#if defined(CONFIG_SERIAL_CONSOLE) -#include "ns16550.h" -struct NS16550 *com_port; -#endif /* CONFIG_SERIAL_CONSOLE */ - -/* - * Please send me load/board info and such data for hardware not - * listed here so I can keep track since things are getting tricky - * with the different load addrs with different firmware. This will - * help to avoid breaking the load/boot process. - * -- Cort - */ -char *avail_ram; -char *end_avail; -extern char _end[]; - -#ifdef CONFIG_CMDLINE -#define CMDLINE CONFIG_CMDLINE -#else -#define CMDLINE ""; -#endif -char cmd_preset[] = CMDLINE; -char cmd_buf[256]; -char *cmd_line = cmd_buf; - -int keyb_present = 1; /* keyboard controller is present by default */ -RESIDUAL hold_resid_buf; -RESIDUAL *hold_residual = &hold_resid_buf; -unsigned long initrd_start = 0, initrd_end = 0; -char *zimage_start; -int zimage_size; - -char *vidmem = (char *)0xC00B8000; -int lines, cols; -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 * memcpy(void * __dest, __const void * __src, - int __n); -void gunzip(void *, int, unsigned char *, int *); -static int _cvt(unsigned long val, char *buf, long radix, char *digits); -unsigned char inb(int); - -void pause() -{ - puts("pause\n"); -} - -void exit() -{ - puts("exit\n"); - while(1); -} - -static void clear_screen() -{ - int i, j; - for (i = 0; i < lines; i++) { - for (j = 0; j < cols; j++) { - vidmem[((i*cols)+j)*2] = ' '; - vidmem[((i*cols)+j)*2+1] = 0x07; - } - } -} - -static void scroll() -{ - int i; - - memcpy ( vidmem, vidmem + cols * 2, ( lines - 1 ) * cols * 2 ); - for ( i = ( lines - 1 ) * cols * 2; i < lines * cols * 2; i += 2 ) - vidmem[i] = ' '; -} - -tstc(void) -{ -#if defined(CONFIG_SERIAL_CONSOLE) - if (keyb_present) - return (CRT_tstc() || NS16550_tstc(com_port)); - else - NS16550_tstc(com_port); -#else - return (CRT_tstc() ); -#endif /* CONFIG_SERIAL_CONSOLE */ -} - -getc(void) -{ - while (1) { -#if defined(CONFIG_SERIAL_CONSOLE) - if (NS16550_tstc(com_port)) return (NS16550_getc(com_port)); -#endif /* CONFIG_SERIAL_CONSOLE */ - if (keyb_present) - if (CRT_tstc()) return (CRT_getc()); - } -} - -void -putc(const char c) -{ - int x,y; - -#if defined(CONFIG_SERIAL_CONSOLE) - NS16550_putc(com_port, c); - if ( c == '\n' ) NS16550_putc(com_port, '\r'); -#endif /* CONFIG_SERIAL_CONSOLE */ - - x = orig_x; - y = orig_y; - - if ( c == '\n' ) { - x = 0; - if ( ++y >= lines ) { - scroll(); - y--; - } - } else if (c == '\r') { - x = 0; - } 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) -{ - int x,y; - char c; - - x = orig_x; - y = orig_y; - - while ( ( c = *s++ ) != '\0' ) { -#if defined(CONFIG_SERIAL_CONSOLE) - NS16550_putc(com_port, c); - if ( c == '\n' ) NS16550_putc(com_port, '\r'); -#endif /* CONFIG_SERIAL_CONSOLE */ - - 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 * memcpy(void * __dest, __const void * __src, - int __n) -{ - int i; - char *d = (char *)__dest, *s = (char *)__src; - - for (i=0;i<__n;i++) d[i] = s[i]; -} - -int memcmp(__const void * __dest, __const void * __src, - int __n) -{ - int i; - char *d = (char *)__dest, *s = (char *)__src; - - for (i=0;i<__n;i++, d++, s++) - { - if (*d != *s) - { - return (*s - *d); - } - } - return (0); -} - -void error(char *x) -{ - puts("\n\n"); - puts(x); - puts("\n\n -- System halted"); - - while(1); /* Halt */ -} - -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) { - puts("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) { - puts("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) { - puts("gunzip: ran out of data in header\n"); - exit(); - } - - s.zalloc = zalloc; - s.zfree = zfree; - r = inflateInit2(&s, -MAX_WBITS); - if (r != Z_OK) { - puts("inflateInit2 returned %d\n"); - 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) { - puts("inflate returned %d\n"); - exit(); - } - *lenp = s.next_out - (unsigned char *) dst; - inflateEnd(&s); -} - -unsigned long -decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, - RESIDUAL *residual, void *OFW_interface) -{ - int timer; - extern unsigned long start; - char *cp, ch; - unsigned long i; - BATU *u; - BATL *l; - unsigned long TotalMemory; - unsigned long orig_MSR; - int dev_handle; - int mem_info[2]; - int res, size; - unsigned char board_type; - unsigned char base_mod; - - lines = 25; - cols = 80; - orig_x = 0; - orig_y = 24; - - /* - * IBM's have the MMU on, so we have to disable it or - * things get really unhappy in the kernel when - * trying to setup the BATs with the MMU on - * -- Cort - */ - flush_instruction_cache(); - _put_HID0(_get_HID0() & ~0x0000C000); - _put_MSR((orig_MSR = _get_MSR()) & ~0x0030); - -#if defined(CONFIG_SERIAL_CONSOLE) - com_port = (struct NS16550 *)NS16550_init(0); -#endif /* CONFIG_SERIAL_CONSOLE */ - vga_init(0xC0000000); - - if (residual) - { - /* Is this Motorola PPCBug? */ - if ((1 & residual->VitalProductData.FirmwareSupports) && - (1 == residual->VitalProductData.FirmwareSupplier)) { - board_type = inb(0x800) & 0xF0; - - /* If this is genesis 2 board then check for no - * keyboard controller and more than one processor. - */ - if (board_type == 0xe0) { - base_mod = inb(0x803); - /* if a MVME2300/2400 or a Sitka then no keyboard */ - if((base_mod == 0xFA) || (base_mod == 0xF9) || - (base_mod == 0xE1)) { - keyb_present = 0; /* no keyboard */ - } - } - } - memcpy(hold_residual,residual,sizeof(RESIDUAL)); - } else { - /* Assume 32M in the absence of more info... */ - TotalMemory = 0x02000000; - /* - * This is a 'best guess' check. We want to make sure - * we don't try this on a PReP box without OF - * -- Cort - */ - while (OFW_interface && ((unsigned long)OFW_interface < 0x10000000) ) - { - /* The MMU needs to be on when we call OFW */ - _put_MSR(orig_MSR); - of_init(OFW_interface); - - /* get handle to memory description */ - res = of_finddevice("/memory@0", - &dev_handle); - // puthex(res); puts("\n"); - if (res) break; - - /* get the info */ - // puts("get info = "); - res = of_getprop(dev_handle, - "reg", - mem_info, - sizeof(mem_info), - &size); - // puthex(res); puts(", info = "); puthex(mem_info[0]); - // puts(" "); puthex(mem_info[1]); puts("\n"); - if (res) break; - - TotalMemory = mem_info[1]; - break; - } - hold_residual->TotalMemory = TotalMemory; - residual = hold_residual; - /* Turn MMU back off */ - _put_MSR(orig_MSR & ~0x0030); - } - - /* assume the chunk below 8M is free */ - end_avail = (char *)0x00800000; - - /* tell the user where we were loaded at and where we - * were relocated to for debugging this process - */ - puts("loaded at: "); puthex(load_addr); - puts(" "); puthex((unsigned long)(load_addr + (4*num_words))); puts("\n"); - if ( (unsigned long)load_addr != (unsigned long)&start ) - { - puts("relocated to: "); puthex((unsigned long)&start); - puts(" "); - puthex((unsigned long)((unsigned long)&start + (4*num_words))); - puts("\n"); - } - - if ( residual ) - { - puts("board data at: "); puthex((unsigned long)residual); - puts(" "); - puthex((unsigned long)((unsigned long)residual + sizeof(RESIDUAL))); - puts("\n"); - puts("relocated to: "); - puthex((unsigned long)hold_residual); - puts(" "); - puthex((unsigned long)((unsigned long)hold_residual + sizeof(RESIDUAL))); - puts("\n"); - } - - /* we have to subtract 0x10000 here to correct for objdump including the - size of the elf header which we strip -- Cort */ - zimage_start = (char *)(load_addr - 0x10000 + ZIMAGE_OFFSET); - zimage_size = ZIMAGE_SIZE; - - if ( INITRD_OFFSET ) - initrd_start = load_addr - 0x10000 + INITRD_OFFSET; - else - initrd_start = 0; - initrd_end = INITRD_SIZE + initrd_start; - - /* - * Find a place to stick the zimage and initrd and - * relocate them if we have to. -- Cort - */ - avail_ram = (char *)PAGE_ALIGN((unsigned long)_end); - puts("zimage at: "); puthex((unsigned long)zimage_start); - puts(" "); puthex((unsigned long)(zimage_size+zimage_start)); puts("\n"); - if ( (unsigned long)zimage_start <= 0x00800000 ) - { - memcpy( (void *)avail_ram, (void *)zimage_start, zimage_size ); - zimage_start = (char *)avail_ram; - puts("relocated to: "); puthex((unsigned long)zimage_start); - puts(" "); - puthex((unsigned long)zimage_size+(unsigned long)zimage_start); - puts("\n"); - avail_ram += zimage_size; - } - - /* relocate initrd */ - if ( initrd_start ) - { - puts("initrd at: "); puthex(initrd_start); - puts(" "); puthex(initrd_end); puts("\n"); - if ( (unsigned long)initrd_start <= 0x00800000 ) - { - memcpy( (void *)avail_ram, - (void *)initrd_start, initrd_end-initrd_start ); - puts("relocated to: "); - initrd_end = (unsigned long) avail_ram + (initrd_end-initrd_start); - initrd_start = (unsigned long)avail_ram; - puthex((unsigned long)initrd_start); - puts(" "); - puthex((unsigned long)initrd_end); - puts("\n"); - } - avail_ram = (char *)PAGE_ALIGN((unsigned long)initrd_end); - } - - avail_ram = (char *)0x00400000; - end_avail = (char *)0x00800000; - puts("avail ram: "); puthex((unsigned long)avail_ram); puts(" "); - puthex((unsigned long)end_avail); puts("\n"); - - if (keyb_present) - CRT_tstc(); /* Forces keyboard to be initialized */ - - puts("\nLinux/PPC load: "); - timer = 0; - cp = cmd_line; - memcpy (cmd_line, cmd_preset, sizeof(cmd_preset)); - while ( *cp ) putc(*cp++); - while (timer++ < 5*1000) { - if (tstc()) { - while ((ch = getc()) != '\n' && ch != '\r') { - if (ch == '\b') { - if (cp != cmd_line) { - cp--; - puts("\b \b"); - } - } else { - *cp++ = ch; - putc(ch); - } - } - break; /* Exit 'timer' loop */ - } - udelay(1000); /* 1 msec */ - } - *cp = 0; - puts("\n"); - - puts("Uncompressing Linux..."); - gunzip(0, 0x400000, zimage_start, &zimage_size); - puts("done.\n"); - - { - struct bi_record *rec; - - rec = (struct bi_record *)PAGE_ALIGN(zimage_size); - - rec->tag = BI_FIRST; - rec->size = sizeof(struct bi_record); - rec = (struct bi_record *)((unsigned long)rec + rec->size); - - rec->tag = BI_BOOTLOADER_ID; - memcpy( (void *)rec->data, "prepboot", 9); - rec->size = sizeof(struct bi_record) + 8 + 1; - rec = (struct bi_record *)((unsigned long)rec + rec->size); - - rec->tag = BI_MACHTYPE; - rec->data[0] = _MACH_prep; - rec->data[1] = 1; - rec->size = sizeof(struct bi_record) + sizeof(unsigned long); - rec = (struct bi_record *)((unsigned long)rec + rec->size); - - rec->tag = BI_CMD_LINE; - memcpy( (char *)rec->data, cmd_line, strlen(cmd_line)+1); - rec->size = sizeof(struct bi_record) + strlen(cmd_line) + 1; - rec = (struct bi_record *)((ulong)rec + rec->size); - - rec->tag = BI_LAST; - rec->size = sizeof(struct bi_record); - rec = (struct bi_record *)((unsigned long)rec + rec->size); - } - puts("Now booting the kernel\n"); - return (unsigned long)hold_residual; -} - -void puthex(unsigned long val) -{ - unsigned char buf[10]; - int i; - for (i = 7; i >= 0; i--) - { - buf[i] = "0123456789ABCDEF"[val & 0x0F]; - val >>= 4; - } - buf[8] = '\0'; - puts(buf); -} - -/* - * PCI/ISA I/O support - */ - -volatile unsigned char *ISA_io = (unsigned char *)0x80000000; -volatile unsigned char *ISA_mem = (unsigned char *)0xC0000000; - -void -outb(int port, char val) -{ - /* Ensure I/O operations complete */ - __asm__ volatile("eieio"); - ISA_io[port] = val; -} - -unsigned char -inb(int port) -{ - /* Ensure I/O operations complete */ - __asm__ volatile("eieio"); - return (ISA_io[port]); -} - -unsigned long -local_to_PCI(unsigned long addr) -{ - return ((addr & 0x7FFFFFFF) | 0x80000000); -} - -void -_bcopy(char *src, char *dst, int len) -{ - while (len--) *dst++ = *src++; -} - - -#define FALSE 0 -#define TRUE 1 -#include - -int -strlen(char *s) -{ - int len = 0; - while (*s++) len++; - return len; -} - -_printk(char const *fmt, ...) -{ - int ret; - va_list ap; - - va_start(ap, fmt); - ret = _vprintk(putc, fmt, ap); - va_end(ap); - return (ret); -} - -#define is_digit(c) ((c >= '0') && (c <= '9')) - -int -_vprintk(putc, fmt0, ap) -int (*putc)(); -const char *fmt0; -va_list ap; -{ - char c, sign, *cp; - int left_prec, right_prec, zero_fill, length, pad, pad_on_right; - char buf[32]; - long val; - while (c = *fmt0++) - { - if (c == '%') - { - c = *fmt0++; - left_prec = right_prec = pad_on_right = 0; - if (c == '-') - { - c = *fmt0++; - pad_on_right++; - } - if (c == '0') - { - zero_fill = TRUE; - c = *fmt0++; - } else - { - zero_fill = FALSE; - } - while (is_digit(c)) - { - left_prec = (left_prec * 10) + (c - '0'); - c = *fmt0++; - } - if (c == '.') - { - c = *fmt0++; - zero_fill++; - while (is_digit(c)) - { - right_prec = (right_prec * 10) + (c - '0'); - c = *fmt0++; - } - } else - { - right_prec = left_prec; - } - sign = '\0'; - switch (c) - { - case 'd': - case 'x': - case 'X': - val = va_arg(ap, long); - switch (c) - { - case 'd': - if (val < 0) - { - sign = '-'; - val = -val; - } - length = _cvt(val, buf, 10, "0123456789"); - break; - case 'x': - length = _cvt(val, buf, 16, "0123456789abcdef"); - break; - case 'X': - length = _cvt(val, buf, 16, "0123456789ABCDEF"); - break; - } - cp = buf; - break; - case 's': - cp = va_arg(ap, char *); - length = strlen(cp); - break; - case 'c': - c = va_arg(ap, long /*char*/); - (*putc)(c); - continue; - default: - (*putc)('?'); - } - pad = left_prec - length; - if (sign != '\0') - { - pad--; - } - if (zero_fill) - { - c = '0'; - if (sign != '\0') - { - (*putc)(sign); - sign = '\0'; - } - } else - { - c = ' '; - } - if (!pad_on_right) - { - while (pad-- > 0) - { - (*putc)(c); - } - } - if (sign != '\0') - { - (*putc)(sign); - } - while (length-- > 0) - { - (*putc)(c = *cp++); - if (c == '\n') - { - (*putc)('\r'); - } - } - if (pad_on_right) - { - while (pad-- > 0) - { - (*putc)(c); - } - } - } else - { - (*putc)(c); - if (c == '\n') - { - (*putc)('\r'); - } - } - } -} - -int _cvt(unsigned long val, char *buf, long radix, char *digits) -{ - char temp[80]; - char *cp = temp; - int length = 0; - if (val == 0) - { /* Special case */ - *cp++ = '0'; - } else - while (val) - { - *cp++ = digits[val % radix]; - val /= radix; - } - while (cp != temp) - { - *buf++ = *--cp; - length++; - } - *buf = '\0'; - return (length); -} - -_dump_buf_with_offset(unsigned char *p, int s, unsigned char *base) -{ - int i, c; - if ((unsigned int)s > (unsigned int)p) - { - s = (unsigned int)s - (unsigned int)p; - } - while (s > 0) - { - if (base) - { - _printk("%06X: ", (int)p - (int)base); - } else - { - _printk("%06X: ", p); - } - for (i = 0; i < 16; i++) - { - if (i < s) - { - _printk("%02X", p[i] & 0xFF); - } else - { - _printk(" "); - } - if ((i % 2) == 1) _printk(" "); - if ((i % 8) == 7) _printk(" "); - } - _printk(" |"); - for (i = 0; i < 16; i++) - { - if (i < s) - { - c = p[i] & 0xFF; - if ((c < 0x20) || (c >= 0x7F)) c = '.'; - } else - { - c = ' '; - } - _printk("%c", c); - } - _printk("|\n"); - s -= 16; - p += 16; - } -} - -_dump_buf(unsigned char *p, int s) -{ - _printk("\n"); - _dump_buf_with_offset(p, s, 0); -} diff -Nru a/arch/ppc/boot/mkprep.c b/arch/ppc/boot/mkprep.c --- a/arch/ppc/boot/mkprep.c Wed May 16 06:00:18 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,287 +0,0 @@ -/* - * Makes a prep bootable image which can be dd'd onto - * a disk device to make a bootdisk. Will take - * as input a elf executable, strip off the header - * and write out a boot image as: - * 1) default - strips elf header - * suitable as a network boot image - * 2) -pbp - strips elf header and writes out prep boot partition image - * cat or dd onto disk for booting - * 3) -asm - strips elf header and writes out as asm data - * useful for generating data for a compressed image - * -- Cort - * - * Modified for x86 hosted builds by Matt Porter - */ - -#include -#include -#include -#include - -#define cpu_to_le32(x) le32_to_cpu((x)) -unsigned long le32_to_cpu(unsigned long x) -{ - return (((x & 0x000000ffU) << 24) | - ((x & 0x0000ff00U) << 8) | - ((x & 0x00ff0000U) >> 8) | - ((x & 0xff000000U) >> 24)); -} - - -#define cpu_to_le16(x) le16_to_cpu((x)) -unsigned short le16_to_cpu(unsigned short x) -{ - return (((x & 0x00ff) << 8) | - ((x & 0xff00) >> 8)); -} - -#define cpu_to_be32(x) (x) -#define be32_to_cpu(x) (x) -#define cpu_to_be16(x) (x) -#define be16_to_cpu(x) (x) - -/* size of read buffer */ -#define SIZE 0x1000 - - -typedef unsigned long dword_t; -typedef unsigned short word_t; -typedef unsigned char byte_t; -typedef byte_t block_t[512]; -typedef byte_t page_t[4096]; - - -/* - * Partition table entry - * - from the PReP spec - */ -typedef struct partition_entry { - byte_t boot_indicator; - byte_t starting_head; - byte_t starting_sector; - byte_t starting_cylinder; - - byte_t system_indicator; - byte_t ending_head; - byte_t ending_sector; - byte_t ending_cylinder; - - dword_t beginning_sector; - dword_t number_of_sectors; -} partition_entry_t; - -#define BootActive 0x80 -#define SystemPrep 0x41 - -void copy_image(int , int); -void write_prep_partition(int , int ); -void write_asm_data( int in, int out ); - -unsigned int elfhdr_size = 65536; - -int main(int argc, char *argv[]) -{ - int in_fd, out_fd; - int argptr = 1; - unsigned int prep = 0; - unsigned int asmoutput = 0; - - if ( (argc < 3) || (argc > 4) ) - { - fprintf(stderr, "usage: %s [-pbp] [-asm] \n",argv[0]); - exit(-1); - } - - /* needs to handle args more elegantly -- but this is a small/simple program */ - - /* check for -pbp */ - if ( !strcmp( argv[argptr], "-pbp" ) ) - { - prep = 1; - argptr++; - } - - /* check for -asm */ - if ( !strcmp( argv[argptr], "-asm" ) ) - { - asmoutput = 1; - argptr++; - } - - /* input file */ - if ( !strcmp( argv[argptr], "-" ) ) - in_fd = 0; /* stdin */ - else - if ((in_fd = open( argv[argptr] , 0)) < 0) - exit(-1); - argptr++; - - /* output file */ - if ( !strcmp( argv[argptr], "-" ) ) - out_fd = 1; /* stdout */ - else - if ((out_fd = creat( argv[argptr] , 0755)) < 0) - exit(-1); - argptr++; - - /* skip elf header in input file */ - /*if ( !prep )*/ - lseek(in_fd, elfhdr_size, SEEK_SET); - - /* write prep partition if necessary */ - if ( prep ) - write_prep_partition( in_fd, out_fd ); - - /* write input image to bootimage */ - if ( asmoutput ) - write_asm_data( in_fd, out_fd ); - else - copy_image(in_fd, out_fd); - - return 0; -} - -void write_prep_partition(int in, int out) -{ - unsigned char block[512]; - partition_entry_t *pe = (partition_entry_t *)&block[0x1BE]; - dword_t *entry = (dword_t *)&block[0]; - dword_t *length = (dword_t *)&block[sizeof(long)]; - struct stat info; - - if (fstat(in, &info) < 0) - { - fprintf(stderr,"info failed\n"); - exit(-1); - } - - bzero( block, sizeof block ); - - /* set entry point and boot image size skipping over elf header */ -#ifdef __i386__ - *entry = 0x400/*+65536*/; - *length = info.st_size-elfhdr_size+0x400; -#else - *entry = cpu_to_le32(0x400/*+65536*/); - *length = cpu_to_le32(info.st_size-elfhdr_size+0x400); -#endif /* __i386__ */ - - /* sets magic number for msdos partition (used by linux) */ - block[510] = 0x55; - block[511] = 0xAA; - - /* - * Build a "PReP" partition table entry in the boot record - * - "PReP" may only look at the system_indicator - */ - pe->boot_indicator = BootActive; - pe->system_indicator = SystemPrep; - /* - * The first block of the diskette is used by this "boot record" which - * actually contains the partition table. (The first block of the - * partition contains the boot image, but I digress...) We'll set up - * one partition on the diskette and it shall contain the rest of the - * diskette. - */ - pe->starting_head = 0; /* zero-based */ - pe->starting_sector = 2; /* one-based */ - pe->starting_cylinder = 0; /* zero-based */ - pe->ending_head = 1; /* assumes two heads */ - pe->ending_sector = 18; /* assumes 18 sectors/track */ - pe->ending_cylinder = 79; /* assumes 80 cylinders/diskette */ - - /* - * The "PReP" software ignores the above fields and just looks at - * the next two. - * - size of the diskette is (assumed to be) - * (2 tracks/cylinder)(18 sectors/tracks)(80 cylinders/diskette) - * - unlike the above sector numbers, the beginning sector is zero-based! - */ -#if 0 - pe->beginning_sector = cpu_to_le32(1); -#else - /* This has to be 0 on the PowerStack? */ -#ifdef __i386__ - pe->beginning_sector = 0; -#else - pe->beginning_sector = cpu_to_le32(0); -#endif /* __i386__ */ -#endif - -#ifdef __i386__ - pe->number_of_sectors = 2*18*80-1; -#else - pe->number_of_sectors = cpu_to_le32(2*18*80-1); -#endif /* __i386__ */ - - write( out, block, sizeof(block) ); - write( out, entry, sizeof(*entry) ); - write( out, length, sizeof(*length) ); - /* set file position to 2nd sector where image will be written */ - lseek( out, 0x400, SEEK_SET ); -} - - - -void -copy_image(int in, int out) -{ - char buf[SIZE]; - int n; - - while ( (n = read(in, buf, SIZE)) > 0 ) - write(out, buf, n); -} - - -void -write_asm_data( int in, int out ) -{ - int i, cnt, pos, len; - unsigned int cksum, val; - unsigned char *lp; - unsigned char buf[SIZE]; - unsigned char str[256]; - - write( out, "\t.data\n\t.globl input_data\ninput_data:\n", - strlen( "\t.data\n\t.globl input_data\ninput_data:\n" ) ); - pos = 0; - cksum = 0; - while ((len = read(in, buf, sizeof(buf))) > 0) - { - cnt = 0; - lp = (unsigned char *)buf; - len = (len + 3) & ~3; /* Round up to longwords */ - for (i = 0; i < len; i += 4) - { - if (cnt == 0) - { - write( out, "\t.long\t", strlen( "\t.long\t" ) ); - } - sprintf( str, "0x%02X%02X%02X%02X", lp[0], lp[1], lp[2], lp[3]); - write( out, str, strlen(str) ); - val = *(unsigned long *)lp; - cksum ^= val; - lp += 4; - if (++cnt == 4) - { - cnt = 0; - sprintf( str, " # %x \n", pos+i-12); - write( out, str, strlen(str) ); - } else - { - write( out, ",", 1 ); - } - } - if (cnt) - { - write( out, "0\n", 2 ); - } - pos += len; - } - sprintf(str, "\t.globl input_len\ninput_len:\t.long\t0x%x\n", pos); - write( out, str, strlen(str) ); - - fprintf(stderr, "cksum = %x\n", cksum); -} diff -Nru a/arch/ppc/boot/ns16550.c b/arch/ppc/boot/ns16550.c --- a/arch/ppc/boot/ns16550.c Wed May 16 06:00:18 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,56 +0,0 @@ -/* - * COM1 NS16550 support - */ - -#include "ns16550.h" -typedef struct NS16550 *NS16550_t; - -const NS16550_t COM_PORTS[] = { (NS16550_t) COM1, - (NS16550_t) COM2, - (NS16550_t) COM3, - (NS16550_t) COM4 }; - -volatile struct NS16550 * -NS16550_init(int chan) -{ - volatile struct NS16550 *com_port; - volatile unsigned char xx; - com_port = (struct NS16550 *) COM_PORTS[chan]; - /* See if port is present */ - com_port->lcr = 0x00; - com_port->ier = 0xFF; -#if 0 - if (com_port->ier != 0x0F) return ((struct NS16550 *)0); -#endif - com_port->ier = 0x00; - com_port->lcr = 0x80; /* Access baud rate */ - com_port->dll = 0xc; /* 9600 baud */ - com_port->dlm = 0xc >> 8; - com_port->lcr = 0x03; /* 8 data, 1 stop, no parity */ - com_port->mcr = 0x03; /* RTS/DTR */ - com_port->fcr = 0x07; /* Clear & enable FIFOs */ - return (com_port); -} - - -NS16550_putc(volatile struct NS16550 *com_port, unsigned char c) -{ - volatile int i; - while ((com_port->lsr & LSR_THRE) == 0) ; - com_port->thr = c; -} - -unsigned char -NS16550_getc(volatile struct NS16550 *com_port) -{ - while ((com_port->lsr & LSR_DR) == 0) ; - return (com_port->rbr); -} - -NS16550_tstc(volatile struct NS16550 *com_port) -{ - return ((com_port->lsr & LSR_DR) != 0); -} - - - diff -Nru a/arch/ppc/boot/ns16550.h b/arch/ppc/boot/ns16550.h --- a/arch/ppc/boot/ns16550.h Wed May 16 06:00:25 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,34 +0,0 @@ -/* - * NS16550 Serial Port - */ - -struct NS16550 - { - unsigned char rbr; /* 0 */ - unsigned char ier; /* 1 */ - unsigned char fcr; /* 2 */ - unsigned char lcr; /* 3 */ - unsigned char mcr; /* 4 */ - unsigned char lsr; /* 5 */ - unsigned char msr; /* 6 */ - unsigned char scr; /* 7 */ - }; - -#define thr rbr -#define iir fcr -#define dll rbr -#define dlm ier - -#define LSR_DR 0x01 /* Data ready */ -#define LSR_OE 0x02 /* Overrun */ -#define LSR_PE 0x04 /* Parity error */ -#define LSR_FE 0x08 /* Framing error */ -#define LSR_BI 0x10 /* Break */ -#define LSR_THRE 0x20 /* Xmit holding register empty */ -#define LSR_TEMT 0x40 /* Xmitter empty */ -#define LSR_ERR 0x80 /* Error */ - -#define COM1 0x800003F8 -#define COM2 0x800002F8 -#define COM3 0x800003F8 -#define COM4 0x80000388 diff -Nru a/arch/ppc/boot/of1275.c b/arch/ppc/boot/of1275.c --- a/arch/ppc/boot/of1275.c Wed May 16 06:00:21 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,427 +0,0 @@ -/* Open Firmware Client Interface */ - - -#include "of1275.h" - - -static int (*of_server)(void *) = (int(*)(void*))-1; - -void -of_init(void *handler) -{ - of_server = (int(*)(void*))handler; -} - - -/* 6.3.2.1 Client interface */ - - -int -of_test(const char *name, int *missing) -{ - int result; - static of_test_service s; - s.service = "test"; - s.n_args = 1; - s.n_returns = 1; - s.name = name; - result = of_server(&s); - *missing = s.missing; - return result; -} - - -/* 6.3.2.2 Device tree */ - - -int -of_peer(int phandle, int *sibling_phandle) -{ - int result; - static of_peer_service s; - s.service = "peer"; - s.n_args = 1; - s.n_returns = 1; - s.phandle = phandle; - result = of_server(&s); - *sibling_phandle = s.sibling_phandle; - return result; -} - -int -of_child(int phandle, int *child_phandle) -{ - int result; - static of_child_service s; - s.service = "child"; - s.n_args = 1; - s.n_returns = 1; - s.phandle = phandle; - result = of_server(&s); - *child_phandle = s.child_phandle; - return result; -} - -int -of_parent(int phandle, int *parent_phandle) -{ - int result; - static of_parent_service s; - s.service = "parent"; - s.n_args = 1; - s.n_returns = 1; - s.phandle = phandle; - result = of_server(&s); - *parent_phandle = s.parent_phandle; - return result; -} - -int -of_instance_to_package(int ihandle, int *phandle) -{ - int result; - static of_instance_to_package_service s; - s.service = "instance-to-package"; - s.n_args = 1; - s.n_returns = 1; - s.ihandle = ihandle; - result = of_server(&s); - *phandle = s.phandle; - return result; -} - -int -of_getproplen(int phandle, const char *name, int *proplen) -{ - int result; - static of_getproplen_service s; - s.service = "getproplen"; - s.n_args = 2; - s.n_returns = 1; - s.phandle = phandle; - s.name = name; - result = of_server(&s); - *proplen = s.proplen; - return result; -} - -int -of_getprop(int phandle, const char *name, void *buf, int buflen, int *size) -{ - int result; - static of_getprop_service s; - s.service = "getprop"; - s.n_args = 4; - s.n_returns = 1; - s.phandle = phandle; - s.name = name; - s.buf = buf; - s.buflen = buflen; - result = of_server(&s); - *size = s.size; - return result; -} - -int -of_nextprop(int phandle, const char *previous, void *buf, int *flag) -{ - int result; - static of_nextprop_service s; - s.service = "nextprop"; - s.n_args = 3; - s.n_returns = 1; - s.phandle = phandle; - s.previous = previous; - s.buf = buf; - result = of_server(&s); - *flag = s.flag; - return result; -} - -int -of_setprop(int phandle, const char *name, void *buf, int len, int *size) -{ - int result; - static of_setprop_service s; - s.service = "setprop"; - s.n_args = 4; - s.n_returns = 1; - s.phandle = phandle; - s.name = name; - s.buf = buf; - s.len = len; - result = of_server(&s); - *size = s.size; - return result; -} - -int -of_canon(const char *device_specifier, void *buf, int buflen, int *length) -{ - int result; - static of_canon_service s; - s.service = "canon"; - s.n_args = 3; - s.n_returns = 1; - s.device_specifier = device_specifier; - s.buf = buf; - s.buflen = buflen; - result = of_server(&s); - *length = s.length; - return result; -} - -int -of_finddevice(const char *device_specifier, int *phandle) -{ - int result; - static of_finddevice_service s; - s.service = "finddevice"; - s.n_args = 1; - s.n_returns = 1; - s.device_specifier = device_specifier; - result = of_server(&s); - *phandle = s.phandle; - return result; -} - -int -of_instance_to_path(int ihandle, void *buf, int buflen, int *length) -{ - int result; - static of_instance_to_path_service s; - s.service = "instance-to-path"; - s.n_args = 3; - s.n_returns = 1; - s.ihandle = ihandle; - s.buf = buf; - s.buflen = buflen; - result = of_server(&s); - *length = s.length; - return result; -} - -int -of_package_to_path(int phandle, void *buf, int buflen, int *length) -{ - int result; - static of_package_to_path_service s; - s.service = "package-to-path"; - s.n_args = 3; - s.n_returns = 1; - s.phandle = phandle; - s.buf = buf; - s.buflen = buflen; - result = of_server(&s); - *length = s.length; - return result; -} - -/* int of_call_method(const char *method, int ihandle, ...); */ - - -/* 6.3.2.3 Device I/O */ - - -int -of_open(const char *device_specifier, int *ihandle) -{ - int result; - static of_open_service s; - s.service = "open"; - s.n_args = 1; - s.n_returns = 1; - s.device_specifier = device_specifier; - result = of_server(&s); - *ihandle = s.ihandle; - return result; -} - -int -of_close(int ihandle) -{ - int result; - static of_close_service s; - s.service = "close"; - s.n_args = 1; - s.n_returns = 0; - s.ihandle = ihandle; - result = of_server(&s); - return result; -} - -int -of_read(int ihandle, void *addr, int len, int *actual) -{ - int result; - static of_read_service s; - s.service = "read"; - s.n_args = 3; - s.n_returns = 1; - s.ihandle = ihandle; - s.addr = addr; - s.len = len; - result = of_server(&s); - *actual = s.actual; - return result; -} - -int -of_write(int ihandle, void *addr, int len, int *actual) -{ - int result; - static of_write_service s; - s.service = "write"; - s.n_args = 3; - s.n_returns = 1; - s.ihandle = ihandle; - s.addr = addr; - s.len = len; - result = of_server(&s); - *actual = s.actual; - return result; -} - -int -of_seek(int ihandle, int pos_hi, int pos_lo, int *status) -{ - int result; - static of_seek_service s; - s.service = "seek"; - s.n_args = 3; - s.n_returns = 1; - s.ihandle = ihandle; - s.pos_hi = pos_hi; - s.pos_lo = pos_lo; - result = of_server(&s); - *status = s.status; - return result; -} - - -/* 6.3.2.4 Memory */ - - -int -of_claim(void *virt, int size, int align, void **baseaddr) -{ - int result; - static of_claim_service s; - s.service = "claim"; - s.n_args = 3; - s.n_returns = 1; - s.virt = virt; - s.size = size; - s.align = align; - result = of_server(&s); - *baseaddr = s.baseaddr; - return result; -} - -int -of_release(void *virt, int size) -{ - int result; - static of_release_service s; - s.service = "release"; - s.n_args = 2; - s.n_returns = 0; - s.virt = virt; - s.size = size; - result = of_server(&s); - return result; -} - - -/* 6.3.2.5 Control transfer */ - - -int -of_boot(const char *bootspec) -{ - int result; - static of_boot_service s; - s.service = "boot"; - s.n_args = 1; - s.n_returns = 0; - s.bootspec = bootspec; - result = of_server(&s); - return result; -} - -int -of_enter(void) -{ - int result; - static of_enter_service s; - s.service = "enter"; - s.n_args = 0; - s.n_returns = 0; - result = of_server(&s); - return result; -} - -int -of_exit(void) -{ - int result; - static of_exit_service s; - s.service = "exit"; - s.n_args = 0; - s.n_returns = 0; - result = of_server(&s); - return result; -} - -/* int of_chain(void *virt, int size, void *entry, void *args, int len); */ - - -/* 6.3.2.6 User interface */ - - -/* int of_interpret(const char *arg, ...); */ - -int -of_set_callback(void *newfunc, void **oldfunc) -{ - int result; - static of_set_callback_service s; - s.service = "set-callback"; - s.n_args = 1; - s.n_returns = 1; - s.newfunc = newfunc; - result = of_server(&s); - *oldfunc = s.oldfunc; - return result; -} - -int -of_set_symbol_lookup(void *sym_to_value, void *value_to_sym) -{ - int result; - static of_set_symbol_lookup_service s; - s.service = "set-symbol-lookup"; - s.n_args = 2; - s.n_returns = 0; - s.sym_to_value = sym_to_value; - s.value_to_sym = s.value_to_sym; - result = of_server(&s); - return result; -} - - -/* 6.3.2.7 Time */ - - -int -of_milliseconds(int *ms) -{ - int result; - static of_milliseconds_service s; - s.service = "milliseconds"; - s.n_args = 0; - s.n_returns = 1; - result = of_server(&s); - *ms = s.ms; - return result; -} diff -Nru a/arch/ppc/boot/of1275.h b/arch/ppc/boot/of1275.h --- a/arch/ppc/boot/of1275.h Wed May 16 06:00:20 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,421 +0,0 @@ -/* 6.3.2.1 Client interface */ - - -typedef struct _of_test_service { - const char *service; - int n_args; - int n_returns; - /*in*/ - const char *name; - /*out*/ - int missing; -} of_test_service; - -int of_test(const char *name, int *missing); - - -/* 6.3.2.2 Device tree */ - - -typedef struct _of_peer_service { - const char *service; - int n_args; - int n_returns; - /*in*/ - int phandle; - /*out*/ - int sibling_phandle; -} of_peer_service; - -int of_peer(int phandle, int *sibling_phandle); - - -typedef struct _of_child_service { - const char *service; - int n_args; - int n_returns; - /*in*/ - int phandle; - /*out*/ - int child_phandle; -} of_child_service; - -int of_child(int phandle, int *child_phandle); - - -typedef struct _of_parent_service { - const char *service; - int n_args; - int n_returns; - /*in*/ - int phandle; - /*out*/ - int parent_phandle; -} of_parent_service; - -int of_child(int phandle, int *parent_phandle); - - -typedef struct _of_instance_to_package_service { - const char *service; - int n_args; - int n_returns; - /*in*/ - int ihandle; - /*out*/ - int phandle; -} of_instance_to_package_service; - -int of_instance_to_package(int ihandle, int *phandle); - - -typedef struct _of_getproplen_service { - const char *service; - int n_args; - int n_returns; - /*in*/ - int phandle; - const char *name; - /*out*/ - int proplen; -} of_getproplen_service; - -int of_getproplen(int phandle, const char *name, int *proplen); - - -typedef struct _of_getprop_service { - const char *service; - int n_args; - int n_returns; - /*in*/ - int phandle; - const char *name; - void *buf; - int buflen; - /*out*/ - int size; -} of_getprop_service; - -int of_getprop(int phandle, const char *name, void *buf, int buflen, - int *size); - - -typedef struct _of_nextprop_service { - const char *service; - int n_args; - int n_returns; - /*in*/ - int phandle; - const char *previous; - void *buf; - /*out*/ - int flag; -} of_nextprop_service; - -int of_nextprop(int phandle, const char *previous, void *buf, int *flag); - - -typedef struct _of_setprop_service { - const char *service; - int n_args; - int n_returns; - /*in*/ - int phandle; - const char *name; - void *buf; - int len; - /*out*/ - int size; -} of_setprop_service; - -int of_setprop(int phandle, const char *name, void *buf, int len, int *size); - - -typedef struct _of_canon_service { - const char *service; - int n_args; - int n_returns; - /*in*/ - const char *device_specifier; - void *buf; - int buflen; - /*out*/ - int length; -} of_canon_service; - -int of_canon(const char *device_specifier, void *buf, int buflen, int *length); - - -typedef struct _of_finddevice_service { - const char *service; - int n_args; - int n_returns; - /*in*/ - const char *device_specifier; - /*out*/ - int phandle; -} of_finddevice_service; - -int of_finddevice(const char *device_specifier, int *phandle); - - -typedef struct _of_instance_to_path_service { - const char *service; - int n_args; - int n_returns; - /*in*/ - int ihandle; - void *buf; - int buflen; - /*out*/ - int length; -} of_instance_to_path_service; - -int of_instance_to_path(int ihandle, void *buf, int buflen, int *length); - - -typedef struct _of_package_to_path_service { - const char *service; - int n_args; - int n_returns; - /*in*/ - int phandle; - void *buf; - int buflen; - /*out*/ - int length; -} of_package_to_path_service; - -int of_package_to_path(int phandle, void *buf, int buflen, int *length); - - -typedef struct _of_call_method_service { - const char *service; - int n_args; - int n_returns; - /*in*/ - const char *method; - int ihandle; - /*...*/ - int args[0]; -} of_call_method_service; - -int of_call_method(const char *method, int ihandle, ...); - - -/* 6.3.2.3 Device I/O */ - - -typedef struct _of_open_service { - const char *service; - int n_args; - int n_returns; - /*in*/ - const char *device_specifier; - /*out*/ - int ihandle; -} of_open_service; - -int of_open(const char *device_specifier, - int *ihandle); - - -typedef struct _of_close_service { - const char *service; - int n_args; - int n_returns; - /*in*/ - int ihandle; - /*out*/ -} of_close_service; - -int of_close(int ihandle); - - -typedef struct _of_read_service { - const char *service; - int n_args; - int n_returns; - /*in*/ - int ihandle; - void *addr; - int len; - /*out*/ - int actual; -} of_read_service; - -int of_read(int ihandle, void *addr, int len, int *actual); - - -typedef struct _of_write_service { - const char *service; - int n_args; - int n_returns; - /*in*/ - int ihandle; - void *addr; - int len; - /*out*/ - int actual; -} of_write_service; - -int of_write(int ihandle, void *addr, int len, int *actual); - - -typedef struct _of_seek_service { - const char *service; - int n_args; - int n_returns; - /*in*/ - int ihandle; - int pos_hi; - int pos_lo; - /*out*/ - int status; -} of_seek_service; - -int of_seek(int ihandle, int pos_hi, int pos_lo, int *status); - - -/* 6.3.2.4 Memory */ - - -typedef struct _of_claim_service { - const char *service; - int n_args; - int n_returns; - /*in*/ - void *virt; - int size; - int align; - /*out*/ - void *baseaddr; -} of_claim_service; - -int of_claim(void *virt, int size, int align, void **baseaddr); - - -typedef struct _of_release_service { - const char *service; - int n_args; - int n_returns; - /*in*/ - void *virt; - int size; - int align; - /*out*/ -} of_release_service; - -int of_release(void *virt, int size); - - -/* 6.3.2.5 Control transfer */ - - -typedef struct _of_boot_service { - const char *service; - int n_args; - int n_returns; - /*in*/ - const char *bootspec; - /*out*/ -} of_boot_service; - -int of_boot(const char *bootspec); - - -typedef struct _of_enter_service { - const char *service; - int n_args; - int n_returns; - /*in*/ - /*out*/ -} of_enter_service; - -int of_enter(void); - - -typedef struct _of_exit_service { - const char *service; - int n_args; - int n_returns; - /*in*/ - /*out*/ -} of_exit_service; - -int of_exit(void); - - -typedef struct _of_chain_service { - const char *service; - int n_args; - int n_returns; - /*in*/ - void *virt; - int size; - void *entry; - void *args; - int len; - /*out*/ -} of_chain_service; - -int of_chain(void *virt, int size, void *entry, void *args, int len); - - -/* 6.3.2.6 User interface */ - - -typedef struct _of_interpret_service { - const char *service; - int n_args; - int n_returns; - /*in*/ - const char *cmd; - int args[0]; - /*...*/ - /*out*/ - /*...*/ -} of_interpret_service; - -int of_interpret(const char *arg, ...); - - -typedef struct _of_set_callback_service { - const char *service; - int n_args; - int n_returns; - /*in*/ - void *newfunc; - /*out*/ - void *oldfunc; -} of_set_callback_service; - -int of_set_callback(void *newfunc, void **oldfunc); - - -typedef struct _of_set_symbol_lookup_service { - const char *service; - int n_args; - int n_returns; - /*in*/ - void *sym_to_value; - void *value_to_sym; - /*out*/ -} of_set_symbol_lookup_service; - -int of_set_symbol_lookup(void *sym_to_value, void *value_to_sym); - - -/* 6.3.2.7 Time */ - - -typedef struct _of_milliseconds_service { - const char *service; - int n_args; - int n_returns; - /*in*/ - /*out*/ - int ms; -} of_milliseconds_service; - -int of_milliseconds(int *ms); diff -Nru a/arch/ppc/boot/offset b/arch/ppc/boot/offset --- a/arch/ppc/boot/offset Wed May 16 06:00:19 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,4 +0,0 @@ -#!/bin/bash - -OFFSET=`$1 -h $2 | grep $3 | grep -v zvmlinux| awk '{print $6}'` -echo "0x"$OFFSET diff -Nru a/arch/ppc/boot/pmac/Makefile b/arch/ppc/boot/pmac/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/pmac/Makefile Wed May 16 06:00:23 2001 @@ -0,0 +1,113 @@ +# Makefile for making XCOFF bootable images for booting on PowerMacs +# using Open Firmware. +# +# Paul Mackerras January 1997 +# +# Cleaned up, moved into arch/ppc/boot/pmac +# Tom Rini January 2001 + +OBJCOPY_ARGS = -O aixcoff-rs6000 -R .stab -R .stabstr -R .comment +COFF_LD_ARGS = -e _start -T ld.script -Ttext 500000 -Tdata 510000 -Bstatic +CHRP_LD_ARGS = -Ttext 0x01000000 + +COMMONOBJS = start.o misc.o ../common/string.o image.o +COFFOBJS = ../common/coffcrt0.o $(COMMONOBJS) coffmain.o +CHRPOBJS = ../common/crt0.o $(COMMONOBJS) chrpmain.o +LIBS = $(TOPDIR)/lib/lib.a ../lib/zlib.a + +MKNOTE := ../utils/mknote +SIZE := ../utils/size +OFFSET := ../utils/offset +PIGGYBACK := ../utils/piggyback +HACKCOFF := ../utils/hack-coff + +ifeq ($(CONFIG_PPC64BRIDGE),y) +MSIZE=.64 +else +MSIZE= +endif + +ifeq ($(CONFIG_SMP),y) +TFTPIMAGE=/tftpboot/zImage.pmac.smp$(MSIZE) +else +TFTPIMAGE=/tftpboot/zImage.pmac$(MSIZE) +endif + +../common/crt0.o: + $(MAKE) -C ../common crt0.o + +../common/coffcrt0.o: + $(MAKE) -C ../common coffcrt0.o + +chrpmain.o: chrpmain.c + $(CC) $(CFLAGS) -DSYSMAP_OFFSET=0 -DSYSMAP_SIZE=0 -c chrpmain.c + +znetboot: vmlinux.coff vmlinux.elf-pmac zImage + cp ../images/vmlinux.coff $(TFTPIMAGE) + cp ../images/vmlinux.elf-pmac $(TFTPIMAGE).elf + +znetboot.initrd: vmlinux.coff.initrd vmlinux.initrd.elf-pmac + cp ../images/vmlinux.coff.initrd $(TFTPIMAGE) + cp ../images/vmlinux.elf.pmac.initrd $(TFTPIMAGE).elf + +#floppy: zImage +# mount -t hfs /dev/fd0 /mnt +# cp vmlinux.coff /mnt +# umount /mnt + +miboot.image: dummy.o ../images/vmlinux.gz + $(OBJCOPY) $(OBJCOPY_ARGS) --add-section=image=../images/vmlinux.gz \ + dummy.o ../images/$@ + +miboot.image.initrd: miboot.image ../images/ramdisk.image.gz + $(OBJCOPY) $(OBJCOPY_ARGS) --add-section=initrd=../images/ramdisk.image.gz \ + ../images/miboot.image $@ + +coffboot: $(COFFOBJS) $(LIBS) ../common/no_initrd.o ld.script ../images/vmlinux.gz + $(LD) -o $@ $(COFF_LD_ARGS) $(COFFOBJS) ../common/no_initrd.o $(LIBS) + +coffboot.initrd: $(COFFOBJS) $(LIBS) initrd.o ld.script ../images/vmlinux.gz + $(LD) -o $@ $(COFF_LD_ARGS) $(COFFOBJS) initrd.o $(LIBS) + +image.o: $(PIGGYBACK) ../images/vmlinux.gz + $(PIGGYBACK) image < ../images/vmlinux.gz | $(AS) -o $@ + +initrd.o: ../images/ramdisk.image.gz $(PIGGYBACK) + $(PIGGYBACK) initrd < ../images/ramdisk.image.gz | $(AS) -o $@ + +vmlinux.coff: coffboot $(HACKCOFF) + $(OBJCOPY) $(OBJCOPY_ARGS) coffboot ../images/$@ + $(HACKCOFF) ../images/$@ + rm -f coffboot + ln -sf vmlinux.coff ../images/zImage.pmac + +vmlinux.coff.initrd: coffboot.initrd $(HACKCOFF) + $(OBJCOPY) $(OBJCOPY_ARGS) coffboot.initrd ../images/$@ + $(HACKCOFF) ../images/$@ + rm -f coffboot.initrd + ln -sf vmlinux.coff.initrd ../images/zImage.initrd.pmac + +vmlinux.elf-pmac: $(CHRPOBJS) $(LIBS) ../common/no_initrd.o $(MKNOTE) ../images/vmlinux.gz + $(LD) $(CHRP_LD_ARGS) -o ../images/$@ $(CHRPOBJS) ../common/no_initrd.o $(LIBS) + $(MKNOTE) > note + $(OBJCOPY) ../images/$@ ../images/$@ --add-section=.note=note \ + --add-section=sysmap=$(TOPDIR)/System.map -R .comment + $(CC) $(CFLAGS) chrpmain.c -c -o chrpmain.o \ + -DSYSMAP_OFFSET=`sh $(OFFSET) $(OBJDUMP) ../images/$@ sysmap` \ + -DSYSMAP_SIZE=`sh $(SIZE) $(OBJDUMP) ../images/$@ sysmap` + $(LD) $(CHRP_LD_ARGS) -o ../images/$@ $(CHRPOBJS) ../common/no_initrd.o $(LIBS) + $(OBJCOPY) ../images/$@ ../images/$@ --add-section=.note=note \ + --add-section=sysmap=$(TOPDIR)/System.map -R .comment + rm -f note + +vmlinux.initrd.elf-pmac: $(CHRPOBJS) $(LIBS) initrd.o $(MKNOTE) ../images/vmlinux.gz + $(LD) $(CHRP_LD_ARGS) -o ../images/$@ $(CHRPOBJS) initrd.o $(LIBS) + $(MKNOTE) > note + $(OBJCOPY) ../images/$@ ../images/$@ --add-section=.note=note -R .comment + rm -f note + +zImage: vmlinux.coff vmlinux.elf-pmac miboot.image + +zImage.initrd: vmlinux.coff.initrd vmlinux.initrd.elf-pmac miboot.image.initrd + +include $(TOPDIR)/Rules.make diff -Nru a/arch/ppc/boot/pmac/chrpmain.c b/arch/ppc/boot/pmac/chrpmain.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/pmac/chrpmain.c Wed May 16 06:00:23 2001 @@ -0,0 +1,309 @@ +/* + * 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 "zlib.h" +#include +#include +#include + +extern void *finddevice(const char *); +extern int getprop(void *, const char *, void *, int); +extern void *claim(unsigned int, unsigned int, unsigned int); +extern void release(void *ptr, unsigned int len); +void make_bi_recs(unsigned long); +void gunzip(void *, int, unsigned char *, int *); +void stop_imac_ethernet(void); +void stop_imac_usb(void); + +#define get_16be(x) (*(unsigned short *)(x)) +#define get_32be(x) (*(unsigned *)(x)) + +#define RAM_END (16 << 20) + +#define PROG_START 0x00010000 +#define PROG_SIZE 0x003f0000 + +#define SCRATCH_SIZE (128 << 10) + +#ifdef CONFIG_CMDLINE +#define CMDLINE CONFIG_CMDLINE +#else +#define CMDLINE "" +#endif +char cmd_preset[] = CMDLINE; +char cmd_buf[256]; +char *cmd_line = cmd_buf; + +char *avail_ram; +char *begin_avail, *end_avail; +char *avail_high; +unsigned int heap_use; +unsigned int heap_max; + +extern char _end[]; +extern char image_data[]; +extern int image_len; +extern char initrd_data[]; +extern int initrd_len; + + +boot(int a1, int a2, void *prom) +{ + int ns, oh, i; + unsigned sa, len; + void *dst; + unsigned char *im; + unsigned initrd_start, initrd_size; + extern char _start; + + printf("chrpboot starting: loaded at 0x%x\n", &_start); + if (initrd_len) { + initrd_size = initrd_len; + initrd_start = (RAM_END - initrd_size) & ~0xFFF; + a1 = initrd_start; + a2 = initrd_size; + claim(initrd_start, RAM_END - initrd_start, 0); + printf("initial ramdisk moving 0x%x <- 0x%x (%x bytes)\n", initrd_start, + initrd_data,initrd_size); + memcpy((char *)initrd_start, initrd_data, initrd_size); + } + im = image_data; + len = image_len; + /* claim 3MB starting at PROG_START */ + claim(PROG_START, PROG_SIZE, 0); + dst = (void *) PROG_START; + if (im[0] == 0x1f && im[1] == 0x8b) { + /* claim some memory for scratch space */ + avail_ram = (char *) claim(0, SCRATCH_SIZE, 0x10); + begin_avail = avail_high = avail_ram; + end_avail = avail_ram + SCRATCH_SIZE; + printf("heap at 0x%x\n", avail_ram); + printf("gunzipping (0x%x <- 0x%x:0x%0x)...", dst, im, im+len); + gunzip(dst, PROG_SIZE, im, &len); + printf("done %u bytes\n", len); + printf("%u bytes of heap consumed, max in use %u\n", + avail_high - begin_avail, heap_max); + release(begin_avail, SCRATCH_SIZE); + } else { + memmove(dst, im, len); + } + + flush_cache(dst, len); + memcpy (cmd_line, cmd_preset, sizeof(cmd_preset)); + make_bi_recs((unsigned long) dst + len); + + sa = (unsigned long)PROG_START; + printf("start address = 0x%x\n", sa); + + (*(void (*)())sa)(a1, a2, prom); + + printf("returned?\n"); + + pause(); +} + +void make_bi_recs(unsigned long addr) +{ + struct bi_record *rec; + + /* leave a 1MB gap then align to the next 1MB boundary */ + addr = _ALIGN(addr+ (1<<20) - 1, (1<<20)); + if (addr >= PROG_START + PROG_SIZE) + claim(addr, 0x1000, 0); + + rec = (struct bi_record *)addr; + rec->tag = BI_FIRST; + rec->size = sizeof(struct bi_record); + rec = (struct bi_record *)((unsigned long)rec + rec->size); + + rec->tag = BI_BOOTLOADER_ID; + sprintf( (char *)rec->data, "coffboot"); + rec->size = sizeof(struct bi_record) + strlen("coffboot") + 1; + rec = (struct bi_record *)((unsigned long)rec + rec->size); + + rec->tag = BI_MACHTYPE; + rec->data[0] = _MACH_Pmac; + rec->data[1] = 1; + rec->size = sizeof(struct bi_record) + sizeof(unsigned long); + rec = (struct bi_record *)((unsigned long)rec + rec->size); + + rec->tag = BI_CMD_LINE; + memcpy( (char *)rec->data, cmd_line, strlen(cmd_line)+1); + rec->size = sizeof(struct bi_record) + strlen(cmd_line) + 1; + rec = (struct bi_record *)((unsigned long)rec + rec->size); + +#ifdef SYSMAP_OFFSET + rec->tag = BI_SYSMAP; + rec->data[0] = SYSMAP_OFFSET; + rec->data[1] = SYSMAP_SIZE; + rec->size = sizeof(struct bi_record) + sizeof(unsigned long); + rec = (struct bi_record *)((unsigned long)rec + rec->size); +#endif /* SYSMAP_OFFSET */ + + rec->tag = BI_LAST; + rec->size = sizeof(struct bi_record); + rec = (struct bi_record *)((unsigned long)rec + rec->size); +} + +#if 0 +#define eieio() asm volatile("eieio"); + +void stop_imac_ethernet(void) +{ + void *macio, *enet; + unsigned int macio_addr[5], enet_reg[6]; + int len; + volatile unsigned int *dbdma; + + macio = finddevice("/pci/mac-io"); + enet = finddevice("/pci/mac-io/ethernet"); + if (macio == NULL || enet == NULL) + return; + len = getprop(macio, "assigned-addresses", macio_addr, sizeof(macio_addr)); + if (len != sizeof(macio_addr)) + return; + len = getprop(enet, "reg", enet_reg, sizeof(enet_reg)); + if (len != sizeof(enet_reg)) + return; + printf("macio base %x, dma at %x & %x\n", + macio_addr[2], enet_reg[2], enet_reg[4]); + + /* hope this is mapped... */ + dbdma = (volatile unsigned int *) (macio_addr[2] + enet_reg[2]); + *dbdma = 0x80; /* clear the RUN bit */ + eieio(); + dbdma = (volatile unsigned int *) (macio_addr[2] + enet_reg[4]); + *dbdma = 0x80; /* clear the RUN bit */ + eieio(); +} + +void stop_imac_usb(void) +{ + void *usb; + unsigned int usb_addr[5]; + int len; + volatile unsigned int *usb_ctrl; + + usb = finddevice("/pci/usb"); + if (usb == NULL) + return; + len = getprop(usb, "assigned-addresses", usb_addr, sizeof(usb_addr)); + if (len != sizeof(usb_addr)) + return; + printf("usb base %x\n", usb_addr[2]); + + usb_ctrl = (volatile unsigned int *) (usb_addr[2] + 8); + *usb_ctrl = 0x01000000; /* cpu_to_le32(1) */ + eieio(); +} +#endif + +struct memchunk { + unsigned int size; + struct memchunk *next; +}; + +static struct memchunk *freechunks; + +void *zalloc(void *x, unsigned items, unsigned size) +{ + void *p; + struct memchunk **mpp, *mp; + + size *= items; + size = (size + 7) & -8; + heap_use += size; + if (heap_use > heap_max) + heap_max = heap_use; + for (mpp = &freechunks; (mp = *mpp) != 0; mpp = &mp->next) { + if (mp->size == size) { + *mpp = mp->next; + return mp; + } + } + p = avail_ram; + avail_ram += size; + if (avail_ram > avail_high) + avail_high = avail_ram; + if (avail_ram > end_avail) { + printf("oops... out of memory\n"); + pause(); + } + return p; +} + +void zfree(void *x, void *addr, unsigned nb) +{ + struct memchunk *mp = addr; + + nb = (nb + 7) & -8; + heap_use -= nb; + if (avail_ram == addr + nb) { + avail_ram = addr; + return; + } + mp->size = nb; + mp->next = freechunks; + freechunks = mp; +} + +#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 msg: %s\n", r, s.msg); + exit(); + } + *lenp = s.next_out - (unsigned char *) dst; + inflateEnd(&s); +} diff -Nru a/arch/ppc/boot/pmac/coffmain.c b/arch/ppc/boot/pmac/coffmain.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/pmac/coffmain.c Wed May 16 06:00:19 2001 @@ -0,0 +1,246 @@ +/* + * 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 "zlib.h" +#include +#include +#include + +extern void *finddevice(const char *); +extern int getprop(void *, const char *, void *, int); +extern char *claim(unsigned, unsigned, unsigned); +void make_bi_recs(unsigned long); +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 (RAM_START + 0x800000) /* only 8M mapped with BATs */ + +#define PROG_START RAM_START +#define PROG_SIZE 0x00400000 + +#define SCRATCH_SIZE (128 << 10) + +#ifdef CONFIG_CMDLINE +#define CMDLINE CONFIG_CMDLINE +#else +#define CMDLINE "" +#endif +char cmd_preset[] = CMDLINE; +char cmd_buf[256]; +char *cmd_line = cmd_buf; + +char *avail_ram; +char *begin_avail, *end_avail; +char *avail_high; +unsigned int heap_use; +unsigned int heap_max; + +extern char _start[], _end[]; +extern char image_data[]; +extern int image_len; +extern char initrd_data[]; +extern int initrd_len; + +char heap[SCRATCH_SIZE]; + +boot(int a1, int a2, void *prom) +{ + int ns, oh, i; + unsigned sa, len; + void *dst; + unsigned char *im; + unsigned initrd_start, initrd_size; + + printf("coffboot starting: loaded at 0x%x\n", _start); + setup_bats(RAM_START); + if (initrd_len) { + initrd_size = initrd_len; + initrd_start = (RAM_END - initrd_size) & ~0xFFF; + a1 = initrd_start; + a2 = initrd_size; + claim(initrd_start - RAM_START, RAM_END - initrd_start, 0); + printf("initial ramdisk moving 0x%x <- 0x%x (%x bytes)\n", + initrd_start, initrd_data, initrd_size); + memcpy((char *)initrd_start, initrd_data, initrd_size); + } + im = image_data; + len = image_len; + /* claim 3MB starting at 0 */ + claim(0, PROG_SIZE, 0); + dst = (void *) RAM_START; + if (im[0] == 0x1f && im[1] == 0x8b) { + /* claim some memory for scratch space */ + begin_avail = avail_high = avail_ram = heap; + end_avail = heap + sizeof(heap); + printf("heap at 0x%x\n", avail_ram); + printf("gunzipping (0x%x <- 0x%x:0x%0x)...", dst, im, im+len); + gunzip(dst, PROG_SIZE, im, &len); + printf("done %u bytes\n", len); + printf("%u bytes of heap consumed, max in use %u\n", + avail_high - begin_avail, heap_max); + } else { + memmove(dst, im, len); + } + + flush_cache(dst, len); + memcpy (cmd_line, cmd_preset, sizeof(cmd_preset)); + make_bi_recs((unsigned long)dst + len); + + sa = (unsigned long)PROG_START; + printf("start address = 0x%x\n", sa); + + (*(void (*)())sa)(a1, a2, prom); + + printf("returned?\n"); + + pause(); +} + +void make_bi_recs(unsigned long addr) +{ + struct bi_record *rec; + + addr = _ALIGN(addr+ (1<<20) - 1, (1<<20)); +#if 0 + if (addr >= PROG_START + PROG_SIZE) + claim(addr, 0x1000, 0); +#endif + + rec = (struct bi_record *)addr; + rec->tag = BI_FIRST; + rec->size = sizeof(struct bi_record); + rec = (struct bi_record *)((unsigned long)rec + rec->size); + + rec->tag = BI_BOOTLOADER_ID; + sprintf( (char *)rec->data, "coffboot"); + rec->size = sizeof(struct bi_record) + strlen("coffboot") + 1; + rec = (struct bi_record *)((unsigned long)rec + rec->size); + + rec->tag = BI_MACHTYPE; + rec->data[0] = _MACH_Pmac; + rec->data[1] = 1; + rec->size = sizeof(struct bi_record) + sizeof(unsigned long); + rec = (struct bi_record *)((unsigned long)rec + rec->size); + + rec->tag = BI_CMD_LINE; + memcpy( (char *)rec->data, cmd_line, strlen(cmd_line)+1); + rec->size = sizeof(struct bi_record) + strlen(cmd_line) + 1; + rec = (struct bi_record *)((unsigned long)rec + rec->size); + + rec->tag = BI_LAST; + rec->size = sizeof(struct bi_record); + rec = (struct bi_record *)((unsigned long)rec + rec->size); +} + +struct memchunk { + unsigned int size; + struct memchunk *next; +}; + +static struct memchunk *freechunks; + +void *zalloc(void *x, unsigned items, unsigned size) +{ + void *p; + struct memchunk **mpp, *mp; + + size *= items; + size = (size + 7) & -8; + heap_use += size; + if (heap_use > heap_max) + heap_max = heap_use; + for (mpp = &freechunks; (mp = *mpp) != 0; mpp = &mp->next) { + if (mp->size == size) { + *mpp = mp->next; + return mp; + } + } + p = avail_ram; + avail_ram += size; + if (avail_ram > avail_high) + avail_high = avail_ram; + if (avail_ram > end_avail) { + printf("oops... out of memory\n"); + pause(); + } + return p; +} + +void zfree(void *x, void *addr, unsigned nb) +{ + struct memchunk *mp = addr; + + nb = (nb + 7) & -8; + heap_use -= nb; + if (avail_ram == addr + nb) { + avail_ram = addr; + return; + } + mp->size = nb; + mp->next = freechunks; + freechunks = mp; +} + +#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 msg: %s\n", r, s.msg); + exit(); + } + *lenp = s.next_out - (unsigned char *) dst; + inflateEnd(&s); +} diff -Nru a/arch/ppc/boot/pmac/dummy.c b/arch/ppc/boot/pmac/dummy.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/pmac/dummy.c Wed May 16 06:00:23 2001 @@ -0,0 +1,4 @@ +int main(void) +{ + return 0; +} diff -Nru a/arch/ppc/boot/pmac/ld.script b/arch/ppc/boot/pmac/ld.script --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/pmac/ld.script Wed May 16 06:00:22 2001 @@ -0,0 +1,68 @@ +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 = .); +} + diff -Nru a/arch/ppc/boot/pmac/misc.S b/arch/ppc/boot/pmac/misc.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/pmac/misc.S Wed May 16 06:00:19 2001 @@ -0,0 +1,57 @@ +/* + * 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 BAT3 registers to map the 1st 8MB of RAM to + * the address given as the 1st argument. + */ + .globl setup_bats +setup_bats: + mfpvr 5 + rlwinm 5,5,16,16,31 /* r3 = 1 for 601, 4 for 604 */ + cmpi 0,5,1 + li 0,0 + bne 4f + mtibatl 3,0 /* invalidate BAT first */ + ori 3,3,4 /* set up BAT registers for 601 */ + li 4,0x7f + mtibatu 3,3 + mtibatl 3,4 + b 5f +4: mtdbatu 3,0 /* invalidate BATs first */ + mtibatu 3,0 + ori 3,3,0xff /* set up BAT registers for 604 */ + li 4,2 + mtdbatl 3,4 + mtdbatu 3,3 + mtibatl 3,4 + mtibatu 3,3 +5: sync + 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 diff -Nru a/arch/ppc/boot/pmac/start.c b/arch/ppc/boot/pmac/start.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/pmac/start.c Wed May 16 06:00:25 2001 @@ -0,0 +1,340 @@ +/* + * 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 + +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 printk(char *fmt, ...); + +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(); + + boot(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 writestring(void *f, char *ptr, int nb) +{ + int w = 0, i; + char *ret = "\r"; + + for (i = 0; i < nb; ++i) { + if (ptr[i] == '\n') { + if (i > w) { + write(f, ptr + w, i - w); + w = i; + } + write(f, ret, 1); + } + } + if (w < nb) + write(f, ptr + w, nb - w); + return nb; +} + +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; +} + +void * +claim(unsigned int virt, unsigned int size, unsigned int align) +{ + struct prom_args { + char *service; + int nargs; + int nret; + unsigned int virt; + unsigned int size; + unsigned int align; + void *ret; + } args; + + args.service = "claim"; + args.nargs = 3; + args.nret = 1; + args.virt = virt; + args.size = size; + args.align = align; + (*prom)(&args); + return args.ret; +} + +void +release(void *virt, unsigned int size) +{ + struct prom_args { + char *service; + int nargs; + int nret; + void *virt; + unsigned int size; + } args; + + args.service = "release"; + args.nargs = 2; + args.nret = 0; + args.virt = virt; + args.size = size; + (*prom)(&args); +} + +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; + + return writestring(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 writestring(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\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); + writestring(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); + writestring(stdout, sprint_buf, n); + return n; +} diff -Nru a/arch/ppc/boot/pmon/Makefile b/arch/ppc/boot/pmon/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/pmon/Makefile Wed May 16 06:00:34 2001 @@ -0,0 +1,115 @@ +# arch/ppc/pmonboot/Makefile +# +# Makefile for PMON bootloader +# +# Author: Matt Porter +# Cleanups: Tom Rini +# +# Copyright 2000-2001 MontaVista Software Inc. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2 of the License, or (at your +# option) any later version. + +.c.s: + $(CC) $(CFLAGS) -S -o $*.s $< +.s.o: + $(AS) -o $*.o $< +.c.o: + $(CC) $(CFLAGS) -c -o $*.o $< +.S.s: + $(CPP) $(AFLAGS) -traditional -o $*.o $< +.S.o: + $(CC) $(AFLAGS) -traditional -c -o $*.o $< + +ZLINKFLAGS = -T $(TOPDIR)/arch/$(ARCH)/vmlinux.lds -Ttext 0x00800000 + +OBJECTS := head.o ns16550.o ../common/misc-common.o ../common/misc-one.o \ + ../common/string.o +LIBS := ../lib/zlib.a +OBJCOPY_ARGS = -O elf32-powerpc +MKPMON := ../utils/mkpmon +SIZE := ../utils/size +OFFSET := ../utils/offset + +TFTPIMAGE := /tftpboot/zImage.pmon + +all: zImage + +../common/misc-one.o: ../common/misc-one.c + $(CC) $(CFLAGS) -DINITRD_OFFSET=0 -DINITRD_SIZE=0 -DZIMAGE_OFFSET=0 \ + -DZIMAGE_SIZE=0 -c -o $@ $*.c + +ns16550.o: ../common/ns16550.c + $(CC) $(CFLAGS) -DIOOFFSET=0x80000000 -c -o $@ ../common/$*.c + +zImage.initrd: zvmlinux.initrd $(MKPMON) + $(OBJCOPY) $(OBJCOPY_ARGS) --change-addresses=0x100000 \ + --change-section-address=image=0x0 \ + --change-section-address=initrd=0x0 zvmlinux.initrd ../images/$@.pmon + $(MKPMON) `$(OBJDUMP) -h ../images/$@.pmon | grep " initrd" | awk '{print $$6}'` \ + `$(OBJDUMP) -h ../images/$@.pmon | grep " initrd" | awk '{print $$3}'` \ + ../images/$@.pmon + rm -f zvmlinux.initrd + +zImage: zvmlinux $(MKPMON) + $(OBJCOPY) $(OBJCOPY_ARGS) --change-addresses=0x100000 \ + --change-section-address=image=0x0 zvmlinux ../images/$@.pmon + $(MKPMON) `$(OBJDUMP) -h ../images/$@.pmon | grep " image" | \ + awk '{print $$6}'` \ + `$(OBJDUMP) -h ../images/$@.pmon | grep " image" | \ + awk '{print $$3}'` ../images/$@.pmon + rm -f zvmlinux + +zvmlinux.initrd: zvmlinux + $(LD) $(ZLINKFLAGS) -o $@.tmp $(OBJECTS) $(LIBS) + $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ + --add-section=initrd=../images/ramdisk.image.gz \ + --add-section=image=../images/vmlinux.gz \ + $@.tmp $@ + $(CC) $(CFLAGS) -DINITRD_OFFSET=`sh $(OFFSET) $(OBJDUMP) $@ initrd` \ + -DINITRD_SIZE=`sh $(SIZE) $(OBJDUMP) $@ initrd` \ + -DZIMAGE_OFFSET=`sh $(OFFSET) $(OBJDUMP) $@ image` \ + -DZIMAGE_SIZE=`sh $(SIZE) $(OBJDUMP) $@ image` \ + -c -o ../common/misc-one.o ../common/misc-one.c + $(LD) $(ZLINKFLAGS) -o $@.tmp $(OBJECTS) $(LIBS) + $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ + --add-section=initrd=../images/ramdisk.image.gz \ + --add-section=image=../images/vmlinux.gz \ + $@.tmp $@ + rm -f $@.tmp + +zvmlinux: $(OBJECTS) $(LIBS) ../images/vmlinux.gz +# +# build the boot loader image and then compute the offset into it +# for the kernel image +# + $(LD) $(ZLINKFLAGS) -o $@.tmp $(OBJECTS) $(LIBS) + $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ + --add-section=image=../images/vmlinux.gz \ + $@.tmp $@ +# +# then with the offset rebuild the bootloader so we know where the kernel is +# + $(CC) $(CFLAGS) -DINITRD_OFFSET=0 -DINITRD_SIZE=0 \ + -DZIMAGE_OFFSET=`sh $(OFFSET) $(OBJDUMP) $@ image` \ + -DZIMAGE_SIZE=`sh $(SIZE) $(OBJDUMP) $@ image` \ + -D__BOOTER__ \ + -c -o ../common/misc-one.o ../common/misc-one.c + $(LD) $(ZLINKFLAGS) -o $@.tmp $(OBJECTS) $(LIBS) + $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ + --add-section=image=../images/vmlinux.gz \ + $@.tmp $@ + rm -f $@.tmp + +znetboot: zImage + cp ../images/zImage.pmon $(TFTPIMAGE) + +znetboot.initrd: zImage.initrd + cp ../images/zImage.initrd.pmon $(TFTPIMAGE) + +floppy: $(TOPDIR)/vmlinux zImage + dd if=zImage of=/dev/fd0H1440 bs=64b + +include $(TOPDIR)/Rules.make diff -Nru a/arch/ppc/boot/pmon/head.S b/arch/ppc/boot/pmon/head.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/pmon/head.S Wed May 16 06:00:34 2001 @@ -0,0 +1,652 @@ +/* + * arch/ppc/boot/pmon/head.S + * + * Initial board bringup code for PMON equipped systems + * + * Author: Matt Porter + * Derived from arch/ppc/boot/prep/head.S + * + * Copyright 2000 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include "../../kernel/ppc_defs.h" +#include "../../kernel/ppc_asm.tmpl" +#include +#include +#include "../../kernel/cpc710.h" +#include "../../kernel/k2.h" + +/* This is a kludge for the bootloader */ +#define _IO_BASE 0x80000000 + +/* + * Board initialization macros + */ + +#define DELAY \ + lis r3,0x000f; \ + ori r3,r3,0xffff; \ +0: subi r3,r3,1; \ + cmpi 0,0,r3,0; \ + bne 0b + +#define WRITE_MEM_32(address, data) \ + lis r3, address@h; \ + ori r3, r3, address@l; \ + lis r4, data@h; \ + ori r4, r4, data@l; \ + stw r4, 0x0000(r3); \ + sync; \ + eieio; \ + DELAY + +#define WRITE_MEM_8(address, data) \ + lis r3, address@h; \ + ori r3, r3, address@l; \ + li r4, data; \ + stb r4, 0(r3); \ + sync; \ + eieio; \ + DELAY + +#define WRITE_PCI64_CONFIG_32(address, data) \ + lis r3, K2_PCI64_CONFIG_ADDR@h; \ + ori r3, r3, K2_PCI64_CONFIG_ADDR@l; \ + lis r4, address@h; \ + ori r4, r4, address@l; \ + stw r4, 0(r3); \ + lis r3, K2_PCI64_CONFIG_DATA@h; \ + ori r3, r3, K2_PCI64_CONFIG_DATA@l; \ + lis r4, data@h; \ + ori r4, r4, data@l; \ + stw r4, 0(r3); \ + sync; \ + eieio; \ + DELAY + +#define WRITE_PCI32_CONFIG_32(address, data) \ + lis r3, K2_PCI32_CONFIG_ADDR@h; \ + ori r3, r3, K2_PCI32_CONFIG_ADDR@l; \ + lis r4, address@h; \ + ori r4, r4, address@l; \ + stw r4, 0(r3); \ + lis r3, K2_PCI32_CONFIG_DATA@h; \ + ori r3, r3, K2_PCI32_CONFIG_DATA@l; \ + lis r4, data@h; \ + ori r4, r4, data@l; \ + stw r4, 0(r3); \ + sync; \ + eieio; \ + DELAY + +#define WRITE_PCI64_CONFIG_16(address, data) \ + lis r3, K2_PCI64_CONFIG_ADDR@h; \ + ori r3, r3, K2_PCI64_CONFIG_ADDR@l; \ + lis r4, address@h; \ + ori r4, r4, address@l; \ + stw r4, 0(r3); \ + lis r3, K2_PCI64_CONFIG_DATA@h; \ + ori r3, r3, K2_PCI64_CONFIG_DATA@l; \ + lis r4, data@h; \ + ori r4, r4, data@l; \ + sth r4, 0(r3); \ + sync; \ + eieio; \ + DELAY + +#define WRITE_PCI32_CONFIG_16(address, data) \ + lis r3, K2_PCI32_CONFIG_ADDR@h; \ + ori r3, r3, K2_PCI32_CONFIG_ADDR@l; \ + lis r4, address@h; \ + ori r4, r4, address@l; \ + stw r4, 0(r3); \ + lis r3, K2_PCI32_CONFIG_DATA@h; \ + ori r3, r3, K2_PCI32_CONFIG_DATA@l; \ + lis r4, data@h; \ + ori r4, r4, data@l; \ + sth r4, 0(r3); \ + sync; \ + eieio; \ + DELAY + + .text + +/* + * + * Begin at some arbitrary location in RAM or Flash + * Initialize core registers + * Configure memory controller (Not executing from RAM) + * Move the boot code to the link address (8M) + * Setup C stack + * Initialize UART + * Decompress the kernel to 0x0 + * Jump to the kernel entry + * + */ + + .globl start +start: + bl start_ + +start_: +/* + * Configure core registers + */ + + /* Establish default MSR value, exception prefix 0xFFF */ + li r3,MSR_IP|MSR_FP + mtmsr r3 + + /* Clear BATS */ + li r8,0 + mtspr DBAT0U,r8 + mtspr DBAT0L,r8 + mtspr DBAT1U,r8 + mtspr DBAT1L,r8 + mtspr DBAT2U,r8 + mtspr DBAT2L,r8 + mtspr DBAT3U,r8 + mtspr DBAT3L,r8 + mtspr IBAT0U,r8 + mtspr IBAT0L,r8 + mtspr IBAT1U,r8 + mtspr IBAT1L,r8 + mtspr IBAT2U,r8 + mtspr IBAT2L,r8 + mtspr IBAT3U,r8 + mtspr IBAT3L,r8 + isync + sync + sync + + /* Set segment registers */ + lis r8, 0x8000 + isync + mtsr SR0,r8 + mtsr SR1,r8 + mtsr SR2,r8 + mtsr SR3,r8 + mtsr SR4,r8 + mtsr SR5,r8 + mtsr SR6,r8 + mtsr SR7,r8 + mtsr SR8,r8 + mtsr SR9,r8 + mtsr SR10,r8 + mtsr SR11,r8 + mtsr SR12,r8 + mtsr SR13,r8 + mtsr SR14,r8 + mtsr SR15,r8 + isync + sync + sync + + /* Disable L1 icache/dcache */ + li r4,0x0000 + isync + mtspr HID0,r4 + sync + isync + + /* Invalidate and enable L1 icache */ + mfspr r4,HID0 + ori r4,r4,0x8800 + isync + mtspr HID0,r4 + sync + isync + + /* + * If we are executing from flash, then do the full init as + * follows. Otherwise, skip the memory controller reset, etc. + */ + lis r4,0xfff0 + ori r4,r4,0x0104 + mflr r3 + cmp 0,r3,r4 + bne brdgcnfg + +/* + * Configure CPC710 bridge, memory controller, and ALI M1543C PIB + */ + /* Initialize CPC710 core registers */ + WRITE_MEM_32(RSTR, 0xf0000000) + + /* Dummy read */ + lis r3, MPSR@h + ori r3, r3, MPSR@l + lwz r4, 0(r3) + sync + eieio + + WRITE_MEM_32(SIOC, 0x00000000) + WRITE_MEM_32(PIDR, 0x00000000) + WRITE_MEM_32(UCTL, 0x00780080) + WRITE_MEM_32(ABCNTL, 0x70000000) + WRITE_MEM_32(SRST, 0x00000000) + WRITE_MEM_32(ERRC, 0x00000000) + WRITE_MEM_32(SESR, 0x00000000) + WRITE_MEM_32(SEAR, 0x00000000) + WRITE_MEM_32(GPDIR, 0x00000000) + WRITE_MEM_32(ATAS, 0x709c2508) + WRITE_MEM_32(AVDG, 0x00000000) + WRITE_MEM_32(MESR, 0x00000000) + WRITE_MEM_32(MEAR, 0x00000000) + WRITE_MEM_32(MCER0, 0x00000000) + WRITE_MEM_32(MCER1, 0x00000000) + WRITE_MEM_32(MCER2, 0x00000000) + WRITE_MEM_32(MCER3, 0x00000000) + WRITE_MEM_32(MCER4, 0x00000000) + WRITE_MEM_32(MCER5, 0x00000000) + WRITE_MEM_32(MCER6, 0x00000000) + WRITE_MEM_32(MCER7, 0x00000000) + WRITE_MEM_32(MCCR, 0x52b06000) + +brdgcnfg: + WRITE_MEM_32(PGCHP, 0x808000e0) /* Set FPHB modes */ + /* Enable and map PCI32 and PCI64 registers to a base address */ + WRITE_MEM_32(CNFR, 0x80000003) /* Activate CNFR - PCI64 */ + WRITE_MEM_32(BAR, K2_PCI64_BAR) /* Set BAR - PCI64_BAR_VALUE */ + WRITE_MEM_32(PCIENB, 0x80000000) /* Enable PCI Control Space */ + WRITE_MEM_32(CNFR, 0x00000000) /* Deactivate CNFR - PCI64 */ + WRITE_MEM_32(CNFR, 0x80000002) /* Activate CNFR - PCI32 */ + WRITE_MEM_32(BAR, K2_PCI32_BAR) /* Set BAR - PCI32_BAR_VALUE */ + WRITE_MEM_32(PCIENB, 0x80000000) /* Enable PCI Control Space */ + WRITE_MEM_32(CNFR, 0x00000000) /* Deactivate CNFR - PCI32 */ + + /* PCI64 Config space init */ + WRITE_PCI64_CONFIG_32(0x04000080,0x07038002) /* SERR,BMAS,I/O,MEM */ + WRITE_PCI64_CONFIG_32(0x68000080,0x0f000000) /* Reset INTA-D */ + WRITE_PCI64_CONFIG_16(0x40000080,0x000f) /* Set BUS_NO */ + + /* PCI32 Config space init */ + WRITE_PCI32_CONFIG_32(0x04000080,0x07038002) /* SERR,BMAS,I/O,MEM */ + WRITE_PCI32_CONFIG_32(0x68000080,0x0f000000) /* Reset INTA-D */ + WRITE_PCI32_CONFIG_16(0x40000080,0x000f) /* Set BUS_NO */ + + /* PCI64 memory mappings */ + + WRITE_MEM_32(0xff4f6110, 0x00000000) /* PSEA */ + WRITE_MEM_32(0xff4f6120, 0xc0000000) /* PCIDG */ + WRITE_MEM_32(0xff4f7800, 0x08000000) /* PIBAR - PCI I/O base */ + WRITE_MEM_32(0xff4f7810, 0x08000000) /* PMBAR - PCI Mem base */ + WRITE_MEM_32(0xff4f7f20, 0x80008000) /* PR - MRU parking,queue on */ + WRITE_MEM_32(0xff4f7f30, 0xff000000) /* ACR - Enable all levels */ + WRITE_MEM_32(0xff4f7f40, 0xf8000000) /* MSIZE - 128MB */ + WRITE_MEM_32(0xff4f7f60, 0xf8000000) /* IOSIZE - 128MB */ + WRITE_MEM_32(0xff4f7f80, 0xc8000000) /* SMBAR - Base@0xc8000000 */ + WRITE_MEM_32(0xff4f7fc0, 0x88000000) /* SIBAR - Base@0x88000000 */ + WRITE_MEM_32(0xff4f7fd0, 0x02000000) /* CTLRW - ISA contiguous */ + WRITE_MEM_32(0xff4f8100, 0x000000c0) /* PSSIZE - 1GB space */ + WRITE_MEM_32(0xff4f8110, 0x000000c0) /* PPSIZE - 1GB space */ + WRITE_MEM_32(0xff4f8120, 0x00000000) /* BARPS - Base@0x00000000 */ + WRITE_MEM_32(0xff4f8130, 0x00000000) /* BARPP - Base@0x00000000 */ + WRITE_MEM_32(0xff4f8310, 0x00000000) /* Init INT_SET */ + + /* PCI32 memory mappings */ + WRITE_MEM_32(0xff5f6110, 0x00000000) /* Clear PSEA */ + WRITE_MEM_32(0xff5f6120, 0x40000000) /* PIDG */ + WRITE_MEM_32(0xff5f7800, 0x00000000) /* PIBAR - PCI I/O Base */ + WRITE_MEM_32(0xff5f7810, 0x00000000) /* PMBAR - PCI Mem Base */ + WRITE_MEM_32(0xff5f7f20, 0xa000c000) /* PR - Enable translation */ + WRITE_MEM_32(0xff5f7f30, 0xfc000000) /* ACR - Enable all levels */ + WRITE_MEM_32(0xff5f7f40, 0xf8000000) /* MSIZE - 128MB */ + WRITE_MEM_32(0xff5f7f60, 0xf8000000) /* IOSIZE - 128MB */ + WRITE_MEM_32(0xff5f7f80, 0xc0000000) /* SMBAR - Base@0xc0000000 */ + WRITE_MEM_32(0xff5f7fc0, 0x80000000) /* SIBAR - Base@0x80000000 */ + WRITE_MEM_32(0xff5f7fd0, 0x00000000) /* CTLRW - ISA contiguous */ + WRITE_MEM_32(0xff5f8100, 0x000000c0) /* PSSIZE - 1GB space */ + WRITE_MEM_32(0xff5f8110, 0x000000c0) /* PPSIZE - 1GB space */ + WRITE_MEM_32(0xff5f8120, 0x00000000) /* BARPS - Base@0x00000000 */ + WRITE_MEM_32(0xff5f8130, 0x00000000) /* BARPP - Base@0x00000000 */ + + /* PCI64 specific memory mappings */ + WRITE_PCI64_CONFIG_32(0x10000080, 0x00000080) /* PSBAR - Base@0x80 */ + + /* PCI32 specific memory mappings */ + WRITE_MEM_32(0xff5f8140, 0x00000080) /* PSBAR - Base@0x80 */ + WRITE_MEM_32(0xff5f8150, 0x00000000) /* PPBAR */ + WRITE_MEM_32(0xff5f8200, 0xcc000000) /* BPMDLK */ + WRITE_MEM_32(0xff5f8210, 0xff000000) /* TPMDLK */ + WRITE_MEM_32(0xff5f8220, 0x81000000) /* BIODLK */ + WRITE_MEM_32(0xff5f8230, 0xc0000000) /* TIODLK */ + + /* Turn off PCI64/PCI32 resets */ + WRITE_MEM_32(0xff4f7ef0, 0xfc000000) + WRITE_MEM_32(0xff5f7ef0, 0xfc000000) + + /* ALI 1543C PCI-ISA bridge config */ + WRITE_PCI32_CONFIG_32(0x40400080, 0x00000230) /* Set PIC,IORC,ISAC */ + WRITE_PCI32_CONFIG_32(0x44400080, 0x00800000) /* Enable PCI polling */ + WRITE_PCI32_CONFIG_32(0x50400080, 0x00000040) /* Disable USB */ + WRITE_PCI32_CONFIG_32(0x54400080, 0x00030800) + WRITE_PCI32_CONFIG_32(0x58400080, 0x000d0e03) + WRITE_PCI32_CONFIG_32(0x5c400080, 0x0000000c) + WRITE_PCI32_CONFIG_32(0x70400080, 0x00000000) + WRITE_PCI32_CONFIG_32(0x78400080, 0x00000000) + + /* Turn on board fail light and turn off other lights */ + WRITE_MEM_8(0x80000804, 0x22); + + /* Turn off board fail light and turn on User1 light */ + WRITE_MEM_8(0x80000804, 0x24) + + /* Turn on hotswap light and unmask ENUM */ + WRITE_MEM_8(0x8000080c, 0x00); + + /* Enable ALI 1543C UARTs */ + WRITE_MEM_8(K2_ISAPNP_CONFIG, 0x51) /* Write config key */ + WRITE_MEM_8(K2_ISAPNP_CONFIG, 0x23) /* Write config key */ + WRITE_MEM_8(K2_ISAPNP_INDEX, 0x22) /* Access powerdown control */ + WRITE_MEM_8(K2_ISAPNP_DATA, 0x00) /* Wake up UARTs */ + WRITE_MEM_8(K2_ISAPNP_INDEX, 0x07) /* Access logical device reg */ + WRITE_MEM_8(K2_ISAPNP_DATA, 0x04) /* Point to UART1 */ + WRITE_MEM_8(K2_ISAPNP_INDEX, 0x30) /* Access reg 30 */ + WRITE_MEM_8(K2_ISAPNP_DATA, 0x01) /* Enable UART1 */ + WRITE_MEM_8(K2_ISAPNP_INDEX, 0x07) /* Access logical device reg */ + WRITE_MEM_8(K2_ISAPNP_DATA, 0x05) /* Point to UART3 */ + WRITE_MEM_8(K2_ISAPNP_INDEX, 0x30) /* Access reg 30 */ + WRITE_MEM_8(K2_ISAPNP_DATA, 0x01) /* Enable UART3 */ + WRITE_MEM_8(K2_ISAPNP_CONFIG, 0xbb) /* Exit config mode */ + + /* + * Configure CPC710 memory controller + */ + andi. r4,r4,0x00e0 + + /* + * If we are executing from flash, then do the full init as + * follows. Otherwise, skip the memory size configuration. + */ + lis r4,0xfff0 + ori r4,r4,0x0104 + mflr r3 + cmp 0,r3,r4 + bne endmemcfg + + cmpli 0,0,r4,0x0040 + beq config_512x2 + + cmpli 0,0,r4,0x0060 + beq config_512x1 + + cmpli 0,0,r4,0x0080 + beq config_256x2 + + cmpli 0,0,r4,0x00a0 + beq config_256x1 + + cmpli 0,0,r4,0x00c0 + beq config_128x2 + + b config_128x1 /* 0x00e0 or others default to 128x1 */ + +config_512x2: + WRITE_MEM_32(MCER0, 0x80000080) /* Bank 0 MER - 512MB */ + WRITE_MEM_32(MCER1, 0x82000080) /* Bank 1 MER - 512MB */ + b mccr + +config_512x1: + WRITE_MEM_32(MCER0, 0x80000080) /* Bank 0 MER - 512MB */ + b mccr + +config_256x2: + WRITE_MEM_32(MCER0, 0x800000d4) /* Bank 0 MER - 256MB */ + WRITE_MEM_32(MCER1, 0x810000d4) /* Bank 1 MER - 256MB */ + b mccr + +config_256x1: + WRITE_MEM_32(MCER0, 0x800000d4) /* Bank 0 MER - 256MB */ + b mccr + +config_128x2: + WRITE_MEM_32(MCER0, 0x800080c0) /* Bank 0 MER - 128MB */ + WRITE_MEM_32(MCER1, 0x808080c0) /* Bank 1 MER - 128MB */ + b mccr + +config_128x1: + WRITE_MEM_32(MCER0, 0x800080c0) /* Bank 0 MER - 128MB */ + +mccr: + /* Enable memory controller configuration */ + WRITE_MEM_32(MCCR, 0xf2b06000) + +sdwait: + /* Wait until SDRAM initialization is complete */ + nop + lis r3, MCCR@h + ori r3, r3, MCCR@l + lwz r4, 0(r3) + lis r5, 0x2000 + ori r5, r5, 0x0000 + and r4, r4, r5 + cmpl 0, 0, r5, r4 + bne sdwait + +endmemcfg: + /* Configure M5229 IDE PIB settings */ + WRITE_PCI32_CONFIG_32(0x40400080, 0x00000233) /* 3 wait states */ + WRITE_PCI32_CONFIG_32(0x48400080, 0x580731b9) /* PCI IRQ routes */ + WRITE_PCI32_CONFIG_32(0x4c400080, 0x00000000) /* Disable SIRQ maps */ + WRITE_PCI32_CONFIG_32(0x44400080, 0x0d800000) /* primary IDE->14 */ + WRITE_PCI32_CONFIG_32(0x74400080, 0x000d0000) /* secondary IDE->14 */ + + /* Configure PIC level/edge settings */ + WRITE_MEM_8(0x800004d0, 0x62) + WRITE_MEM_8(0x800004d1, 0xde) + + /* Configure M5229 IDE settings */ + WRITE_PCI32_CONFIG_32(0x58400080, 0x480d0e03) /* Enable IDE */ + WRITE_PCI32_CONFIG_32(0x50880080, 0x03000000) /* Enable IDE */ + WRITE_PCI32_CONFIG_32(0x04880080, 0x04008002) /* I/O accesses on */ + WRITE_PCI32_CONFIG_32(0x08880080, 0xc1df0101) /* Native, sec only */ + + /* Turn on User2 LED */ + WRITE_MEM_8(0x80000804, 0x21) + +/* check if we need to relocate ourselves to the link addr or were we + loaded there to begin with -- Cort */ + lis r4,start@h + ori r4,r4,start@l + mflr r3 + subi r3,r3,4 /* we get the nip, not the ip of the branch */ + mr r8,r3 + cmp 0,r3,r4 + bne 1010f +/* compute size of whole image in words. this should be moved to + * start_ldr() -- Cort + */ + lis r4,start@h + ori r4,r4,start@l + lis r5,end@h + ori r5,r5,end@l + addi r5,r5,3 /* round up */ + sub r5,r5,r4 + srwi r5,r5,2 + mr r7,r5 + b start_ldr +1010: +/* + * no matter where we're loaded, move ourselves to -Ttext address + */ +relocate: + mflr r3 /* Compute code bias */ + subi r3,r3,4 + mr r8,r3 + lis r4,start@h + ori r4,r4,start@l + lis r5,end@h + ori r5,r5,end@l + addi r5,r5,3 /* Round up - just in case */ + sub r5,r5,r4 /* Compute # longwords to move */ + srwi r5,r5,2 + mtctr r5 + mr r7,r5 + li r6,0 + subi r3,r3,4 /* Set up for loop */ + subi r4,r4,4 +00: lwzu r5,4(r3) + stwu r5,4(r4) + xor r6,r6,r5 + bdnz 00b + lis r3,start_ldr@h + ori r3,r3,start_ldr@l + mtlr r3 /* Easiest way to do an absolute jump */ + blr +start_ldr: +/* Clear all of BSS and set up stack for C calls */ + lis r3,edata@h + ori r3,r3,edata@l + lis r4,end@h + ori r4,r4,end@l + subi r3,r3,4 + subi r4,r4,4 + li r0,0 +50: stwu r0,4(r3) + cmp 0,r3,r4 + bne 50b +90: mr r9,r1 /* Save old stack pointer (in case it matters) */ + lis r1,.stack@h + ori r1,r1,.stack@l + addi r1,r1,4096*2 + subi r1,r1,256 + li r2,0x000F /* Mask pointer to 16-byte boundary */ + andc r1,r1,r2 + +/* + * Exec kernel loader + */ + mr r3,r8 /* Load point */ + mr r4,r7 /* Program length */ + mr r5,r6 /* Checksum */ + bl decompress_kernel + + lis r6,cmd_line@h + ori r6,r6,cmd_line@l + lwz r6, 0(r6) + subi r7,r6,1 +00: lbzu r2,1(r7) + 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,0x4 + mtlr r9 + + /* + * Jump to kernel start + */ + blr + +hang: + b hang + +/* + * 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 + +.globl _get_HID0 +_get_HID0: + mfspr r3,HID0 + blr + +.globl _put_HID0 +_put_HID0: + mtspr HID0,r3 + blr + +.globl _get_MSR +_get_MSR: + mfmsr r3 + blr + +.globl _put_MSR +_put_MSR: + mtmsr r3 + blr + +/* + * Flush instruction cache + * *** I'm really paranoid here! + */ +_GLOBAL(flush_instruction_cache) + mflr r5 + bl flush_data_cache + mfspr r3,HID0 /* Caches are controlled by this register */ + li r4,0 + ori r4,r4,(HID0_ICE|HID0_ICFI) + or r3,r3,r4 /* Need to enable+invalidate to clear */ + mtspr HID0,r3 + andc r3,r3,r4 + ori r3,r3,HID0_ICE /* Enable cache */ + mtspr HID0,r3 + mtlr r5 + blr + +#define NUM_CACHE_LINES 128*8 +#define CACHE_LINE_SIZE 32 +#define cache_flush_buffer 0x1000 + +/* + * Flush data cache + * *** I'm really paranoid here! + */ +_GLOBAL(flush_data_cache) + lis r3,cache_flush_buffer@h + ori r3,r3,cache_flush_buffer@l + li r4,NUM_CACHE_LINES + mtctr r4 +00: lwz r4,0(r3) + addi r3,r3,CACHE_LINE_SIZE /* Next line, please */ + bdnz 00b +10: blr + .comm .stack,4096*2,4 + diff -Nru a/arch/ppc/boot/pp3/Makefile b/arch/ppc/boot/pp3/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/pp3/Makefile Wed May 16 06:00:33 2001 @@ -0,0 +1,96 @@ +# arch/ppc/pp3boot/Makefile +# +# Makefile for PowerPlus III bootloader +# +# Author: Matt Porter +# +# Copyright 2001 MontaVista Software Inc. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2 of the License, or (at your +# option) any later version. + +.c.s: + $(CC) $(CFLAGS) -S -o $*.s $< +.s.o: + $(AS) -o $*.o $< +.c.o: + $(CC) $(CFLAGS) -D__BOOTER__ -c -o $*.o $< +.S.s: + $(CPP) $(AFLAGS) -traditional -o $*.o $< +.S.o: + $(CC) $(AFLAGS) -traditional -c -o $*.o $< + +ZLINKFLAGS = -T $(TOPDIR)/arch/$(ARCH)/vmlinux.lds -Ttext 0x00800000 + +GZIP_FLAGS = -v9f + +OBJECTS := head.o ../common/misc-common.o ../common/misc-one.o \ + ../common/ns16550.o ../common/string.o +OBJCOPY_ARGS = -O elf32-powerpc +LIBS := ../lib/zlib.a + +OFFSET := ../utils/offset +SIZE := ../utils/size +MKPREP := ../utils/mkprep +MKBUGBOOT := ../utils/mkbugboot + +all: zImage + +../common/misc-one.o: ../common/misc-one.c + $(CC) $(CFLAGS) -DINITRD_OFFSET=0 -DINITRD_SIZE=0 -DZIMAGE_OFFSET=0 \ + -DZIMAGE_SIZE=0 -c -o $@ $*.c + +zvmlinux.initrd: $(OBJECTS) $(LIBS) ../images/vmlinux.gz + $(LD) $(ZLINKFLAGS) -o $@.tmp $(OBJECTS) $(LIBS) + $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ + --add-section=initrd=../images/ramdisk.image.gz \ + --add-section=image=../images/vmlinux.gz \ + $@.tmp $@ + $(CC) $(CFLAGS) -DINITRD_OFFSET=`sh $(OFFSET) $(OBJDUMP) $@ initrd` \ + -DINITRD_SIZE=`sh $(SIZE) $(OBJDUMP) $@ initrd` \ + -DZIMAGE_OFFSET=`sh $(OFFSET) $(OBJDUMP) $@ image` \ + -DZIMAGE_SIZE=`sh $(SIZE) $(OBJDUMP) $@ image` \ + -c -o ../common/misc-one.o ../common/misc-one.c + $(LD) $(ZLINKFLAGS) -o $@.tmp $(OBJECTS) $(LIBS) + $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ + --add-section=initrd=../images/ramdisk.image.gz \ + --add-section=image=../images/vmlinux.gz \ + $@.tmp $@ + rm -f $@.tmp + +zImage: zvmlinux $(MKPREP) $(MKBUGBOOT) + $(MKPREP) -pbp zvmlinux ../images/$@.pp3 + $(MKBUGBOOT) zvmlinux ../images/$@.bugboot + rm -f zvmlinux + +zImage.initrd: zvmlinux.initrd $(MKPREP) $(MKBUGBOOT) + $(MKPREP) -pbp zvmlinux.initrd ../images/$@.pp3 + $(MKBUGBOOT) zvmlinux.initrd ../images/$@.bugboot + rm -f zvmlinux.initrd + +zvmlinux: $(OBJECTS) $(LIBS) ../images/vmlinux.gz +# +# build the boot loader image and then compute the offset into it +# for the kernel image +# + $(LD) $(ZLINKFLAGS) -o $@.tmp $(OBJECTS) $(LIBS) + $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ + --add-section=image=../images/vmlinux.gz \ + $@.tmp $@ +# +# then with the offset rebuild the bootloader so we know where the kernel is +# + $(CC) $(CFLAGS) -DINITRD_OFFSET=0 -DINITRD_SIZE=0 \ + -DZIMAGE_OFFSET=`sh $(OFFSET) $(OBJDUMP) $@ image` \ + -DZIMAGE_SIZE=`sh $(SIZE) $(OBJDUMP) $@ image` \ + -D__BOOTER__ \ + -c -o ../common/misc-one.o ../common/misc-one.c + $(LD) $(ZLINKFLAGS) -o $@.tmp $(OBJECTS) $(LIBS) + $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ + --add-section=image=../images/vmlinux.gz \ + $@.tmp $@ + rm -f $@.tmp + +include $(TOPDIR)/Rules.make diff -Nru a/arch/ppc/boot/pp3/head.S b/arch/ppc/boot/pp3/head.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/pp3/head.S Wed May 16 06:00:33 2001 @@ -0,0 +1,310 @@ +/* + * arch/ppc/boot/pp3/head.S + * + * Initial board bringup code for the PrPMC750 + * + * Author: Matt Porter + * Derived from arch/ppc/boot/prep/head.S + * + * Copyright 2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include "../../kernel/ppc_defs.h" +#include "../../kernel/ppc_asm.tmpl" +#include +#include + + .text + +/* + * + * Begin at some arbitrary location in RAM or Flash + * Initialize core registers + * Configure memory controller (Not executing from RAM) + * Move the boot code to the link address (8M) + * Setup C stack + * Initialize UART + * Decompress the kernel to 0x0 + * Jump to the kernel entry + * + */ + + .globl start +start: + bl start_ + +start_: +/* + * Configure core registers + */ + + /* Establish default MSR value, exception prefix 0xFFF */ + li r3,MSR_IP|MSR_FP + mtmsr r3 + + /* Clear BATS */ + li r8,0 + mtspr DBAT0U,r8 + mtspr DBAT0L,r8 + mtspr DBAT1U,r8 + mtspr DBAT1L,r8 + mtspr DBAT2U,r8 + mtspr DBAT2L,r8 + mtspr DBAT3U,r8 + mtspr DBAT3L,r8 + mtspr IBAT0U,r8 + mtspr IBAT0L,r8 + mtspr IBAT1U,r8 + mtspr IBAT1L,r8 + mtspr IBAT2U,r8 + mtspr IBAT2L,r8 + mtspr IBAT3U,r8 + mtspr IBAT3L,r8 + isync + sync + sync + + /* Set segment registers */ + lis r8, 0x8000 + isync + mtsr SR0,r8 + mtsr SR1,r8 + mtsr SR2,r8 + mtsr SR3,r8 + mtsr SR4,r8 + mtsr SR5,r8 + mtsr SR6,r8 + mtsr SR7,r8 + mtsr SR8,r8 + mtsr SR9,r8 + mtsr SR10,r8 + mtsr SR11,r8 + mtsr SR12,r8 + mtsr SR13,r8 + mtsr SR14,r8 + mtsr SR15,r8 + isync + sync + sync + + /* Disable L1 icache/dcache */ + li r4,0x0000 + isync + mtspr HID0,r4 + sync + isync + + /* Invalidate and enable L1 icache */ + mfspr r4,HID0 + ori r4,r4,0x8800 + isync + mtspr HID0,r4 + sync + isync + +/* check if we need to relocate ourselves to the link addr or were we + loaded there to begin with -- Cort */ + lis r4,start@h + ori r4,r4,start@l + mflr r3 + subi r3,r3,4 /* we get the nip, not the ip of the branch */ + mr r8,r3 + cmp 0,r3,r4 + bne 1010f +/* compute size of whole image in words. this should be moved to + * start_ldr() -- Cort + */ + lis r4,start@h + ori r4,r4,start@l + lis r5,end@h + ori r5,r5,end@l + addi r5,r5,3 /* round up */ + sub r5,r5,r4 + srwi r5,r5,2 + mr r7,r5 + b start_ldr +1010: +/* + * no matter where we're loaded, move ourselves to -Ttext address + */ +relocate: + mflr r3 /* Compute code bias */ + subi r3,r3,4 + mr r8,r3 + lis r4,start@h + ori r4,r4,start@l + lis r5,end@h + ori r5,r5,end@l + addi r5,r5,3 /* Round up - just in case */ + sub r5,r5,r4 /* Compute # longwords to move */ + srwi r5,r5,2 + mtctr r5 + mr r7,r5 + li r6,0 + subi r3,r3,4 /* Set up for loop */ + subi r4,r4,4 +00: lwzu r5,4(r3) + stwu r5,4(r4) + xor r6,r6,r5 + bdnz 00b + lis r3,start_ldr@h + ori r3,r3,start_ldr@l + mtlr r3 /* Easiest way to do an absolute jump */ + blr +start_ldr: +/* Clear all of BSS and set up stack for C calls */ + lis r3,edata@h + ori r3,r3,edata@l + lis r4,end@h + ori r4,r4,end@l + subi r3,r3,4 + subi r4,r4,4 + li r0,0 +50: stwu r0,4(r3) + cmp 0,r3,r4 + bne 50b +90: mr r9,r1 /* Save old stack pointer (in case it matters) */ + lis r1,.stack@h + ori r1,r1,.stack@l + addi r1,r1,4096*2 + subi r1,r1,256 + li r2,0x000F /* Mask pointer to 16-byte boundary */ + andc r1,r1,r2 + +/* + * Exec kernel loader + */ + mr r3,r8 /* Load point */ + mr r4,r7 /* Program length */ + mr r5,r6 /* Checksum */ + bl decompress_kernel + + lis r6,cmd_line@h + ori r6,r6,cmd_line@l + lwz r6, 0(r6) + subi r7,r6,1 +00: lbzu r2,1(r7) + 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,0x4 + mtlr r9 + li r9,0 + + /* + * Jump to kernel start + */ + blr + +hang: + b hang + +/* + * 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 + +.globl _get_HID0 +_get_HID0: + mfspr r3,HID0 + blr + +.globl _put_HID0 +_put_HID0: + mtspr HID0,r3 + blr + +.globl _get_MSR +_get_MSR: + mfmsr r3 + blr + +.globl _put_MSR +_put_MSR: + mtmsr r3 + blr + +/* + * Flush instruction cache + * *** I'm really paranoid here! + */ +_GLOBAL(flush_instruction_cache) + mflr r5 + bl flush_data_cache + mfspr r3,HID0 /* Caches are controlled by this register */ + li r4,0 + ori r4,r4,(HID0_ICE|HID0_ICFI) + or r3,r3,r4 /* Need to enable+invalidate to clear */ + mtspr HID0,r3 + andc r3,r3,r4 + ori r3,r3,HID0_ICE /* Enable cache */ + mtspr HID0,r3 + mtlr r5 + blr + +#define NUM_CACHE_LINES 128*8 +#define CACHE_LINE_SIZE 32 +#define cache_flush_buffer 0x1000 + +/* + * Flush data cache + * *** I'm really paranoid here! + */ +_GLOBAL(flush_data_cache) + lis r3,cache_flush_buffer@h + ori r3,r3,cache_flush_buffer@l + li r4,NUM_CACHE_LINES + mtctr r4 +00: lwz r4,0(r3) + addi r3,r3,CACHE_LINE_SIZE /* Next line, please */ + bdnz 00b +10: blr + .comm .stack,4096*2,4 + diff -Nru a/arch/ppc/boot/prep/Makefile b/arch/ppc/boot/prep/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/prep/Makefile Wed May 16 06:00:25 2001 @@ -0,0 +1,113 @@ +# +# arch/ppc/boot/prep/Makefile +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. +# +# Tom Rini January 2001 +# +# Originally: +# arch/ppc/boot/Makefile +# Copyright (C) 1994 by Linus Torvalds +# Adapted for PowerPC by Gary Thomas +# modified by Cort (cort@cs.nmt.edu) +# + +.c.s: + $(CC) $(CFLAGS) -S -o $*.s $< +.s.o: + $(AS) -o $*.o $< +.c.o: + $(CC) $(CFLAGS) -c -o $*.o $< +.S.s: + $(CPP) $(AFLAGS) -traditional -o $*.o $< +.S.o: + $(CC) $(AFLAGS) -traditional -c -o $*.o $< + +ifeq ($(CONFIG_SMP),y) +TFTPIMAGE=/tftpboot/zImage.prep.smp +else +TFTPIMAGE=/tftpboot/zImage.prep +endif + +ZLINKFLAGS = -T $(TOPDIR)/arch/$(ARCH)/vmlinux.lds -Ttext 0x00800000 +OBJECTS := head.o misc.o vreset.o kbd.o ../common/misc-common.o \ + ../common/string.o of1275.o +OBJCOPY_ARGS = -O elf32-powerpc +LIBS = ../lib/zlib.a + +ifeq ($(CONFIG_SERIAL_CONSOLE),y) +OBJECTS += ns16550.o +endif + +# Tools +MKPREP := ../utils/mkprep +SIZE := ../utils/size +OFFSET := ../utils/offset + +all: zImage + +misc.o: misc.c + $(CC) $(CFLAGS) -DINITRD_OFFSET=0 -DINITRD_SIZE=0 -DZIMAGE_OFFSET=0 \ + -DZIMAGE_SIZE=0 -c -o $@ $*.c + +ns16550.o: ../common/ns16550.c + $(CC) $(CFLAGS) -DIOOFFSET=0x80000000 -c -o $@ ../common/$*.c + +zvmlinux.initrd: zvmlinux ../images/vmlinux.gz + $(LD) $(ZLINKFLAGS) -o $@.tmp $(OBJECTS) $(LIBS) + $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ + --add-section=initrd=../images/ramdisk.image.gz \ + --add-section=image=../images//vmlinux.gz \ + $@.tmp $@ + $(CC) $(CFLAGS) -DINITRD_OFFSET=`sh $(OFFSET) $(OBJDUMP) $@ initrd` \ + -DINITRD_SIZE=`sh $(SIZE) $(OBJDUMP) $@ initrd` \ + -DZIMAGE_OFFSET=`sh $(OFFSET) $(OBJDUMP) $@ image` \ + -DZIMAGE_SIZE=`sh $(SIZE) $(OBJDUMP) $@ image` \ + -c -o misc.o misc.c + $(LD) $(ZLINKFLAGS) -o $@.tmp $(OBJECTS) $(LIBS) + $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ + --add-section=initrd=../images/ramdisk.image.gz \ + --add-section=image=../images/vmlinux.gz \ + $@.tmp $@ + rm -f $@.tmp + +zImage: zvmlinux $(MKPREP) + $(MKPREP) -pbp zvmlinux ../images/zImage.prep + rm -f zvmlinux + +zImage.initrd: zvmlinux.initrd $(MKPREP) + $(MKPREP) -pbp zvmlinux.initrd ../images/zImage.prep.initrd + rm -f zvmlinux.initrd + +zvmlinux: $(OBJECTS) $(LIBS) ../images/vmlinux.gz +# +# build the boot loader image and then compute the offset into it +# for the kernel image +# + $(LD) $(ZLINKFLAGS) -o zvmlinux.tmp $(OBJECTS) $(LIBS) + $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ + --add-section=image=../images/vmlinux.gz zvmlinux.tmp $@ +# +# then with the offset rebuild the bootloader so we know where the kernel is +# + $(CC) $(CFLAGS) -DINITRD_OFFSET=0 -DINITRD_SIZE=0 \ + -DZIMAGE_OFFSET=`sh $(OFFSET) $(OBJDUMP) zvmlinux image` \ + -DZIMAGE_SIZE=`sh $(SIZE) $(OBJDUMP) zvmlinux image` \ + -c -o misc.o misc.c + $(LD) $(ZLINKFLAGS) -o zvmlinux.tmp $(OBJECTS) $(LIBS) + $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ + --add-section=image=../images/vmlinux.gz zvmlinux.tmp $@ + rm zvmlinux.tmp + +floppy: zImage + dd if=../images/zImage.prep of=/dev/fd0H1440 bs=64b + +znetboot : zImage + cp ../images/zImage.prep $(TFTPIMAGE) + +znetboot.initrd : zImage.initrd + cp ../images/zImage.prep.initrd $(TFTPIMAGE) + +include $(TOPDIR)/Rules.make diff -Nru a/arch/ppc/boot/prep/head.S b/arch/ppc/boot/prep/head.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/prep/head.S Wed May 16 06:00:17 2001 @@ -0,0 +1,247 @@ +#include "../../kernel/ppc_defs.h" +#include "../../kernel/ppc_asm.tmpl" +#include +#include + + .text + +/* + * $Id: head.S,v 1.33 1999/09/08 01:06:58 cort Exp $ + * + * Boot loader philosophy: + * ROM loads us to some arbitrary location + * Move the boot code to the link address (8M) + * Call decompress_kernel() + * Relocate the initrd, zimage and residual data to 8M + * Decompress the kernel to 0 + * Jump to the kernel entry + * -- Cort + */ + .globl start +start: + bl start_ +start_: + mr r11,r3 /* Save pointer to residual/board data */ + mr r25,r5 /* Save OFW pointer */ + li r3,MSR_IP /* Establish default MSR value */ + mtmsr r3 + +/* check if we need to relocate ourselves to the link addr or were we + loaded there to begin with -- Cort */ + lis r4,start@h + ori r4,r4,start@l + mflr r3 + subi r3,r3,4 /* we get the nip, not the ip of the branch */ + mr r8,r3 + cmp 0,r3,r4 + bne 1010f +/* compute size of whole image in words. this should be moved to + * start_ldr() -- Cort + */ + lis r4,start@h + ori r4,r4,start@l + lis r5,end@h + ori r5,r5,end@l + addi r5,r5,3 /* round up */ + sub r5,r5,r4 + srwi r5,r5,2 + mr r7,r5 + b start_ldr +1010: +/* + * no matter where we're loaded, move ourselves to -Ttext address + */ +relocate: + mflr r3 /* Compute code bias */ + subi r3,r3,4 + mr r8,r3 + lis r4,start@h + ori r4,r4,start@l + lis r5,end@h + ori r5,r5,end@l + addi r5,r5,3 /* Round up - just in case */ + sub r5,r5,r4 /* Compute # longwords to move */ + srwi r5,r5,2 + mtctr r5 + mr r7,r5 + li r6,0 + subi r3,r3,4 /* Set up for loop */ + subi r4,r4,4 +00: lwzu r5,4(r3) + stwu r5,4(r4) + xor r6,r6,r5 + bdnz 00b + lis r3,start_ldr@h + ori r3,r3,start_ldr@l + mtlr r3 /* Easiest way to do an absolute jump */ + blr +start_ldr: +/* Clear all of BSS */ + lis r3,edata@h + ori r3,r3,edata@l + lis r4,end@h + ori r4,r4,end@l + subi r3,r3,4 + subi r4,r4,4 + li r0,0 +50: stwu r0,4(r3) + cmp 0,r3,r4 + bne 50b +90: mr r9,r1 /* Save old stack pointer (in case it matters) */ + lis r1,.stack@h + ori r1,r1,.stack@l + addi r1,r1,4096*2 + subi r1,r1,256 + li r2,0x000F /* Mask pointer to 16-byte boundary */ + andc r1,r1,r2 +/* Run loader */ + mr r3,r8 /* Load point */ + mr r4,r7 /* Program length */ + mr r5,r6 /* Checksum */ + mr r6,r11 /* Residual data */ + mr r7,r25 /* OFW interfaces */ + bl decompress_kernel + + /* changed to use r3 (as firmware does) for kernel + as ptr to residual -- Cort*/ + lis r6,cmd_line@h + ori r6,r6,cmd_line@l + lwz r6, 0(r6) + subi r7,r6,1 +00: lbzu r2,1(r7) + 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) + + + /* tell kernel we're prep */ + /* + * get start address of kernel code which is stored as a coff + * entry. see boot/head.S -- Cort + */ + li r9,0x4 + mtlr r9 + lis r10,0xdeadc0de@h + ori r10,r10,0xdeadc0de@l + li r9,0 + stw r10,0(r9) +/* + * The Radstone firmware maps PCI memory at 0xc0000000 using BAT2 + * so disable BATs before setting this to avoid a clash + */ + li r8,0 + mtspr DBAT0U,r8 + mtspr DBAT1U,r8 + mtspr DBAT2U,r8 + mtspr DBAT3U,r8 + mtspr IBAT0U,r8 + mtspr IBAT1U,r8 + mtspr IBAT2U,r8 + mtspr IBAT3U,r8 + + blr +hang: + b hang + +/* + * 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 + +.globl _get_HID0 +_get_HID0: + mfspr r3,HID0 + blr + +.globl _put_HID0 +_put_HID0: + mtspr HID0,r3 + blr + +.globl _get_MSR +_get_MSR: + mfmsr r3 + blr + +.globl _put_MSR +_put_MSR: + mtmsr r3 + blr + +/* + * Flush instruction cache + * *** I'm really paranoid here! + */ +_GLOBAL(flush_instruction_cache) + mflr r5 + bl flush_data_cache + mfspr r3,HID0 /* Caches are controlled by this register */ + li r4,0 + ori r4,r4,(HID0_ICE|HID0_ICFI) + or r3,r3,r4 /* Need to enable+invalidate to clear */ + mtspr HID0,r3 + andc r3,r3,r4 + ori r3,r3,HID0_ICE /* Enable cache */ + mtspr HID0,r3 + mtlr r5 + blr + +#define NUM_CACHE_LINES 128*8 +#define CACHE_LINE_SIZE 32 +#define cache_flush_buffer 0x1000 + +/* + * Flush data cache + * *** I'm really paranoid here! + */ +_GLOBAL(flush_data_cache) + lis r3,cache_flush_buffer@h + ori r3,r3,cache_flush_buffer@l + li r4,NUM_CACHE_LINES + mtctr r4 +00: lwz r4,0(r3) + addi r3,r3,CACHE_LINE_SIZE /* Next line, please */ + bdnz 00b +10: blr + .comm .stack,4096*2,4 diff -Nru a/arch/ppc/boot/prep/iso_font.h b/arch/ppc/boot/prep/iso_font.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/prep/iso_font.h Wed May 16 06:00:25 2001 @@ -0,0 +1,257 @@ +static const unsigned char font[] = { +/* 0x00 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x01 */ 0x00,0x00,0x7E,0x81,0xA5,0x81,0x81,0xBD,0x99,0x81,0x81,0x7E,0x00,0x00,0x00,0x00, +/* 0x02 */ 0x00,0x00,0x7E,0xFF,0xDB,0xFF,0xFF,0xC3,0xC3,0xE7,0xFF,0x7E,0x00,0x00,0x00,0x00, +/* 0x03 */ 0x00,0x00,0x00,0x00,0x6C,0xFE,0xFE,0xFE,0xFE,0x7C,0x38,0x10,0x00,0x00,0x00,0x00, +/* 0x04 */ 0x00,0x00,0x00,0x00,0x10,0x38,0x7C,0xFE,0x7C,0x38,0x10,0x00,0x00,0x00,0x00,0x00, +/* 0x05 */ 0x00,0x00,0x00,0x18,0x3C,0x3C,0xE7,0xE7,0xE7,0x18,0x18,0x3C,0x00,0x00,0x00,0x00, +/* 0x06 */ 0x00,0x00,0x00,0x18,0x3C,0x7E,0xFF,0xFF,0x7E,0x18,0x18,0x3C,0x00,0x00,0x00,0x00, +/* 0x07 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x3C,0x3C,0x18,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x08 */ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xE7,0xC3,0xC3,0xE7,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, +/* 0x09 */ 0x00,0x00,0x00,0x00,0x00,0x3C,0x66,0x42,0x42,0x66,0x3C,0x00,0x00,0x00,0x00,0x00, +/* 0x0A */ 0xFF,0xFF,0xFF,0xFF,0xFF,0xC3,0x99,0xBD,0xBD,0x99,0xC3,0xFF,0xFF,0xFF,0xFF,0xFF, +/* 0x0B */ 0x00,0x00,0x3E,0x0E,0x1A,0x32,0x78,0xCC,0xCC,0xCC,0xCC,0x78,0x00,0x00,0x00,0x00, +/* 0x0C */ 0x00,0x00,0x3C,0x66,0x66,0x66,0x66,0x3C,0x18,0x7E,0x18,0x18,0x00,0x00,0x00,0x00, +/* 0x0D */ 0x00,0x00,0x30,0x38,0x3C,0x36,0x33,0x30,0x30,0x70,0xF0,0xE0,0x00,0x00,0x00,0x00, +/* 0x0E */ 0x00,0x00,0x7F,0x63,0x7F,0x63,0x63,0x63,0x63,0x67,0xE7,0xE6,0xC0,0x00,0x00,0x00, +/* 0x0F */ 0x00,0x00,0x00,0x18,0x18,0xDB,0x3C,0xE7,0x3C,0xDB,0x18,0x18,0x00,0x00,0x00,0x00, +/* 0x10 */ 0x00,0x80,0xC0,0xE0,0xF0,0xF8,0xFE,0xF8,0xF0,0xE0,0xC0,0x80,0x00,0x00,0x00,0x00, +/* 0x11 */ 0x00,0x02,0x06,0x0E,0x1E,0x3E,0xFE,0x3E,0x1E,0x0E,0x06,0x02,0x00,0x00,0x00,0x00, +/* 0x12 */ 0x00,0x00,0x18,0x3C,0x7E,0x18,0x18,0x18,0x7E,0x3C,0x18,0x00,0x00,0x00,0x00,0x00, +/* 0x13 */ 0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x66,0x66,0x00,0x00,0x00,0x00, +/* 0x14 */ 0x00,0x00,0x7F,0xDB,0xDB,0xDB,0x7B,0x1B,0x1B,0x1B,0x1B,0x1B,0x00,0x00,0x00,0x00, +/* 0x15 */ 0x00,0x7C,0xC6,0x60,0x38,0x6C,0xC6,0xC6,0x6C,0x38,0x0C,0xC6,0x7C,0x00,0x00,0x00, +/* 0x16 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0xFE,0xFE,0xFE,0x00,0x00,0x00,0x00, +/* 0x17 */ 0x00,0x00,0x18,0x3C,0x7E,0x18,0x18,0x18,0x7E,0x3C,0x18,0x7E,0x00,0x00,0x00,0x00, +/* 0x18 */ 0x00,0x00,0x18,0x3C,0x7E,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00, +/* 0x19 */ 0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x7E,0x3C,0x18,0x00,0x00,0x00,0x00, +/* 0x1A */ 0x00,0x00,0x00,0x00,0x00,0x18,0x0C,0xFE,0x0C,0x18,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x1B */ 0x00,0x00,0x00,0x00,0x00,0x30,0x60,0xFE,0x60,0x30,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x1C */ 0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xC0,0xC0,0xFE,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x1D */ 0x00,0x00,0x00,0x00,0x00,0x28,0x6C,0xFE,0x6C,0x28,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x1E */ 0x00,0x00,0x00,0x00,0x10,0x38,0x38,0x7C,0x7C,0xFE,0xFE,0x00,0x00,0x00,0x00,0x00, +/* 0x1F */ 0x00,0x00,0x00,0x00,0xFE,0xFE,0x7C,0x7C,0x38,0x38,0x10,0x00,0x00,0x00,0x00,0x00, +/* 0x20 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x21 */ 0x00,0x00,0x18,0x3C,0x3C,0x3C,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00, +/* 0x22 */ 0x00,0x66,0x66,0x66,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x23 */ 0x00,0x00,0x00,0x6C,0x6C,0xFE,0x6C,0x6C,0x6C,0xFE,0x6C,0x6C,0x00,0x00,0x00,0x00, +/* 0x24 */ 0x18,0x18,0x7C,0xC6,0xC2,0xC0,0x7C,0x06,0x06,0x86,0xC6,0x7C,0x18,0x18,0x00,0x00, +/* 0x25 */ 0x00,0x00,0x00,0x00,0xC2,0xC6,0x0C,0x18,0x30,0x60,0xC6,0x86,0x00,0x00,0x00,0x00, +/* 0x26 */ 0x00,0x00,0x38,0x6C,0x6C,0x38,0x76,0xDC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, +/* 0x27 */ 0x00,0x30,0x30,0x30,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x28 */ 0x00,0x00,0x0C,0x18,0x30,0x30,0x30,0x30,0x30,0x30,0x18,0x0C,0x00,0x00,0x00,0x00, +/* 0x29 */ 0x00,0x00,0x30,0x18,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x18,0x30,0x00,0x00,0x00,0x00, +/* 0x2A */ 0x00,0x00,0x00,0x00,0x00,0x66,0x3C,0xFF,0x3C,0x66,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x2B */ 0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x7E,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x2C */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x18,0x30,0x00,0x00,0x00, +/* 0x2D */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x2E */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00, +/* 0x2F */ 0x00,0x00,0x00,0x00,0x02,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x00,0x00,0x00,0x00, +/* 0x30 */ 0x00,0x00,0x38,0x6C,0xC6,0xC6,0xD6,0xD6,0xC6,0xC6,0x6C,0x38,0x00,0x00,0x00,0x00, +/* 0x31 */ 0x00,0x00,0x18,0x38,0x78,0x18,0x18,0x18,0x18,0x18,0x18,0x7E,0x00,0x00,0x00,0x00, +/* 0x32 */ 0x00,0x00,0x7C,0xC6,0x06,0x0C,0x18,0x30,0x60,0xC0,0xC6,0xFE,0x00,0x00,0x00,0x00, +/* 0x33 */ 0x00,0x00,0x7C,0xC6,0x06,0x06,0x3C,0x06,0x06,0x06,0xC6,0x7C,0x00,0x00,0x00,0x00, +/* 0x34 */ 0x00,0x00,0x0C,0x1C,0x3C,0x6C,0xCC,0xFE,0x0C,0x0C,0x0C,0x1E,0x00,0x00,0x00,0x00, +/* 0x35 */ 0x00,0x00,0xFE,0xC0,0xC0,0xC0,0xFC,0x06,0x06,0x06,0xC6,0x7C,0x00,0x00,0x00,0x00, +/* 0x36 */ 0x00,0x00,0x38,0x60,0xC0,0xC0,0xFC,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, +/* 0x37 */ 0x00,0x00,0xFE,0xC6,0x06,0x06,0x0C,0x18,0x30,0x30,0x30,0x30,0x00,0x00,0x00,0x00, +/* 0x38 */ 0x00,0x00,0x7C,0xC6,0xC6,0xC6,0x7C,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, +/* 0x39 */ 0x00,0x00,0x7C,0xC6,0xC6,0xC6,0x7E,0x06,0x06,0x06,0x0C,0x78,0x00,0x00,0x00,0x00, +/* 0x3A */ 0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00, +/* 0x3B */ 0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x30,0x00,0x00,0x00,0x00, +/* 0x3C */ 0x00,0x00,0x00,0x06,0x0C,0x18,0x30,0x60,0x30,0x18,0x0C,0x06,0x00,0x00,0x00,0x00, +/* 0x3D */ 0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x3E */ 0x00,0x00,0x00,0x60,0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x60,0x00,0x00,0x00,0x00, +/* 0x3F */ 0x00,0x00,0x7C,0xC6,0xC6,0x0C,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00, +/* 0x40 */ 0x00,0x00,0x00,0x7C,0xC6,0xC6,0xDE,0xDE,0xDE,0xDC,0xC0,0x7C,0x00,0x00,0x00,0x00, +/* 0x41 */ 0x00,0x00,0x10,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00, +/* 0x42 */ 0x00,0x00,0xFC,0x66,0x66,0x66,0x7C,0x66,0x66,0x66,0x66,0xFC,0x00,0x00,0x00,0x00, +/* 0x43 */ 0x00,0x00,0x3C,0x66,0xC2,0xC0,0xC0,0xC0,0xC0,0xC2,0x66,0x3C,0x00,0x00,0x00,0x00, +/* 0x44 */ 0x00,0x00,0xF8,0x6C,0x66,0x66,0x66,0x66,0x66,0x66,0x6C,0xF8,0x00,0x00,0x00,0x00, +/* 0x45 */ 0x00,0x00,0xFE,0x66,0x62,0x68,0x78,0x68,0x60,0x62,0x66,0xFE,0x00,0x00,0x00,0x00, +/* 0x46 */ 0x00,0x00,0xFE,0x66,0x62,0x68,0x78,0x68,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00, +/* 0x47 */ 0x00,0x00,0x3C,0x66,0xC2,0xC0,0xC0,0xDE,0xC6,0xC6,0x66,0x3A,0x00,0x00,0x00,0x00, +/* 0x48 */ 0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00, +/* 0x49 */ 0x00,0x00,0x3C,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00, +/* 0x4A */ 0x00,0x00,0x1E,0x0C,0x0C,0x0C,0x0C,0x0C,0xCC,0xCC,0xCC,0x78,0x00,0x00,0x00,0x00, +/* 0x4B */ 0x00,0x00,0xE6,0x66,0x66,0x6C,0x78,0x78,0x6C,0x66,0x66,0xE6,0x00,0x00,0x00,0x00, +/* 0x4C */ 0x00,0x00,0xF0,0x60,0x60,0x60,0x60,0x60,0x60,0x62,0x66,0xFE,0x00,0x00,0x00,0x00, +/* 0x4D */ 0x00,0x00,0xC6,0xEE,0xFE,0xFE,0xD6,0xC6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00, +/* 0x4E */ 0x00,0x00,0xC6,0xE6,0xF6,0xFE,0xDE,0xCE,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00, +/* 0x4F */ 0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, +/* 0x50 */ 0x00,0x00,0xFC,0x66,0x66,0x66,0x7C,0x60,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00, +/* 0x51 */ 0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xD6,0xDE,0x7C,0x0C,0x0E,0x00,0x00, +/* 0x52 */ 0x00,0x00,0xFC,0x66,0x66,0x66,0x7C,0x6C,0x66,0x66,0x66,0xE6,0x00,0x00,0x00,0x00, +/* 0x53 */ 0x00,0x00,0x7C,0xC6,0xC6,0x60,0x38,0x0C,0x06,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, +/* 0x54 */ 0x00,0x00,0x7E,0x7E,0x5A,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00, +/* 0x55 */ 0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, +/* 0x56 */ 0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x6C,0x38,0x10,0x00,0x00,0x00,0x00, +/* 0x57 */ 0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xD6,0xD6,0xD6,0xFE,0xEE,0x6C,0x00,0x00,0x00,0x00, +/* 0x58 */ 0x00,0x00,0xC6,0xC6,0x6C,0x7C,0x38,0x38,0x7C,0x6C,0xC6,0xC6,0x00,0x00,0x00,0x00, +/* 0x59 */ 0x00,0x00,0x66,0x66,0x66,0x66,0x3C,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00, +/* 0x5A */ 0x00,0x00,0xFE,0xC6,0x86,0x0C,0x18,0x30,0x60,0xC2,0xC6,0xFE,0x00,0x00,0x00,0x00, +/* 0x5B */ 0x00,0x00,0x3C,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x3C,0x00,0x00,0x00,0x00, +/* 0x5C */ 0x00,0x00,0x00,0x80,0xC0,0xE0,0x70,0x38,0x1C,0x0E,0x06,0x02,0x00,0x00,0x00,0x00, +/* 0x5D */ 0x00,0x00,0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3C,0x00,0x00,0x00,0x00, +/* 0x5E */ 0x10,0x38,0x6C,0xC6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x5F */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00, +/* 0x60 */ 0x30,0x30,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x61 */ 0x00,0x00,0x00,0x00,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, +/* 0x62 */ 0x00,0x00,0xE0,0x60,0x60,0x78,0x6C,0x66,0x66,0x66,0x66,0x7C,0x00,0x00,0x00,0x00, +/* 0x63 */ 0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xC0,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00, +/* 0x64 */ 0x00,0x00,0x1C,0x0C,0x0C,0x3C,0x6C,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, +/* 0x65 */ 0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xFE,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00, +/* 0x66 */ 0x00,0x00,0x38,0x6C,0x64,0x60,0xF0,0x60,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00, +/* 0x67 */ 0x00,0x00,0x00,0x00,0x00,0x3E,0x66,0x66,0x66,0x66,0x66,0x3E,0x06,0x66,0x3C,0x00, +/* 0x68 */ 0x00,0x00,0xE0,0x60,0x60,0x6C,0x76,0x66,0x66,0x66,0x66,0xE6,0x00,0x00,0x00,0x00, +/* 0x69 */ 0x00,0x00,0x18,0x18,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00, +/* 0x6A */ 0x00,0x00,0x06,0x06,0x00,0x0E,0x06,0x06,0x06,0x06,0x06,0x06,0x66,0x66,0x3C,0x00, +/* 0x6B */ 0x00,0x00,0xE0,0x60,0x60,0x66,0x6C,0x78,0x78,0x6C,0x66,0xE6,0x00,0x00,0x00,0x00, +/* 0x6C */ 0x00,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00, +/* 0x6D */ 0x00,0x00,0x00,0x00,0x00,0x6C,0xFE,0xD6,0xD6,0xD6,0xC6,0xC6,0x00,0x00,0x00,0x00, +/* 0x6E */ 0x00,0x00,0x00,0x00,0x00,0xDC,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x00,0x00,0x00, +/* 0x6F */ 0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, +/* 0x70 */ 0x00,0x00,0x00,0x00,0x00,0xFC,0x66,0x66,0x66,0x66,0x66,0x7C,0x60,0x60,0xF0,0x00, +/* 0x71 */ 0x00,0x00,0x00,0x00,0x00,0x7E,0xCC,0xCC,0xCC,0xCC,0xCC,0x7C,0x0C,0x0C,0x1E,0x00, +/* 0x72 */ 0x00,0x00,0x00,0x00,0x00,0xDC,0x76,0x66,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00, +/* 0x73 */ 0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0x60,0x38,0x0C,0xC6,0x7C,0x00,0x00,0x00,0x00, +/* 0x74 */ 0x00,0x00,0x10,0x30,0x30,0xFC,0x30,0x30,0x30,0x30,0x36,0x1C,0x00,0x00,0x00,0x00, +/* 0x75 */ 0x00,0x00,0x00,0x00,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, +/* 0x76 */ 0x00,0x00,0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x3C,0x18,0x00,0x00,0x00,0x00, +/* 0x77 */ 0x00,0x00,0x00,0x00,0x00,0xC6,0xC6,0xD6,0xD6,0xD6,0xFE,0x6C,0x00,0x00,0x00,0x00, +/* 0x78 */ 0x00,0x00,0x00,0x00,0x00,0xC6,0x6C,0x38,0x38,0x38,0x6C,0xC6,0x00,0x00,0x00,0x00, +/* 0x79 */ 0x00,0x00,0x00,0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7E,0x06,0x0C,0xF8,0x00, +/* 0x7A */ 0x00,0x00,0x00,0x00,0x00,0xFE,0xCC,0x18,0x30,0x60,0xC6,0xFE,0x00,0x00,0x00,0x00, +/* 0x7B */ 0x00,0x00,0x0E,0x18,0x18,0x18,0x70,0x18,0x18,0x18,0x18,0x0E,0x00,0x00,0x00,0x00, +/* 0x7C */ 0x00,0x00,0x18,0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00, +/* 0x7D */ 0x00,0x00,0x70,0x18,0x18,0x18,0x0E,0x18,0x18,0x18,0x18,0x70,0x00,0x00,0x00,0x00, +/* 0x7E */ 0x00,0x00,0x76,0xDC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x7F */ 0x00,0x00,0x00,0x00,0x10,0x38,0x6C,0xC6,0xC6,0xC6,0xFE,0x00,0x00,0x00,0x00,0x00, +/* 0x80 */ 0x00,0x00,0x3C,0x66,0xC2,0xC0,0xC0,0xC0,0xC2,0x66,0x3C,0x0C,0x06,0x7C,0x00,0x00, +/* 0x81 */ 0x00,0x00,0xCC,0x00,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, +/* 0x82 */ 0x00,0x0C,0x18,0x30,0x00,0x7C,0xC6,0xC6,0xFE,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00, +/* 0x83 */ 0x00,0x10,0x38,0x6C,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, +/* 0x84 */ 0x00,0x00,0xCC,0x00,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, +/* 0x85 */ 0x00,0x60,0x30,0x18,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, +/* 0x86 */ 0x00,0x38,0x6C,0x38,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, +/* 0x87 */ 0x00,0x00,0x00,0x00,0x3C,0x66,0x60,0x60,0x66,0x3C,0x0C,0x06,0x3C,0x00,0x00,0x00, +/* 0x88 */ 0x00,0x10,0x38,0x6C,0x00,0x7C,0xC6,0xC6,0xFE,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00, +/* 0x89 */ 0x00,0x00,0xC6,0x00,0x00,0x7C,0xC6,0xC6,0xFE,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00, +/* 0x8A */ 0x00,0x60,0x30,0x18,0x00,0x7C,0xC6,0xC6,0xFE,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00, +/* 0x8B */ 0x00,0x00,0x66,0x00,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00, +/* 0x8C */ 0x00,0x18,0x3C,0x66,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00, +/* 0x8D */ 0x00,0x60,0x30,0x18,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00, +/* 0x8E */ 0x00,0xC6,0x00,0x10,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00, +/* 0x8F */ 0x38,0x6C,0x38,0x00,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00, +/* 0x90 */ 0x18,0x30,0x60,0x00,0xFE,0x66,0x60,0x7C,0x60,0x60,0x66,0xFE,0x00,0x00,0x00,0x00, +/* 0x91 */ 0x00,0x00,0x00,0x00,0x00,0xCC,0x76,0x36,0x7E,0xD8,0xD8,0x6E,0x00,0x00,0x00,0x00, +/* 0x92 */ 0x00,0x00,0x3E,0x6C,0xCC,0xCC,0xFE,0xCC,0xCC,0xCC,0xCC,0xCE,0x00,0x00,0x00,0x00, +/* 0x93 */ 0x00,0x10,0x38,0x6C,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, +/* 0x94 */ 0x00,0x00,0xC6,0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, +/* 0x95 */ 0x00,0x60,0x30,0x18,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, +/* 0x96 */ 0x00,0x30,0x78,0xCC,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, +/* 0x97 */ 0x00,0x60,0x30,0x18,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, +/* 0x98 */ 0x00,0x00,0xC6,0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7E,0x06,0x0C,0x78,0x00, +/* 0x99 */ 0x00,0xC6,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, +/* 0x9A */ 0x00,0xC6,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, +/* 0x9B */ 0x00,0x18,0x18,0x3C,0x66,0x60,0x60,0x60,0x66,0x3C,0x18,0x18,0x00,0x00,0x00,0x00, +/* 0x9C */ 0x00,0x38,0x6C,0x64,0x60,0xF8,0x60,0x60,0x60,0x60,0xE6,0xFC,0x00,0x00,0x00,0x00, +/* 0x9D */ 0x00,0x00,0x66,0x66,0x3C,0x18,0x7E,0x18,0x7E,0x18,0x18,0x18,0x00,0x00,0x00,0x00, +/* 0x9E */ 0x00,0xF8,0xCC,0xCC,0xF8,0xC4,0xCC,0xDE,0xCC,0xCC,0xCC,0xC6,0x00,0x00,0x00,0x00, +/* 0x9F */ 0x00,0x0E,0x1B,0x18,0x18,0x18,0x7E,0x18,0x18,0x18,0x18,0x18,0xD8,0x70,0x00,0x00, +/* 0xA0 */ 0x00,0x18,0x30,0x60,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, +/* 0xA1 */ 0x00,0x0C,0x18,0x30,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00, +/* 0xA2 */ 0x00,0x18,0x30,0x60,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, +/* 0xA3 */ 0x00,0x18,0x30,0x60,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, +/* 0xA4 */ 0x00,0x00,0x76,0xDC,0x00,0xDC,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x00,0x00,0x00, +/* 0xA5 */ 0x76,0xDC,0x00,0xC6,0xE6,0xF6,0xFE,0xDE,0xCE,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00, +/* 0xA6 */ 0x00,0x3C,0x6C,0x6C,0x3E,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0xA7 */ 0x00,0x38,0x6C,0x6C,0x38,0x00,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0xA8 */ 0x00,0x00,0x30,0x30,0x00,0x30,0x30,0x60,0xC0,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, +/* 0xA9 */ 0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0xC0,0xC0,0xC0,0xC0,0x00,0x00,0x00,0x00,0x00, +/* 0xAA */ 0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x06,0x06,0x06,0x06,0x00,0x00,0x00,0x00,0x00, +/* 0xAB */ 0x00,0xC0,0xC0,0xC2,0xC6,0xCC,0x18,0x30,0x60,0xDC,0x86,0x0C,0x18,0x3E,0x00,0x00, +/* 0xAC */ 0x00,0xC0,0xC0,0xC2,0xC6,0xCC,0x18,0x30,0x66,0xCE,0x9E,0x3E,0x06,0x06,0x00,0x00, +/* 0xAD */ 0x00,0x00,0x18,0x18,0x00,0x18,0x18,0x18,0x3C,0x3C,0x3C,0x18,0x00,0x00,0x00,0x00, +/* 0xAE */ 0x00,0x00,0x00,0x00,0x00,0x36,0x6C,0xD8,0x6C,0x36,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0xAF */ 0x00,0x00,0x00,0x00,0x00,0xD8,0x6C,0x36,0x6C,0xD8,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0xB0 */ 0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44, +/* 0xB1 */ 0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA, +/* 0xB2 */ 0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77, +/* 0xB3 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 0xB4 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 0xB5 */ 0x18,0x18,0x18,0x18,0x18,0xF8,0x18,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 0xB6 */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xF6,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, +/* 0xB7 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, +/* 0xB8 */ 0x00,0x00,0x00,0x00,0x00,0xF8,0x18,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 0xB9 */ 0x36,0x36,0x36,0x36,0x36,0xF6,0x06,0xF6,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, +/* 0xBA */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, +/* 0xBB */ 0x00,0x00,0x00,0x00,0x00,0xFE,0x06,0xF6,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, +/* 0xBC */ 0x36,0x36,0x36,0x36,0x36,0xF6,0x06,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0xBD */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0xBE */ 0x18,0x18,0x18,0x18,0x18,0xF8,0x18,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0xBF */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 0xC0 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0xC1 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0xC2 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 0xC3 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 0xC4 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0xC5 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 0xC6 */ 0x18,0x18,0x18,0x18,0x18,0x1F,0x18,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 0xC7 */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x37,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, +/* 0xC8 */ 0x36,0x36,0x36,0x36,0x36,0x37,0x30,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0xC9 */ 0x00,0x00,0x00,0x00,0x00,0x3F,0x30,0x37,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, +/* 0xCA */ 0x36,0x36,0x36,0x36,0x36,0xF7,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0xCB */ 0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0xF7,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, +/* 0xCC */ 0x36,0x36,0x36,0x36,0x36,0x37,0x30,0x37,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, +/* 0xCD */ 0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0xCE */ 0x36,0x36,0x36,0x36,0x36,0xF7,0x00,0xF7,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, +/* 0xCF */ 0x18,0x18,0x18,0x18,0x18,0xFF,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0xD0 */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0xD1 */ 0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 0xD2 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, +/* 0xD3 */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0xD4 */ 0x18,0x18,0x18,0x18,0x18,0x1F,0x18,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0xD5 */ 0x00,0x00,0x00,0x00,0x00,0x1F,0x18,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 0xD6 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, +/* 0xD7 */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xFF,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, +/* 0xD8 */ 0x18,0x18,0x18,0x18,0x18,0xFF,0x18,0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 0xD9 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0xDA */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 0xDB */ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, +/* 0xDC */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, +/* 0xDD */ 0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0, +/* 0xDE */ 0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F, +/* 0xDF */ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0xE0 */ 0x00,0x00,0x00,0x00,0x00,0x76,0xDC,0xD8,0xD8,0xD8,0xDC,0x76,0x00,0x00,0x00,0x00, +/* 0xE1 */ 0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xFC,0xC6,0xC6,0xC6,0xC6,0xDC,0xC0,0xC0,0x00,0x00, +/* 0xE2 */ 0x00,0x00,0xFE,0xC6,0xC6,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0x00,0x00,0x00,0x00, +/* 0xE3 */ 0x00,0x00,0x00,0x00,0x00,0xFE,0x6C,0x6C,0x6C,0x6C,0x6C,0x6C,0x00,0x00,0x00,0x00, +/* 0xE4 */ 0x00,0x00,0xFE,0xC6,0x60,0x30,0x18,0x18,0x30,0x60,0xC6,0xFE,0x00,0x00,0x00,0x00, +/* 0xE5 */ 0x00,0x00,0x00,0x00,0x00,0x7E,0xD8,0xD8,0xD8,0xD8,0xD8,0x70,0x00,0x00,0x00,0x00, +/* 0xE6 */ 0x00,0x00,0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x7C,0x60,0xC0,0x00,0x00,0x00, +/* 0xE7 */ 0x00,0x00,0x00,0x00,0x00,0x76,0xDC,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00, +/* 0xE8 */ 0x00,0x00,0x7E,0x18,0x3C,0x66,0x66,0x66,0x66,0x3C,0x18,0x7E,0x00,0x00,0x00,0x00, +/* 0xE9 */ 0x00,0x00,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0x6C,0x38,0x00,0x00,0x00,0x00, +/* 0xEA */ 0x00,0x00,0x38,0x6C,0xC6,0xC6,0xC6,0x6C,0x6C,0x6C,0x6C,0xEE,0x00,0x00,0x00,0x00, +/* 0xEB */ 0x00,0x00,0x1E,0x30,0x18,0x0C,0x3E,0x66,0x66,0x66,0x66,0x3C,0x00,0x00,0x00,0x00, +/* 0xEC */ 0x00,0x00,0x00,0x00,0x00,0x7E,0xDB,0xDB,0xDB,0x7E,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0xED */ 0x00,0x00,0x00,0x03,0x06,0x7E,0xDB,0xDB,0xF3,0x7E,0x60,0xC0,0x00,0x00,0x00,0x00, +/* 0xEE */ 0x00,0x00,0x1C,0x30,0x60,0x60,0x7C,0x60,0x60,0x60,0x30,0x1C,0x00,0x00,0x00,0x00, +/* 0xEF */ 0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00, +/* 0xF0 */ 0x00,0x00,0x00,0x00,0xFE,0x00,0x00,0xFE,0x00,0x00,0xFE,0x00,0x00,0x00,0x00,0x00, +/* 0xF1 */ 0x00,0x00,0x00,0x00,0x18,0x18,0x7E,0x18,0x18,0x00,0x00,0xFF,0x00,0x00,0x00,0x00, +/* 0xF2 */ 0x00,0x00,0x00,0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x00,0x7E,0x00,0x00,0x00,0x00, +/* 0xF3 */ 0x00,0x00,0x00,0x0C,0x18,0x30,0x60,0x30,0x18,0x0C,0x00,0x7E,0x00,0x00,0x00,0x00, +/* 0xF4 */ 0x00,0x0E,0x1B,0x1B,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 0xF5 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xD8,0xD8,0xD8,0x70,0x00,0x00,0x00,0x00, +/* 0xF6 */ 0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x7E,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00, +/* 0xF7 */ 0x00,0x00,0x00,0x00,0x00,0x76,0xDC,0x00,0x76,0xDC,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0xF8 */ 0x00,0x38,0x6C,0x6C,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0xF9 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0xFA */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0xFB */ 0x00,0x0F,0x0C,0x0C,0x0C,0x0C,0x0C,0xEC,0x6C,0x6C,0x3C,0x1C,0x00,0x00,0x00,0x00, +/* 0xFC */ 0x00,0xD8,0x6C,0x6C,0x6C,0x6C,0x6C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0xFD */ 0x00,0x70,0xD8,0x30,0x60,0xC8,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0xFE */ 0x00,0x00,0x00,0x00,0x7C,0x7C,0x7C,0x7C,0x7C,0x7C,0x7C,0x00,0x00,0x00,0x00,0x00, +}; diff -Nru a/arch/ppc/boot/prep/kbd.c b/arch/ppc/boot/prep/kbd.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/prep/kbd.c Wed May 16 06:00:22 2001 @@ -0,0 +1,215 @@ +#include + +#include <../drivers/char/defkeymap.c> /* yeah I know it's bad -- Cort */ + + +unsigned char shfts, ctls, alts, caps; + +#define KBDATAP 0x60 /* kbd data port */ +#define KBSTATUSPORT 0x61 /* kbd status */ +#define KBSTATP 0x64 /* kbd status port */ +#define KBINRDY 0x01 +#define KBOUTRDY 0x02 + +extern unsigned char inb(int port); +extern void outb(int port, char val); +extern void puts(const char *); +extern void puthex(unsigned long val); +extern void udelay(long x); + +static int kbd(int noblock) +{ + unsigned char dt, brk, val; + unsigned code; +loop: + if (noblock) { + if ((inb(KBSTATP) & KBINRDY) == 0) + return (-1); + } else while((inb(KBSTATP) & KBINRDY) == 0) ; + + dt = inb(KBDATAP); + + brk = dt & 0x80; /* brk == 1 on key release */ + dt = dt & 0x7f; /* keycode */ + + if (shfts) + code = shift_map[dt]; + else if (ctls) + code = ctrl_map[dt]; + else + code = plain_map[dt]; + + val = KVAL(code); + switch (KTYP(code) & 0x0f) { + case KT_LATIN: + if (brk) + break; + if (alts) + val |= 0x80; + if (val == 0x7f) /* map delete to backspace */ + val = '\b'; + return val; + + case KT_LETTER: + if (brk) + break; + if (caps) + val -= 'a'-'A'; + return val; + + case KT_SPEC: + if (brk) + break; + if (val == KVAL(K_CAPS)) + caps = !caps; + else if (val == KVAL(K_ENTER)) { +enter: /* Wait for key up */ + while (1) { + while((inb(KBSTATP) & KBINRDY) == 0) ; + dt = inb(KBDATAP); + if (dt & 0x80) /* key up */ break; + } + return 10; + } + break; + + case KT_PAD: + if (brk) + break; + if (val < 10) + return val; + if (val == KVAL(K_PENTER)) + goto enter; + break; + + case KT_SHIFT: + switch (val) { + case KG_SHIFT: + case KG_SHIFTL: + case KG_SHIFTR: + shfts = brk ? 0 : 1; + break; + case KG_ALT: + case KG_ALTGR: + alts = brk ? 0 : 1; + break; + case KG_CTRL: + case KG_CTRLL: + case KG_CTRLR: + ctls = brk ? 0 : 1; + break; + } + break; + + case KT_LOCK: + switch (val) { + case KG_SHIFT: + case KG_SHIFTL: + case KG_SHIFTR: + if (brk) + shfts = !shfts; + break; + case KG_ALT: + case KG_ALTGR: + if (brk) + alts = !alts; + break; + case KG_CTRL: + case KG_CTRLL: + case KG_CTRLR: + if (brk) + ctls = !ctls; + break; + } + break; + } + if (brk) return (-1); /* Ignore initial 'key up' codes */ + goto loop; +} + +static void kbdreset(void) +{ + unsigned char c; + int i; + + /* flush input queue */ + while ((inb(KBSTATP) & KBINRDY)) + { + (void)inb(KBDATAP); + } + /* Send self-test */ + while (inb(KBSTATP) & KBOUTRDY) ; + outb(KBSTATP,0xAA); + while ((inb(KBSTATP) & KBINRDY) == 0) ; /* wait input ready */ + if ((c = inb(KBDATAP)) != 0x55) + { + puts("Keyboard self test failed - result:"); + puthex(c); + puts("\n"); + } + /* Enable interrupts and keyboard controller */ + while (inb(KBSTATP) & KBOUTRDY) ; + outb(KBSTATP,0x60); + while (inb(KBSTATP) & KBOUTRDY) ; + outb(KBDATAP,0x45); + for (i = 0; i < 10000; i++) udelay(1); + + while (inb(KBSTATP) & KBOUTRDY) ; + outb(KBSTATP,0x20); + while ((inb(KBSTATP) & KBINRDY) == 0) ; /* wait input ready */ + if (! (inb(KBDATAP) & 0x40)) { + /* + * Quote from PS/2 System Reference Manual: + * + * "Address hex 0060 and address hex 0064 should be + * written only when the input-buffer-full bit and + * output-buffer-full bit in the Controller Status + * register are set 0." (KBINRDY and KBOUTRDY) + */ + + while (inb(KBSTATP) & (KBINRDY | KBOUTRDY)) ; + outb(KBDATAP,0xF0); + while (inb(KBSTATP) & (KBINRDY | KBOUTRDY)) ; + outb(KBDATAP,0x01); + } + + while (inb(KBSTATP) & KBOUTRDY) ; + outb(KBSTATP,0xAE); +} + +/* We have to actually read the keyboard when CRT_tstc is called, + * since the pending data might be a key release code, and therefore + * not valid data. In this case, kbd() will return -1, even though there's + * data to be read. Of course, we might actually read a valid key press, + * in which case it gets queued into key_pending for use by CRT_getc. + */ + +static int kbd_reset = 0; + +static int key_pending = -1; + +int CRT_getc(void) +{ + int c; + if (!kbd_reset) {kbdreset(); kbd_reset++; } + + if (key_pending != -1) { + c = key_pending; + key_pending = -1; + return c; + } else { + while ((c = kbd(0)) == 0) ; + return c; + } +} + +int CRT_tstc(void) +{ + if (!kbd_reset) {kbdreset(); kbd_reset++; } + + while (key_pending == -1 && ((inb(KBSTATP) & KBINRDY) != 0)) { + key_pending = kbd(1); + } + + return (key_pending != -1); +} diff -Nru a/arch/ppc/boot/prep/misc.c b/arch/ppc/boot/prep/misc.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/prep/misc.c Wed May 16 06:00:17 2001 @@ -0,0 +1,452 @@ +/* + * misc.c + * + * $Id: misc.c,v 1.68 1999/10/20 22:08:08 cort Exp $ + * + * Adapted for PowerPC by Gary Thomas + * + * Rewritten by Cort Dougan (cort@cs.nmt.edu) + * One day to be replaced by a single bootloader for chrp/prep/pmac. -- Cort + */ + +#include +#include "zlib.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(CONFIG_SERIAL_CONSOLE) +unsigned long com_port; +#endif /* CONFIG_SERIAL_CONSOLE */ + +/* + * Please send me load/board info and such data for hardware not + * listed here so I can keep track since things are getting tricky + * with the different load addrs with different firmware. This will + * help to avoid breaking the load/boot process. + * -- Cort + */ +char *avail_ram; +char *end_avail; +extern char _end[]; + +#ifdef CONFIG_CMDLINE +#define CMDLINE CONFIG_CMDLINE +#else +#define CMDLINE ""; +#endif +char cmd_preset[] = CMDLINE; +char cmd_buf[256]; +char *cmd_line = cmd_buf; + +int keyb_present = 1; /* keyboard controller is present by default */ +RESIDUAL hold_resid_buf; +RESIDUAL *hold_residual = &hold_resid_buf; +unsigned long initrd_start = 0, initrd_end = 0; +char *zimage_start; +int zimage_size; + +char *vidmem = (char *)0xC00B8000; +int lines, cols; +int orig_x, orig_y; + +extern void puts(const char *); +extern void putc(const char c); +extern int tstc(void); +extern int getc(void); +extern void puthex(unsigned long val); +extern void * memcpy(void * __dest, __const void * __src, __kernel_size_t __n); +extern int CRT_tstc(void); +extern void of_init(void *handler); +extern int of_finddevice(const char *device_specifier, int *phandle); +extern int of_getprop(int phandle, const char *name, void *buf, int buflen, + int *size); +extern __kernel_size_t strlen(const char *s); +extern int vga_init(unsigned char *ISA_mem); +extern void udelay(long x); +void gunzip(void *, int, unsigned char *, int *); +unsigned char inb(int); + +void +writel(unsigned int val, unsigned int address) +{ + /* Ensure I/O operations complete */ + __asm__ volatile("eieio"); + *(unsigned int *)address = cpu_to_le32(val); +} + +unsigned int +readl(unsigned int address) +{ + /* Ensure I/O operations complete */ + __asm__ volatile("eieio"); + return le32_to_cpu(*(unsigned int *)address); +} + +#define PCI_CFG_ADDR(dev,off) ((0x80<<24) | (dev<<8) | (off&0xfc)) +#define PCI_CFG_DATA(off) (0x80000cfc+(off&3)) + +static void +pci_read_config_32(unsigned char devfn, + unsigned char offset, + unsigned int *val) +{ + writel(PCI_CFG_ADDR(devfn,offset), 0x80000cf8); + *val = readl(PCI_CFG_DATA(offset)); + return; +} + +void +scroll() +{ + int i; + + memcpy ( vidmem, vidmem + cols * 2, ( lines - 1 ) * cols * 2 ); + for ( i = ( lines - 1 ) * cols * 2; i < lines * cols * 2; i += 2 ) + vidmem[i] = ' '; +} + +/* + * This routine is used to control the second processor on the + * Motorola dual processor platforms. + */ +void +park_cpus() +{ + volatile void (*go)(RESIDUAL *, int, int, char *, int); + unsigned int i; + volatile unsigned long *smp_iar = &(hold_residual->VitalProductData.SmpIar); + + /* Wait for indication to continue. If the kernel + was not compiled with SMP support then the second + processor will spin forever here makeing the kernel + multiprocessor safe. */ + while (*smp_iar == 0) { + for (i=0; i < 512; i++); + } + + (unsigned long)go = hold_residual->VitalProductData.SmpIar; + go(hold_residual, 0, 0, cmd_line, sizeof(cmd_preset)); +} + +unsigned long +decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, + RESIDUAL *residual, void *OFW_interface) +{ + int timer; + extern unsigned long start; + char *cp, ch; + unsigned long TotalMemory; + unsigned long orig_MSR; + int dev_handle; + int mem_info[2]; + int res, size; + unsigned char board_type; + unsigned char base_mod; + int start_multi = 0; + unsigned int pci_viddid, pci_did, tulip_pci_base, tulip_base; + + lines = 25; + cols = 80; + orig_x = 0; + orig_y = 24; + + /* + * IBM's have the MMU on, so we have to disable it or + * things get really unhappy in the kernel when + * trying to setup the BATs with the MMU on + * -- Cort + */ + flush_instruction_cache(); + _put_HID0(_get_HID0() & ~0x0000C000); + _put_MSR((orig_MSR = _get_MSR()) & ~0x0030); + +#if defined(CONFIG_SERIAL_CONSOLE) + com_port = serial_init(0); +#endif /* CONFIG_SERIAL_CONSOLE */ + vga_init((char)0xC0000000); + + if (residual) + { + /* Is this Motorola PPCBug? */ + if ((1 & residual->VitalProductData.FirmwareSupports) && + (1 == residual->VitalProductData.FirmwareSupplier)) { + board_type = inb(0x800) & 0xF0; + + /* + * Reset the onboard 21x4x Ethernet + * Motorola Ethernet is at IDSEL 14 (devfn 0x70) + */ + pci_read_config_32(0x70, 0x00, &pci_viddid); + pci_did = (pci_viddid & 0xffff0000) >> 16; + /* Be sure we've really found a 21x4x chip */ + if (((pci_viddid & 0xffff) == PCI_VENDOR_ID_DEC) && + ((pci_did == PCI_DEVICE_ID_DEC_TULIP_FAST) || + (pci_did == PCI_DEVICE_ID_DEC_TULIP) || + (pci_did == PCI_DEVICE_ID_DEC_TULIP_PLUS) || + (pci_did == PCI_DEVICE_ID_DEC_21142))) + { + pci_read_config_32(0x70, + 0x10, + &tulip_pci_base); + /* Get the physical base address */ + tulip_base = + (tulip_pci_base & ~0x03UL) + 0x80000000; + /* Strobe the 21x4x reset bit in CSR0 */ + writel(0x1, tulip_base); + } + + /* If this is genesis 2 board then check for no + * keyboard controller and more than one processor. + */ + if (board_type == 0xe0) { + base_mod = inb(0x803); + /* if a MVME2300/2400 or a Sitka then no keyboard */ + if((base_mod == 0xFA) || (base_mod == 0xF9) || + (base_mod == 0xE1)) { + keyb_present = 0; /* no keyboard */ + } + } + /* If this is a multiprocessor system then + * park the other processor so that the + * kernel knows where to find them. + */ + if (residual->MaxNumCpus > 1) { + start_multi = 1; + } + } + memcpy(hold_residual,residual,sizeof(RESIDUAL)); + } else { + /* Assume 32M in the absence of more info... */ + TotalMemory = 0x02000000; + /* + * This is a 'best guess' check. We want to make sure + * we don't try this on a PReP box without OF + * -- Cort + */ + while (OFW_interface && ((unsigned long)OFW_interface < 0x10000000) ) + { + /* The MMU needs to be on when we call OFW */ + _put_MSR(orig_MSR); + of_init(OFW_interface); + + /* get handle to memory description */ + res = of_finddevice("/memory@0", + &dev_handle); + // puthex(res); puts("\n"); + if (res) break; + + /* get the info */ + // puts("get info = "); + res = of_getprop(dev_handle, + "reg", + mem_info, + sizeof(mem_info), + &size); + // puthex(res); puts(", info = "); puthex(mem_info[0]); + // puts(" "); puthex(mem_info[1]); puts("\n"); + if (res) break; + + TotalMemory = mem_info[1]; + break; + } + hold_residual->TotalMemory = TotalMemory; + residual = hold_residual; + /* Turn MMU back off */ + _put_MSR(orig_MSR & ~0x0030); + } + + if (start_multi) { + hold_residual->VitalProductData.SmpIar = 0; + hold_residual->Cpus[1].CpuState = CPU_GOOD_FW; + residual->VitalProductData.SmpIar = (unsigned long)park_cpus; + residual->Cpus[1].CpuState = CPU_GOOD; + hold_residual->VitalProductData.Reserved5 = 0xdeadbeef; + } + + /* assume the chunk below 8M is free */ + end_avail = (char *)0x00800000; + + /* tell the user where we were loaded at and where we + * were relocated to for debugging this process + */ + puts("loaded at: "); puthex(load_addr); + puts(" "); puthex((unsigned long)(load_addr + (4*num_words))); puts("\n"); + if ( (unsigned long)load_addr != (unsigned long)&start ) + { + puts("relocated to: "); puthex((unsigned long)&start); + puts(" "); + puthex((unsigned long)((unsigned long)&start + (4*num_words))); + puts("\n"); + } + + if ( residual ) + { + puts("board data at: "); puthex((unsigned long)residual); + puts(" "); + puthex((unsigned long)((unsigned long)residual + sizeof(RESIDUAL))); + puts("\n"); + puts("relocated to: "); + puthex((unsigned long)hold_residual); + puts(" "); + puthex((unsigned long)((unsigned long)hold_residual + sizeof(RESIDUAL))); + puts("\n"); + } + + /* we have to subtract 0x10000 here to correct for objdump including the + size of the elf header which we strip -- Cort */ + zimage_start = (char *)(load_addr - 0x10000 + ZIMAGE_OFFSET); + zimage_size = ZIMAGE_SIZE; + + if ( INITRD_OFFSET ) + initrd_start = load_addr - 0x10000 + INITRD_OFFSET; + else + initrd_start = 0; + initrd_end = INITRD_SIZE + initrd_start; + + /* + * Find a place to stick the zimage and initrd and + * relocate them if we have to. -- Cort + */ + avail_ram = (char *)PAGE_ALIGN((unsigned long)_end); + puts("zimage at: "); puthex((unsigned long)zimage_start); + puts(" "); puthex((unsigned long)(zimage_size+zimage_start)); puts("\n"); + if ( (unsigned long)zimage_start <= 0x00800000 ) + { + memcpy( (void *)avail_ram, (void *)zimage_start, zimage_size ); + zimage_start = (char *)avail_ram; + puts("relocated to: "); puthex((unsigned long)zimage_start); + puts(" "); + puthex((unsigned long)zimage_size+(unsigned long)zimage_start); + puts("\n"); + + /* relocate initrd */ + if ( initrd_start ) + { + puts("initrd at: "); puthex(initrd_start); + puts(" "); puthex(initrd_end); puts("\n"); + avail_ram = (char *)PAGE_ALIGN( + (unsigned long)zimage_size+(unsigned long)zimage_start); + memcpy ((void *)avail_ram, (void *)initrd_start, INITRD_SIZE ); + initrd_start = (unsigned long)avail_ram; + initrd_end = initrd_start + INITRD_SIZE; + puts("relocated to: "); puthex(initrd_start); + puts(" "); puthex(initrd_end); puts("\n"); + } + } else if ( initrd_start ) { + puts("initrd at: "); puthex(initrd_start); + puts(" "); puthex(initrd_end); puts("\n"); + } + + avail_ram = (char *)0x00400000; + end_avail = (char *)0x00800000; + puts("avail ram: "); puthex((unsigned long)avail_ram); puts(" "); + puthex((unsigned long)end_avail); puts("\n"); + + if (keyb_present) + CRT_tstc(); /* Forces keyboard to be initialized */ + + puts("\nLinux/PPC load: "); + timer = 0; + cp = cmd_line; + memcpy (cmd_line, cmd_preset, sizeof(cmd_preset)); + while ( *cp ) putc(*cp++); + while (timer++ < 5*1000) { + if (tstc()) { + while ((ch = getc()) != '\n' && ch != '\r') { + if (ch == '\b') { + if (cp != cmd_line) { + cp--; + puts("\b \b"); + } + } else { + *cp++ = ch; + putc(ch); + } + } + break; /* Exit 'timer' loop */ + } + udelay(1000); /* 1 msec */ + } + *cp = 0; + puts("\n"); + + /* mappings on early boot can only handle 16M */ + if ( (int)(cmd_line[0]) > (16<<20)) + puts("cmd_line located > 16M\n"); + if ( (int)hold_residual > (16<<20)) + puts("hold_residual located > 16M\n"); + if ( initrd_start > (16<<20)) + puts("initrd_start located > 16M\n"); + + puts("Uncompressing Linux..."); + + gunzip(0, 0x400000, zimage_start, &zimage_size); + puts("done.\n"); + + { + struct bi_record *rec; + + rec = (struct bi_record *)PAGE_ALIGN(zimage_size); + + rec->tag = BI_FIRST; + rec->size = sizeof(struct bi_record); + rec = (struct bi_record *)((unsigned long)rec + rec->size); + + rec->tag = BI_BOOTLOADER_ID; + memcpy( (void *)rec->data, "prepboot", 9); + rec->size = sizeof(struct bi_record) + 8 + 1; + rec = (struct bi_record *)((unsigned long)rec + rec->size); + + rec->tag = BI_MACHTYPE; + rec->data[0] = _MACH_prep; + rec->data[1] = 1; + rec->size = sizeof(struct bi_record) + sizeof(unsigned long); + rec = (struct bi_record *)((unsigned long)rec + rec->size); + + rec->tag = BI_CMD_LINE; + memcpy( (char *)rec->data, cmd_line, strlen(cmd_line)+1); + rec->size = sizeof(struct bi_record) + strlen(cmd_line) + 1; + rec = (struct bi_record *)((ulong)rec + rec->size); + + rec->tag = BI_LAST; + rec->size = sizeof(struct bi_record); + rec = (struct bi_record *)((unsigned long)rec + rec->size); + } + puts("Now booting the kernel\n"); + return (unsigned long)hold_residual; +} + +/* + * PCI/ISA I/O support + */ + +volatile unsigned char *ISA_io = (unsigned char *)0x80000000; +volatile unsigned char *ISA_mem = (unsigned char *)0xC0000000; + +void +outb(int port, char val) +{ + /* Ensure I/O operations complete */ + __asm__ volatile("eieio"); + ISA_io[port] = val; +} + +unsigned char +inb(int port) +{ + /* Ensure I/O operations complete */ + __asm__ volatile("eieio"); + return (ISA_io[port]); +} + +unsigned long +local_to_PCI(unsigned long addr) +{ + return ((addr & 0x7FFFFFFF) | 0x80000000); +} diff -Nru a/arch/ppc/boot/prep/of1275.c b/arch/ppc/boot/prep/of1275.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/prep/of1275.c Wed May 16 06:00:21 2001 @@ -0,0 +1,427 @@ +/* Open Firmware Client Interface */ + + +#include "of1275.h" + + +static int (*of_server)(void *) = (int(*)(void*))-1; + +void +of_init(void *handler) +{ + of_server = (int(*)(void*))handler; +} + + +/* 6.3.2.1 Client interface */ + + +int +of_test(const char *name, int *missing) +{ + int result; + static of_test_service s; + s.service = "test"; + s.n_args = 1; + s.n_returns = 1; + s.name = name; + result = of_server(&s); + *missing = s.missing; + return result; +} + + +/* 6.3.2.2 Device tree */ + + +int +of_peer(int phandle, int *sibling_phandle) +{ + int result; + static of_peer_service s; + s.service = "peer"; + s.n_args = 1; + s.n_returns = 1; + s.phandle = phandle; + result = of_server(&s); + *sibling_phandle = s.sibling_phandle; + return result; +} + +int +of_child(int phandle, int *child_phandle) +{ + int result; + static of_child_service s; + s.service = "child"; + s.n_args = 1; + s.n_returns = 1; + s.phandle = phandle; + result = of_server(&s); + *child_phandle = s.child_phandle; + return result; +} + +int +of_parent(int phandle, int *parent_phandle) +{ + int result; + static of_parent_service s; + s.service = "parent"; + s.n_args = 1; + s.n_returns = 1; + s.phandle = phandle; + result = of_server(&s); + *parent_phandle = s.parent_phandle; + return result; +} + +int +of_instance_to_package(int ihandle, int *phandle) +{ + int result; + static of_instance_to_package_service s; + s.service = "instance-to-package"; + s.n_args = 1; + s.n_returns = 1; + s.ihandle = ihandle; + result = of_server(&s); + *phandle = s.phandle; + return result; +} + +int +of_getproplen(int phandle, const char *name, int *proplen) +{ + int result; + static of_getproplen_service s; + s.service = "getproplen"; + s.n_args = 2; + s.n_returns = 1; + s.phandle = phandle; + s.name = name; + result = of_server(&s); + *proplen = s.proplen; + return result; +} + +int +of_getprop(int phandle, const char *name, void *buf, int buflen, int *size) +{ + int result; + static of_getprop_service s; + s.service = "getprop"; + s.n_args = 4; + s.n_returns = 1; + s.phandle = phandle; + s.name = name; + s.buf = buf; + s.buflen = buflen; + result = of_server(&s); + *size = s.size; + return result; +} + +int +of_nextprop(int phandle, const char *previous, void *buf, int *flag) +{ + int result; + static of_nextprop_service s; + s.service = "nextprop"; + s.n_args = 3; + s.n_returns = 1; + s.phandle = phandle; + s.previous = previous; + s.buf = buf; + result = of_server(&s); + *flag = s.flag; + return result; +} + +int +of_setprop(int phandle, const char *name, void *buf, int len, int *size) +{ + int result; + static of_setprop_service s; + s.service = "setprop"; + s.n_args = 4; + s.n_returns = 1; + s.phandle = phandle; + s.name = name; + s.buf = buf; + s.len = len; + result = of_server(&s); + *size = s.size; + return result; +} + +int +of_canon(const char *device_specifier, void *buf, int buflen, int *length) +{ + int result; + static of_canon_service s; + s.service = "canon"; + s.n_args = 3; + s.n_returns = 1; + s.device_specifier = device_specifier; + s.buf = buf; + s.buflen = buflen; + result = of_server(&s); + *length = s.length; + return result; +} + +int +of_finddevice(const char *device_specifier, int *phandle) +{ + int result; + static of_finddevice_service s; + s.service = "finddevice"; + s.n_args = 1; + s.n_returns = 1; + s.device_specifier = device_specifier; + result = of_server(&s); + *phandle = s.phandle; + return result; +} + +int +of_instance_to_path(int ihandle, void *buf, int buflen, int *length) +{ + int result; + static of_instance_to_path_service s; + s.service = "instance-to-path"; + s.n_args = 3; + s.n_returns = 1; + s.ihandle = ihandle; + s.buf = buf; + s.buflen = buflen; + result = of_server(&s); + *length = s.length; + return result; +} + +int +of_package_to_path(int phandle, void *buf, int buflen, int *length) +{ + int result; + static of_package_to_path_service s; + s.service = "package-to-path"; + s.n_args = 3; + s.n_returns = 1; + s.phandle = phandle; + s.buf = buf; + s.buflen = buflen; + result = of_server(&s); + *length = s.length; + return result; +} + +/* int of_call_method(const char *method, int ihandle, ...); */ + + +/* 6.3.2.3 Device I/O */ + + +int +of_open(const char *device_specifier, int *ihandle) +{ + int result; + static of_open_service s; + s.service = "open"; + s.n_args = 1; + s.n_returns = 1; + s.device_specifier = device_specifier; + result = of_server(&s); + *ihandle = s.ihandle; + return result; +} + +int +of_close(int ihandle) +{ + int result; + static of_close_service s; + s.service = "close"; + s.n_args = 1; + s.n_returns = 0; + s.ihandle = ihandle; + result = of_server(&s); + return result; +} + +int +of_read(int ihandle, void *addr, int len, int *actual) +{ + int result; + static of_read_service s; + s.service = "read"; + s.n_args = 3; + s.n_returns = 1; + s.ihandle = ihandle; + s.addr = addr; + s.len = len; + result = of_server(&s); + *actual = s.actual; + return result; +} + +int +of_write(int ihandle, void *addr, int len, int *actual) +{ + int result; + static of_write_service s; + s.service = "write"; + s.n_args = 3; + s.n_returns = 1; + s.ihandle = ihandle; + s.addr = addr; + s.len = len; + result = of_server(&s); + *actual = s.actual; + return result; +} + +int +of_seek(int ihandle, int pos_hi, int pos_lo, int *status) +{ + int result; + static of_seek_service s; + s.service = "seek"; + s.n_args = 3; + s.n_returns = 1; + s.ihandle = ihandle; + s.pos_hi = pos_hi; + s.pos_lo = pos_lo; + result = of_server(&s); + *status = s.status; + return result; +} + + +/* 6.3.2.4 Memory */ + + +int +of_claim(void *virt, int size, int align, void **baseaddr) +{ + int result; + static of_claim_service s; + s.service = "claim"; + s.n_args = 3; + s.n_returns = 1; + s.virt = virt; + s.size = size; + s.align = align; + result = of_server(&s); + *baseaddr = s.baseaddr; + return result; +} + +int +of_release(void *virt, int size) +{ + int result; + static of_release_service s; + s.service = "release"; + s.n_args = 2; + s.n_returns = 0; + s.virt = virt; + s.size = size; + result = of_server(&s); + return result; +} + + +/* 6.3.2.5 Control transfer */ + + +int +of_boot(const char *bootspec) +{ + int result; + static of_boot_service s; + s.service = "boot"; + s.n_args = 1; + s.n_returns = 0; + s.bootspec = bootspec; + result = of_server(&s); + return result; +} + +int +of_enter(void) +{ + int result; + static of_enter_service s; + s.service = "enter"; + s.n_args = 0; + s.n_returns = 0; + result = of_server(&s); + return result; +} + +int +of_exit(void) +{ + int result; + static of_exit_service s; + s.service = "exit"; + s.n_args = 0; + s.n_returns = 0; + result = of_server(&s); + return result; +} + +/* int of_chain(void *virt, int size, void *entry, void *args, int len); */ + + +/* 6.3.2.6 User interface */ + + +/* int of_interpret(const char *arg, ...); */ + +int +of_set_callback(void *newfunc, void **oldfunc) +{ + int result; + static of_set_callback_service s; + s.service = "set-callback"; + s.n_args = 1; + s.n_returns = 1; + s.newfunc = newfunc; + result = of_server(&s); + *oldfunc = s.oldfunc; + return result; +} + +int +of_set_symbol_lookup(void *sym_to_value, void *value_to_sym) +{ + int result; + static of_set_symbol_lookup_service s; + s.service = "set-symbol-lookup"; + s.n_args = 2; + s.n_returns = 0; + s.sym_to_value = sym_to_value; + s.value_to_sym = s.value_to_sym; + result = of_server(&s); + return result; +} + + +/* 6.3.2.7 Time */ + + +int +of_milliseconds(int *ms) +{ + int result; + static of_milliseconds_service s; + s.service = "milliseconds"; + s.n_args = 0; + s.n_returns = 1; + result = of_server(&s); + *ms = s.ms; + return result; +} diff -Nru a/arch/ppc/boot/prep/of1275.h b/arch/ppc/boot/prep/of1275.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/prep/of1275.h Wed May 16 06:00:20 2001 @@ -0,0 +1,421 @@ +/* 6.3.2.1 Client interface */ + + +typedef struct _of_test_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + const char *name; + /*out*/ + int missing; +} of_test_service; + +int of_test(const char *name, int *missing); + + +/* 6.3.2.2 Device tree */ + + +typedef struct _of_peer_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + int phandle; + /*out*/ + int sibling_phandle; +} of_peer_service; + +int of_peer(int phandle, int *sibling_phandle); + + +typedef struct _of_child_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + int phandle; + /*out*/ + int child_phandle; +} of_child_service; + +int of_child(int phandle, int *child_phandle); + + +typedef struct _of_parent_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + int phandle; + /*out*/ + int parent_phandle; +} of_parent_service; + +int of_child(int phandle, int *parent_phandle); + + +typedef struct _of_instance_to_package_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + int ihandle; + /*out*/ + int phandle; +} of_instance_to_package_service; + +int of_instance_to_package(int ihandle, int *phandle); + + +typedef struct _of_getproplen_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + int phandle; + const char *name; + /*out*/ + int proplen; +} of_getproplen_service; + +int of_getproplen(int phandle, const char *name, int *proplen); + + +typedef struct _of_getprop_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + int phandle; + const char *name; + void *buf; + int buflen; + /*out*/ + int size; +} of_getprop_service; + +int of_getprop(int phandle, const char *name, void *buf, int buflen, + int *size); + + +typedef struct _of_nextprop_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + int phandle; + const char *previous; + void *buf; + /*out*/ + int flag; +} of_nextprop_service; + +int of_nextprop(int phandle, const char *previous, void *buf, int *flag); + + +typedef struct _of_setprop_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + int phandle; + const char *name; + void *buf; + int len; + /*out*/ + int size; +} of_setprop_service; + +int of_setprop(int phandle, const char *name, void *buf, int len, int *size); + + +typedef struct _of_canon_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + const char *device_specifier; + void *buf; + int buflen; + /*out*/ + int length; +} of_canon_service; + +int of_canon(const char *device_specifier, void *buf, int buflen, int *length); + + +typedef struct _of_finddevice_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + const char *device_specifier; + /*out*/ + int phandle; +} of_finddevice_service; + +int of_finddevice(const char *device_specifier, int *phandle); + + +typedef struct _of_instance_to_path_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + int ihandle; + void *buf; + int buflen; + /*out*/ + int length; +} of_instance_to_path_service; + +int of_instance_to_path(int ihandle, void *buf, int buflen, int *length); + + +typedef struct _of_package_to_path_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + int phandle; + void *buf; + int buflen; + /*out*/ + int length; +} of_package_to_path_service; + +int of_package_to_path(int phandle, void *buf, int buflen, int *length); + + +typedef struct _of_call_method_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + const char *method; + int ihandle; + /*...*/ + int args[0]; +} of_call_method_service; + +int of_call_method(const char *method, int ihandle, ...); + + +/* 6.3.2.3 Device I/O */ + + +typedef struct _of_open_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + const char *device_specifier; + /*out*/ + int ihandle; +} of_open_service; + +int of_open(const char *device_specifier, + int *ihandle); + + +typedef struct _of_close_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + int ihandle; + /*out*/ +} of_close_service; + +int of_close(int ihandle); + + +typedef struct _of_read_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + int ihandle; + void *addr; + int len; + /*out*/ + int actual; +} of_read_service; + +int of_read(int ihandle, void *addr, int len, int *actual); + + +typedef struct _of_write_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + int ihandle; + void *addr; + int len; + /*out*/ + int actual; +} of_write_service; + +int of_write(int ihandle, void *addr, int len, int *actual); + + +typedef struct _of_seek_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + int ihandle; + int pos_hi; + int pos_lo; + /*out*/ + int status; +} of_seek_service; + +int of_seek(int ihandle, int pos_hi, int pos_lo, int *status); + + +/* 6.3.2.4 Memory */ + + +typedef struct _of_claim_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + void *virt; + int size; + int align; + /*out*/ + void *baseaddr; +} of_claim_service; + +int of_claim(void *virt, int size, int align, void **baseaddr); + + +typedef struct _of_release_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + void *virt; + int size; + int align; + /*out*/ +} of_release_service; + +int of_release(void *virt, int size); + + +/* 6.3.2.5 Control transfer */ + + +typedef struct _of_boot_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + const char *bootspec; + /*out*/ +} of_boot_service; + +int of_boot(const char *bootspec); + + +typedef struct _of_enter_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + /*out*/ +} of_enter_service; + +int of_enter(void); + + +typedef struct _of_exit_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + /*out*/ +} of_exit_service; + +int of_exit(void); + + +typedef struct _of_chain_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + void *virt; + int size; + void *entry; + void *args; + int len; + /*out*/ +} of_chain_service; + +int of_chain(void *virt, int size, void *entry, void *args, int len); + + +/* 6.3.2.6 User interface */ + + +typedef struct _of_interpret_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + const char *cmd; + int args[0]; + /*...*/ + /*out*/ + /*...*/ +} of_interpret_service; + +int of_interpret(const char *arg, ...); + + +typedef struct _of_set_callback_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + void *newfunc; + /*out*/ + void *oldfunc; +} of_set_callback_service; + +int of_set_callback(void *newfunc, void **oldfunc); + + +typedef struct _of_set_symbol_lookup_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + void *sym_to_value; + void *value_to_sym; + /*out*/ +} of_set_symbol_lookup_service; + +int of_set_symbol_lookup(void *sym_to_value, void *value_to_sym); + + +/* 6.3.2.7 Time */ + + +typedef struct _of_milliseconds_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + /*out*/ + int ms; +} of_milliseconds_service; + +int of_milliseconds(int *ms); diff -Nru a/arch/ppc/boot/prep/vreset.c b/arch/ppc/boot/prep/vreset.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/prep/vreset.c Wed May 16 06:00:22 2001 @@ -0,0 +1,860 @@ +/* + * vreset.c + * + * Initialize the VGA control registers to 80x25 text mode. + * + * Adapted from a program by: + * Steve Sellgren + * San Francisco Indigo Company + * sfindigo!sellgren@uunet.uu.net + * + * Original concept by: + * Gary Thomas + * Adapted for Moto boxes by: + * Pat Kane & Mark Scott, 1996 + * Adapted for IBM portables by: + * Takeshi Ishimoto + * Multi-console support: + * Terje Malmedal + */ + +#include "iso_font.h" + +extern char *vidmem; +extern int lines, cols; +extern void udelay(long x); +extern void outb(int port, char val); +extern unsigned char inb(int port); +struct VaRegs; + +/* + * VGA Register + */ +struct VgaRegs +{ + unsigned short io_port; + unsigned char io_index; + unsigned char io_value; +}; + +void unlockVideo(int slot); +void setTextRegs(struct VgaRegs *svp); +void setTextCLUT(int shift); +void clearVideoMemory(); +void loadFont(unsigned char *ISA_mem); + +static void mdelay(int ms) +{ + for (; ms > 0; --ms) + udelay(1000); +} + +/* + * Default console text mode registers used to reset + * graphics adapter. + */ +#define NREGS 54 +#define ENDMK 0xFFFF /* End marker */ + +#define S3Vendor 0x5333 +#define CirrusVendor 0x1013 +#define DiamondVendor 0x100E +#define MatroxVendor 0x102B +#define ParadiseVendor 0x101C + +struct VgaRegs GenVgaTextRegs[NREGS+1] = { +/* port index value */ + /* SR Regs */ + 0x3c4, 0x1, 0x0, + 0x3c4, 0x2, 0x3, + 0x3c4, 0x3, 0x0, + 0x3c4, 0x4, 0x2, + /* CR Regs */ + 0x3d4, 0x0, 0x5f, + 0x3d4, 0x1, 0x4f, + 0x3d4, 0x2, 0x50, + 0x3d4, 0x3, 0x82, + 0x3d4, 0x4, 0x55, + 0x3d4, 0x5, 0x81, + 0x3d4, 0x6, 0xbf, + 0x3d4, 0x7, 0x1f, + 0x3d4, 0x8, 0x00, + 0x3d4, 0x9, 0x4f, + 0x3d4, 0xa, 0x0d, + 0x3d4, 0xb, 0x0e, + 0x3d4, 0xc, 0x00, + 0x3d4, 0xd, 0x00, + 0x3d4, 0xe, 0x00, + 0x3d4, 0xf, 0x00, + 0x3d4, 0x10, 0x9c, + 0x3d4, 0x11, 0x8e, + 0x3d4, 0x12, 0x8f, + 0x3d4, 0x13, 0x28, + 0x3d4, 0x14, 0x1f, + 0x3d4, 0x15, 0x96, + 0x3d4, 0x16, 0xb9, + 0x3d4, 0x17, 0xa3, + /* GR Regs */ + 0x3ce, 0x0, 0x0, + 0x3ce, 0x1, 0x0, + 0x3ce, 0x2, 0x0, + 0x3ce, 0x3, 0x0, + 0x3ce, 0x4, 0x0, + 0x3ce, 0x5, 0x10, + 0x3ce, 0x6, 0xe, + 0x3ce, 0x7, 0x0, + 0x3ce, 0x8, 0xff, + ENDMK +}; + +struct VgaRegs S3TextRegs[NREGS+1] = { +/* port index value */ + /* SR Regs */ + 0x3c4, 0x1, 0x0, + 0x3c4, 0x2, 0x3, + 0x3c4, 0x3, 0x0, + 0x3c4, 0x4, 0x2, + /* CR Regs */ + 0x3d4, 0x0, 0x5f, + 0x3d4, 0x1, 0x4f, + 0x3d4, 0x2, 0x50, + 0x3d4, 0x3, 0x82, + 0x3d4, 0x4, 0x55, + 0x3d4, 0x5, 0x81, + 0x3d4, 0x6, 0xbf, + 0x3d4, 0x7, 0x1f, + 0x3d4, 0x8, 0x00, + 0x3d4, 0x9, 0x4f, + 0x3d4, 0xa, 0x0d, + 0x3d4, 0xb, 0x0e, + 0x3d4, 0xc, 0x00, + 0x3d4, 0xd, 0x00, + 0x3d4, 0xe, 0x00, + 0x3d4, 0xf, 0x00, + 0x3d4, 0x10, 0x9c, + 0x3d4, 0x11, 0x8e, + 0x3d4, 0x12, 0x8f, + 0x3d4, 0x13, 0x28, + 0x3d4, 0x14, 0x1f, + 0x3d4, 0x15, 0x96, + 0x3d4, 0x16, 0xb9, + 0x3d4, 0x17, 0xa3, + /* GR Regs */ + 0x3ce, 0x0, 0x0, + 0x3ce, 0x1, 0x0, + 0x3ce, 0x2, 0x0, + 0x3ce, 0x3, 0x0, + 0x3ce, 0x4, 0x0, + 0x3ce, 0x5, 0x10, + 0x3ce, 0x6, 0xe, + 0x3ce, 0x7, 0x0, + 0x3ce, 0x8, 0xff, + ENDMK +}; + +struct RGBColors +{ + unsigned char r, g, b; +}; + +/* + * Default console text mode color table. + * These values were obtained by booting Linux with + * text mode firmware & then dumping the registers. + */ +struct RGBColors TextCLUT[256] = +{ + /* red green blue */ + 0x0, 0x0, 0x0, + 0x0, 0x0, 0x2a, + 0x0, 0x2a, 0x0, + 0x0, 0x2a, 0x2a, + 0x2a, 0x0, 0x0, + 0x2a, 0x0, 0x2a, + 0x2a, 0x2a, 0x0, + 0x2a, 0x2a, 0x2a, + 0x0, 0x0, 0x15, + 0x0, 0x0, 0x3f, + 0x0, 0x2a, 0x15, + 0x0, 0x2a, 0x3f, + 0x2a, 0x0, 0x15, + 0x2a, 0x0, 0x3f, + 0x2a, 0x2a, 0x15, + 0x2a, 0x2a, 0x3f, + 0x0, 0x15, 0x0, + 0x0, 0x15, 0x2a, + 0x0, 0x3f, 0x0, + 0x0, 0x3f, 0x2a, + 0x2a, 0x15, 0x0, + 0x2a, 0x15, 0x2a, + 0x2a, 0x3f, 0x0, + 0x2a, 0x3f, 0x2a, + 0x0, 0x15, 0x15, + 0x0, 0x15, 0x3f, + 0x0, 0x3f, 0x15, + 0x0, 0x3f, 0x3f, + 0x2a, 0x15, 0x15, + 0x2a, 0x15, 0x3f, + 0x2a, 0x3f, 0x15, + 0x2a, 0x3f, 0x3f, + 0x15, 0x0, 0x0, + 0x15, 0x0, 0x2a, + 0x15, 0x2a, 0x0, + 0x15, 0x2a, 0x2a, + 0x3f, 0x0, 0x0, + 0x3f, 0x0, 0x2a, + 0x3f, 0x2a, 0x0, + 0x3f, 0x2a, 0x2a, + 0x15, 0x0, 0x15, + 0x15, 0x0, 0x3f, + 0x15, 0x2a, 0x15, + 0x15, 0x2a, 0x3f, + 0x3f, 0x0, 0x15, + 0x3f, 0x0, 0x3f, + 0x3f, 0x2a, 0x15, + 0x3f, 0x2a, 0x3f, + 0x15, 0x15, 0x0, + 0x15, 0x15, 0x2a, + 0x15, 0x3f, 0x0, + 0x15, 0x3f, 0x2a, + 0x3f, 0x15, 0x0, + 0x3f, 0x15, 0x2a, + 0x3f, 0x3f, 0x0, + 0x3f, 0x3f, 0x2a, + 0x15, 0x15, 0x15, + 0x15, 0x15, 0x3f, + 0x15, 0x3f, 0x15, + 0x15, 0x3f, 0x3f, + 0x3f, 0x15, 0x15, + 0x3f, 0x15, 0x3f, + 0x3f, 0x3f, 0x15, + 0x3f, 0x3f, 0x3f, + 0x39, 0xc, 0x5, + 0x15, 0x2c, 0xf, + 0x26, 0x10, 0x3d, + 0x29, 0x29, 0x38, + 0x4, 0x1a, 0xe, + 0x2, 0x1e, 0x3a, + 0x3c, 0x25, 0x33, + 0x3c, 0xc, 0x2c, + 0x3f, 0x3, 0x2b, + 0x1c, 0x9, 0x13, + 0x25, 0x2a, 0x35, + 0x1e, 0xa, 0x38, + 0x24, 0x8, 0x3, + 0x3, 0xe, 0x36, + 0xc, 0x6, 0x2a, + 0x26, 0x3, 0x32, + 0x5, 0x2f, 0x33, + 0x3c, 0x35, 0x2f, + 0x2d, 0x26, 0x3e, + 0xd, 0xa, 0x10, + 0x25, 0x3c, 0x11, + 0xd, 0x4, 0x2e, + 0x5, 0x19, 0x3e, + 0xc, 0x13, 0x34, + 0x2b, 0x6, 0x24, + 0x4, 0x3, 0xd, + 0x2f, 0x3c, 0xc, + 0x2a, 0x37, 0x1f, + 0xf, 0x12, 0x38, + 0x38, 0xe, 0x2a, + 0x12, 0x2f, 0x19, + 0x29, 0x2e, 0x31, + 0x25, 0x13, 0x3e, + 0x33, 0x3e, 0x33, + 0x1d, 0x2c, 0x25, + 0x15, 0x15, 0x5, + 0x32, 0x25, 0x39, + 0x1a, 0x7, 0x1f, + 0x13, 0xe, 0x1d, + 0x36, 0x17, 0x34, + 0xf, 0x15, 0x23, + 0x2, 0x35, 0xd, + 0x15, 0x3f, 0xc, + 0x14, 0x2f, 0xf, + 0x19, 0x21, 0x3e, + 0x27, 0x11, 0x2f, + 0x38, 0x3f, 0x3c, + 0x36, 0x2d, 0x15, + 0x16, 0x17, 0x2, + 0x1, 0xa, 0x3d, + 0x1b, 0x11, 0x3f, + 0x21, 0x3c, 0xd, + 0x1a, 0x39, 0x3d, + 0x8, 0xe, 0xe, + 0x22, 0x21, 0x23, + 0x1e, 0x30, 0x5, + 0x1f, 0x22, 0x3d, + 0x1e, 0x2f, 0xa, + 0x0, 0x1c, 0xe, + 0x0, 0x1c, 0x15, + 0x0, 0x1c, 0x1c, + 0x0, 0x15, 0x1c, + 0x0, 0xe, 0x1c, + 0x0, 0x7, 0x1c, + 0xe, 0xe, 0x1c, + 0x11, 0xe, 0x1c, + 0x15, 0xe, 0x1c, + 0x18, 0xe, 0x1c, + 0x1c, 0xe, 0x1c, + 0x1c, 0xe, 0x18, + 0x1c, 0xe, 0x15, + 0x1c, 0xe, 0x11, + 0x1c, 0xe, 0xe, + 0x1c, 0x11, 0xe, + 0x1c, 0x15, 0xe, + 0x1c, 0x18, 0xe, + 0x1c, 0x1c, 0xe, + 0x18, 0x1c, 0xe, + 0x15, 0x1c, 0xe, + 0x11, 0x1c, 0xe, + 0xe, 0x1c, 0xe, + 0xe, 0x1c, 0x11, + 0xe, 0x1c, 0x15, + 0xe, 0x1c, 0x18, + 0xe, 0x1c, 0x1c, + 0xe, 0x18, 0x1c, + 0xe, 0x15, 0x1c, + 0xe, 0x11, 0x1c, + 0x14, 0x14, 0x1c, + 0x16, 0x14, 0x1c, + 0x18, 0x14, 0x1c, + 0x1a, 0x14, 0x1c, + 0x1c, 0x14, 0x1c, + 0x1c, 0x14, 0x1a, + 0x1c, 0x14, 0x18, + 0x1c, 0x14, 0x16, + 0x1c, 0x14, 0x14, + 0x1c, 0x16, 0x14, + 0x1c, 0x18, 0x14, + 0x1c, 0x1a, 0x14, + 0x1c, 0x1c, 0x14, + 0x1a, 0x1c, 0x14, + 0x18, 0x1c, 0x14, + 0x16, 0x1c, 0x14, + 0x14, 0x1c, 0x14, + 0x14, 0x1c, 0x16, + 0x14, 0x1c, 0x18, + 0x14, 0x1c, 0x1a, + 0x14, 0x1c, 0x1c, + 0x14, 0x1a, 0x1c, + 0x14, 0x18, 0x1c, + 0x14, 0x16, 0x1c, + 0x0, 0x0, 0x10, + 0x4, 0x0, 0x10, + 0x8, 0x0, 0x10, + 0xc, 0x0, 0x10, + 0x10, 0x0, 0x10, + 0x10, 0x0, 0xc, + 0x10, 0x0, 0x8, + 0x10, 0x0, 0x4, + 0x10, 0x0, 0x0, + 0x10, 0x4, 0x0, + 0x10, 0x8, 0x0, + 0x10, 0xc, 0x0, + 0x10, 0x10, 0x0, + 0xc, 0x10, 0x0, + 0x8, 0x10, 0x0, + 0x4, 0x10, 0x0, + 0x0, 0x10, 0x0, + 0x0, 0x10, 0x4, + 0x0, 0x10, 0x8, + 0x0, 0x10, 0xc, + 0x0, 0x10, 0x10, + 0x0, 0xc, 0x10, + 0x0, 0x8, 0x10, + 0x0, 0x4, 0x10, + 0x8, 0x8, 0x10, + 0xa, 0x8, 0x10, + 0xc, 0x8, 0x10, + 0xe, 0x8, 0x10, + 0x10, 0x8, 0x10, + 0x10, 0x8, 0xe, + 0x10, 0x8, 0xc, + 0x10, 0x8, 0xa, + 0x10, 0x8, 0x8, + 0x10, 0xa, 0x8, + 0x10, 0xc, 0x8, + 0x10, 0xe, 0x8, + 0x10, 0x10, 0x8, + 0xe, 0x10, 0x8, + 0xc, 0x10, 0x8, + 0xa, 0x10, 0x8, + 0x8, 0x10, 0x8, + 0x8, 0x10, 0xa, + 0x8, 0x10, 0xc, + 0x8, 0x10, 0xe, + 0x8, 0x10, 0x10, + 0x8, 0xe, 0x10, + 0x8, 0xc, 0x10, + 0x8, 0xa, 0x10, + 0xb, 0xb, 0x10, + 0xc, 0xb, 0x10, + 0xd, 0xb, 0x10, + 0xf, 0xb, 0x10, + 0x10, 0xb, 0x10, + 0x10, 0xb, 0xf, + 0x10, 0xb, 0xd, + 0x10, 0xb, 0xc, + 0x10, 0xb, 0xb, + 0x10, 0xc, 0xb, + 0x10, 0xd, 0xb, + 0x10, 0xf, 0xb, + 0x10, 0x10, 0xb, + 0xf, 0x10, 0xb, + 0xd, 0x10, 0xb, + 0xc, 0x10, 0xb, + 0xb, 0x10, 0xb, + 0xb, 0x10, 0xc, + 0xb, 0x10, 0xd, + 0xb, 0x10, 0xf, + 0xb, 0x10, 0x10, + 0xb, 0xf, 0x10, + 0xb, 0xd, 0x10, + 0xb, 0xc, 0x10, + 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0 +}; + +unsigned char AC[21] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, + 0x0C, 0x00, 0x0F, 0x08, 0x00}; + +static int scanPCI(int start_slt); +static int PCIVendor(int); +#ifdef DEBUG +static void printslots(void); +#endif +extern void puthex(unsigned long); +extern void puts(const char *); +static void unlockS3(void); + +static void inline +outw(int port, unsigned short val) +{ + outb(port, val >> 8); + outb(port+1, val); +} + +#define PPC_601 1 + +int +vga_init(unsigned char *ISA_mem) +{ + int slot; + struct VgaRegs *VgaTextRegs; +#if 0 + if ((_get_PVR()>>16) == PPC_601) { + return(old_vga_init(ISA_mem)); + } +#endif + + /* See if VGA already in TEXT mode - exit if so! */ + outb(0x3CE, 0x06); + if ((inb(0x3CF) & 0x01) == 0){ + puts("VGA already in text mode\n"); + return 0; + } + + /* If no VGA responding in text mode, then we have some work to do... + */ + slot = -1; + while((slot = scanPCI(slot)) > -1) { /* find video card in use */ + unlockVideo(slot); /* enable I/O to card */ + VgaTextRegs = GenVgaTextRegs; + + switch (PCIVendor(slot)) { + default: + break; + case(S3Vendor): + unlockS3(); + VgaTextRegs = S3TextRegs; + break; + + case(CirrusVendor): + outw(0x3C4, 0x0612); /* unlock ext regs */ + outw(0x3C4, 0x0700); /* reset ext sequence mode */ + break; + + case(ParadiseVendor): /* IBM Portable 850 */ + outw(0x3ce, 0x0f05); /* unlock pardise registers */ + outw(0x3c4, 0x0648); + outw(0x3d4, 0x2985); + outw(0x3d4, 0x34a6); + outb(0x3ce, 0x0b); /* disable linear addressing */ + outb(0x3cf, inb(0x3cf) & ~0x30); + outw(0x3c4, 0x1400); + outb(0x3ce, 0x0e); /* disable 256 color mode */ + outb(0x3cf, inb(0x3cf) & ~0x01); + outb(0xd00, 0xff); /* enable auto-centering */ + if (!(inb(0xd01) & 0x03)) { + outb(0x3d4, 0x33); + outb(0x3d5, inb(0x3d5) & ~0x90); + outb(0x3d4, 0x32); + outb(0x3d5, inb(0x3d5) | 0x04); + outw(0x3d4, 0x0250); + outw(0x3d4, 0x07ba); + outw(0x3d4, 0x0900); + outw(0x3d4, 0x15e7); + outw(0x3d4, 0x2a95); + } + outw(0x3d4, 0x34a0); + break; + + #if 0 /* Untested - probably doesn't work */ + case(MatroxVendor): + case(DiamondVendor): + puts("VGA Chip Vendor ID: "); + puthex(PCIVendor(slot)); + puts("\n"); + mdelay(1000); + #endif + }; + + outw(0x3C4, 0x0120); /* disable video */ + setTextRegs(VgaTextRegs); /* initial register setup */ + setTextCLUT(0); /* load color lookup table */ + loadFont(ISA_mem); /* load font */ + setTextRegs(VgaTextRegs); /* reload registers */ + outw(0x3C4, 0x0100); /* re-enable video */ + clearVideoMemory(); + + if (PCIVendor(slot) == S3Vendor) { + outb(0x3c2, 0x63); /* MISC */ + } /* endif */ + + #ifdef DEBUG + printslots(); + mdelay(5000); + #endif + + mdelay(1000); /* give time for the video monitor to come up */ + } + return (1); /* 'CRT' I/O supported */ +} + +/* + * Write to VGA Attribute registers. + */ +void +writeAttr(unsigned char index, unsigned char data, unsigned char videoOn) +{ + unsigned char v; + v = inb(0x3da); /* reset attr. address toggle */ + if (videoOn) + outb(0x3c0, (index & 0x1F) | 0x20); + else + outb(0x3c0, (index & 0x1F)); + outb(0x3c0, data); +} + +void +setTextRegs(struct VgaRegs *svp) +{ + int i; + + /* + * saved settings + */ + while( svp->io_port != ENDMK ) { + outb(svp->io_port, svp->io_index); + outb(svp->io_port+1, svp->io_value); + svp++; + } + + outb(0x3c2, 0x67); /* MISC */ + outb(0x3c6, 0xff); /* MASK */ + + for ( i = 0; i < 0x10; i++) + writeAttr(i, AC[i], 0); /* pallete */ + writeAttr(0x10, 0x0c, 0); /* text mode */ + writeAttr(0x11, 0x00, 0); /* overscan color (border) */ + writeAttr(0x12, 0x0f, 0); /* plane enable */ + writeAttr(0x13, 0x08, 0); /* pixel panning */ + writeAttr(0x14, 0x00, 1); /* color select; video on */ +} + +void +setTextCLUT(int shift) +{ + int i; + + outb(0x3C6, 0xFF); + i = inb(0x3C7); + outb(0x3C8, 0); + i = inb(0x3C7); + + for ( i = 0; i < 256; i++) { + outb(0x3C9, TextCLUT[i].r << shift); + outb(0x3C9, TextCLUT[i].g << shift); + outb(0x3C9, TextCLUT[i].b << shift); + } +} + +void +loadFont(unsigned char *ISA_mem) +{ + int i, j; + unsigned char *font_page = (unsigned char *) &ISA_mem[0xA0000]; + + outb(0x3C2, 0x67); + /* + * Load font + */ + i = inb(0x3DA); /* Reset Attr toggle */ + + outb(0x3C0,0x30); + outb(0x3C0, 0x01); /* graphics mode */ + + outw(0x3C4, 0x0001); /* reset sequencer */ + outw(0x3C4, 0x0204); /* write to plane 2 */ + outw(0x3C4, 0x0406); /* enable plane graphics */ + outw(0x3C4, 0x0003); /* reset sequencer */ + outw(0x3CE, 0x0402); /* read plane 2 */ + outw(0x3CE, 0x0500); /* write mode 0, read mode 0 */ + outw(0x3CE, 0x0605); /* set graphics mode */ + + for (i = 0; i < sizeof(font); i += 16) { + for (j = 0; j < 16; j++) { + __asm__ volatile("eieio"); + font_page[(2*i)+j] = font[i+j]; + } + } +} + +static void +unlockS3(void) +{ + int s3_device_id; + outw(0x3d4, 0x3848); + outw(0x3d4, 0x39a5); + outb(0x3d4, 0x2d); + s3_device_id = inb(0x3d5) << 8; + outb(0x3d4, 0x2e); + s3_device_id |= inb(0x3d5); + + if (s3_device_id != 0x8812) { + /* From the S3 manual */ + outb(0x46E8, 0x10); /* Put into setup mode */ + outb(0x3C3, 0x10); + outb(0x102, 0x01); /* Enable registers */ + outb(0x46E8, 0x08); /* Enable video */ + outb(0x3C3, 0x08); + outb(0x4AE8, 0x00); + +#if 0 + outb(0x42E8, 0x80); /* Reset graphics engine? */ +#endif + + outb(0x3D4, 0x38); /* Unlock all registers */ + outb(0x3D5, 0x48); + outb(0x3D4, 0x39); + outb(0x3D5, 0xA5); + outb(0x3D4, 0x40); + outb(0x3D5, inb(0x3D5)|0x01); + outb(0x3D4, 0x33); + outb(0x3D5, inb(0x3D5)&~0x52); + outb(0x3D4, 0x35); + outb(0x3D5, inb(0x3D5)&~0x30); + outb(0x3D4, 0x3A); + outb(0x3D5, 0x00); + outb(0x3D4, 0x53); + outb(0x3D5, 0x00); + outb(0x3D4, 0x31); + outb(0x3D5, inb(0x3D5)&~0x4B); + outb(0x3D4, 0x58); + + outb(0x3D5, 0); + + outb(0x3D4, 0x54); + outb(0x3D5, 0x38); + outb(0x3D4, 0x60); + outb(0x3D5, 0x07); + outb(0x3D4, 0x61); + outb(0x3D5, 0x80); + outb(0x3D4, 0x62); + outb(0x3D5, 0xA1); + outb(0x3D4, 0x69); /* High order bits for cursor address */ + outb(0x3D5, 0); + + outb(0x3D4, 0x32); + outb(0x3D5, inb(0x3D5)&~0x10); + } else { + outw(0x3c4, 0x0806); /* IBM Portable 860 */ + outw(0x3c4, 0x1041); + outw(0x3c4, 0x1128); + outw(0x3d4, 0x4000); + outw(0x3d4, 0x3100); + outw(0x3d4, 0x3a05); + outw(0x3d4, 0x6688); + outw(0x3d4, 0x5800); /* disable linear addressing */ + outw(0x3d4, 0x4500); /* disable H/W cursor */ + outw(0x3c4, 0x5410); /* enable auto-centering */ + outw(0x3c4, 0x561f); + outw(0x3c4, 0x1b80); /* lock DCLK selection */ + outw(0x3d4, 0x3900); /* lock S3 registers */ + outw(0x3d4, 0x3800); + } /* endif */ +} + +/* + * cursor() sets an offset (0-1999) into the 80x25 text area + */ +void +cursor(int x, int y) +{ + int pos = (y*cols)+x; + outb(0x3D4, 14); + outb(0x3D5, pos >> 8); + outb(0x3D4, 15); + outb(0x3D5, pos); +} + +void +clearVideoMemory() +{ + int i, j; + for (i = 0; i < lines; i++) { + for (j = 0; j < cols; j++) { + vidmem[((i*cols)+j)*2] = 0x20; /* fill with space character */ + vidmem[((i*cols)+j)*2+1] = 0x07; /* set bg & fg attributes */ + } + } +} + +/* ============ */ + + +#define NSLOTS 8 +#define NPCIREGS 5 + + +/* + should use devfunc number/indirect method to be totally safe on + all machines, this works for now on 3 slot Moto boxes +*/ + +struct PCI_ConfigInfo { + unsigned long * config_addr; + unsigned long regs[NPCIREGS]; +} PCI_slots [NSLOTS] = { + + { (unsigned long *)0x80808000, 0xDEADBEEF }, /* onboard */ + { (unsigned long *)0x80800800, 0xDEADBEEF }, /* onboard */ + { (unsigned long *)0x80801000, 0xDEADBEEF }, /* onboard */ + { (unsigned long *)0x80802000, 0xDEADBEEF }, /* onboard */ + { (unsigned long *)0x80804000, 0xDEADBEEF }, /* onboard */ + { (unsigned long *)0x80810000, 0xDEADBEEF }, /* slot A/1 */ + { (unsigned long *)0x80820000, 0xDEADBEEF }, /* slot B/2 */ + { (unsigned long *)0x80840000, 0xDEADBEEF } /* slot C/3 */ +}; + + + +/* + * The following code modifies the PCI Command register + * to enable memory and I/O accesses. + */ +void +unlockVideo(int slot) +{ + volatile unsigned char * ppci; + + ppci = (unsigned char * )PCI_slots[slot].config_addr; + ppci[4] = 0x0003; /* enable memory and I/O accesses */ + ppci[0x10] = 0x00000; /* turn off memory mapping */ + ppci[0x11] = 0x00000; /* mem_base = 0 */ + ppci[0x12] = 0x00000; + ppci[0x13] = 0x00000; + __asm__ volatile("eieio"); + + outb(0x3d4, 0x11); + outb(0x3d5, 0x0e); /* unlock CR0-CR7 */ +} + +long +SwapBytes(long lv) /* turn little endian into big indian long */ +{ + long t; + t = (lv&0x000000FF) << 24; + t |= (lv&0x0000FF00) << 8; + t |= (lv&0x00FF0000) >> 8; + t |= (lv&0xFF000000) >> 24; + return(t); +} + + +#define DEVID 0 +#define CMD 1 +#define CLASS 2 +#define MEMBASE 4 + +int +scanPCI(int start_slt) +{ + int slt, r; + struct PCI_ConfigInfo *pslot; + int theSlot = -1; + int highVgaSlot = 0; + + for ( slt = start_slt + 1; slt < NSLOTS; slt++) { + pslot = &PCI_slots[slt]; + for ( r = 0; r < NPCIREGS; r++) { + pslot->regs[r] = SwapBytes ( pslot->config_addr[r] ); + } + /* card in slot ? */ + if ( pslot->regs[DEVID] != 0xFFFFFFFF ) { + /* VGA ? */ + if ( ((pslot->regs[CLASS] & 0xFFFFFF00) == 0x03000000) || + ((pslot->regs[CLASS] & 0xFFFFFF00) == 0x00010000)) { + highVgaSlot = slt; + /* did firmware enable it ? */ + if ( (pslot->regs[CMD] & 0x03) ) { + theSlot = slt; + break; + } + } + } + } + + return ( theSlot ); +} + +/* return Vendor ID of card in the slot */ +static +int PCIVendor(int slotnum) { + struct PCI_ConfigInfo *pslot; + + pslot = &PCI_slots[slotnum]; + +return (pslot->regs[DEVID] & 0xFFFF); +} + +#ifdef DEBUG +static +void printslots(void) +{ + int i; +#if 0 + struct PCI_ConfigInfo *pslot; +#endif + for(i=0; i < NSLOTS; i++) { +#if 0 + pslot = &PCI_slots[i]; + printf("Slot: %d, Addr: %x, Vendor: %08x, Class: %08x\n", + i, pslot->config_addr, pslot->regs[0], pslot->regs[2]); +#else + puts("PCI Slot number: "); puthex(i); + puts(" Vendor ID: "); + puthex(PCIVendor(i)); puts("\n"); +#endif + } +} +#endif /* DEBUG */ diff -Nru a/arch/ppc/boot/size b/arch/ppc/boot/size --- a/arch/ppc/boot/size Wed May 16 06:00:25 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,4 +0,0 @@ -#!/bin/bash - -OFFSET=`$1 -h $2 | grep $3 | grep -v zvmlinux | awk '{print $3}'` -echo "0x"$OFFSET diff -Nru a/arch/ppc/boot/spruce/Makefile b/arch/ppc/boot/spruce/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/spruce/Makefile Wed May 16 06:00:33 2001 @@ -0,0 +1,101 @@ +# arch/ppc/spruceboot/Makefile +# +# Makefile for IBM Spruce reference platform +# +# Author: Johnnie Peters +# jpeters@mvista.com +# +# Cleanups: Tom Rini +# trini@mvista.com +# +# Copyright 2000-2001 MontaVista Software Inc. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2 of the License, or (at your +# option) any later version. +# +# THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED +# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN +# NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 675 Mass Ave, Cambridge, MA 02139, USA. + +.c.s: + $(CC) $(CFLAGS) -S -o $*.s $< +.s.o: + $(AS) -o $*.o $< +.c.o: + $(CC) $(CFLAGS) -c -o $*.o $< +.S.s: + $(CPP) $(AFLAGS) -traditional -o $*.o $< +.S.o: + $(CC) $(AFLAGS) -traditional -c -o $*.o $< + +TFTPIMAGE := /tftpboot/zImage.spruce + +ZLINKFLAGS := -T $(TOPDIR)/arch/$(ARCH)/vmlinux.lds -Ttext 0x00800000 + +OBJECTS := head.o misc.o ../common/misc-common.o ../common/string.o +ifdef CONFIG_SERIAL_CONSOLE +OBJECTS += ../common/ns16550.o +endif + +LIBS := ../lib/zlib.a +OBJCOPY = $(CROSS_COMPILE)objcopy +OBJCOPY_ARGS = -O elf32-powerpc +MKEVIMG = ../utils/mkevimg -l -v +MKIRIMG = ../utils/mkirimg + +all: zImage + +zImage.initrd: zvmlinux.initrd + $(OBJDUMP) --syms zvmlinux.initrd | grep irSectStart > irSectStart.txt + $(MKIRIMG) zvmlinux.initrd zvmlinux.out irSectStart.txt + $(MKEVIMG) zvmlinux.out ../images/zImage.spruce.initrd + rm -f zvmlinux.out irSectStart.txt zvmlinux.initrd + +zImage: zvmlinux + $(OBJDUMP) --syms zvmlinux | grep irSectStart > irSectStart.txt + $(MKIRIMG) zvmlinux zvmlinux.out irSectStart.txt + $(MKEVIMG) zvmlinux.out ../images/zImage.spruce + rm -f zvmlinux.out irSectStart.txt zvmlinux + + +zvmlinux.initrd: $(OBJECTS) $(LIBS) ../images/vmlinux.gz + $(LD) $(ZLINKFLAGS) -o $@.tmp $(OBJECTS) $(LIBS) + $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ + --add-section=initrd=../images/ramdisk.image.gz \ + --add-section=image=../images/vmlinux.gz \ + $@.tmp $@ + rm -f $@.tmp + +zvmlinux: $(OBJECTS) $(LIBS) ../images/vmlinux.gz + $(LD) $(ZLINKFLAGS) -o $@.tmp $(OBJECTS) $(LIBS) + $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ + --add-section=image=../images/vmlinux.gz \ + $@.tmp $@ + rm -f $@.tmp + +znetboot: zImage + cp ../images/zImage.spruce $(TFTPIMAGE) + +znetboot.initrd: zImage.initrd + cp ../images/zImage.spruce.initrd $(TFTPIMAGE) + +floppy: $(TOPDIR)/vmlinux zImage + dd if=zImage of=/dev/fd0H1440 bs=64b + +clean: + rm -f irSectStart.txt + +include $(TOPDIR)/Rules.make diff -Nru a/arch/ppc/boot/spruce/head.S b/arch/ppc/boot/spruce/head.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/spruce/head.S Wed May 16 06:00:33 2001 @@ -0,0 +1,293 @@ +/* + * arch/ppc/boot/spruce/head.S + * + * Initial board bringup code for IBM Spruce + * + * Author: Matt Porter and Johnnie Peters + * mporter@mvista.com + * jpeters@mvista.com + * + * Derived from arch/ppc/boot/pmon/head.S + * + * Copyright 2000 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "../../kernel/ppc_defs.h" +#include "../../kernel/ppc_asm.tmpl" +#include +#include + +/* This is a kludge for the bootloader */ +#define _IO_BASE 0x80000000 + +.text + +/* + * Move the boot code to the link address (8M) + * Setup C stack + * Initialize UART + * Decompress the kernel to 0x0 + * Jump to the kernel entry + */ + + .globl start +start: + bl start_ + +start_: + /* Disable and flash the L1 Cache */ + mfspr r3,HID0 + ori r3,r3,(HID0_ICFI|HID0_DCI) + andi. r3,r3,0x3fff + mtspr HID0,r3 + sync + isync + + /* Disable and flush L2 Cache */ + mfspr r3,L2CR + oris r3,r3,0x20 + andis. r3,r3,0x7fff + mtspr L2CR,r3 + sync + isync + + /* Trun the data cache flush assist bit back off */ + mfspr r3,HID0 + andi. r3,r3,0x3fbf + mtspr HID0,r3 + sync + isync + + /* check if we need to relocate ourselves to the link addr or were we + loaded there to begin with -- Cort */ + lis r4,start@h + ori r4,r4,start@l + mflr r3 + subi r3,r3,4 /* we get the nip, not the ip of the branch */ + mr r8,r3 + cmp 0,r3,r4 + bne 1010f +/* compute size of whole image in words. this should be moved to + * start_ldr() -- Cort + */ + lis r4,start@h + ori r4,r4,start@l + lis r5,end@h + ori r5,r5,end@l + addi r5,r5,3 /* round up */ + sub r5,r5,r4 + srwi r5,r5,2 + mr r7,r5 + b start_ldr +1010: +/* + * no matter where we're loaded, move ourselves to -Ttext address + */ +relocate: + mflr r3 /* Compute code bias */ + subi r3,r3,4 + mr r8,r3 + lis r4,start@h + ori r4,r4,start@l + lis r5,end@h + ori r5,r5,end@l + addi r5,r5,3 /* Round up - just in case */ + sub r5,r5,r4 /* Compute # longwords to move */ + srwi r5,r5,2 + mtctr r5 + mr r7,r5 + li r6,0 + subi r3,r3,4 /* Set up for loop */ + subi r4,r4,4 +00: lwzu r5,4(r3) + stwu r5,4(r4) + xor r6,r6,r5 + bdnz 00b + lis r3,start_ldr@h + ori r3,r3,start_ldr@l + mtlr r3 /* Easiest way to do an absolute jump */ + blr +start_ldr: +/* Clear all of BSS and set up stack for C calls */ + lis r3,edata@h + ori r3,r3,edata@l + lis r4,end@h + ori r4,r4,end@l + subi r3,r3,4 + subi r4,r4,4 + li r0,0 +50: stwu r0,4(r3) + cmp 0,r3,r4 + bne 50b +90: mr r9,r1 /* Save old stack pointer (in case it matters) */ + lis r1,.stack@h + ori r1,r1,.stack@l + addi r1,r1,4096*2 + subi r1,r1,256 + li r2,0x000F /* Mask pointer to 16-byte boundary */ + andc r1,r1,r2 + +/* + * Exec kernel loader + */ + mr r3,r8 /* Load point */ + mr r4,r7 /* Program length */ + mr r5,r6 /* Checksum */ + bl decompress_kernel + + lis r6,cmd_line@h + ori r6,r6,cmd_line@l + lwz r6, 0(r6) + subi r7,r6,1 +00: lbzu r2,1(r7) + 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,0x4 + mtlr r9 + li r9,0 + stb r20,0(r9) /* Save MSIZ reg for kernel */ + + /* + * Jump to kernel start + */ + blr + +hang: + b hang + +/* + * 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 + +.globl _get_HID0 +_get_HID0: + mfspr r3,HID0 + blr + +.globl _put_HID0 +_put_HID0: + mtspr HID0,r3 + blr + +.globl _get_MSR +_get_MSR: + mfmsr r3 + blr + +.globl _put_MSR +_put_MSR: + mtmsr r3 + blr + + +.globl _get_L2CR +_get_L2CR: + mfspr r3,L2CR + blr + +.globl _put_L2CR +_put_L2CR: + mtspr L2CR,r3 + blr + +/* + * Flush instruction cache + * *** I'm really paranoid here! + */ +_GLOBAL(flush_instruction_cache) + mflr r5 + bl flush_data_cache + mfspr r3,HID0 /* Caches are controlled by this register */ + li r4,0 + ori r4,r4,(HID0_ICE|HID0_ICFI) + or r3,r3,r4 /* Need to enable+invalidate to clear */ + mtspr HID0,r3 + andc r3,r3,r4 + ori r3,r3,HID0_ICE /* Enable cache */ + mtspr HID0,r3 + mtlr r5 + blr + +#define NUM_CACHE_LINES 128*8 +#define CACHE_LINE_SIZE 32 +#define cache_flush_buffer 0x1000 + +/* + * Flush data cache + * *** I'm really paranoid here! + */ +_GLOBAL(flush_data_cache) + lis r3,cache_flush_buffer@h + ori r3,r3,cache_flush_buffer@l + li r4,NUM_CACHE_LINES + mtctr r4 +00: lwz r4,0(r3) + addi r3,r3,CACHE_LINE_SIZE /* Next line, please */ + bdnz 00b +10: blr + .comm .stack,4096*2,4 + diff -Nru a/arch/ppc/boot/spruce/misc.c b/arch/ppc/boot/spruce/misc.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/spruce/misc.c Wed May 16 06:00:34 2001 @@ -0,0 +1,438 @@ +/* + * arch/ppc/boot/spruce/misc.c + * + * Misc. bootloader code for IBM Spruce reference platform + * + * Author: Johnnie Peters + * jpeters@mvista.com + * + * Derived from arch/ppc/boot/prep/misc.c + * + * Copyright 2000-2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include "zlib.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +unsigned long com_port; + +unsigned int irSectStart = 0xdeadbeaf; + +unsigned int imageSect_start = 0; +unsigned int imageSect_size = 0; +unsigned int initrdSect_start = 0; +unsigned int initrdSect_size = 0; + +char *avail_ram; +char *end_avail; +extern char _end[]; + +#ifdef CONFIG_CMDLINE +#define CMDLINE CONFIG_CMDLINE +#else +#define CMDLINE "" +#endif +char cmd_preset[] = CMDLINE; +char cmd_buf[256]; +char *cmd_line = cmd_buf; + +unsigned long initrd_start = 0, initrd_end = 0; +char *zimage_start; +int zimage_size; + +extern void udelay(long); +extern void puts(const char *); +extern void putc(const char c); +extern void puthex(unsigned long val); +extern void gunzip(void *, int, unsigned char *, int *); + +volatile struct NS16550 * serial_init(int); + +/* PCI configuration space access routines. */ +unsigned int *pci_config_address = (unsigned int *)SPRUCE_PCI_CONFIG_ADDR; +unsigned char *pci_config_data = (unsigned char *)SPRUCE_PCI_CONFIG_DATA; + +void cpc700_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn, + unsigned char offset, unsigned char *val) +{ + out_le32(pci_config_address, + (((bus & 0xff)<<16) | (dev_fn<<8) | (offset&0xfc) | 0x80000000)); + + *val= (in_le32((unsigned *)pci_config_data) >> (8 * (offset & 3))) & 0xff; +} + +void cpc700_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn, + unsigned char offset, unsigned char val) +{ + out_le32(pci_config_address, + (((bus & 0xff)<<16) | (dev_fn<<8) | (offset&0xfc) | 0x80000000)); + + out_8(pci_config_data + (offset&3), val); +} + +void cpc700_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn, + unsigned char offset, unsigned short *val) +{ + out_le32(pci_config_address, + (((bus & 0xff)<<16) | (dev_fn<<8) | (offset&0xfc) | 0x80000000)); + + *val= in_le16((unsigned short *)(pci_config_data + (offset&3))); +} + +void cpc700_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn, + unsigned char offset, unsigned short val) +{ + out_le32(pci_config_address, + (((bus & 0xff)<<16) | (dev_fn<<8) | (offset&0xfc) | 0x80000000)); + + out_le16((unsigned short *)(pci_config_data + (offset&3)), val); +} + +void cpc700_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn, + unsigned char offset, unsigned int *val) +{ + out_le32(pci_config_address, + (((bus & 0xff)<<16) | (dev_fn<<8) | (offset&0xfc) | 0x80000000)); + + *val= in_le32((unsigned *)pci_config_data); +} + +void cpc700_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn, + unsigned char offset, unsigned int val) +{ + out_le32(pci_config_address, + (((bus & 0xff)<<16) | (dev_fn<<8) | (offset&0xfc) | 0x80000000)); + + out_le32((unsigned *)pci_config_data, val); +} + +unsigned long isa_io_base = SPRUCE_ISA_IO_BASE; + +#define PCNET32_WIO_RDP 0x10 +#define PCNET32_WIO_RAP 0x12 +#define PCNET32_WIO_RESET 0x14 + +#define PCNET32_DWIO_RDP 0x10 +#define PCNET32_DWIO_RAP 0x14 +#define PCNET32_DWIO_RESET 0x18 + +/* Processor interface config register access */ +#define PIFCFGADDR 0xff500000 +#define PIFCFGDATA 0xff500004 + +#define PLBMIFOPT 0x18 /* PLB Master Interface Options */ +#define PLBMTLSA1 0x20 /* PLB Master Byte Swap Region 1 Starting Address */ +#define PLBMTLEA1 0x24 /* PLB Master Byte Swap Region 1 Ending Address */ + +#define MEM_MBEN 0x24 +#define MEM_TYPE 0x28 +#define MEM_B1SA 0x3c +#define MEM_B1EA 0x5c +#define MEM_B2SA 0x40 +#define MEM_B2EA 0x60 + +unsigned long +decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum) +{ + int loop; + int timer; + char *cp, ch; + unsigned long TotalMemory; + int csr0; + int csr_id; + int *mem_addr = (int *)0xff500008; + int *mem_data = (int *)0xff50000c; + int mem_size = 0; + unsigned long mem_mben; + unsigned long mem_type; + unsigned long mem_start; + unsigned long mem_end; + int *pif_addr = (int *)0xff500000; + int *pif_data = (int *)0xff500004; + int pci_devfn; + int found_multi = 0; + unsigned short vendor; + unsigned short device; + unsigned short command; + unsigned char header_type; + unsigned int bar0; + + /* Initialize the serial console port */ + com_port = (unsigned long *)serial_init(0); + + /* Set the PCI memory space mapping to be little endian */ + *pif_addr = PLBMTLSA1; + *pif_data = 0x80000000; + + *pif_addr = PLBMTLEA1; + *pif_data = 0xff4fffff; + + *pif_addr = PLBMIFOPT; + *pif_data = 0x80000000; + + /* Get the size of memory from the memory controller. */ + *mem_addr = MEM_MBEN; + asm("isync"); + mem_mben = *mem_data; + asm("isync"); + for(loop = 0; loop < 1000; loop++); + + *mem_addr = MEM_TYPE; + asm("isync"); + mem_type = *mem_data; + asm("isync"); + for(loop = 0; loop < 1000; loop++); + + *mem_addr = MEM_TYPE; + /* Confirm bank 1 has DRAM memory */ + if ((mem_mben & 0x40000000) && + ((mem_type & 0x30000000) == 0x10000000)) { + *mem_addr = MEM_B1SA; + asm("isync"); + mem_start = *mem_data; + asm("isync"); + for(loop = 0; loop < 1000; loop++); + + *mem_addr = MEM_B1EA; + asm("isync"); + mem_end = *mem_data; + asm("isync"); + for(loop = 0; loop < 1000; loop++); + + mem_size = mem_end - mem_start + 0x100000; + } + + /* Confirm bank 2 has DRAM memory */ + if ((mem_mben & 0x20000000) && + ((mem_type & 0xc000000) == 0x4000000)) { + *mem_addr = MEM_B2SA; + asm("isync"); + mem_start = *mem_data; + asm("isync"); + for(loop = 0; loop < 1000; loop++); + + *mem_addr = MEM_B2EA; + asm("isync"); + mem_end = *mem_data; + asm("isync"); + for(loop = 0; loop < 1000; loop++); + + mem_size += mem_end - mem_start + 0x100000; + } + + /* Search out and turn off the PcNet ethernet boot device. */ + for (pci_devfn = 1; pci_devfn < 0xff; pci_devfn++) { + if (PCI_FUNC(pci_devfn) && !found_multi) + continue; + + cpc700_pcibios_read_config_byte(0, pci_devfn, + PCI_HEADER_TYPE, &header_type); + + if (!PCI_FUNC(pci_devfn)) + found_multi = header_type & 0x80; + + cpc700_pcibios_read_config_word(0, pci_devfn, PCI_VENDOR_ID, + &vendor); + + if (vendor != 0xffff) { + cpc700_pcibios_read_config_word(0, pci_devfn, + PCI_DEVICE_ID, &device); + + /* If this PCI device is the Lance PCNet board then turn it off */ + if ((vendor == PCI_VENDOR_ID_AMD) && + (device == PCI_DEVICE_ID_AMD_LANCE)) { + + /* Turn on I/O Space on the board. */ + cpc700_pcibios_read_config_word(0, pci_devfn, + PCI_COMMAND, &command); + command |= 0x1; + cpc700_pcibios_write_config_word(0, pci_devfn, + PCI_COMMAND, command); + + /* Get the I/O space address */ + cpc700_pcibios_read_config_dword(0, pci_devfn, + PCI_BASE_ADDRESS_0, &bar0); + bar0 &= 0xfffffffe; + + /* Reset the PCNet Board */ + inl (bar0+PCNET32_DWIO_RESET); + inw (bar0+PCNET32_WIO_RESET); + + /* First do a work oriented read of csr0. If the value is + * 4 then this is the correct mode to access the board. + * If not try a double word ortiented read. + */ + outw(0, bar0 + PCNET32_WIO_RAP); + csr0 = inw(bar0 + PCNET32_WIO_RDP); + + if (csr0 == 4) { + /* Check the Chip id register */ + outw(88, bar0 + PCNET32_WIO_RAP); + csr_id = inw(bar0 + PCNET32_WIO_RDP); + + if (csr_id) { + /* This is the valid mode - set the stop bit */ + outw(0, bar0 + PCNET32_WIO_RAP); + outw(csr0, bar0 + PCNET32_WIO_RDP); + } + } else { + outl(0, bar0 + PCNET32_DWIO_RAP); + csr0 = inl(bar0 + PCNET32_DWIO_RDP); + if (csr0 == 4) { + /* Check the Chip id register */ + outl(88, bar0 + PCNET32_WIO_RAP); + csr_id = inl(bar0 + PCNET32_WIO_RDP); + + if (csr_id) { + /* This is the valid mode - set the stop bit*/ + outl(0, bar0 + PCNET32_WIO_RAP); + outl(csr0, bar0 + PCNET32_WIO_RDP); + } + } + } + } + } + } + + /* Assume 128MB on the SBS K2 */ + TotalMemory = 0x08000000; + + /* assume the chunk below 8M is free */ + end_avail = (char *)0x00800000; + + /* + * Reveal where we were loaded at and where we + * were relocated to. + */ + puts("loaded at: "); puthex(load_addr); + puts(" "); puthex((unsigned long)(load_addr + (4*num_words))); puts("\n"); + zimage_start = (char *)imageSect_start; + zimage_size = imageSect_size; + + if (initrdSect_start) + initrd_start = initrdSect_start; + else + initrd_start = 0; + + initrd_end = initrd_start + initrdSect_size; + + if (initrd_start) { + puts("initrd at: "); puthex(initrd_start); + puts(" "); puthex(initrd_end); puts("\n"); + } + + avail_ram = (char *)0x00400000; + end_avail = (char *)0x00800000; + puts("avail ram: "); puthex((unsigned long)avail_ram); puts(" "); + puthex((unsigned long)end_avail); puts("\n"); + + /* Display standard Linux/PPC boot prompt for kernel args */ + puts("\nLinux/PPC load: "); + timer = 0; + cp = cmd_line; + memcpy (cmd_line, cmd_preset, sizeof(cmd_preset)); + while ( *cp ) putc(*cp++); + while (timer++ < 5*1000) { + if (tstc()) { + while ((ch = getc()) != '\n' && ch != '\r') { + if (ch == '\b') { + if (cp != cmd_line) { + cp--; + puts("\b \b"); + } + } else { + *cp++ = ch; + putc(ch); + } + } + break; /* Exit 'timer' loop */ + } + udelay(1000); /* 1 msec */ + } + *cp = 0; + puts("\n"); + + puts("Uncompressing Linux..."); + + gunzip(0, 0x400000, zimage_start, &zimage_size); + + puts("done.\n"); + + { + struct bi_record *rec; + + rec = (struct bi_record *)_ALIGN((ulong)zimage_size + + (1<<20)-1,(1<<20)); + + rec->tag = BI_FIRST; + rec->size = sizeof(struct bi_record); + rec = (struct bi_record *)((unsigned long)rec + rec->size); + + rec->tag = BI_BOOTLOADER_ID; + memcpy( (void *)rec->data, "spruceboot", 11); + rec->size = sizeof(struct bi_record) + 10 + 1; + rec = (struct bi_record *)((unsigned long)rec + rec->size); + + rec->tag = BI_MACHTYPE; + rec->data[0] = _MACH_spruce; + rec->data[1] = 1; + rec->size = sizeof(struct bi_record) + sizeof(unsigned long); + rec = (struct bi_record *)((unsigned long)rec + rec->size); + + rec->tag = BI_MEMSIZE; + rec->data[0] = mem_size; + rec->size = sizeof(struct bi_record) + sizeof(unsigned long); + rec = (struct bi_record *)((unsigned long)rec + rec->size); + + rec->tag = BI_CMD_LINE; + memcpy( (char *)rec->data, cmd_line, strlen(cmd_line)+1); + rec->size = sizeof(struct bi_record) + strlen(cmd_line) + 1; + rec = (struct bi_record *)((ulong)rec + rec->size); + + rec->tag = BI_LAST; + rec->size = sizeof(struct bi_record); + rec = (struct bi_record *)((unsigned long)rec + rec->size); + } + + puts("Now booting the kernel\n"); + + return 0; +} + +/* + * Local variables: + * c-indent-level: 8 + * c-basic-offset: 8 + * tab-width: 8 + * End: + */ diff -Nru a/arch/ppc/boot/tree/Makefile b/arch/ppc/boot/tree/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/tree/Makefile Wed May 16 06:00:21 2001 @@ -0,0 +1,64 @@ +# +# +# Module name: Makefile +# +# Description: +# Makefile for the IBM "tree" evaluation board Linux kernel +# boot loaders. +# +# +# Copyright (c) 1999 Grant Erickson +# +# PPC-405 modification +# Copyright 2000-2001 MontaVista Software Inc. +# Author: MontaVista Software, Inc. +# frank_rowand@mvista.com or source@mvista.com +# debbie_chu@mvista.com +# + +HOSTCFLAGS = -O -I$(TOPDIR)/include + +CC = $(CROSS_COMPILE)gcc +LD = $(CROSS_COMPILE)ld +OBJCOPY = $(CROSS_COMPILE)objcopy +OBJDUMP = $(CROSS_COMPILE)objdump + +GZIP = gzip -vf9 +RM = rm -f +MKEVIMG = ../utils/mkevimg -l +MKIRIMG = ../utils/mkirimg +LD_ARGS = -e _start -T ld.script -Ttext 0x00200000 -Bstatic + +OBJS = ../common/crt0.o main.o misc.o irSect.o ../common/string.o \ + ../common/misc-common.o +LIBS = ../lib/zlib.a + +treeboot: $(OBJS) $(LIBS) ld.script + $(LD) -o $@ $(LD_ARGS) $(OBJS) $(LIBS) + +zImage: vmlinux.img + +zImage.initrd: vmlinux.initrd.img + +treeboot.image: treeboot + $(OBJCOPY) --add-section=image=../images/vmlinux.gz treeboot $@ + +treeboot.initrd: treeboot.image ramdisk.image.gz + $(OBJCOPY) --add-section=initrd=ramdisk.image.gz treeboot.image $@ + +vmlinux.img: treeboot.image + $(OBJDUMP) --syms treeboot.image | grep irSectStart > irSectStart.txt + $(MKIRIMG) treeboot.image treeboot.image.out irSectStart.txt + $(MKEVIMG) treeboot.image.out ../images/vmlinux.tree.img + $(RM) treeboot.image treeboot.image.out irSectStart.txt + +vmlinux.initrd.img: treeboot.initrd + $(OBJDUMP) --all-headers treeboot.initrd | grep irSectStart > irSectStart.txt + $(MKIRIMG) treeboot.initrd treeboot.initrd.out irSectStart.txt + $(MKEVIMG) treeboot.initrd.out ../images/vmlinux.tree.initrd.img + $(RM) treeboot.initrd treeboot.initrd.out irSectStart.txt + +clean: + rm -f treeboot treeboot.image treeboot.initrd irSectStart.txt vmlinux.* + +include $(TOPDIR)/Rules.make diff -Nru a/arch/ppc/boot/tree/irSect.c b/arch/ppc/boot/tree/irSect.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/tree/irSect.c Wed May 16 06:00:25 2001 @@ -0,0 +1,36 @@ +/* + * + * Copyright (c) 1999 Grant Erickson + * + * Module name: irSect.c + * + * Description: + * Defines variables to hold the absolute starting address and size + * of the Linux kernel "image" and the initial RAM disk "initrd" + * sections within the boot loader. + * + */ + +#include "irSect.h" + + +/* + * The order of globals below must not change. If more globals are added, + * you must change the script 'mkirimg' accordingly. + * + */ + +/* + * irSectStart must be at beginning of file + */ +unsigned int irSectStart = 0xdeadbeaf; + +unsigned int imageSect_start = 0; +unsigned int imageSect_size = 0; +unsigned int initrdSect_start = 0; +unsigned int initrdSect_size = 0; + +/* + * irSectEnd must be at end of file + */ +unsigned int irSectEnd = 0xdeadbeaf; diff -Nru a/arch/ppc/boot/tree/irSect.h b/arch/ppc/boot/tree/irSect.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/tree/irSect.h Wed May 16 06:00:24 2001 @@ -0,0 +1,32 @@ +/* + * + * Copyright (c) 1999 Grant Erickson + * + * Module name: irSect.h + * + * Description: + * Defines variables to hold the absolute starting address and size + * of the Linux kernel "image" and the initial RAM disk "initrd" + * sections within the boot loader. + * + */ + +#ifndef __IRSECT_H__ +#define __IRSECT_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +extern unsigned int imageSect_start; +extern unsigned int imageSect_size; + +extern unsigned int initrdSect_start; +extern unsigned int initrdSect_size; + + +#ifdef __cplusplus +} +#endif + +#endif /* __IRSECT_H__ */ diff -Nru a/arch/ppc/boot/tree/ld.script b/arch/ppc/boot/tree/ld.script --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/tree/ld.script Wed May 16 06:00:16 2001 @@ -0,0 +1,68 @@ +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 = .); +} + diff -Nru a/arch/ppc/boot/tree/main.c b/arch/ppc/boot/tree/main.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/tree/main.c Wed May 16 06:00:18 2001 @@ -0,0 +1,246 @@ +/* + * Copyright (c) 1997 Paul Mackerras + * Initial Power Macintosh COFF version. + * Copyright (c) 1999 Grant Erickson + * Modifications for an ELF-based IBM evaluation board version. + * Copyright 2000-2001 MontaVista Software Inc. + * PPC405GP modifications + * Author: MontaVista Software, Inc. + * frank_rowand@mvista.com or source@mvista.com + * debbie_chu@mvista.com + * + * + * Module name: main.c + * + * Description: + * This module does most of the real work for the boot loader. It + * checks the variables holding the absolute start address and size + * of the Linux kernel "image" and initial RAM disk "initrd" sections + * and if they are present, moves them to their "proper" locations. + * + * For the Linux kernel, "proper" is physical address 0x00000000. + * For the RAM disk, "proper" is the image's size below the top + * of physical memory. The Linux kernel may be in either raw + * binary form or compressed with GNU zip (aka gzip). + * + * 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 +#include + +#include "nonstdio.h" +#include "irSect.h" +#if defined(CONFIG_SERIAL_CONSOLE) +#include "ns16550.h" +#endif /* CONFIG_SERIAL_CONSOLE */ + + +/* Preprocessor Defines */ + +/* + * Location of the IBM boot ROM function pointer address for retrieving + * the board information structure. + */ + +#define BOARD_INFO_VECTOR 0xFFFE0B50 + +/* + * Warning: the board_info doesn't contain valid data until get_board_info() + * gets called in start(). + */ +#define RAM_SIZE board_info.bi_memsize + +#define RAM_PBASE 0x00000000 +#define RAM_PEND (RAM_PBASE + RAM_SIZE) + +#define RAM_VBASE 0xC0000000 +#define RAM_VEND (RAM_VBASE + RAM_SIZE) + +#define RAM_START RAM_PBASE +#define RAM_END RAM_PEND +#define RAM_FREE (imageSect_start + imageSect_size + initrdSect_size) + +#define PROG_START RAM_START + + +/* Function Macros */ + +#define ALIGN_UP(x, align) (((x) + ((align) - 1)) & ~((align) - 1)) + +#define stringify(s) tostring(s) +#define tostring(s) #s + +#define mtdcr(rn, v) asm volatile("mtdcr " stringify(rn) ",%0" : : "r" (v)) +#define mfdcr(rn) ({unsigned int rval; \ + asm volatile("mfdcr %0," stringify(rn) \ + : "=r" (rval)); rval;}) +#define DCRN_MALCR 0x180 /* MAL Configuration */ +#define MALCR_SR 0x80000000 /* Software Reset */ + +/* Global Variables */ + +/* Needed by zalloc and zfree for allocating memory */ + +char *avail_ram; /* Indicates start of RAM available for heap */ +char *end_avail; /* Indicates end of RAM available for heap */ + +bd_t board_info; + +/* + * XXX - Until either the IBM boot ROM provides a way of passing arguments to + * the program it launches or until I/O is working in the boot loader, + * this is a good spot to pass in command line arguments to the kernel + * (e.g. console=tty0). + */ + + +/* +** The bootrom may change bootrom_cmdline to point to a buffer in the +** bootrom. +*/ +char *bootrom_cmdline = ""; +char treeboot_bootrom_cmdline[512]; + +#ifdef CONFIG_CMDLINE +char *cmdline = CONFIG_CMDLINE; +#else +char *cmdline = ""; +#endif + +/* Function Prototypes */ + +extern void *zalloc(void *x, unsigned items, unsigned size); + +/* serial I/O functions. + * These should have generic names, although this is similar to 16550.... + */ +static volatile unsigned char *uart0_lsr = (unsigned char *)0xef600305; +static volatile unsigned char *uart0_xcvr = (unsigned char *)0xef600300; + +void +serial_putc(void *unused, unsigned char c) +{ + while ((*uart0_lsr & LSR_THRE) == 0); + *uart0_xcvr = c; +} + +unsigned char +serial_getc(void *unused) +{ + while ((*uart0_lsr & LSR_DR) == 0); + return (*uart0_xcvr); +} + +int +serial_tstc(void *unused) +{ + return ((*uart0_lsr & LSR_DR) != 0); +} + + +void start(void) +{ + void *options; + int ns, oh, i; + unsigned long sa, len; + void *dst; + unsigned char *im; + unsigned long initrd_start, initrd_size; + bd_t *(*get_board_info)(void) = + (bd_t *(*)(void))(*(unsigned long *)BOARD_INFO_VECTOR); + bd_t *bip = NULL; + volatile unsigned long *em0mr0 = (long *)0xEF600800; /* ftr fixup */ + + + +#if defined(CONFIG_WALNUT) + /* turn off ethernet */ + /* This is to fix a problem with early walnut bootrom. */ + + mtdcr(DCRN_MALCR, MALCR_SR); /* 1st reset MAL */ + + while (mfdcr(DCRN_MALCR) & MALCR_SR) {}; /* wait for the reset */ + + *em0mr0 = 0x20000000; /* then reset EMAC */ +#endif + + +#if 0 + /* ftr revisit - remove printf()s */ + + printf("\n\nbootrom_cmdline = >%s<\n\n", bootrom_cmdline); + if (*bootrom_cmdline != '\0') { + printf("bootrom_cmdline != NULL, copying it into cmdline\n\n"); + *treeboot_bootrom_cmdline = '\0'; + strcat(treeboot_bootrom_cmdline, bootrom_cmdline); + cmdline = treeboot_bootrom_cmdline; + } +#endif + + + if ((bip = get_board_info()) != NULL) + memcpy(&board_info, bip, sizeof(bd_t)); + + /* Init RAM disk (initrd) section */ + + if (initrdSect_start != 0 && (initrd_size = initrdSect_size) != 0) { + initrd_start = (RAM_END - initrd_size) & ~0xFFF; + + _printk("Initial RAM disk at 0x%08x (%u bytes)\n", + initrd_start, initrd_size); + + memcpy((char *)initrd_start, + (char *)(initrdSect_start), + initrdSect_size); + + end_avail = (char *)initrd_start; + } else { + initrd_start = initrd_size = 0; + end_avail = (char *)RAM_END; + } + + /* Linux kernel image section */ + + im = (unsigned char *)(imageSect_start); + len = imageSect_size; + dst = (void *)PROG_START; + + /* Check for the gzip archive magic numbers */ + + if (im[0] == 0x1f && im[1] == 0x8b) { + + /* The gunzip routine needs everything nice and aligned */ + + void *cp = (void *)ALIGN_UP(RAM_FREE, 8); + avail_ram = (void *)(cp + ALIGN_UP(len, 8)); /* used by zalloc() */ + memcpy(cp, im, len); + + /* I'm not sure what the 0x200000 parameter is for, but it works. */ + /* It tells gzip the end of the area you wish to reserve, and it + * can use data past that point....unfortunately, this value + * isn't big enough (luck ran out). -- Dan + */ + + gunzip(dst, 0x400000, cp, (int *)&len); + } else { + memmove(dst, im, len); + } + + + flush_cache(dst, len); + + sa = (unsigned long)dst; + + (*(void (*)())sa)(&board_info, + initrd_start, + initrd_start + initrd_size, + cmdline, + cmdline + strlen(cmdline)); + + pause(); +} diff -Nru a/arch/ppc/boot/tree/misc.S b/arch/ppc/boot/tree/misc.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/tree/misc.S Wed May 16 06:00:20 2001 @@ -0,0 +1,40 @@ +/* + * 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 "../../kernel/ppc_asm.tmpl" + + .text + +/* + * Flush the dcache and invalidate the icache for a range of addresses. + * + * flush_cache(addr, len) + */ + .global flush_cache +flush_cache: + mfpvr r5 # Get processor version register + extrwi r5,r5,16,0 # Get the version bits + cmpwi cr0,r5,0x0020 # Is this a 403-based processor? + beq 1f # Yes, it is + li r5,32 # It is not a 403, set to 32 bytes + addi r4,r4,32-1 # len += line_size - 1 + srwi. r4,r4,5 # Convert from bytes to lines + b 2f +1: li r5,16 # It is a 403, set to 16 bytes + addi r4,r4,16-1 # len += line_size - 1 + srwi. r4,r4,4 # Convert from bytes to lines +2: mtctr r4 # Set-up the counter register + beqlr # If it is 0, we are done +3: dcbf r0,r3 # Flush and invalidate the data line + icbi r0,r3 # Invalidate the instruction line + add r3,r3,r5 # Move to the next line + bdnz 3b # Are we done yet? + sync + isync + blr # Return to the caller diff -Nru a/arch/ppc/boot/utils/Makefile b/arch/ppc/boot/utils/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/utils/Makefile Wed May 16 06:00:34 2001 @@ -0,0 +1,19 @@ +# +# arch/ppc/boot/utils/Makefile +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. + +HOSTCFLAGS += -I$(TOPDIR)/arch/$(ARCH)/boot/include + +# Simple programs with 1 file and no extra CFLAGS +UTILS = addnote hack-coff mkprep mksimage mknote piggyback mkpmon mkbugboot + +$(UTILS): + $(HOSTCC) $(HOSTCFLAGS) -o $@ $@.c + +clean: + rm -f $(UTILS) + +include $(TOPDIR)/Rules.make diff -Nru a/arch/ppc/boot/utils/addnote.c b/arch/ppc/boot/utils/addnote.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/utils/addnote.c Wed May 16 06:00:16 2001 @@ -0,0 +1,174 @@ +/* + * Program to hack in a PT_NOTE program header entry in an ELF file. + * This is needed for OF on RS/6000s to load an image correctly. + * Note that OF needs a program header entry for the note, not an + * ELF section. + * + * Copyright 2000 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. + * + * Usage: addnote zImage + */ +#include +#include +#include +#include + +char arch[] = "PowerPC"; + +#define N_DESCR 6 +unsigned int descr[N_DESCR] = { +#if 1 + /* values for IBM RS/6000 machines */ + 0xffffffff, /* real-mode = true */ + 0x00c00000, /* real-base, i.e. where we expect OF to be */ + 0xffffffff, /* real-size */ + 0xffffffff, /* virt-base */ + 0xffffffff, /* virt-size */ + 0x4000, /* load-base */ +#else + /* values for longtrail CHRP */ + 0, /* real-mode = false */ + 0xffffffff, /* real-base */ + 0xffffffff, /* real-size */ + 0xffffffff, /* virt-base */ + 0xffffffff, /* virt-size */ + 0x00600000, /* load-base */ +#endif +}; + +unsigned char buf[512]; + +#define GET_16BE(off) ((buf[off] << 8) + (buf[(off)+1])) +#define GET_32BE(off) ((GET_16BE(off) << 16) + GET_16BE((off)+2)) + +#define PUT_16BE(off, v) (buf[off] = ((v) >> 8) & 0xff, \ + buf[(off) + 1] = (v) & 0xff) +#define PUT_32BE(off, v) (PUT_16BE((off), (v) >> 16), \ + PUT_16BE((off) + 2, (v))) + +/* Structure of an ELF file */ +#define E_IDENT 0 /* ELF header */ +#define E_PHOFF 28 +#define E_PHENTSIZE 42 +#define E_PHNUM 44 +#define E_HSIZE 52 /* size of ELF header */ + +#define EI_MAGIC 0 /* offsets in E_IDENT area */ +#define EI_CLASS 4 +#define EI_DATA 5 + +#define PH_TYPE 0 /* ELF program header */ +#define PH_OFFSET 4 +#define PH_FILESZ 16 +#define PH_HSIZE 32 /* size of program header */ + +#define PT_NOTE 4 /* Program header type = note */ + +#define ELFCLASS32 1 +#define ELFDATA2MSB 2 + +unsigned char elf_magic[4] = { 0x7f, 'E', 'L', 'F' }; + +int main(int ac, char **av) +{ + int fd, n, i; + int ph, ps, np; + int nnote, ns; + + if (ac != 2) { + fprintf(stderr, "Usage: %s elf-file\n", av[0]); + exit(1); + } + fd = open(av[1], O_RDWR); + if (fd < 0) { + perror(av[1]); + exit(1); + } + + nnote = strlen(arch) + 1 + (N_DESCR + 3) * 4; + + n = read(fd, buf, sizeof(buf)); + if (n < 0) { + perror("read"); + exit(1); + } + + if (n < E_HSIZE || memcmp(&buf[E_IDENT+EI_MAGIC], elf_magic, 4) != 0) + goto notelf; + + if (buf[E_IDENT+EI_CLASS] != ELFCLASS32 + || buf[E_IDENT+EI_DATA] != ELFDATA2MSB) { + fprintf(stderr, "%s is not a big-endian 32-bit ELF image\n", + av[1]); + exit(1); + } + + ph = GET_32BE(E_PHOFF); + ps = GET_16BE(E_PHENTSIZE); + np = GET_16BE(E_PHNUM); + if (ph < E_HSIZE || ps < PH_HSIZE || np < 1) + goto notelf; + if (ph + (np + 1) * ps + nnote > n) + goto nospace; + + for (i = 0; i < np; ++i) { + if (GET_32BE(ph + PH_TYPE) == PT_NOTE) { + fprintf(stderr, "%s already has a note entry\n", + av[1]); + exit(0); + } + ph += ps; + } + + /* XXX check that the area we want to use is all zeroes */ + for (i = 0; i < ps + nnote; ++i) + if (buf[ph + i] != 0) + goto nospace; + + /* fill in the program header entry */ + ns = ph + ps; + PUT_32BE(ph + PH_TYPE, PT_NOTE); + PUT_32BE(ph + PH_OFFSET, ns); + PUT_32BE(ph + PH_FILESZ, nnote); + + /* fill in the note area we point to */ + /* XXX we should probably make this a proper section */ + PUT_32BE(ns, strlen(arch) + 1); + PUT_32BE(ns + 4, N_DESCR * 4); + PUT_32BE(ns + 8, 0x1275); + strcpy(&buf[ns + 12], arch); + ns += 12 + strlen(arch) + 1; + for (i = 0; i < N_DESCR; ++i) + PUT_32BE(ns + i * 4, descr[i]); + + /* Update the number of program headers */ + PUT_16BE(E_PHNUM, np + 1); + + /* write back */ + lseek(fd, (long) 0, SEEK_SET); + i = write(fd, buf, n); + if (i < 0) { + perror("write"); + exit(1); + } + if (i < n) { + fprintf(stderr, "%s: write truncated\n", av[1]); + exit(1); + } + + exit(0); + + notelf: + fprintf(stderr, "%s does not appear to be an ELF file\n", av[0]); + exit(1); + + nospace: + fprintf(stderr, "sorry, I can't find space in %s to put the note\n", + av[0]); + exit(1); +} diff -Nru a/arch/ppc/boot/utils/elf.pl b/arch/ppc/boot/utils/elf.pl --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/utils/elf.pl Wed May 16 06:00:22 2001 @@ -0,0 +1,33 @@ +# +# ELF header field numbers +# + +$e_ident = 0; # Identification bytes / magic number +$e_type = 1; # ELF file type +$e_machine = 2; # Target machine type +$e_version = 3; # File version +$e_entry = 4; # Start address +$e_phoff = 5; # Program header file offset +$e_shoff = 6; # Section header file offset +$e_flags = 7; # File flags +$e_ehsize = 8; # Size of ELF header +$e_phentsize = 9; # Size of program header +$e_phnum = 10; # Number of program header entries +$e_shentsize = 11; # Size of section header +$e_shnum = 12; # Number of section header entries +$e_shstrndx = 13; # Section header table string index + +# +# Section header field numbers +# + +$sh_name = 0; # Section name +$sh_type = 1; # Section header type +$sh_flags = 2; # Section header flags +$sh_addr = 3; # Virtual address +$sh_offset = 4; # File offset +$sh_size = 5; # Section size +$sh_link = 6; # Miscellaneous info +$sh_info = 7; # More miscellaneous info +$sh_addralign = 8; # Memory alignment +$sh_entsize = 9; # Entry size if this is a table diff -Nru a/arch/ppc/boot/utils/hack-coff.c b/arch/ppc/boot/utils/hack-coff.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/utils/hack-coff.c Wed May 16 06:00:23 2001 @@ -0,0 +1,82 @@ +/* + * 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 +#include +#include +#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]) + +int +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); +} diff -Nru a/arch/ppc/boot/utils/mkbugboot.c b/arch/ppc/boot/utils/mkbugboot.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/utils/mkbugboot.c Wed May 16 06:00:33 2001 @@ -0,0 +1,188 @@ +/* + * arch/ppc/pp3boot/mkbugboot.c + * + * Makes a Motorola PPCBUG ROM bootable image which can be flashed + * into one of the FLASH banks on a Motorola PowerPlus board. + * + * Author: Matt Porter + * + * Copyright 2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#define ELF_HEADER_SIZE 65536 + +#include +#include +#include +#include +#include +#include + +#ifdef __i386__ +#define cpu_to_be32(x) le32_to_cpu(x) +#define cpu_to_be16(x) le16_to_cpu(x) +#else +#define cpu_to_be32(x) (x) +#define cpu_to_be16(x) (x) +#endif + +#define cpu_to_le32(x) le32_to_cpu((x)) +unsigned long le32_to_cpu(unsigned long x) +{ + return (((x & 0x000000ffU) << 24) | + ((x & 0x0000ff00U) << 8) | + ((x & 0x00ff0000U) >> 8) | + ((x & 0xff000000U) >> 24)); +} + +#define cpu_to_le16(x) le16_to_cpu((x)) +unsigned short le16_to_cpu(unsigned short x) +{ + return (((x & 0x00ff) << 8) | + ((x & 0xff00) >> 8)); +} + +/* size of read buffer */ +#define SIZE 0x1000 + +/* typedef long int32_t; */ +typedef unsigned long uint32_t; +typedef unsigned short uint16_t; +typedef unsigned char uint8_t; + +/* PPCBUG ROM boot header */ +typedef struct bug_boot_header { + uint8_t magic_word[4]; /* "BOOT" */ + uint32_t entry_offset; /* Offset from top of header to code */ + uint32_t routine_length; /* Length of code */ + uint8_t routine_name[8]; /* Name of the boot code */ +} bug_boot_header_t; + +#define HEADER_SIZE sizeof(bug_boot_header_t) + +uint32_t copy_image(int32_t in_fd, int32_t out_fd) +{ + uint8_t buf[SIZE]; + int n; + uint32_t image_size = 0; + uint8_t zero = 0; + + lseek(in_fd, ELF_HEADER_SIZE, SEEK_SET); + + /* Copy an image while recording its size */ + while ( (n = read(in_fd, buf, SIZE)) > 0 ) + { + image_size = image_size + n; + write(out_fd, buf, n); + } + + /* BUG romboot requires that our size is divisible by 2 */ + /* align image to 2 byte boundary */ + if (image_size % 2) + { + image_size++; + write(out_fd, &zero, 1); + } + + return image_size; +} + +void write_bugboot_header(int32_t out_fd, uint32_t boot_size) +{ + uint8_t header_block[HEADER_SIZE]; + bug_boot_header_t *bbh = (bug_boot_header_t *)&header_block[0]; + + bzero(header_block, HEADER_SIZE); + + /* Fill in the PPCBUG ROM boot header */ + strncpy(bbh->magic_word, "BOOT", 4); /* PPCBUG magic word */ + bbh->entry_offset = cpu_to_be32(HEADER_SIZE); /* Entry address */ + bbh->routine_length= cpu_to_be32(HEADER_SIZE+boot_size+2); /* Routine length */ + strncpy(bbh->routine_name, "LINUXROM", 8); /* Routine name */ + + /* Output the header and bootloader to the file */ + write(out_fd, header_block, HEADER_SIZE); +} + +uint16_t calc_checksum(int32_t bug_fd) +{ + uint32_t checksum_var = 0; + uint8_t buf[2]; + int n; + + /* Checksum loop */ + while ( (n = read(bug_fd, buf, 2) ) ) + { + checksum_var = checksum_var + *(uint16_t *)buf; + + /* If we carry out, mask it and add one to the checksum */ + if (checksum_var >> 16) + checksum_var = (checksum_var & 0x0000ffff) + 1; + } + + return checksum_var; +} + +int main(int argc, char *argv[]) +{ + int32_t image_fd, bugboot_fd; + int argptr = 1; + uint32_t kernel_size = 0; + uint16_t checksum = 0; + uint8_t bugbootname[256]; + + if ( (argc != 3) ) + { + fprintf(stderr, "usage: %s \n",argv[0]); + exit(-1); + } + + /* Get file args */ + + /* kernel image file */ + if ((image_fd = open( argv[argptr] , 0)) < 0) + exit(-1); + argptr++; + + /* bugboot file */ + if ( !strcmp( argv[argptr], "-" ) ) + bugboot_fd = 1; /* stdout */ + else + if ((bugboot_fd = creat( argv[argptr] , 0755)) < 0) + exit(-1); + else + strcpy(bugbootname, argv[argptr]); + argptr++; + + /* Set file position after ROM header block where zImage will be written */ + lseek(bugboot_fd, HEADER_SIZE, SEEK_SET); + + /* Copy kernel image into bugboot image */ + kernel_size = copy_image(image_fd, bugboot_fd); + close(image_fd); + + /* Set file position to beginning where header/romboot will be written */ + lseek(bugboot_fd, 0, SEEK_SET); + + /* Write out BUG header/romboot */ + write_bugboot_header(bugboot_fd, kernel_size); + + /* Close bugboot file */ + close(bugboot_fd); + + /* Reopen it as read/write */ + bugboot_fd = open(bugbootname, O_RDWR); + + /* Calculate checksum */ + checksum = calc_checksum(bugboot_fd); + + /* Write out the calculated checksum */ + write(bugboot_fd, &checksum, 2); + + return 0; +} diff -Nru a/arch/ppc/boot/utils/mkevimg b/arch/ppc/boot/utils/mkevimg --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/utils/mkevimg Wed May 16 06:00:17 2001 @@ -0,0 +1,437 @@ +#!/usr/bin/perl + +# +# Copyright (c) 1998-1999 TiVo, Inc. +# All rights reserved. +# +# Copyright (c) 1999 Grant Erickson +# Major syntactic and usability rework. +# +# Module name: mkevimg +# +# Description: +# Converts an ELF output file from the linker into the format used by +# the IBM evaluation board ROM Monitor to load programs from a host +# onto the evaluation board. The ELF file must be an otherwise execut- +# able file (with the text and data addresses bound at link time) and +# have space reserved after the entry point for the load information +# block: +# +# typedef struct boot_block { +# unsigned long magic; 0x0052504F +# unsigned long dest; Target address of the image +# unsigned long num_512blocks; Size, rounded-up, in 512 byte blocks +# unsigned long debug_flag; Run the debugger or image after load +# unsigned long entry_point; The image address to jump to after load +# unsigned long reserved[3]; +# } boot_block_t; +# +# + +use File::Basename; +use Getopt::Std; + +# +# usage() +# +# Description: +# This routine prints out the proper command line usage for this program +# +# Input(s): +# status - Flag determining what usage information will be printed and what +# the exit status of the program will be after the information is +# printed. +# +# Output(s): +# N/A +# +# Returns: +# This subroutine does not return. +# + +sub usage { + my($status); + $status = $_[0]; + + printf("Usage: %s [-hlvV] \n", + $program); + + if ($status != 0) { + printf("Try `%s -h' for more information.\n", $program); + } + + if ($status != 1) { + print(" -h Print out this message and exit.\n"); + print(" -l Linux mode; if present, copy 'image' and 'initrd' sections.\n"); + print(" -v Verbose. Print out lots of ELF information.\n"); + print(" -V Print out version information and exit.\n"); + } + + exit($status); +} + +# +# version() +# +# Description: +# This routine prints out program version information +# +# Input(s): +# N/A +# +# Output(s): +# N/A +# +# Returns: +# This subroutine does not return. +# + +sub version { + print("mkevimg Version 1.1.0\n"); + print("Copyright (c) 1998-1999 TiVo, Inc.\n"); + print("Copyright (c) 1999 Grant Erickson \n"); + + exit (0); +} + +# +# file_check() +# +# Description: +# This routine checks an input file to ensure that it exists, is a +# regular file, and is readable. +# +# Input(s): +# file - Input file to be checked. +# +# Output(s): +# N/A +# +# Returns: +# 0 if the file exists, is a regular file, and is readable, otherwise -1. +# + +sub file_check { + my($file); + $file = $_[0]; + + if (!(-e $file)) { + printf("The file \"%s\" does not exist.\n", $file); + return (-1); + } elsif (!(-f $file)) { + printf("The file \"%s\" is not a regular file.\n", $file); + return (-1); + } elsif (!(-r $file)) { + printf("The file \"%s\" is not readable.\n", $file); + return (-1); + } + + return (0); +} + +# +# decode_options() +# +# Description: +# This routine steps through the command-line arguments, parsing out +# recognzied options. +# +# Input(s): +# N/A +# +# Output(s): +# N/A +# +# Returns: +# N/A +# + +sub decode_options { + + if (!getopts("hlvV")) { + usage(1); + } + + if ($opt_h) { + usage(0); + } + + if ($opt_l) { + $linux = 1; + } + + if ($opt_V) { + version(); + exit (0); + } + + if ($opt_v) { + $verbose = 1; + } + + if (!($ifile = shift(@ARGV))) { + usage(1); + } + + if (!($ofile = shift(@ARGV))) { + usage (1); + } + + if (file_check($ifile)) { + exit(1); + } + +} + +# +# ELF file and section header field numbers +# + +require '../utils/elf.pl'; + +# +# Main program body +# + +{ + $program = basename($0); + + decode_options(); + + open(ELF, "<$ifile") || die "Cannot open input file"; + + $ifilesize = (-s $ifile); + + if ($verbose) { + print("Output file: $ofile\n"); + print("Input file: $ifile, $ifilesize bytes.\n"); + } + + if (read(ELF, $ibuf, $ifilesize) != $ifilesize) { + print("Failed to read input file!\n"); + exit(1); + } + + # + # Parse ELF header + # + + @eh = unpack("a16n2N5n6", $ibuf); + + # + # Make sure this is actually a PowerPC ELF file. + # + + if (substr($eh[$e_ident], 0, 4) ne "\177ELF") { + printf("The file \"%s\" is not an ELF file.\n", $ifile); + exit (1); + } elsif ($eh[$e_machine] != 20) { + printf("The file \"%s\" is not a PowerPC ELF file.\n", $ifile); + exit (1); + } + + if ($verbose) { + print("File header:\n"); + printf(" Identifier: %s\n", $eh[$e_ident]); + printf(" Type: %d\n", $eh[$e_type]); + printf(" Machine: %d\n", $eh[$e_machine]); + printf(" Version: %d\n", $eh[$e_version]); + printf(" Entry point: 0x%08x\n", $eh[$e_entry]); + printf(" Program header offset: 0x%x\n", $eh[$e_phoff]); + printf(" Section header offset: 0x%x\n", $eh[$e_shoff]); + printf(" Flags: 0x%08x\n", $eh[$e_flags]); + printf(" Header size: %d\n", $eh[$e_ehsize]); + printf(" Program entry size: %d\n", $eh[$e_phentsize]); + printf(" Program table entries: %d\n", $eh[$e_phnum]); + printf(" Section header size: %d\n", $eh[$e_shentsize]); + printf(" Section table entries: %d\n", $eh[$e_shnum]); + printf(" String table section: %d\n", $eh[$e_shstrndx]); + } + + # + # Find the section header for the string table. + # + + $strtable_section_offset = $eh[$e_shoff] + + $eh[$e_shstrndx] * $eh[$e_shentsize]; + + if ($verbose) { + printf("String table section header offset: 0x%x\n", + $strtable_section_offset); + } + + # + # Find the start of the string table. + # + + @strh = unpack("N10", substr($ibuf, $strtable_section_offset, + $eh[$e_shentsize])); + + if ($verbose) { + printf("Section name strings start at: 0x%x, %d bytes.\n", + $strh[$sh_offset], $strh[$sh_size]); + } + + $names = substr($ibuf, $strh[$sh_offset], $strh[$sh_size]); + + # Grab each section header and find '.text' and '.bss' sections in + # particular. + + if ($verbose) { + print("Section headers:\n"); + print("Idx Name Size Address File off Algn\n"); + print("--- ------------------------ -------- -------- -------- ----\n"); + } + + $off = $eh[$e_shoff]; + + for($i = 0; $i < $eh[$e_shnum]; $i++, $off += $eh[$e_shentsize]) { + @sh = unpack("N10", substr($ibuf, $off, $eh[$e_shentsize])); + + # Take the first section name from the array returned by split. + + ($name) = split(/\000/, substr($names, $sh[$sh_name])); + + if ($verbose) { + printf("%3d %-24s %8x %08x %08x %4d\n", + $i, $name, $sh[$sh_size], $sh[$sh_addr], + $sh[$sh_offset], $sh[$sh_addralign]); + } + + # Attempt to find the .text and .bss sections + + if ($name =~ /^\.bss$/) { + ($bss_addr, $bss_offset, $bss_size) = + ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]); + + } elsif ($name =~ /^\.text$/) { + ($text_addr, $text_offset, $text_size) = + ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]); + + } elsif ($linux && ($name =~ /^\image$/)) { + $image_found = 1; + + ($image_addr, $image_offset, $image_size) = + ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]); + + } elsif ($linux && ($name =~ /^\initrd$/)) { + $initrd_found = 1; + + ($initrd_addr, $initrd_offset, $initrd_size) = + ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]); + + } + } + + printf("Text section - Address: 0x%08x, Size: 0x%08x\n", + $text_addr, $text_size); + printf("Bss section - Address: 0x%08x, Size: 0x%08x\n", + $bss_addr, $bss_size); + + if ($linux) { + if ($image_found) { + printf("Image section - Address: 0x%08x, Size: 0x%08x\n", + $image_addr, $image_size); + } + + if ($initrd_found) { + printf("Initrd section - Address: 0x%08x, Size: 0x%08x\n", + $initrd_addr, $initrd_size); + } + } + + # + # Open output file + # + + open(BOOT, ">$ofile") || die "Cannot open output file"; + + # + # Compute image size + # + + $output_size = $bss_offset - $text_offset + $bss_size; + + if ($linux && $image_found) { + $output_size += $image_size; + } + + if ($linux && $initrd_found) { + $output_size += $initrd_size; + } + + $num_blocks = $output_size / 512 + 1; + + # + # Write IBM PowerPC evaluation board boot_block_t header + # + + $header = pack("H8N7", "0052504f", $text_addr, $num_blocks, 0, + $text_addr, 0, 0, 0); + + $bytes = length($header); + + if (($resid = syswrite(BOOT, $header, $bytes)) != $bytes) { + die("Could not write boot image header to output file."); + } + + printf("Entry point = 0x%08x\n", $text_addr); + printf("Image size = 0x%08x (%d bytes) (%d blocks).\n", + $output_size, $output_size, $num_blocks); + + # + # Write image starting after ELF and program headers and + # continuing to beginning of bss + # + + $bytes = $bss_offset - $text_offset + $bss_size; + + if (($resid = syswrite(BOOT, $ibuf, $bytes, $text_offset)) != $bytes) { + die("Could not write boot image to output file.\n"); + } + + # + # If configured, write out the image and initrd sections as well + # + + if ($linux) { + if ($image_found) { + $bytes = $image_size; + if (($resid = syswrite(BOOT, $ibuf, $bytes, $image_offset)) != $bytes) { + die("Could not write boot image to output file.\n"); + } + } + + if ($initrd_found) { + $bytes = $initrd_size; + if (($resid = syswrite(BOOT, $ibuf, $bytes, $initrd_offset)) != $bytes) { + die("Could not write boot image to output file.\n"); + } + } + } + + # + # Pad to a multiple of 512 bytes + # + + $pad_size = 512 - (length($header) + $output_size) % 512; + + if ($verbose) { + print("Padding boot image by an additional $pad_size bytes.\n"); + } + + $pad_string = pack(("H8","deadbeef") x 128); + + syswrite(BOOT, $pad_string, $pad_size) or + die "Could not pad boot image in output file.\n"; + + # + # Clean-up and leave + # + + close(BOOT); + + print("\nBoot image file \"$ofile\" built successfuly.\n\n"); + + exit(0); +} diff -Nru a/arch/ppc/boot/utils/mkirimg b/arch/ppc/boot/utils/mkirimg --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/utils/mkirimg Wed May 16 06:00:25 2001 @@ -0,0 +1,367 @@ +#!/usr/bin/perl +# +# Copyright (c) 1998-1999 TiVo, Inc. +# Original ELF parsing code. +# +# Copyright (c) 1999 Grant Erickson +# Original code from 'mkevimg'. +# +# Module name: mkirimg +# +# Description: +# Reads an ELF file and assigns global variables 'imageSect_start', +# 'imageSect_size', 'initrdSect_start', and 'initrdSect_size' from +# the "image" and "initrd" section header information. It then +# rewrites the input ELF file with assigned globals to an output +# file. +# +# An input file, "irSectStart.txt" has the memory address of +# 'irSectStart'. The irSectStart memory address is used to find +# the global variables in the ".data" section of the ELF file. +# The 'irSectStart' and the above global variables are defined +# in "irSect.c". +# +# + +use File::Basename; +use Getopt::Std; + +# +# usage() +# +# Description: +# This routine prints out the proper command line usage for this program +# +# Input(s): +# status - Flag determining what usage information will be printed and what +# the exit status of the program will be after the information is +# printed. +# +# Output(s): +# N/A +# +# Returns: +# This subroutine does not return. +# + +sub usage { + my($status); + $status = $_[0]; + + printf("Usage: %s [-hvV] \n", + $program); + + if ($status != 0) { + printf("Try `%s -h' for more information.\n", $program); + } + + if ($status != 1) { + print(" -h Print out this message and exit.\n"); + print(" -v Verbose. Print out lots of ELF information.\n"); + print(" -V Print out version information and exit.\n"); + } + + exit($status); +} + +# +# version() +# +# Description: +# This routine prints out program version information +# +# Input(s): +# N/A +# +# Output(s): +# N/A +# +# Returns: +# This subroutine does not return. +# + +sub version { + print("mkirimg Version 1.1.0\n"); + print("Copyright (c) 1998-1999 TiVo, Inc.\n"); + print("Copyright (c) 1999 Grant Erickson \n"); + + exit (0); +} + +# +# file_check() +# +# Description: +# This routine checks an input file to ensure that it exists, is a +# regular file, and is readable. +# +# Input(s): +# file - Input file to be checked. +# +# Output(s): +# N/A +# +# Returns: +# 0 if the file exists, is a regular file, and is readable, otherwise -1. +# + +sub file_check { + my($file); + $file = $_[0]; + + if (!(-e $file)) { + printf("The file \"%s\" does not exist.\n", $file); + return (-1); + } elsif (!(-f $file)) { + printf("The file \"%s\" is not a regular file.\n", $file); + return (-1); + } elsif (!(-r $file)) { + printf("The file \"%s\" is not readable.\n", $file); + return (-1); + } + + return (0); +} + +# +# decode_options() +# +# Description: +# This routine steps through the command-line arguments, parsing out +# recognzied options. +# +# Input(s): +# N/A +# +# Output(s): +# N/A +# +# Returns: +# N/A +# + +sub decode_options { + + if (!getopts("hvV")) { + usage(1); + } + + if ($opt_h) { + usage(0); + } + + if ($opt_V) { + version(); + exit (0); + } + + if ($opt_v) { + $verbose = 1; + } + + if (!($ElfFile = shift(@ARGV))) { + usage(1); + } + + if (!($OutputFile = shift(@ARGV))) { + usage (1); + } + + if (!($IrFile = shift(@ARGV))) { + usage (1); + } + + if (file_check($ElfFile)) { + exit(1); + } + + if (file_check($IrFile)) { + exit(1); + } +} + +# +# ELF file and section header field numbers +# + +require '../utils/elf.pl'; + +# +# Main program body +# + +{ + $program = basename($0); + decode_options(); + + open(ELF, "<$ElfFile") || die "Cannot open input file"; + open(OUTPUT, ">$OutputFile") || die "Cannot open output file"; + open(IR, "$IrFile") || die "Cannot open input file"; + + $ElfFilesize = (-s $ElfFile); + + if (read(ELF, $ibuf, $ElfFilesize) != $ElfFilesize) { + print("Failed to read ELF input file!\n"); + exit(1); + } + + if (read(IR, $irbuf, 8) != 8) { + print("Failed to read Ir input file!\n"); + exit(1); + } + + # + # Parse ELF header + # + + @eh = unpack("a16n2N5n6", $ibuf); + + # + # Make sure this is actually a PowerPC ELF file. + # + + if (substr($eh[$e_ident], 0, 4) ne "\177ELF") { + printf("The file \"%s\" is not an ELF file.\n", $ElfFile); + exit (1); + } elsif ($eh[$e_machine] != 20) { + printf("The file \"%s\" is not a PowerPC ELF file.\n", $ElfFile); + exit (1); + } + + # + # Find the section header for the string table. + # + + $strtable_section_offset = $eh[$e_shoff] + + + $eh[$e_shstrndx] * $eh[$e_shentsize]; + + if ($verbose) { + printf("String table section header offset: 0x%x\n", + $strtable_section_offset); + } + + # + # Find the start of the string table. + # + + @strh = unpack("N10", substr($ibuf, $strtable_section_offset, + $eh[$e_shentsize])); + + if ($verbose) { + printf("Section name strings start at: 0x%x, %d bytes.\n", + $strh[$sh_offset], $strh[$sh_size]); + } + + $names = substr($ibuf, $strh[$sh_offset], $strh[$sh_size]); + + # Grab each section header and find '.data', 'image', and + # 'initrd' sections in particular. + + $off = $eh[$e_shoff]; + $imageFound = 0; + $initrdFound = 0; + + for($i = 0; $i < $eh[$e_shnum]; $i++, $off += $eh[$e_shentsize]) { + @sh = unpack("N10", substr($ibuf, $off, $eh[$e_shentsize])); + + # Take the first section name from the array returned by split. + + ($name) = split(/\000/, substr($names, $sh[$sh_name])); + + # Attempt to find the .data, image, and initrd sections + + if ($name =~ /^\image$/) { + ($image_addr, $image_offset, $image_size) = + ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]); + $imageFound = 1; + + } elsif ($name =~ /^\initrd$/) { + ($initrd_addr, $initrd_offset, $initrd_size) = + ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]); + $initrdFound = 1; + + } elsif ($name =~ /^\.data$/) { + ($data_addr, $data_offset, $data_size) = + ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]); + + } elsif ($name =~ /^\.bss$/) { + ($bss_addr, $bss_offset, $bss_size) = + ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]); + + } + } + + if ($verbose) { + printf("Data section - Address: 0x%08x, Size: 0x%08x, File Offset 0x%08x\n", + $data_addr, $data_size, $data_offset); + printf("Bss section - Address: 0x%08x, Size: 0x%08x, File Offset 0x%08x\n", + $bss_addr, $bss_size, $bss_offset); + } + + if ($verbose) { + if ($imageFound) { + printf("Image section - Address: 0x%08x, Size: 0x%08x\n", + $image_addr, $image_size); + } else { + printf("Image section not found in file: $ElfFile\n"); + } + + if ($initrdFound) { + printf("Initrd section - Address: 0x%08x, Size: 0x%08x\n", + $initrd_addr, $initrd_size); + } else { + printf("Initrd section not found in file: $ElfFile\n"); + } + } + + # get file offset of irSectStart + + $irSectStartoffset = hex ($irbuf); + + if ($verbose) { + printf("irSectStartOffset Address: 0x%08x\n", $irSectStartoffset); + } + + # get the offset of global variables + + $initialOffset = ($irSectStartoffset - $data_addr) + $data_offset + 4; + + # write modified values to OUTPUT file + + syswrite(OUTPUT, $ibuf, $initialOffset); + + if ($imageFound) { + $testN = pack ("N2", $bss_addr + $bss_size, $image_size); + syswrite(OUTPUT, $testN, length($testN)); + printf("Updated symbol \"imageSect_start\" to 0x%08x\n", + $bss_addr + $bss_size); + printf("Updated symbol \"imageSect_size\" to 0x%08x\n", $image_size); + } else { + syswrite(OUTPUT, $ibuf, 8, $initialOffset); + } + + if ($initrdFound) { + $testN = pack ("N2", $bss_addr + $bss_size + $image_size, $initrd_size); + syswrite(OUTPUT, $testN, length($testN)); + printf("Updated symbol \"initrdSect_start\" to 0x%08x\n", + $bss_addr + $bss_size + $image_size); + printf("Updated symbol \"initrdSect_size\" to 0x%08x\n", $initrd_size); + } else { + syswrite(OUTPUT, $ibuf,8, $initialOffset + 8); + } + + syswrite(OUTPUT, $ibuf, $ElfFilesize - ($initialOffset + 16), + $initialOffset + 16); + + # + # Clean-up and leave + # + + close (ELF); + close (OUTPUT); + close (IR); + + exit (0); +} + diff -Nru a/arch/ppc/boot/utils/mknote.c b/arch/ppc/boot/utils/mknote.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/utils/mknote.c Wed May 16 06:00:23 2001 @@ -0,0 +1,43 @@ +/* + * Copyright (C) Cort Dougan 1999. + * + * 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. + * + * Generate a note section as per the CHRP specification. + * + */ + +#include + +#define PL(x) printf("%c%c%c%c", ((x)>>24)&0xff, ((x)>>16)&0xff, ((x)>>8)&0xff, (x)&0xff ); + +int main(void) +{ +/* header */ + /* namesz */ + PL(strlen("PowerPC")+1); + /* descrsz */ + PL(6*4); + /* type */ + PL(0x1275); + /* name */ + printf("PowerPC"); printf("%c", 0); + +/* descriptor */ + /* real-mode */ + PL(0xffffffff); + /* real-base */ + PL(0x00c00000); + /* real-size */ + PL(0xffffffff); + /* virt-base */ + PL(0xffffffff); + /* virt-size */ + PL(0xffffffff); + /* load-base */ + PL(0x4000); + return 0; +} diff -Nru a/arch/ppc/boot/utils/mkpmon.c b/arch/ppc/boot/utils/mkpmon.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/utils/mkpmon.c Wed May 16 06:00:33 2001 @@ -0,0 +1,49 @@ +/* + * arch/ppc/pmonboot/mkpmon.c + * + * Munger code to create PMON bootable images + * + * Author: Matt Porter + * + * Copyright 2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +int main(int argc, char *argv[]) +{ + int file; + unsigned long image_address = 0, image_size = 0, file_size = 0; + + if ( argc != 4 ) + { + fprintf(stderr, "usage: %s \n",argv[0]); + exit(-1); + } + + image_address = strtoul(argv[1], NULL, 16); + image_size = strtoul(argv[2], NULL, 16); + file_size = __cpu_to_be32(image_address + image_size - 0x10000); + + file = open(argv[3], O_RDWR); + + /* Seek to the program header file size field */ + lseek(file, 0x44, SEEK_SET); + + /* Write out new file size */ + write(file, &file_size, sizeof(file_size)); + + return 0; +} diff -Nru a/arch/ppc/boot/utils/mkprep.c b/arch/ppc/boot/utils/mkprep.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/utils/mkprep.c Wed May 16 06:00:18 2001 @@ -0,0 +1,289 @@ +/* + * Makes a prep bootable image which can be dd'd onto + * a disk device to make a bootdisk. Will take + * as input a elf executable, strip off the header + * and write out a boot image as: + * 1) default - strips elf header + * suitable as a network boot image + * 2) -pbp - strips elf header and writes out prep boot partition image + * cat or dd onto disk for booting + * 3) -asm - strips elf header and writes out as asm data + * useful for generating data for a compressed image + * -- Cort + * + * Modified for x86 hosted builds by Matt Porter + */ + +#include +#include +#include +#include +#include +#include + +#define cpu_to_le32(x) le32_to_cpu((x)) +unsigned long le32_to_cpu(unsigned long x) +{ + return (((x & 0x000000ffU) << 24) | + ((x & 0x0000ff00U) << 8) | + ((x & 0x00ff0000U) >> 8) | + ((x & 0xff000000U) >> 24)); +} + + +#define cpu_to_le16(x) le16_to_cpu((x)) +unsigned short le16_to_cpu(unsigned short x) +{ + return (((x & 0x00ff) << 8) | + ((x & 0xff00) >> 8)); +} + +#define cpu_to_be32(x) (x) +#define be32_to_cpu(x) (x) +#define cpu_to_be16(x) (x) +#define be16_to_cpu(x) (x) + +/* size of read buffer */ +#define SIZE 0x1000 + + +typedef unsigned long dword_t; +typedef unsigned short word_t; +typedef unsigned char byte_t; +typedef byte_t block_t[512]; +typedef byte_t page_t[4096]; + + +/* + * Partition table entry + * - from the PReP spec + */ +typedef struct partition_entry { + byte_t boot_indicator; + byte_t starting_head; + byte_t starting_sector; + byte_t starting_cylinder; + + byte_t system_indicator; + byte_t ending_head; + byte_t ending_sector; + byte_t ending_cylinder; + + dword_t beginning_sector; + dword_t number_of_sectors; +} partition_entry_t; + +#define BootActive 0x80 +#define SystemPrep 0x41 + +void copy_image(int , int); +void write_prep_partition(int , int ); +void write_asm_data( int in, int out ); + +unsigned int elfhdr_size = 65536; + +int main(int argc, char *argv[]) +{ + int in_fd, out_fd; + int argptr = 1; + unsigned int prep = 0; + unsigned int asmoutput = 0; + + if ( (argc < 3) || (argc > 4) ) + { + fprintf(stderr, "usage: %s [-pbp] [-asm] \n",argv[0]); + exit(-1); + } + + /* needs to handle args more elegantly -- but this is a small/simple program */ + + /* check for -pbp */ + if ( !strcmp( argv[argptr], "-pbp" ) ) + { + prep = 1; + argptr++; + } + + /* check for -asm */ + if ( !strcmp( argv[argptr], "-asm" ) ) + { + asmoutput = 1; + argptr++; + } + + /* input file */ + if ( !strcmp( argv[argptr], "-" ) ) + in_fd = 0; /* stdin */ + else + if ((in_fd = open( argv[argptr] , 0)) < 0) + exit(-1); + argptr++; + + /* output file */ + if ( !strcmp( argv[argptr], "-" ) ) + out_fd = 1; /* stdout */ + else + if ((out_fd = creat( argv[argptr] , 0755)) < 0) + exit(-1); + argptr++; + + /* skip elf header in input file */ + /*if ( !prep )*/ + lseek(in_fd, elfhdr_size, SEEK_SET); + + /* write prep partition if necessary */ + if ( prep ) + write_prep_partition( in_fd, out_fd ); + + /* write input image to bootimage */ + if ( asmoutput ) + write_asm_data( in_fd, out_fd ); + else + copy_image(in_fd, out_fd); + + return 0; +} + +void write_prep_partition(int in, int out) +{ + unsigned char block[512]; + partition_entry_t *pe = (partition_entry_t *)&block[0x1BE]; + dword_t *entry = (dword_t *)&block[0]; + dword_t *length = (dword_t *)&block[sizeof(long)]; + struct stat info; + + if (fstat(in, &info) < 0) + { + fprintf(stderr,"info failed\n"); + exit(-1); + } + + bzero( block, sizeof block ); + + /* set entry point and boot image size skipping over elf header */ +#ifdef __i386__ + *entry = 0x400/*+65536*/; + *length = info.st_size-elfhdr_size+0x400; +#else + *entry = cpu_to_le32(0x400/*+65536*/); + *length = cpu_to_le32(info.st_size-elfhdr_size+0x400); +#endif /* __i386__ */ + + /* sets magic number for msdos partition (used by linux) */ + block[510] = 0x55; + block[511] = 0xAA; + + /* + * Build a "PReP" partition table entry in the boot record + * - "PReP" may only look at the system_indicator + */ + pe->boot_indicator = BootActive; + pe->system_indicator = SystemPrep; + /* + * The first block of the diskette is used by this "boot record" which + * actually contains the partition table. (The first block of the + * partition contains the boot image, but I digress...) We'll set up + * one partition on the diskette and it shall contain the rest of the + * diskette. + */ + pe->starting_head = 0; /* zero-based */ + pe->starting_sector = 2; /* one-based */ + pe->starting_cylinder = 0; /* zero-based */ + pe->ending_head = 1; /* assumes two heads */ + pe->ending_sector = 18; /* assumes 18 sectors/track */ + pe->ending_cylinder = 79; /* assumes 80 cylinders/diskette */ + + /* + * The "PReP" software ignores the above fields and just looks at + * the next two. + * - size of the diskette is (assumed to be) + * (2 tracks/cylinder)(18 sectors/tracks)(80 cylinders/diskette) + * - unlike the above sector numbers, the beginning sector is zero-based! + */ +#if 0 + pe->beginning_sector = cpu_to_le32(1); +#else + /* This has to be 0 on the PowerStack? */ +#ifdef __i386__ + pe->beginning_sector = 0; +#else + pe->beginning_sector = cpu_to_le32(0); +#endif /* __i386__ */ +#endif + +#ifdef __i386__ + pe->number_of_sectors = 2*18*80-1; +#else + pe->number_of_sectors = cpu_to_le32(2*18*80-1); +#endif /* __i386__ */ + + write( out, block, sizeof(block) ); + write( out, entry, sizeof(*entry) ); + write( out, length, sizeof(*length) ); + /* set file position to 2nd sector where image will be written */ + lseek( out, 0x400, SEEK_SET ); +} + + + +void +copy_image(int in, int out) +{ + char buf[SIZE]; + int n; + + while ( (n = read(in, buf, SIZE)) > 0 ) + write(out, buf, n); +} + + +void +write_asm_data( int in, int out ) +{ + int i, cnt, pos, len; + unsigned int cksum, val; + unsigned char *lp; + unsigned char buf[SIZE]; + unsigned char str[256]; + + write( out, "\t.data\n\t.globl input_data\ninput_data:\n", + strlen( "\t.data\n\t.globl input_data\ninput_data:\n" ) ); + pos = 0; + cksum = 0; + while ((len = read(in, buf, sizeof(buf))) > 0) + { + cnt = 0; + lp = (unsigned char *)buf; + len = (len + 3) & ~3; /* Round up to longwords */ + for (i = 0; i < len; i += 4) + { + if (cnt == 0) + { + write( out, "\t.long\t", strlen( "\t.long\t" ) ); + } + sprintf( str, "0x%02X%02X%02X%02X", lp[0], lp[1], lp[2], lp[3]); + write( out, str, strlen(str) ); + val = *(unsigned long *)lp; + cksum ^= val; + lp += 4; + if (++cnt == 4) + { + cnt = 0; + sprintf( str, " # %x \n", pos+i-12); + write( out, str, strlen(str) ); + } else + { + write( out, ",", 1 ); + } + } + if (cnt) + { + write( out, "0\n", 2 ); + } + pos += len; + } + sprintf(str, "\t.globl input_len\ninput_len:\t.long\t0x%x\n", pos); + write( out, str, strlen(str) ); + + fprintf(stderr, "cksum = %x\n", cksum); +} diff -Nru a/arch/ppc/boot/utils/mksimage.c b/arch/ppc/boot/utils/mksimage.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/utils/mksimage.c Wed May 16 06:00:34 2001 @@ -0,0 +1,124 @@ +/* + * + * + * + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + + +#define SIZE 1024 +#define BLOCK_ALIGN(x) (((x)+SIZE-1)&(~(SIZE-1))) + +static void +die(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + vfprintf(stderr, fmt, args); + fputc('\n', stderr); + exit(1); +} + +static void +usage(void) +{ + printf("Usage: mkbinimg -o \n"); + exit(1); +} + +static int +copy_blocks(int ifd, int ofd, unsigned long *offset, unsigned long *size) +{ + off_t cur; + int amt; + unsigned long len = 0; + char buffer[SIZE]; + + cur = lseek(ofd, 0, SEEK_CUR); + + if (cur % SIZE) { + cur = BLOCK_ALIGN(cur); + cur = lseek(ofd, cur, SEEK_SET); + } + + *offset = (unsigned long) cur; + while((amt = read(ifd, buffer, SIZE)) > 0) { + write(ofd, buffer, amt); + len += amt; + } + *size = len; + return 0; +} + + +int +main(int argc, char *argv[]) +{ + char *kernel, *loader, *rdimage = NULL; + unsigned long ld_off, kern_off, rd_off; + unsigned long ld_size, kern_size, rd_size; + int fd, ofd, len; + char buffer[500]; + + if (argc < 5 && !strcmp(argv[argc-2], "-o")) + usage(); + + if (argc > 5) + rdimage = argv[3]; + + kernel = argv[2]; + loader = argv[1]; + + ofd = open(argv[argc-1], (O_RDWR|O_CREAT), 0755); + if (ofd < 0) { + die("can't open %s: %s", argv[5], strerror(errno)); + } + + ld_off = kern_off = rd_off = 0; + ld_size = kern_size = rd_size = 0; + memset(buffer, 0, 500); + len = 0; + + fd = open(loader, O_RDONLY); + if (fd < 0) + die("can't open loader: %s", strerror(errno)); + + copy_blocks(fd, ofd, &ld_off, &ld_size); + len = sprintf(buffer, "bootloader: %x %x\n", ld_off, ld_size); + close(fd); + + fd = open(kernel, O_RDONLY); + if (fd < 0) + die("can't open kernel: %s", strerror(errno)); + + copy_blocks(fd, ofd, &kern_off, &kern_size); + len += sprintf(buffer+len, "zimage: %x %x\n", kern_off, kern_size); + close(fd); + + if (rdimage) { + fd = open(rdimage, O_RDONLY); + if (fd < 0) + die("can't get ramdisk: %s", strerror(errno)); + + copy_blocks(fd, ofd, &rd_off, &rd_size); + close(fd); + } + + len += sprintf(buffer+len, "initrd: %x %x", rd_off, rd_size); + + close(ofd); + + printf("%s\n", buffer); + + return 0; +} + diff -Nru a/arch/ppc/boot/utils/offset b/arch/ppc/boot/utils/offset --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/utils/offset Wed May 16 06:00:19 2001 @@ -0,0 +1,4 @@ +#!/bin/bash + +OFFSET=`$1 -h $2 | grep $3 | grep -v zvmlinux| awk '{print $6}'` +echo "0x"$OFFSET diff -Nru a/arch/ppc/boot/utils/piggyback.c b/arch/ppc/boot/utils/piggyback.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/utils/piggyback.c Wed May 16 06:00:21 2001 @@ -0,0 +1,66 @@ +#include +#include + +extern long ce_exec_config[]; + +int main(int argc, char *argv[]) +{ + int i, cnt, pos, len; + unsigned int cksum, val; + unsigned char *lp; + unsigned char buf[8192]; + if (argc != 2) + { + fprintf(stderr, "usage: %s name out-file\n", + argv[0]); + exit(1); + } + fprintf(stdout, "#\n"); + fprintf(stdout, "# Miscellaneous data structures:\n"); + fprintf(stdout, "# WARNING - this file is automatically generated!\n"); + fprintf(stdout, "#\n"); + fprintf(stdout, "\n"); + fprintf(stdout, "\t.data\n"); + fprintf(stdout, "\t.globl %s_data\n", argv[1]); + fprintf(stdout, "%s_data:\n", argv[1]); + pos = 0; + cksum = 0; + while ((len = read(0, buf, sizeof(buf))) > 0) + { + cnt = 0; + lp = (unsigned char *)buf; + len = (len + 3) & ~3; /* Round up to longwords */ + for (i = 0; i < len; i += 4) + { + if (cnt == 0) + { + fprintf(stdout, "\t.long\t"); + } + fprintf(stdout, "0x%02X%02X%02X%02X", lp[0], lp[1], lp[2], lp[3]); + val = *(unsigned long *)lp; + cksum ^= val; + lp += 4; + if (++cnt == 4) + { + cnt = 0; + fprintf(stdout, " # %x \n", pos+i-12); + fflush(stdout); + } else + { + fprintf(stdout, ","); + } + } + if (cnt) + { + fprintf(stdout, "0\n"); + } + pos += len; + } + fprintf(stdout, "\t.globl %s_len\n", argv[1]); + fprintf(stdout, "%s_len:\t.long\t0x%x\n", argv[1], pos); + fflush(stdout); + fclose(stdout); + fprintf(stderr, "cksum = %x\n", cksum); + exit(0); +} + diff -Nru a/arch/ppc/boot/utils/sioffset b/arch/ppc/boot/utils/sioffset --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/utils/sioffset Wed May 16 06:00:25 2001 @@ -0,0 +1,4 @@ +#!/bin/bash + +OFFSET=`grep $1 sImage.map | awk '{print $2}'` +echo "0x"$OFFSET diff -Nru a/arch/ppc/boot/utils/sisize b/arch/ppc/boot/utils/sisize --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/utils/sisize Wed May 16 06:00:33 2001 @@ -0,0 +1,4 @@ +#!/bin/bash + +OFFSET=`grep $1 sImage.map | awk '{print $3}'` +echo "0x"$OFFSET diff -Nru a/arch/ppc/boot/utils/size b/arch/ppc/boot/utils/size --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/boot/utils/size Wed May 16 06:00:25 2001 @@ -0,0 +1,4 @@ +#!/bin/bash + +OFFSET=`$1 -h $2 | grep $3 | grep -v zvmlinux | awk '{print $3}'` +echo "0x"$OFFSET diff -Nru a/arch/ppc/boot/vreset.c b/arch/ppc/boot/vreset.c --- a/arch/ppc/boot/vreset.c Wed May 16 06:00:22 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,838 +0,0 @@ -/* - * vreset.c - * - * Initialize the VGA control registers to 80x25 text mode. - * - * Adapted from a program by: - * Steve Sellgren - * San Francisco Indigo Company - * sfindigo!sellgren@uunet.uu.net - * - * Original concept by: - * Gary Thomas - * Adapted for Moto boxes by: - * Pat Kane & Mark Scott, 1996 - * Adapted for IBM portables by: - * Takeshi Ishimoto - * Multi-console support: - * Terje Malmedal - */ - -#include "iso_font.h" - -extern char *vidmem; -extern int lines, cols; - -static void mdelay(int ms) -{ - for (; ms > 0; --ms) - udelay(1000); -} - -/* - * VGA Register - */ -struct VgaRegs -{ - unsigned short io_port; - unsigned char io_index; - unsigned char io_value; -}; - -/* - * Default console text mode registers used to reset - * graphics adapter. - */ -#define NREGS 54 -#define ENDMK 0xFFFF /* End marker */ - -#define S3Vendor 0x5333 -#define CirrusVendor 0x1013 -#define DiamondVendor 0x100E -#define MatroxVendor 0x102B -#define ParadiseVendor 0x101C - -struct VgaRegs GenVgaTextRegs[NREGS+1] = { -/* port index value */ - /* SR Regs */ - 0x3c4, 0x1, 0x0, - 0x3c4, 0x2, 0x3, - 0x3c4, 0x3, 0x0, - 0x3c4, 0x4, 0x2, - /* CR Regs */ - 0x3d4, 0x0, 0x5f, - 0x3d4, 0x1, 0x4f, - 0x3d4, 0x2, 0x50, - 0x3d4, 0x3, 0x82, - 0x3d4, 0x4, 0x55, - 0x3d4, 0x5, 0x81, - 0x3d4, 0x6, 0xbf, - 0x3d4, 0x7, 0x1f, - 0x3d4, 0x8, 0x00, - 0x3d4, 0x9, 0x4f, - 0x3d4, 0xa, 0x0d, - 0x3d4, 0xb, 0x0e, - 0x3d4, 0xc, 0x00, - 0x3d4, 0xd, 0x00, - 0x3d4, 0xe, 0x00, - 0x3d4, 0xf, 0x00, - 0x3d4, 0x10, 0x9c, - 0x3d4, 0x11, 0x8e, - 0x3d4, 0x12, 0x8f, - 0x3d4, 0x13, 0x28, - 0x3d4, 0x14, 0x1f, - 0x3d4, 0x15, 0x96, - 0x3d4, 0x16, 0xb9, - 0x3d4, 0x17, 0xa3, - /* GR Regs */ - 0x3ce, 0x0, 0x0, - 0x3ce, 0x1, 0x0, - 0x3ce, 0x2, 0x0, - 0x3ce, 0x3, 0x0, - 0x3ce, 0x4, 0x0, - 0x3ce, 0x5, 0x10, - 0x3ce, 0x6, 0xe, - 0x3ce, 0x7, 0x0, - 0x3ce, 0x8, 0xff, - ENDMK -}; - -struct VgaRegs S3TextRegs[NREGS+1] = { -/* port index value */ - /* SR Regs */ - 0x3c4, 0x1, 0x0, - 0x3c4, 0x2, 0x3, - 0x3c4, 0x3, 0x0, - 0x3c4, 0x4, 0x2, - /* CR Regs */ - 0x3d4, 0x0, 0x5f, - 0x3d4, 0x1, 0x4f, - 0x3d4, 0x2, 0x50, - 0x3d4, 0x3, 0x82, - 0x3d4, 0x4, 0x55, - 0x3d4, 0x5, 0x81, - 0x3d4, 0x6, 0xbf, - 0x3d4, 0x7, 0x1f, - 0x3d4, 0x8, 0x00, - 0x3d4, 0x9, 0x4f, - 0x3d4, 0xa, 0x0d, - 0x3d4, 0xb, 0x0e, - 0x3d4, 0xc, 0x00, - 0x3d4, 0xd, 0x00, - 0x3d4, 0xe, 0x00, - 0x3d4, 0xf, 0x00, - 0x3d4, 0x10, 0x9c, - 0x3d4, 0x11, 0x8e, - 0x3d4, 0x12, 0x8f, - 0x3d4, 0x13, 0x28, - 0x3d4, 0x14, 0x1f, - 0x3d4, 0x15, 0x96, - 0x3d4, 0x16, 0xb9, - 0x3d4, 0x17, 0xa3, - /* GR Regs */ - 0x3ce, 0x0, 0x0, - 0x3ce, 0x1, 0x0, - 0x3ce, 0x2, 0x0, - 0x3ce, 0x3, 0x0, - 0x3ce, 0x4, 0x0, - 0x3ce, 0x5, 0x10, - 0x3ce, 0x6, 0xe, - 0x3ce, 0x7, 0x0, - 0x3ce, 0x8, 0xff, - ENDMK -}; - -struct RGBColors -{ - unsigned char r, g, b; -}; - -/* - * Default console text mode color table. - * These values were obtained by booting Linux with - * text mode firmware & then dumping the registers. - */ -struct RGBColors TextCLUT[256] = -{ - /* red green blue */ - 0x0, 0x0, 0x0, - 0x0, 0x0, 0x2a, - 0x0, 0x2a, 0x0, - 0x0, 0x2a, 0x2a, - 0x2a, 0x0, 0x0, - 0x2a, 0x0, 0x2a, - 0x2a, 0x2a, 0x0, - 0x2a, 0x2a, 0x2a, - 0x0, 0x0, 0x15, - 0x0, 0x0, 0x3f, - 0x0, 0x2a, 0x15, - 0x0, 0x2a, 0x3f, - 0x2a, 0x0, 0x15, - 0x2a, 0x0, 0x3f, - 0x2a, 0x2a, 0x15, - 0x2a, 0x2a, 0x3f, - 0x0, 0x15, 0x0, - 0x0, 0x15, 0x2a, - 0x0, 0x3f, 0x0, - 0x0, 0x3f, 0x2a, - 0x2a, 0x15, 0x0, - 0x2a, 0x15, 0x2a, - 0x2a, 0x3f, 0x0, - 0x2a, 0x3f, 0x2a, - 0x0, 0x15, 0x15, - 0x0, 0x15, 0x3f, - 0x0, 0x3f, 0x15, - 0x0, 0x3f, 0x3f, - 0x2a, 0x15, 0x15, - 0x2a, 0x15, 0x3f, - 0x2a, 0x3f, 0x15, - 0x2a, 0x3f, 0x3f, - 0x15, 0x0, 0x0, - 0x15, 0x0, 0x2a, - 0x15, 0x2a, 0x0, - 0x15, 0x2a, 0x2a, - 0x3f, 0x0, 0x0, - 0x3f, 0x0, 0x2a, - 0x3f, 0x2a, 0x0, - 0x3f, 0x2a, 0x2a, - 0x15, 0x0, 0x15, - 0x15, 0x0, 0x3f, - 0x15, 0x2a, 0x15, - 0x15, 0x2a, 0x3f, - 0x3f, 0x0, 0x15, - 0x3f, 0x0, 0x3f, - 0x3f, 0x2a, 0x15, - 0x3f, 0x2a, 0x3f, - 0x15, 0x15, 0x0, - 0x15, 0x15, 0x2a, - 0x15, 0x3f, 0x0, - 0x15, 0x3f, 0x2a, - 0x3f, 0x15, 0x0, - 0x3f, 0x15, 0x2a, - 0x3f, 0x3f, 0x0, - 0x3f, 0x3f, 0x2a, - 0x15, 0x15, 0x15, - 0x15, 0x15, 0x3f, - 0x15, 0x3f, 0x15, - 0x15, 0x3f, 0x3f, - 0x3f, 0x15, 0x15, - 0x3f, 0x15, 0x3f, - 0x3f, 0x3f, 0x15, - 0x3f, 0x3f, 0x3f, - 0x39, 0xc, 0x5, - 0x15, 0x2c, 0xf, - 0x26, 0x10, 0x3d, - 0x29, 0x29, 0x38, - 0x4, 0x1a, 0xe, - 0x2, 0x1e, 0x3a, - 0x3c, 0x25, 0x33, - 0x3c, 0xc, 0x2c, - 0x3f, 0x3, 0x2b, - 0x1c, 0x9, 0x13, - 0x25, 0x2a, 0x35, - 0x1e, 0xa, 0x38, - 0x24, 0x8, 0x3, - 0x3, 0xe, 0x36, - 0xc, 0x6, 0x2a, - 0x26, 0x3, 0x32, - 0x5, 0x2f, 0x33, - 0x3c, 0x35, 0x2f, - 0x2d, 0x26, 0x3e, - 0xd, 0xa, 0x10, - 0x25, 0x3c, 0x11, - 0xd, 0x4, 0x2e, - 0x5, 0x19, 0x3e, - 0xc, 0x13, 0x34, - 0x2b, 0x6, 0x24, - 0x4, 0x3, 0xd, - 0x2f, 0x3c, 0xc, - 0x2a, 0x37, 0x1f, - 0xf, 0x12, 0x38, - 0x38, 0xe, 0x2a, - 0x12, 0x2f, 0x19, - 0x29, 0x2e, 0x31, - 0x25, 0x13, 0x3e, - 0x33, 0x3e, 0x33, - 0x1d, 0x2c, 0x25, - 0x15, 0x15, 0x5, - 0x32, 0x25, 0x39, - 0x1a, 0x7, 0x1f, - 0x13, 0xe, 0x1d, - 0x36, 0x17, 0x34, - 0xf, 0x15, 0x23, - 0x2, 0x35, 0xd, - 0x15, 0x3f, 0xc, - 0x14, 0x2f, 0xf, - 0x19, 0x21, 0x3e, - 0x27, 0x11, 0x2f, - 0x38, 0x3f, 0x3c, - 0x36, 0x2d, 0x15, - 0x16, 0x17, 0x2, - 0x1, 0xa, 0x3d, - 0x1b, 0x11, 0x3f, - 0x21, 0x3c, 0xd, - 0x1a, 0x39, 0x3d, - 0x8, 0xe, 0xe, - 0x22, 0x21, 0x23, - 0x1e, 0x30, 0x5, - 0x1f, 0x22, 0x3d, - 0x1e, 0x2f, 0xa, - 0x0, 0x1c, 0xe, - 0x0, 0x1c, 0x15, - 0x0, 0x1c, 0x1c, - 0x0, 0x15, 0x1c, - 0x0, 0xe, 0x1c, - 0x0, 0x7, 0x1c, - 0xe, 0xe, 0x1c, - 0x11, 0xe, 0x1c, - 0x15, 0xe, 0x1c, - 0x18, 0xe, 0x1c, - 0x1c, 0xe, 0x1c, - 0x1c, 0xe, 0x18, - 0x1c, 0xe, 0x15, - 0x1c, 0xe, 0x11, - 0x1c, 0xe, 0xe, - 0x1c, 0x11, 0xe, - 0x1c, 0x15, 0xe, - 0x1c, 0x18, 0xe, - 0x1c, 0x1c, 0xe, - 0x18, 0x1c, 0xe, - 0x15, 0x1c, 0xe, - 0x11, 0x1c, 0xe, - 0xe, 0x1c, 0xe, - 0xe, 0x1c, 0x11, - 0xe, 0x1c, 0x15, - 0xe, 0x1c, 0x18, - 0xe, 0x1c, 0x1c, - 0xe, 0x18, 0x1c, - 0xe, 0x15, 0x1c, - 0xe, 0x11, 0x1c, - 0x14, 0x14, 0x1c, - 0x16, 0x14, 0x1c, - 0x18, 0x14, 0x1c, - 0x1a, 0x14, 0x1c, - 0x1c, 0x14, 0x1c, - 0x1c, 0x14, 0x1a, - 0x1c, 0x14, 0x18, - 0x1c, 0x14, 0x16, - 0x1c, 0x14, 0x14, - 0x1c, 0x16, 0x14, - 0x1c, 0x18, 0x14, - 0x1c, 0x1a, 0x14, - 0x1c, 0x1c, 0x14, - 0x1a, 0x1c, 0x14, - 0x18, 0x1c, 0x14, - 0x16, 0x1c, 0x14, - 0x14, 0x1c, 0x14, - 0x14, 0x1c, 0x16, - 0x14, 0x1c, 0x18, - 0x14, 0x1c, 0x1a, - 0x14, 0x1c, 0x1c, - 0x14, 0x1a, 0x1c, - 0x14, 0x18, 0x1c, - 0x14, 0x16, 0x1c, - 0x0, 0x0, 0x10, - 0x4, 0x0, 0x10, - 0x8, 0x0, 0x10, - 0xc, 0x0, 0x10, - 0x10, 0x0, 0x10, - 0x10, 0x0, 0xc, - 0x10, 0x0, 0x8, - 0x10, 0x0, 0x4, - 0x10, 0x0, 0x0, - 0x10, 0x4, 0x0, - 0x10, 0x8, 0x0, - 0x10, 0xc, 0x0, - 0x10, 0x10, 0x0, - 0xc, 0x10, 0x0, - 0x8, 0x10, 0x0, - 0x4, 0x10, 0x0, - 0x0, 0x10, 0x0, - 0x0, 0x10, 0x4, - 0x0, 0x10, 0x8, - 0x0, 0x10, 0xc, - 0x0, 0x10, 0x10, - 0x0, 0xc, 0x10, - 0x0, 0x8, 0x10, - 0x0, 0x4, 0x10, - 0x8, 0x8, 0x10, - 0xa, 0x8, 0x10, - 0xc, 0x8, 0x10, - 0xe, 0x8, 0x10, - 0x10, 0x8, 0x10, - 0x10, 0x8, 0xe, - 0x10, 0x8, 0xc, - 0x10, 0x8, 0xa, - 0x10, 0x8, 0x8, - 0x10, 0xa, 0x8, - 0x10, 0xc, 0x8, - 0x10, 0xe, 0x8, - 0x10, 0x10, 0x8, - 0xe, 0x10, 0x8, - 0xc, 0x10, 0x8, - 0xa, 0x10, 0x8, - 0x8, 0x10, 0x8, - 0x8, 0x10, 0xa, - 0x8, 0x10, 0xc, - 0x8, 0x10, 0xe, - 0x8, 0x10, 0x10, - 0x8, 0xe, 0x10, - 0x8, 0xc, 0x10, - 0x8, 0xa, 0x10, - 0xb, 0xb, 0x10, - 0xc, 0xb, 0x10, - 0xd, 0xb, 0x10, - 0xf, 0xb, 0x10, - 0x10, 0xb, 0x10, - 0x10, 0xb, 0xf, - 0x10, 0xb, 0xd, - 0x10, 0xb, 0xc, - 0x10, 0xb, 0xb, - 0x10, 0xc, 0xb, - 0x10, 0xd, 0xb, - 0x10, 0xf, 0xb, - 0x10, 0x10, 0xb, - 0xf, 0x10, 0xb, - 0xd, 0x10, 0xb, - 0xc, 0x10, 0xb, - 0xb, 0x10, 0xb, - 0xb, 0x10, 0xc, - 0xb, 0x10, 0xd, - 0xb, 0x10, 0xf, - 0xb, 0x10, 0x10, - 0xb, 0xf, 0x10, - 0xb, 0xd, 0x10, - 0xb, 0xc, 0x10, - 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0 -}; - -unsigned char AC[21] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, - 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, - 0x0C, 0x00, 0x0F, 0x08, 0x00}; - -static int scanPCI(int start_slt); -static int PCIVendor(int); -static void printslots(void); -extern void puthex(unsigned long); -extern void puts(const char *); -static void unlockS3(void); - -static inline -outw(int port, unsigned short val) -{ - outb(port, val >> 8); - outb(port+1, val); -} - -#define PPC_601 1 - -vga_init(unsigned char *ISA_mem) -{ - int slot; - struct VgaRegs *VgaTextRegs; -#if 0 - if ((_get_PVR()>>16) == PPC_601) { - return(old_vga_init(ISA_mem)); - } -#endif - - /* See if VGA already in TEXT mode - exit if so! */ - outb(0x3CE, 0x06); - if ((inb(0x3CF) & 0x01) == 0){puts("VGA already in text mode\n"); return;} - - /* If no VGA responding in text mode, then we have some work to do... - */ - slot = -1; - while((slot = scanPCI(slot)) > -1) { /* find video card in use */ - unlockVideo(slot); /* enable I/O to card */ - VgaTextRegs = GenVgaTextRegs; - - switch (PCIVendor(slot)) { - default: - break; - case(S3Vendor): - unlockS3(); - VgaTextRegs = S3TextRegs; - break; - - case(CirrusVendor): - outw(0x3C4, 0x0612); /* unlock ext regs */ - outw(0x3C4, 0x0700); /* reset ext sequence mode */ - break; - - case(ParadiseVendor): /* IBM Portable 850 */ - outw(0x3ce, 0x0f05); /* unlock pardise registers */ - outw(0x3c4, 0x0648); - outw(0x3d4, 0x2985); - outw(0x3d4, 0x34a6); - outb(0x3ce, 0x0b); /* disable linear addressing */ - outb(0x3cf, inb(0x3cf) & ~0x30); - outw(0x3c4, 0x1400); - outb(0x3ce, 0x0e); /* disable 256 color mode */ - outb(0x3cf, inb(0x3cf) & ~0x01); - outb(0xd00, 0xff); /* enable auto-centering */ - if (!(inb(0xd01) & 0x03)) { - outb(0x3d4, 0x33); - outb(0x3d5, inb(0x3d5) & ~0x90); - outb(0x3d4, 0x32); - outb(0x3d5, inb(0x3d5) | 0x04); - outw(0x3d4, 0x0250); - outw(0x3d4, 0x07ba); - outw(0x3d4, 0x0900); - outw(0x3d4, 0x15e7); - outw(0x3d4, 0x2a95); - } - outw(0x3d4, 0x34a0); - break; - - #if 0 /* Untested - probably doesn't work */ - case(MatroxVendor): - case(DiamondVendor): - puts("VGA Chip Vendor ID: "); - puthex(PCIVendor(slot)); - puts("\n"); - mdelay(1000); - #endif - }; - - outw(0x3C4, 0x0120); /* disable video */ - setTextRegs(VgaTextRegs); /* initial register setup */ - setTextCLUT(0); /* load color lookup table */ - loadFont(ISA_mem); /* load font */ - setTextRegs(VgaTextRegs); /* reload registers */ - outw(0x3C4, 0x0100); /* re-enable video */ - clearVideoMemory(); - - if (PCIVendor(slot) == S3Vendor) { - outb(0x3c2, 0x63); /* MISC */ - } /* endif */ - - #ifdef DEBUG - printslots(); - mdelay(5000); - #endif - - mdelay(1000); /* give time for the video monitor to come up */ - } - return (1); /* 'CRT' I/O supported */ -} - -/* - * Write to VGA Attribute registers. - */ -writeAttr(index, data, videoOn) - unsigned char index; - unsigned char data; - unsigned char videoOn; /* video on flag */ -{ - unsigned char v; - v = inb(0x3da); /* reset attr. address toggle */ - if (videoOn) - outb(0x3c0, (index & 0x1F) | 0x20); - else - outb(0x3c0, (index & 0x1F)); - outb(0x3c0, data); -} - -setTextRegs(struct VgaRegs *svp) -{ - int i; - - /* - * saved settings - */ - while( svp->io_port != ENDMK ) { - outb(svp->io_port, svp->io_index); - outb(svp->io_port+1, svp->io_value); - svp++; - } - - outb(0x3c2, 0x67); /* MISC */ - outb(0x3c6, 0xff); /* MASK */ - - for ( i = 0; i < 0x10; i++) - writeAttr(i, AC[i], 0); /* pallete */ - writeAttr(0x10, 0x0c, 0); /* text mode */ - writeAttr(0x11, 0x00, 0); /* overscan color (border) */ - writeAttr(0x12, 0x0f, 0); /* plane enable */ - writeAttr(0x13, 0x08, 0); /* pixel panning */ - writeAttr(0x14, 0x00, 1); /* color select; video on */ -} - -setTextCLUT(int shift) -{ - int i; - - outb(0x3C6, 0xFF); - i = inb(0x3C7); - outb(0x3C8, 0); - i = inb(0x3C7); - - for ( i = 0; i < 256; i++) { - outb(0x3C9, TextCLUT[i].r << shift); - outb(0x3C9, TextCLUT[i].g << shift); - outb(0x3C9, TextCLUT[i].b << shift); - } -} - - -loadFont(unsigned char *ISA_mem) -{ - int i, j; - unsigned char *font_page = (unsigned char *) &ISA_mem[0xA0000]; - - outb(0x3C2, 0x67); - /* - * Load font - */ - i = inb(0x3DA); /* Reset Attr toggle */ - - outb(0x3C0,0x30); - outb(0x3C0, 0x01); /* graphics mode */ - - outw(0x3C4, 0x0001); /* reset sequencer */ - outw(0x3C4, 0x0204); /* write to plane 2 */ - outw(0x3C4, 0x0406); /* enable plane graphics */ - outw(0x3C4, 0x0003); /* reset sequencer */ - outw(0x3CE, 0x0402); /* read plane 2 */ - outw(0x3CE, 0x0500); /* write mode 0, read mode 0 */ - outw(0x3CE, 0x0605); /* set graphics mode */ - - for (i = 0; i < sizeof(font); i += 16) { - for (j = 0; j < 16; j++) { - __asm__ volatile("eieio"); - font_page[(2*i)+j] = font[i+j]; - } - } -} - -static void -unlockS3(void) -{ - int s3_device_id; - outw(0x3d4, 0x3848); - outw(0x3d4, 0x39a5); - outb(0x3d4, 0x2d); - s3_device_id = inb(0x3d5) << 8; - outb(0x3d4, 0x2e); - s3_device_id |= inb(0x3d5); - - if (s3_device_id != 0x8812) { - /* From the S3 manual */ - outb(0x46E8, 0x10); /* Put into setup mode */ - outb(0x3C3, 0x10); - outb(0x102, 0x01); /* Enable registers */ - outb(0x46E8, 0x08); /* Enable video */ - outb(0x3C3, 0x08); - outb(0x4AE8, 0x00); - -#if 0 - outb(0x42E8, 0x80); /* Reset graphics engine? */ -#endif - - outb(0x3D4, 0x38); /* Unlock all registers */ - outb(0x3D5, 0x48); - outb(0x3D4, 0x39); - outb(0x3D5, 0xA5); - outb(0x3D4, 0x40); - outb(0x3D5, inb(0x3D5)|0x01); - outb(0x3D4, 0x33); - outb(0x3D5, inb(0x3D5)&~0x52); - outb(0x3D4, 0x35); - outb(0x3D5, inb(0x3D5)&~0x30); - outb(0x3D4, 0x3A); - outb(0x3D5, 0x00); - outb(0x3D4, 0x53); - outb(0x3D5, 0x00); - outb(0x3D4, 0x31); - outb(0x3D5, inb(0x3D5)&~0x4B); - outb(0x3D4, 0x58); - - outb(0x3D5, 0); - - outb(0x3D4, 0x54); - outb(0x3D5, 0x38); - outb(0x3D4, 0x60); - outb(0x3D5, 0x07); - outb(0x3D4, 0x61); - outb(0x3D5, 0x80); - outb(0x3D4, 0x62); - outb(0x3D5, 0xA1); - outb(0x3D4, 0x69); /* High order bits for cursor address */ - outb(0x3D5, 0); - - outb(0x3D4, 0x32); - outb(0x3D5, inb(0x3D5)&~0x10); - } else { - outw(0x3c4, 0x0806); /* IBM Portable 860 */ - outw(0x3c4, 0x1041); - outw(0x3c4, 0x1128); - outw(0x3d4, 0x4000); - outw(0x3d4, 0x3100); - outw(0x3d4, 0x3a05); - outw(0x3d4, 0x6688); - outw(0x3d4, 0x5800); /* disable linear addressing */ - outw(0x3d4, 0x4500); /* disable H/W cursor */ - outw(0x3c4, 0x5410); /* enable auto-centering */ - outw(0x3c4, 0x561f); - outw(0x3c4, 0x1b80); /* lock DCLK selection */ - outw(0x3d4, 0x3900); /* lock S3 registers */ - outw(0x3d4, 0x3800); - } /* endif */ -} - -/* - * cursor() sets an offset (0-1999) into the 80x25 text area - */ -void -cursor(int x, int y) -{ - int pos = (y*cols)+x; - outb(0x3D4, 14); - outb(0x3D5, pos >> 8); - outb(0x3D4, 15); - outb(0x3D5, pos); -} - -clearVideoMemory() -{ - int i, j; - for (i = 0; i < lines; i++) { - for (j = 0; j < cols; j++) { - vidmem[((i*cols)+j)*2] = 0x20; /* fill with space character */ - vidmem[((i*cols)+j)*2+1] = 0x07; /* set bg & fg attributes */ - } - } -} - -/* ============ */ - - -#define NSLOTS 8 -#define NPCIREGS 5 - - -/* - should use devfunc number/indirect method to be totally safe on - all machines, this works for now on 3 slot Moto boxes -*/ - -struct PCI_ConfigInfo { - unsigned long * config_addr; - unsigned long regs[NPCIREGS]; -} PCI_slots [NSLOTS] = { - - { (unsigned long *)0x80808000, 0xDEADBEEF }, /* onboard */ - { (unsigned long *)0x80800800, 0xDEADBEEF }, /* onboard */ - { (unsigned long *)0x80801000, 0xDEADBEEF }, /* onboard */ - { (unsigned long *)0x80802000, 0xDEADBEEF }, /* onboard */ - { (unsigned long *)0x80804000, 0xDEADBEEF }, /* onboard */ - { (unsigned long *)0x80810000, 0xDEADBEEF }, /* slot A/1 */ - { (unsigned long *)0x80820000, 0xDEADBEEF }, /* slot B/2 */ - { (unsigned long *)0x80840000, 0xDEADBEEF } /* slot C/3 */ -}; - - - -/* - * The following code modifies the PCI Command register - * to enable memory and I/O accesses. - */ -unlockVideo(slot) -{ - volatile unsigned char * ppci; - - ppci = (unsigned char * )PCI_slots[slot].config_addr; - ppci[4] = 0x0003; /* enable memory and I/O accesses */ - ppci[0x10] = 0x00000; /* turn off memory mapping */ - ppci[0x11] = 0x00000; /* mem_base = 0 */ - ppci[0x12] = 0x00000; - ppci[0x13] = 0x00000; - __asm__ volatile("eieio"); - - outb(0x3d4, 0x11); - outb(0x3d5, 0x0e); /* unlock CR0-CR7 */ -} - -long -SwapBytes(long lv) /* turn little endian into big indian long */ -{ - long t; - t = (lv&0x000000FF) << 24; - t |= (lv&0x0000FF00) << 8; - t |= (lv&0x00FF0000) >> 8; - t |= (lv&0xFF000000) >> 24; - return(t); -} - - -#define DEVID 0 -#define CMD 1 -#define CLASS 2 -#define MEMBASE 4 - -int -scanPCI(int start_slt) -{ - int slt, r; - struct PCI_ConfigInfo *pslot; - int theSlot = -1; - int highVgaSlot = 0; - - for ( slt = start_slt + 1; slt < NSLOTS; slt++) { - pslot = &PCI_slots[slt]; - for ( r = 0; r < NPCIREGS; r++) { - pslot->regs[r] = SwapBytes ( pslot->config_addr[r] ); - } - /* card in slot ? */ - if ( pslot->regs[DEVID] != 0xFFFFFFFF ) { - /* VGA ? */ - if ( ((pslot->regs[CLASS] & 0xFFFFFF00) == 0x03000000) || - ((pslot->regs[CLASS] & 0xFFFFFF00) == 0x00010000)) { - highVgaSlot = slt; - /* did firmware enable it ? */ - if ( (pslot->regs[CMD] & 0x03) ) { - theSlot = slt; - break; - } - } - } - } - - return ( theSlot ); -} - -/* return Vendor ID of card in the slot */ -static -int PCIVendor(int slotnum) { - struct PCI_ConfigInfo *pslot; - - pslot = &PCI_slots[slotnum]; - -return (pslot->regs[DEVID] & 0xFFFF); -} - -static -void printslots(void) -{ - int i; - struct PCI_ConfigInfo *pslot; - for(i=0; i < NSLOTS; i++) { -#if 0 - pslot = &PCI_slots[i]; - printf("Slot: %d, Addr: %x, Vendor: %08x, Class: %08x\n", - i, pslot->config_addr, pslot->regs[0], pslot->regs[2]); -#else - puts("PCI Slot number: "); puthex(i); - puts(" Vendor ID: "); - puthex(PCIVendor(i)); puts("\n"); -#endif - } -} diff -Nru a/arch/ppc/chrpboot/Makefile b/arch/ppc/chrpboot/Makefile --- a/arch/ppc/chrpboot/Makefile Wed May 16 06:00:23 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,101 +0,0 @@ -# Makefile for making ELF bootable images for booting on CHRP -# using Open Firmware. -# -# Geert Uytterhoeven September 1997 -# -# Based on coffboot by Paul Mackerras - -ifeq ($(CONFIG_PPC64BRIDGE),y) -MSIZE=.64 -AFLAGS += -Wa,-mppc64bridge -else -MSIZE= -endif - -.c.o: - $(CC) $(CFLAGS) -DKERNELBASE=$(KERNELBASE) -c -o $*.o $< -.S.o: - $(CC) $(AFLAGS) -traditional -c -o $*.o $< - -CFLAGS = $(CPPFLAGS) -O -fno-builtin -DSTDC_HEADERS -LD_ARGS = -Ttext 0x00400000 - -OBJS = crt0.o start.o main.o misc.o ../coffboot/string.o ../coffboot/zlib.o image.o -LIBS = $(TOPDIR)/lib/lib.a - -ifeq ($(CONFIG_SMP),y) -TFTPIMAGE=/tftpboot/zImage.chrp.smp$(MSIZE) -else -TFTPIMAGE=/tftpboot/zImage.chrp$(MSIZE) -endif - -all: $(TOPDIR)/zImage - -# -# Only build anything here if we're configured for ALL_PPC -# -- cort -# -ifeq ($(CONFIG_ALL_PPC),y) -znetboot: zImage - cp zImage $(TFTPIMAGE) - -znetboot.initrd: zImage.initrd - cp zImage.initrd $(TFTPIMAGE) - -floppy: zImage - mcopy zImage a:zImage - -piggyback: piggyback.c - $(HOSTCC) $(HOSTCFLAGS) -DKERNELBASE=$(KERNELBASE) -o piggyback piggyback.c - -addnote: addnote.c - $(HOSTCC) $(HOSTCFLAGS) -o addnote addnote.c - -image.o: piggyback ../coffboot/vmlinux.gz - ./piggyback image < ../coffboot/vmlinux.gz | $(AS) -o image.o - -sysmap.o: piggyback ../../../System.map - ./piggyback sysmap < ../../../System.map | $(AS) -o sysmap.o - -initrd.o: ramdisk.image.gz piggyback - ./piggyback initrd < ramdisk.image.gz | $(AS) -o initrd.o - -zImage: $(OBJS) no_initrd.o addnote - $(LD) $(LD_ARGS) -o $@ $(OBJS) no_initrd.o $(LIBS) - cp $@ $@.rs6k - ./addnote $@.rs6k - -zImage.initrd: $(OBJS) initrd.o addnote - $(LD) $(LD_ARGS) -o $@ $(OBJS) initrd.o $(LIBS) - cp $@ $@.rs6k - ./addnote $@.rs6k - -else -znetboot: - -znetboot.initrd: - -floppy: - -zImage: - -zImage.initrd: - -endif - -# just here to match coffboot/Makefile -vmlinux.coff: - -vmlinux.coff.initrd: - - -clean: - rm -f piggyback note addnote $(OBJS) zImage - rm -f zImage.rs6k zImage.initrd zImage.initrd.rs6k - -fastdep: - $(TOPDIR)/scripts/mkdep *.[Sch] > .depend - -dep: - $(CPP) $(CPPFLAGS) -M *.S *.c > .depend - diff -Nru a/arch/ppc/chrpboot/addnote.c b/arch/ppc/chrpboot/addnote.c --- a/arch/ppc/chrpboot/addnote.c Wed May 16 06:00:16 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,174 +0,0 @@ -/* - * Program to hack in a PT_NOTE program header entry in an ELF file. - * This is needed for OF on RS/6000s to load an image correctly. - * Note that OF needs a program header entry for the note, not an - * ELF section. - * - * Copyright 2000 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. - * - * Usage: addnote zImage - */ -#include -#include -#include -#include - -char arch[] = "PowerPC"; - -#define N_DESCR 6 -unsigned int descr[N_DESCR] = { -#if 1 - /* values for IBM RS/6000 machines */ - 0xffffffff, /* real-mode = true */ - 0x00c00000, /* real-base, i.e. where we expect OF to be */ - 0xffffffff, /* real-size */ - 0xffffffff, /* virt-base */ - 0xffffffff, /* virt-size */ - 0x4000, /* load-base */ -#else - /* values for longtrail CHRP */ - 0, /* real-mode = false */ - 0xffffffff, /* real-base */ - 0xffffffff, /* real-size */ - 0xffffffff, /* virt-base */ - 0xffffffff, /* virt-size */ - 0x00600000, /* load-base */ -#endif -}; - -unsigned char buf[512]; - -#define GET_16BE(off) ((buf[off] << 8) + (buf[(off)+1])) -#define GET_32BE(off) ((GET_16BE(off) << 16) + GET_16BE((off)+2)) - -#define PUT_16BE(off, v) (buf[off] = ((v) >> 8) & 0xff, \ - buf[(off) + 1] = (v) & 0xff) -#define PUT_32BE(off, v) (PUT_16BE((off), (v) >> 16), \ - PUT_16BE((off) + 2, (v))) - -/* Structure of an ELF file */ -#define E_IDENT 0 /* ELF header */ -#define E_PHOFF 28 -#define E_PHENTSIZE 42 -#define E_PHNUM 44 -#define E_HSIZE 52 /* size of ELF header */ - -#define EI_MAGIC 0 /* offsets in E_IDENT area */ -#define EI_CLASS 4 -#define EI_DATA 5 - -#define PH_TYPE 0 /* ELF program header */ -#define PH_OFFSET 4 -#define PH_FILESZ 16 -#define PH_HSIZE 32 /* size of program header */ - -#define PT_NOTE 4 /* Program header type = note */ - -#define ELFCLASS32 1 -#define ELFDATA2MSB 2 - -unsigned char elf_magic[4] = { 0x7f, 'E', 'L', 'F' }; - -int main(int ac, char **av) -{ - int fd, n, i; - int ph, ps, np; - int nnote, ns; - - if (ac != 2) { - fprintf(stderr, "Usage: %s elf-file\n", av[0]); - exit(1); - } - fd = open(av[1], O_RDWR); - if (fd < 0) { - perror(av[1]); - exit(1); - } - - nnote = strlen(arch) + 1 + (N_DESCR + 3) * 4; - - n = read(fd, buf, sizeof(buf)); - if (n < 0) { - perror("read"); - exit(1); - } - - if (n < E_HSIZE || memcmp(&buf[E_IDENT+EI_MAGIC], elf_magic, 4) != 0) - goto notelf; - - if (buf[E_IDENT+EI_CLASS] != ELFCLASS32 - || buf[E_IDENT+EI_DATA] != ELFDATA2MSB) { - fprintf(stderr, "%s is not a big-endian 32-bit ELF image\n", - av[1]); - exit(1); - } - - ph = GET_32BE(E_PHOFF); - ps = GET_16BE(E_PHENTSIZE); - np = GET_16BE(E_PHNUM); - if (ph < E_HSIZE || ps < PH_HSIZE || np < 1) - goto notelf; - if (ph + (np + 1) * ps + nnote > n) - goto nospace; - - for (i = 0; i < np; ++i) { - if (GET_32BE(ph + PH_TYPE) == PT_NOTE) { - fprintf(stderr, "%s already has a note entry\n", - av[1]); - exit(0); - } - ph += ps; - } - - /* XXX check that the area we want to use is all zeroes */ - for (i = 0; i < ps + nnote; ++i) - if (buf[ph + i] != 0) - goto nospace; - - /* fill in the program header entry */ - ns = ph + ps; - PUT_32BE(ph + PH_TYPE, PT_NOTE); - PUT_32BE(ph + PH_OFFSET, ns); - PUT_32BE(ph + PH_FILESZ, nnote); - - /* fill in the note area we point to */ - /* XXX we should probably make this a proper section */ - PUT_32BE(ns, strlen(arch) + 1); - PUT_32BE(ns + 4, N_DESCR * 4); - PUT_32BE(ns + 8, 0x1275); - strcpy(&buf[ns + 12], arch); - ns += 12 + strlen(arch) + 1; - for (i = 0; i < N_DESCR; ++i) - PUT_32BE(ns + i * 4, descr[i]); - - /* Update the number of program headers */ - PUT_16BE(E_PHNUM, np + 1); - - /* write back */ - lseek(fd, (long) 0, SEEK_SET); - i = write(fd, buf, n); - if (i < 0) { - perror("write"); - exit(1); - } - if (i < n) { - fprintf(stderr, "%s: write truncated\n", av[1]); - exit(1); - } - - exit(0); - - notelf: - fprintf(stderr, "%s does not appear to be an ELF file\n", av[0]); - exit(1); - - nospace: - fprintf(stderr, "sorry, I can't find space in %s to put the note\n", - av[0]); - exit(1); -} diff -Nru a/arch/ppc/chrpboot/crt0.S b/arch/ppc/chrpboot/crt0.S --- a/arch/ppc/chrpboot/crt0.S Wed May 16 06:00:18 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,20 +0,0 @@ -/* - * 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: - 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 diff -Nru a/arch/ppc/chrpboot/main.c b/arch/ppc/chrpboot/main.c --- a/arch/ppc/chrpboot/main.c Wed May 16 06:00:16 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,195 +0,0 @@ -/* - * 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 "../coffboot/nonstdio.h" -#include "../coffboot/zlib.h" -#include -#include -#include - -extern void *finddevice(const char *); -extern int getprop(void *, const char *, void *, int); -void gunzip(void *, int, unsigned char *, int *); - -#define RAM_START 0x00000000 -#define RAM_END (64<<20) - -#define BOOT_START ((unsigned long)_start) -#define BOOT_END ((unsigned long)(_end + 0xFFF) & ~0xFFF) - -#define RAM_FREE ((unsigned long)(_end+0x1000)&~0xFFF) -#define PROG_START 0x00010000 - -char *avail_ram; -char *end_avail; - -extern char _end[]; -extern char image_data[]; -extern int image_len; -extern char initrd_data[]; -extern int initrd_len; -extern char sysmap_data[]; -extern int sysmap_len; - -static char scratch[1024<<10]; /* 1MB of scratch space for gunzip */ - -chrpboot(int a1, int a2, void *prom) -{ - int ns, oh, i; - unsigned sa, len; - void *dst; - unsigned char *im; - unsigned initrd_start, initrd_size; - extern char _start; - - printf("chrpboot starting: loaded at 0x%x\n\r", &_start); - - if (initrd_len) { - initrd_size = initrd_len; - initrd_start = (RAM_END - initrd_size) & ~0xFFF; - a1 = initrd_start; - a2 = initrd_size; - claim(initrd_start, RAM_END - initrd_start, 0); - printf("initial ramdisk moving 0x%x <- 0x%x (%x bytes)\n\r", - initrd_start, initrd_data, initrd_size); - memcpy((char *)initrd_start, initrd_data, initrd_size); - } - - im = image_data; - len = image_len; - /* claim 4MB starting at PROG_START */ - claim(PROG_START, (4<<20) - PROG_START, 0); - dst = (void *) PROG_START; - if (im[0] == 0x1f && im[1] == 0x8b) { - avail_ram = scratch; - end_avail = scratch + sizeof(scratch); - printf("gunzipping (0x%x <- 0x%x:0x%0x)...", dst, im, im+len); - gunzip(dst, 0x400000, im, &len); - printf("done %u bytes\n\r", len); - } else { - memmove(dst, im, len); - } - - flush_cache(dst, len); - - sa = (unsigned long)PROG_START; - printf("start address = 0x%x\n\r", sa); - - { - struct bi_record *rec; - - rec = (struct bi_record *)_ALIGN((unsigned long)dst+len+(1<<20)-1,(1<<20)); - - rec->tag = BI_FIRST; - rec->size = sizeof(struct bi_record); - rec = (struct bi_record *)((unsigned long)rec + rec->size); - - rec->tag = BI_BOOTLOADER_ID; - sprintf( (char *)rec->data, "chrpboot"); - rec->size = sizeof(struct bi_record) + strlen("chrpboot") + 1; - rec = (struct bi_record *)((unsigned long)rec + rec->size); - - rec->tag = BI_MACHTYPE; - rec->data[0] = _MACH_chrp; - rec->data[1] = 1; - rec->size = sizeof(struct bi_record) + sizeof(unsigned long); - rec = (struct bi_record *)((unsigned long)rec + rec->size); -#if 0 - rec->tag = BI_SYSMAP; - rec->data[0] = (unsigned long)sysmap_data; - rec->data[1] = sysmap_len; - rec->size = sizeof(struct bi_record) + sizeof(unsigned long); - rec = (struct bi_record *)((unsigned long)rec + rec->size); -#endif - rec->tag = BI_LAST; - rec->size = sizeof(struct bi_record); - rec = (struct bi_record *)((unsigned long)rec + rec->size); - } - (*(void (*)())sa)(a1, a2, prom); - - printf("returned?\n\r"); - - 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\r"); - pause(); - } - return p; -} - -void zfree(void *x, void *addr, unsigned nb) -{ - nb = (nb + 7) & -8; - if (addr == (avail_ram - nb)) { - avail_ram -= 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\r"); - 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\r"); - exit(); - } - - s.zalloc = zalloc; - s.zfree = zfree; - r = inflateInit2(&s, -MAX_WBITS); - if (r != Z_OK) { - printf("inflateInit2 returned %d\n\r", 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 msg: %s\n\r", r, s.msg); - exit(); - } - *lenp = s.next_out - (unsigned char *) dst; - inflateEnd(&s); -} diff -Nru a/arch/ppc/chrpboot/misc.S b/arch/ppc/chrpboot/misc.S --- a/arch/ppc/chrpboot/misc.S Wed May 16 06:00:25 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,50 +0,0 @@ -/* - * 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 0x90000000. - */ - .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,0x9000 - 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 3,4 - mtdbatl 3,5 -5: mtibatu 3,4 - mtibatl 3,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 diff -Nru a/arch/ppc/chrpboot/mknote.c b/arch/ppc/chrpboot/mknote.c --- a/arch/ppc/chrpboot/mknote.c Wed May 16 06:00:23 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,43 +0,0 @@ -/* - * Copyright (C) Cort Dougan 1999. - * - * 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. - * - * Generate a note section as per the CHRP specification. - * - */ - -#include - -#define PL(x) printf("%c%c%c%c", ((x)>>24)&0xff, ((x)>>16)&0xff, ((x)>>8)&0xff, (x)&0xff ); - -int main(void) -{ -/* header */ - /* namesz */ - PL(strlen("PowerPC")+1); - /* descrsz */ - PL(6*4); - /* type */ - PL(0x1275); - /* name */ - printf("PowerPC"); printf("%c", 0); - -/* descriptor */ - /* real-mode */ - PL(0xffffffff); - /* real-base */ - PL(0x00c00000); - /* real-size */ - PL(0xffffffff); - /* virt-base */ - PL(0xffffffff); - /* virt-size */ - PL(0xffffffff); - /* load-base */ - PL(0x4000); - return 0; -} diff -Nru a/arch/ppc/chrpboot/no_initrd.c b/arch/ppc/chrpboot/no_initrd.c --- a/arch/ppc/chrpboot/no_initrd.c Wed May 16 06:00:20 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,2 +0,0 @@ -char initrd_data[1]; -int initrd_len = 0; diff -Nru a/arch/ppc/chrpboot/piggyback.c b/arch/ppc/chrpboot/piggyback.c --- a/arch/ppc/chrpboot/piggyback.c Wed May 16 06:00:21 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,66 +0,0 @@ -#include -#include - -extern long ce_exec_config[]; - -int main(int argc, char *argv[]) -{ - int i, cnt, pos, len; - unsigned int cksum, val; - unsigned char *lp; - unsigned char buf[8192]; - if (argc != 2) - { - fprintf(stderr, "usage: %s name out-file\n", - argv[0]); - exit(1); - } - fprintf(stdout, "#\n"); - fprintf(stdout, "# Miscellaneous data structures:\n"); - fprintf(stdout, "# WARNING - this file is automatically generated!\n"); - fprintf(stdout, "#\n"); - fprintf(stdout, "\n"); - fprintf(stdout, "\t.data\n"); - fprintf(stdout, "\t.globl %s_data\n", argv[1]); - fprintf(stdout, "%s_data:\n", argv[1]); - pos = 0; - cksum = 0; - while ((len = read(0, buf, sizeof(buf))) > 0) - { - cnt = 0; - lp = (unsigned char *)buf; - len = (len + 3) & ~3; /* Round up to longwords */ - for (i = 0; i < len; i += 4) - { - if (cnt == 0) - { - fprintf(stdout, "\t.long\t"); - } - fprintf(stdout, "0x%02X%02X%02X%02X", lp[0], lp[1], lp[2], lp[3]); - val = *(unsigned long *)lp; - cksum ^= val; - lp += 4; - if (++cnt == 4) - { - cnt = 0; - fprintf(stdout, " # %x \n", pos+i-12); - fflush(stdout); - } else - { - fprintf(stdout, ","); - } - } - if (cnt) - { - fprintf(stdout, "0\n"); - } - pos += len; - } - fprintf(stdout, "\t.globl %s_len\n", argv[1]); - fprintf(stdout, "%s_len:\t.long\t0x%x\n", argv[1], pos); - fflush(stdout); - fclose(stdout); - fprintf(stderr, "cksum = %x\n", cksum); - exit(0); -} - diff -Nru a/arch/ppc/chrpboot/start.c b/arch/ppc/chrpboot/start.c --- a/arch/ppc/chrpboot/start.c Wed May 16 06:00:18 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,305 +0,0 @@ -/* - * 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 - -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 printk(char *fmt, ...); - -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(); - - chrpboot(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; -} - -void * -claim(unsigned int virt, unsigned int size, unsigned int align) -{ - struct prom_args { - char *service; - int nargs; - int nret; - unsigned int virt; - unsigned int size; - unsigned int align; - void *ret; - } args; - - args.service = "claim"; - args.nargs = 3; - args.nret = 1; - args.virt = virt; - args.size = size; - args.align = align; - (*prom)(&args); - return args.ret; -} - -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; -} diff -Nru a/arch/ppc/coffboot/Makefile b/arch/ppc/coffboot/Makefile --- a/arch/ppc/coffboot/Makefile Wed May 16 06:00:23 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,131 +0,0 @@ -# Makefile for making XCOFF bootable images for booting on PowerMacs -# using Open Firmware. -# -# Paul Mackerras January 1997 - -HOSTCFLAGS = -O -I$(TOPDIR)/include - -CFLAGS = $(CPPFLAGS) -O -fno-builtin -OBJCOPY_ARGS = -O aixcoff-rs6000 -R .stab -R .stabstr -R .comment -COFF_LD_ARGS = -e _start -T ld.script -Ttext 500000 -Tdata 510000 -Bstatic -CHRP_LD_ARGS = -Ttext 0x01000000 - -COFFOBJS = coffcrt0.o start.o coffmain.o misc.o string.o zlib.o image.o -CHRPOBJS = crt0.o start.o chrpmain.o misc.o string.o zlib.o image.o -LIBS = $(TOPDIR)/lib/lib.a - -ifeq ($(CONFIG_PPC64BRIDGE),y) -MSIZE=.64 -else -MSIZE= -endif - -ifeq ($(CONFIG_SMP),y) -TFTPIMAGE=/tftpboot/zImage.pmac.smp$(MSIZE) -else -TFTPIMAGE=/tftpboot/zImage.pmac$(MSIZE) -endif - -ifeq ($(CONFIG_ALL_PPC),y) -chrpmain.o: chrpmain.c - $(CC) $(CFLAGS) -DSYSMAP_OFFSET=0 -DSYSMAP_SIZE=0 -c chrpmain.c - -hack-coff: hack-coff.c - $(HOSTCC) $(HOSTCFLAGS) -o hack-coff hack-coff.c - -znetboot: vmlinux.coff vmlinux.elf zImage - cp vmlinux.coff $(TFTPIMAGE) - cp vmlinux.elf $(TFTPIMAGE).elf - -znetboot.initrd: vmlinux.coff.initrd vmlinux.elf.initrd - cp vmlinux.coff.initrd $(TFTPIMAGE) - cp vmlinux.elf.initrd $(TFTPIMAGE).elf - -floppy: zImage -# mount -t hfs /dev/fd0 /mnt -# cp vmlinux.coff /mnt -# umount /mnt - -miboot.image: dummy.o vmlinux.gz - $(OBJCOPY) $(OBJCOPY_ARGS) --add-section=image=vmlinux.gz dummy.o $@ - -miboot.image.initrd: miboot.image ramdisk.image.gz - $(OBJCOPY) $(OBJCOPY_ARGS) --add-section=initrd=ramdisk.image.gz miboot.image $@ - -coffboot: $(COFFOBJS) no_initrd.o ld.script - $(LD) -o $@ $(COFF_LD_ARGS) $(COFFOBJS) no_initrd.o $(LIBS) - -coffboot.initrd: $(COFFOBJS) initrd.o ld.script - $(LD) -o $@ $(COFF_LD_ARGS) $(COFFOBJS) initrd.o $(LIBS) - -piggyback: piggyback.c - $(HOSTCC) $(HOSTCFLAGS) -DKERNELBASE=$(KERNELBASE) -o piggyback piggyback.c - -mknote: mknote.c - $(HOSTCC) $(HOSTCFLAGS) -o mknote mknote.c - -image.o: piggyback vmlinux.gz - ./piggyback image < vmlinux.gz | $(AS) -o image.o - -initrd.o: ramdisk.image.gz piggyback - ./piggyback initrd < ramdisk.image.gz | $(AS) -o initrd.o - -vmlinux.coff: coffboot hack-coff - $(OBJCOPY) $(OBJCOPY_ARGS) coffboot $@ - ./hack-coff $@ - ln -sf vmlinux.coff zImage - -vmlinux.coff.initrd: coffboot.initrd hack-coff - $(OBJCOPY) $(OBJCOPY_ARGS) coffboot.initrd $@ - ./hack-coff $@ - -vmlinux.elf: $(CHRPOBJS) no_initrd.o mknote - $(LD) $(CHRP_LD_ARGS) -o $@ $(CHRPOBJS) no_initrd.o $(LIBS) - ./mknote > note - $(OBJCOPY) $@ $@ --add-section=.note=note \ - --add-section=sysmap=../../../System.map -R .comment - $(CC) $(CFLAGS) chrpmain.c -c -o chrpmain.o \ - -DSYSMAP_OFFSET=`sh ../boot/offset $(OBJDUMP) $@ sysmap` \ - -DSYSMAP_SIZE=`sh ../boot/size $(OBJDUMP) $@ sysmap` - $(LD) $(CHRP_LD_ARGS) -o $@ $(CHRPOBJS) no_initrd.o $(LIBS) - $(OBJCOPY) $@ $@ --add-section=.note=note \ - --add-section=sysmap=../../../System.map -R .comment - -vmlinux.elf.initrd: $(CHRPOBJS) initrd.o mknote - $(LD) $(CHRP_LD_ARGS) -o $@ $(CHRPOBJS) initrd.o $(LIBS) - ./mknote > note - $(OBJCOPY) $@ $@ --add-section=.note=note -R .comment - -zImage: vmlinux.coff vmlinux.elf miboot.image - -zImage.initrd: vmlinux.coff.initrd vmlinux.elf.initrd miboot.image.initrd - -else -znetboot: vmlinux.gz - -znetboot.initrd: vmlinux.gz - -coffboot: vmlinux.gz - -zImage: vmlinux.gz - -zImage.initrd: vmlinux.gz - -vmlinux.coff: vmlinux.gz - -vmlinux.coff.initrd: vmlinux.gz - -floppy: vmlinux.gz - -endif - -vmlinux.gz: $(TOPDIR)/vmlinux - $(OBJCOPY) -S -O binary $(TOPDIR)/vmlinux vmlinux - gzip -vf9 vmlinux - -clean: - rm -f hack-coff coffboot zImage vmlinux.coff vmlinux.gz - rm -f mknote piggyback vmlinux.elf note - rm -f miboot.image miboot.image.initrd - -fastdep: diff -Nru a/arch/ppc/coffboot/chrpmain.c b/arch/ppc/coffboot/chrpmain.c --- a/arch/ppc/coffboot/chrpmain.c Wed May 16 06:00:23 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,286 +0,0 @@ -/* - * 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 "zlib.h" -#include -#include -#include - -extern void *finddevice(const char *); -extern int getprop(void *, const char *, void *, int); -void make_bi_recs(unsigned long); -void gunzip(void *, int, unsigned char *, int *); -void stop_imac_ethernet(void); -void stop_imac_usb(void); - -#define get_16be(x) (*(unsigned short *)(x)) -#define get_32be(x) (*(unsigned *)(x)) - -#define RAM_END (16 << 20) - -#define PROG_START 0x00010000 -#define PROG_SIZE 0x003f0000 - -#define SCRATCH_SIZE (128 << 10) - -char *avail_ram; -char *begin_avail, *end_avail; -char *avail_high; -unsigned int heap_use; -unsigned int heap_max; - -extern char _end[]; -extern char image_data[]; -extern int image_len; -extern char initrd_data[]; -extern int initrd_len; - - -boot(int a1, int a2, void *prom) -{ - int ns, oh, i; - unsigned sa, len; - void *dst; - unsigned char *im; - unsigned initrd_start, initrd_size; - extern char _start; - - printf("chrpboot starting: loaded at 0x%x\n", &_start); - if (initrd_len) { - initrd_size = initrd_len; - initrd_start = (RAM_END - initrd_size) & ~0xFFF; - a1 = initrd_start; - a2 = initrd_size; - claim(initrd_start, RAM_END - initrd_start, 0); - printf("initial ramdisk moving 0x%x <- 0x%x (%x bytes)\n", initrd_start, - initrd_data,initrd_size); - memcpy((char *)initrd_start, initrd_data, initrd_size); - } - im = image_data; - len = image_len; - /* claim 3MB starting at PROG_START */ - claim(PROG_START, PROG_SIZE, 0); - dst = (void *) PROG_START; - if (im[0] == 0x1f && im[1] == 0x8b) { - /* claim some memory for scratch space */ - avail_ram = (char *) claim(0, SCRATCH_SIZE, 0x10); - begin_avail = avail_high = avail_ram; - end_avail = avail_ram + SCRATCH_SIZE; - printf("heap at 0x%x\n", avail_ram); - printf("gunzipping (0x%x <- 0x%x:0x%0x)...", dst, im, im+len); - gunzip(dst, PROG_SIZE, im, &len); - printf("done %u bytes\n", len); - printf("%u bytes of heap consumed, max in use %u\n", - avail_high - begin_avail, heap_max); - } else { - memmove(dst, im, len); - } - - flush_cache(dst, len); - make_bi_recs((unsigned long) dst + len); - - sa = (unsigned long)PROG_START; - printf("start address = 0x%x\n", sa); - - (*(void (*)())sa)(a1, a2, prom); - - printf("returned?\n"); - - pause(); -} - -void make_bi_recs(unsigned long addr) -{ - struct bi_record *rec; - rec = (struct bi_record *)_ALIGN((unsigned long)addr+(1<<20)-1,(1<<20)); - - rec->tag = BI_FIRST; - rec->size = sizeof(struct bi_record); - rec = (struct bi_record *)((unsigned long)rec + rec->size); - - rec->tag = BI_BOOTLOADER_ID; - sprintf( (char *)rec->data, "coffboot"); - rec->size = sizeof(struct bi_record) + strlen("coffboot") + 1; - rec = (struct bi_record *)((unsigned long)rec + rec->size); - - rec->tag = BI_MACHTYPE; - rec->data[0] = _MACH_Pmac; - rec->data[1] = 1; - rec->size = sizeof(struct bi_record) + sizeof(unsigned long); - rec = (struct bi_record *)((unsigned long)rec + rec->size); - -#ifdef SYSMAP_OFFSET - rec->tag = BI_SYSMAP; - rec->data[0] = SYSMAP_OFFSET; - rec->data[1] = SYSMAP_SIZE; - rec->size = sizeof(struct bi_record) + sizeof(unsigned long); - rec = (struct bi_record *)((unsigned long)rec + rec->size); -#endif /* SYSMAP_OFFSET */ - - rec->tag = BI_LAST; - rec->size = sizeof(struct bi_record); - rec = (struct bi_record *)((unsigned long)rec + rec->size); -} - -#if 0 -#define eieio() asm volatile("eieio"); - -void stop_imac_ethernet(void) -{ - void *macio, *enet; - unsigned int macio_addr[5], enet_reg[6]; - int len; - volatile unsigned int *dbdma; - - macio = finddevice("/pci/mac-io"); - enet = finddevice("/pci/mac-io/ethernet"); - if (macio == NULL || enet == NULL) - return; - len = getprop(macio, "assigned-addresses", macio_addr, sizeof(macio_addr)); - if (len != sizeof(macio_addr)) - return; - len = getprop(enet, "reg", enet_reg, sizeof(enet_reg)); - if (len != sizeof(enet_reg)) - return; - printf("macio base %x, dma at %x & %x\n", - macio_addr[2], enet_reg[2], enet_reg[4]); - - /* hope this is mapped... */ - dbdma = (volatile unsigned int *) (macio_addr[2] + enet_reg[2]); - *dbdma = 0x80; /* clear the RUN bit */ - eieio(); - dbdma = (volatile unsigned int *) (macio_addr[2] + enet_reg[4]); - *dbdma = 0x80; /* clear the RUN bit */ - eieio(); -} - -void stop_imac_usb(void) -{ - void *usb; - unsigned int usb_addr[5]; - int len; - volatile unsigned int *usb_ctrl; - - usb = finddevice("/pci/usb"); - if (usb == NULL) - return; - len = getprop(usb, "assigned-addresses", usb_addr, sizeof(usb_addr)); - if (len != sizeof(usb_addr)) - return; - printf("usb base %x\n", usb_addr[2]); - - usb_ctrl = (volatile unsigned int *) (usb_addr[2] + 8); - *usb_ctrl = 0x01000000; /* cpu_to_le32(1) */ - eieio(); -} -#endif - -struct memchunk { - unsigned int size; - struct memchunk *next; -}; - -static struct memchunk *freechunks; - -void *zalloc(void *x, unsigned items, unsigned size) -{ - void *p; - struct memchunk **mpp, *mp; - - size *= items; - size = (size + 7) & -8; - heap_use += size; - if (heap_use > heap_max) - heap_max = heap_use; - for (mpp = &freechunks; (mp = *mpp) != 0; mpp = &mp->next) { - if (mp->size == size) { - *mpp = mp->next; - return mp; - } - } - p = avail_ram; - avail_ram += size; - if (avail_ram > avail_high) - avail_high = avail_ram; - if (avail_ram > end_avail) { - printf("oops... out of memory\n"); - pause(); - } - return p; -} - -void zfree(void *x, void *addr, unsigned nb) -{ - struct memchunk *mp = addr; - - nb = (nb + 7) & -8; - heap_use -= nb; - if (avail_ram == addr + nb) { - avail_ram = addr; - return; - } - mp->size = nb; - mp->next = freechunks; - freechunks = mp; -} - -#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 msg: %s\n", r, s.msg); - exit(); - } - *lenp = s.next_out - (unsigned char *) dst; - inflateEnd(&s); -} diff -Nru a/arch/ppc/coffboot/coffcrt0.S b/arch/ppc/coffboot/coffcrt0.S --- a/arch/ppc/coffboot/coffcrt0.S Wed May 16 06:00:19 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,24 +0,0 @@ -/* - * 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 diff -Nru a/arch/ppc/coffboot/coffmain.c b/arch/ppc/coffboot/coffmain.c --- a/arch/ppc/coffboot/coffmain.c Wed May 16 06:00:19 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,226 +0,0 @@ -/* - * 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 "zlib.h" -#include -#include -#include - -extern void *finddevice(const char *); -extern int getprop(void *, const char *, void *, int); -extern char *claim(unsigned, unsigned, unsigned); -void make_bi_recs(unsigned long); -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 (RAM_START + 0x800000) /* only 8M mapped with BATs */ - -#define PROG_START RAM_START -#define PROG_SIZE 0x00400000 - -#define SCRATCH_SIZE (128 << 10) - -char *avail_ram; -char *begin_avail, *end_avail; -char *avail_high; -unsigned int heap_use; -unsigned int heap_max; - -extern char _start[], _end[]; -extern char image_data[]; -extern int image_len; -extern char initrd_data[]; -extern int initrd_len; - -char heap[SCRATCH_SIZE]; - -boot(int a1, int a2, void *prom) -{ - int ns, oh, i; - unsigned sa, len; - void *dst; - unsigned char *im; - unsigned initrd_start, initrd_size; - - printf("coffboot starting: loaded at 0x%x\n", _start); - setup_bats(RAM_START); - if (initrd_len) { - initrd_size = initrd_len; - initrd_start = (RAM_END - initrd_size) & ~0xFFF; - a1 = initrd_start; - a2 = initrd_size; - claim(initrd_start - RAM_START, RAM_END - initrd_start, 0); - printf("initial ramdisk moving 0x%x <- 0x%x (%x bytes)\n", - initrd_start, initrd_data, initrd_size); - memcpy((char *)initrd_start, initrd_data, initrd_size); - } - im = image_data; - len = image_len; - /* claim 3MB starting at 0 */ - claim(0, PROG_SIZE, 0); - dst = (void *) RAM_START; - if (im[0] == 0x1f && im[1] == 0x8b) { - /* claim some memory for scratch space */ - begin_avail = avail_high = avail_ram = heap; - end_avail = heap + sizeof(heap); - printf("heap at 0x%x\n", avail_ram); - printf("gunzipping (0x%x <- 0x%x:0x%0x)...", dst, im, im+len); - gunzip(dst, PROG_SIZE, im, &len); - printf("done %u bytes\n", len); - printf("%u bytes of heap consumed, max in use %u\n", - avail_high - begin_avail, heap_max); - } else { - memmove(dst, im, len); - } - - flush_cache(dst, len); - make_bi_recs((unsigned long)dst + len); - - sa = (unsigned long)PROG_START; - printf("start address = 0x%x\n", sa); - - (*(void (*)())sa)(a1, a2, prom); - - printf("returned?\n"); - - pause(); -} - -void make_bi_recs(unsigned long addr) -{ - struct bi_record *rec; - - rec = (struct bi_record *)PAGE_ALIGN(addr); - - rec->tag = BI_FIRST; - rec->size = sizeof(struct bi_record); - rec = (struct bi_record *)((unsigned long)rec + rec->size); - - rec->tag = BI_BOOTLOADER_ID; - sprintf( (char *)rec->data, "coffboot"); - rec->size = sizeof(struct bi_record) + strlen("coffboot") + 1; - rec = (struct bi_record *)((unsigned long)rec + rec->size); - - rec->tag = BI_MACHTYPE; - rec->data[0] = _MACH_Pmac; - rec->data[1] = 1; - rec->size = sizeof(struct bi_record) + sizeof(unsigned long); - rec = (struct bi_record *)((unsigned long)rec + rec->size); - - rec->tag = BI_LAST; - rec->size = sizeof(struct bi_record); - rec = (struct bi_record *)((unsigned long)rec + rec->size); -} - -struct memchunk { - unsigned int size; - struct memchunk *next; -}; - -static struct memchunk *freechunks; - -void *zalloc(void *x, unsigned items, unsigned size) -{ - void *p; - struct memchunk **mpp, *mp; - - size *= items; - size = (size + 7) & -8; - heap_use += size; - if (heap_use > heap_max) - heap_max = heap_use; - for (mpp = &freechunks; (mp = *mpp) != 0; mpp = &mp->next) { - if (mp->size == size) { - *mpp = mp->next; - return mp; - } - } - p = avail_ram; - avail_ram += size; - if (avail_ram > avail_high) - avail_high = avail_ram; - if (avail_ram > end_avail) { - printf("oops... out of memory\n"); - pause(); - } - return p; -} - -void zfree(void *x, void *addr, unsigned nb) -{ - struct memchunk *mp = addr; - - nb = (nb + 7) & -8; - heap_use -= nb; - if (avail_ram == addr + nb) { - avail_ram = addr; - return; - } - mp->size = nb; - mp->next = freechunks; - freechunks = mp; -} - -#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 msg: %s\n", r, s.msg); - exit(); - } - *lenp = s.next_out - (unsigned char *) dst; - inflateEnd(&s); -} diff -Nru a/arch/ppc/coffboot/crt0.S b/arch/ppc/coffboot/crt0.S --- a/arch/ppc/coffboot/crt0.S Wed May 16 06:00:22 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,20 +0,0 @@ -/* - * 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: - 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 diff -Nru a/arch/ppc/coffboot/dummy.c b/arch/ppc/coffboot/dummy.c --- a/arch/ppc/coffboot/dummy.c Wed May 16 06:00:23 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,4 +0,0 @@ -int main(void) -{ - return 0; -} diff -Nru a/arch/ppc/coffboot/hack-coff.c b/arch/ppc/coffboot/hack-coff.c --- a/arch/ppc/coffboot/hack-coff.c Wed May 16 06:00:23 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,79 +0,0 @@ -/* - * 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 -#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); -} diff -Nru a/arch/ppc/coffboot/ld.script b/arch/ppc/coffboot/ld.script --- a/arch/ppc/coffboot/ld.script Wed May 16 06:00:22 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,68 +0,0 @@ -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 = .); -} - diff -Nru a/arch/ppc/coffboot/misc.S b/arch/ppc/coffboot/misc.S --- a/arch/ppc/coffboot/misc.S Wed May 16 06:00:19 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,57 +0,0 @@ -/* - * 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 BAT3 registers to map the 1st 8MB of RAM to - * the address given as the 1st argument. - */ - .globl setup_bats -setup_bats: - mfpvr 5 - rlwinm 5,5,16,16,31 /* r3 = 1 for 601, 4 for 604 */ - cmpi 0,5,1 - li 0,0 - bne 4f - mtibatl 3,0 /* invalidate BAT first */ - ori 3,3,4 /* set up BAT registers for 601 */ - li 4,0x7f - mtibatu 3,3 - mtibatl 3,4 - b 5f -4: mtdbatu 3,0 /* invalidate BATs first */ - mtibatu 3,0 - ori 3,3,0xff /* set up BAT registers for 604 */ - li 4,2 - mtdbatl 3,4 - mtdbatu 3,3 - mtibatl 3,4 - mtibatu 3,3 -5: sync - 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 diff -Nru a/arch/ppc/coffboot/mknote.c b/arch/ppc/coffboot/mknote.c --- a/arch/ppc/coffboot/mknote.c Wed May 16 06:00:18 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,43 +0,0 @@ -/* - * Copyright (C) Cort Dougan 1999. - * - * 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. - * - * Generate a note section as per the CHRP specification. - * - */ - -#include - -#define PL(x) printf("%c%c%c%c", ((x)>>24)&0xff, ((x)>>16)&0xff, ((x)>>8)&0xff, (x)&0xff ); - -int main(void) -{ -/* header */ - /* namesz */ - PL(strlen("PowerPC")+1); - /* descrsz */ - PL(6*4); - /* type */ - PL(0x1275); - /* name */ - printf("PowerPC"); printf("%c", 0); - -/* descriptor */ - /* real-mode */ - PL(0xffffffff); - /* real-base */ - PL(0x00c00000); - /* real-size */ - PL(0xffffffff); - /* virt-base */ - PL(0xffffffff); - /* virt-size */ - PL(0xffffffff); - /* load-base */ - PL(0x4000); - return 0; -} diff -Nru a/arch/ppc/coffboot/no_initrd.c b/arch/ppc/coffboot/no_initrd.c --- a/arch/ppc/coffboot/no_initrd.c Wed May 16 06:00:24 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,2 +0,0 @@ -char initrd_data[1]; -int initrd_len = 0; diff -Nru a/arch/ppc/coffboot/nonstdio.h b/arch/ppc/coffboot/nonstdio.h --- a/arch/ppc/coffboot/nonstdio.h Wed May 16 06:00:17 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,18 +0,0 @@ -/* - * 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)) diff -Nru a/arch/ppc/coffboot/piggyback.c b/arch/ppc/coffboot/piggyback.c --- a/arch/ppc/coffboot/piggyback.c Wed May 16 06:00:25 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,66 +0,0 @@ -#include -#include - -extern long ce_exec_config[]; - -int main(int argc, char *argv[]) -{ - int i, cnt, pos, len; - unsigned int cksum, val; - unsigned char *lp; - unsigned char buf[8192]; - if (argc != 2) - { - fprintf(stderr, "usage: %s name out-file\n", - argv[0]); - exit(1); - } - fprintf(stdout, "#\n"); - fprintf(stdout, "# Miscellaneous data structures:\n"); - fprintf(stdout, "# WARNING - this file is automatically generated!\n"); - fprintf(stdout, "#\n"); - fprintf(stdout, "\n"); - fprintf(stdout, "\t.data\n"); - fprintf(stdout, "\t.globl %s_data\n", argv[1]); - fprintf(stdout, "%s_data:\n", argv[1]); - pos = 0; - cksum = 0; - while ((len = read(0, buf, sizeof(buf))) > 0) - { - cnt = 0; - lp = (unsigned char *)buf; - len = (len + 3) & ~3; /* Round up to longwords */ - for (i = 0; i < len; i += 4) - { - if (cnt == 0) - { - fprintf(stdout, "\t.long\t"); - } - fprintf(stdout, "0x%02X%02X%02X%02X", lp[0], lp[1], lp[2], lp[3]); - val = *(unsigned long *)lp; - cksum ^= val; - lp += 4; - if (++cnt == 4) - { - cnt = 0; - fprintf(stdout, " # %x \n", pos+i-12); - fflush(stdout); - } else - { - fprintf(stdout, ","); - } - } - if (cnt) - { - fprintf(stdout, "0\n"); - } - pos += len; - } - fprintf(stdout, "\t.globl %s_len\n", argv[1]); - fprintf(stdout, "%s_len:\t.long\t0x%x\n", argv[1], pos); - fflush(stdout); - fclose(stdout); - fprintf(stderr, "cksum = %x\n", cksum); - exit(0); -} - diff -Nru a/arch/ppc/coffboot/rs6000.h b/arch/ppc/coffboot/rs6000.h --- a/arch/ppc/coffboot/rs6000.h Wed May 16 06:00:22 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,243 +0,0 @@ -/* 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 diff -Nru a/arch/ppc/coffboot/start.c b/arch/ppc/coffboot/start.c --- a/arch/ppc/coffboot/start.c Wed May 16 06:00:25 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,321 +0,0 @@ -/* - * 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 - -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 printk(char *fmt, ...); - -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(); - - boot(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 writestring(void *f, char *ptr, int nb) -{ - int w = 0, i; - char *ret = "\r"; - - for (i = 0; i < nb; ++i) { - if (ptr[i] == '\n') { - if (i > w) { - write(f, ptr + w, i - w); - w = i; - } - write(f, ret, 1); - } - } - if (w < nb) - write(f, ptr + w, nb - w); - return nb; -} - -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; -} - -void * -claim(unsigned int virt, unsigned int size, unsigned int align) -{ - struct prom_args { - char *service; - int nargs; - int nret; - unsigned int virt; - unsigned int size; - unsigned int align; - void *ret; - } args; - - args.service = "claim"; - args.nargs = 3; - args.nret = 1; - args.virt = virt; - args.size = size; - args.align = align; - (*prom)(&args); - return args.ret; -} - -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; - - return writestring(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 writestring(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\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); - writestring(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); - writestring(stdout, sprint_buf, n); - return n; -} diff -Nru a/arch/ppc/coffboot/string.S b/arch/ppc/coffboot/string.S --- a/arch/ppc/coffboot/string.S Wed May 16 06:00:25 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,206 +0,0 @@ -/* - * 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 diff -Nru a/arch/ppc/coffboot/zlib.c b/arch/ppc/coffboot/zlib.c --- a/arch/ppc/coffboot/zlib.c Wed May 16 06:00:16 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,2148 +0,0 @@ -/* - * 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.3 1999/05/27 22:22:54 cort 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 -#define zmemcpy memcpy -#define zmemzero(dest, len) memset(dest, 0, len) - -/* Diagnostic functions */ -#ifdef DEBUG_ZLIB -# include -# 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)<>=(j);k-=(j);} -/* output bytes */ -#define WAVAIL (qread?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} - -/* - * The IBM 150 firmware munges the data right after _etext[]. This - * protects it. -- Cort - */ -local uInt protect_mask[] = {0, 0, 0, 0, 0, 0, 0, 0, 0 ,0 ,0 ,0}; -/* 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)<>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; -} diff -Nru a/arch/ppc/coffboot/zlib.h b/arch/ppc/coffboot/zlib.h --- a/arch/ppc/coffboot/zlib.h Wed May 16 06:00:17 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,432 +0,0 @@ -/* $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 -#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<end() member of irq_desc[x]. -- Cort + /*ppc_md.post_irq = apus_post_irq;*/ + #ifdef CONFIG_HEARTBEAT ppc_md.heartbeat = apus_heartbeat; ppc_md.heartbeat_count = 1; @@ -1091,6 +1143,8 @@ ppc_md.set_rtc_time = apus_set_rtc_time; ppc_md.get_rtc_time = apus_get_rtc_time; ppc_md.calibrate_decr = apus_calibrate_decr; + + ppc_md.find_end_of_memory = apus_find_end_of_memory; ppc_md.nvram_read_val = NULL; ppc_md.nvram_write_val = NULL; diff -Nru a/arch/ppc/kernel/bitops.c b/arch/ppc/kernel/bitops.c --- a/arch/ppc/kernel/bitops.c Wed May 16 06:00:18 2001 +++ b/arch/ppc/kernel/bitops.c Wed May 16 06:00:18 2001 @@ -16,10 +16,10 @@ unsigned long mask = 1 << (nr & 0x1f); unsigned long *p = ((unsigned long *)addr) + (nr >> 5); - __asm__ __volatile__(SMP_WMB "\ -1: lwarx %0,0,%3 - or %0,%0,%2 - stwcx. %0,0,%3 + __asm__ __volatile__(SMP_WMB "\n\ +1: lwarx %0,0,%3 \n\ + or %0,%0,%2 \n\ + stwcx. %0,0,%3 \n\ bne 1b" SMP_MB : "=&r" (old), "=m" (*p) @@ -33,10 +33,10 @@ unsigned long mask = 1 << (nr & 0x1f); unsigned long *p = ((unsigned long *)addr) + (nr >> 5); - __asm__ __volatile__(SMP_WMB "\ -1: lwarx %0,0,%3 - andc %0,%0,%2 - stwcx. %0,0,%3 + __asm__ __volatile__(SMP_WMB "\n\ +1: lwarx %0,0,%3 \n\ + andc %0,%0,%2 \n\ + stwcx. %0,0,%3 \n\ bne 1b" SMP_MB : "=&r" (old), "=m" (*p) @@ -50,10 +50,10 @@ unsigned long mask = 1 << (nr & 0x1f); unsigned long *p = ((unsigned long *)addr) + (nr >> 5); - __asm__ __volatile__(SMP_WMB "\ -1: lwarx %0,0,%3 - xor %0,%0,%2 - stwcx. %0,0,%3 + __asm__ __volatile__(SMP_WMB "\n\ +1: lwarx %0,0,%3 \n\ + xor %0,%0,%2 \n\ + stwcx. %0,0,%3 \n\ bne 1b" SMP_MB : "=&r" (old), "=m" (*p) @@ -67,10 +67,10 @@ unsigned int mask = 1 << (nr & 0x1f); volatile unsigned int *p = ((volatile unsigned int *)addr) + (nr >> 5); - __asm__ __volatile__(SMP_WMB "\ -1: lwarx %0,0,%4 - or %1,%0,%3 - stwcx. %1,0,%4 + __asm__ __volatile__(SMP_WMB "\n\ +1: lwarx %0,0,%4 \n\ + or %1,%0,%3 \n\ + stwcx. %1,0,%4 \n\ bne 1b" SMP_MB : "=&r" (old), "=&r" (t), "=m" (*p) @@ -86,10 +86,10 @@ unsigned int mask = 1 << (nr & 0x1f); volatile unsigned int *p = ((volatile unsigned int *)addr) + (nr >> 5); - __asm__ __volatile__(SMP_WMB "\ -1: lwarx %0,0,%4 - andc %1,%0,%3 - stwcx. %1,0,%4 + __asm__ __volatile__(SMP_WMB "\n\ +1: lwarx %0,0,%4 \n\ + andc %1,%0,%3 \n\ + stwcx. %1,0,%4 \n\ bne 1b" SMP_MB : "=&r" (old), "=&r" (t), "=m" (*p) @@ -105,10 +105,10 @@ unsigned int mask = 1 << (nr & 0x1f); volatile unsigned int *p = ((volatile unsigned int *)addr) + (nr >> 5); - __asm__ __volatile__(SMP_WMB "\ -1: lwarx %0,0,%4 - xor %1,%0,%3 - stwcx. %1,0,%4 + __asm__ __volatile__(SMP_WMB "\n\ +1: lwarx %0,0,%4 \n\ + xor %1,%0,%3 \n\ + stwcx. %1,0,%4 \n\ bne 1b" SMP_MB : "=&r" (old), "=&r" (t), "=m" (*p) diff -Nru a/arch/ppc/kernel/chrp_pci.c b/arch/ppc/kernel/chrp_pci.c --- a/arch/ppc/kernel/chrp_pci.c Wed May 16 06:00:16 2001 +++ b/arch/ppc/kernel/chrp_pci.c Wed May 16 06:00:16 2001 @@ -264,6 +264,7 @@ } } +#if 0 static struct { /* parent is iomem */ struct resource ram, pci_mem, isa_mem, pci_io, pci_cfg, rom_exp, flash; @@ -297,62 +298,7 @@ { bus->resource[1] = &gg2_resources.pci_mem; } - -/* this is used by the pmac_pci code too... - paulus */ -void process_bridge_ranges(struct pci_controller *hose, - struct device_node *dev, int primary) -{ - unsigned int *ranges; - int rlen = 0; - int memno = 0; - struct resource *res; - - hose->io_base_phys = 0; - ranges = (unsigned int *) get_property(dev, "ranges", &rlen); - while ((rlen -= 6 * sizeof(unsigned int)) >= 0) { - res = NULL; - switch (ranges[0] >> 24) { - case 1: /* I/O space */ - if (ranges[2] != 0) - break; - hose->io_base_phys = ranges[3]; - hose->io_base_virt = ioremap(ranges[3], ranges[5]); - if (primary) - isa_io_base = (unsigned long) hose->io_base_virt; - res = &hose->io_resource; - res->flags = IORESOURCE_IO; - res->start = ranges[2]; - break; - case 2: /* memory space */ - memno = 0; - if (ranges[1] == 0 && ranges[2] == 0 - && ranges[5] <= (16 << 20)) { - /* 1st 16MB, i.e. ISA memory area */ - if (primary) - isa_mem_base = ranges[3]; - memno = 1; - } - while (memno < 3 && hose->mem_resources[memno].flags) - ++memno; - if (memno == 0) - hose->pci_mem_offset = ranges[3] - ranges[2]; - if (memno < 3) { - res = &hose->mem_resources[memno]; - res->flags = IORESOURCE_MEM; - res->start = ranges[3]; - } - break; - } - if (res != NULL) { - res->name = dev->full_name; - res->end = res->start + ranges[5] - 1; - res->parent = NULL; - res->sibling = NULL; - res->child = NULL; - } - ranges += 6; - } -} +#endif /* 0 */ /* this is largely modeled and stolen after the pmac_pci code -- tgall */ @@ -366,8 +312,10 @@ volatile unsigned char *cfg; unsigned int *dma; #ifdef CONFIG_POWER3 - unsigned long *opprop = (unsigned long *) - get_property(find_path_device("/"), "platform-open-pic", NULL); + struct device_node *root = find_path_device("/"); + unsigned int *opprop = (unsigned int *) + get_property(root, "platform-open-pic", NULL); + int i; #endif for(; dev != NULL; dev = dev->next, ++index) { @@ -405,10 +353,11 @@ hose->cfg_addr = (volatile unsigned int *) cfg; hose->cfg_data = cfg + 0x10; - process_bridge_ranges(hose, dev, index == 0); + pci_process_bridge_OF_ranges(hose, dev, index == 0); #ifdef CONFIG_POWER3 - openpic_setup_ISU(index, opprop[index+1]); + i = prom_n_addr_cells(root) * (index + 2) - 1; + openpic_setup_ISU(index, opprop[i]); #endif /* CONFIG_POWER3 */ /* check the first bridge for a property that we can @@ -442,7 +391,7 @@ void __init chrp_find_bridges(void) { - struct device_node *py; + struct device_node *py, *dev; char *model, *name; struct pci_controller* hose; @@ -453,7 +402,7 @@ #else /* CONFIG_POWER4 */ model = get_property(find_path_device("/"), "model", NULL); if (!strncmp("MOT", model, 3)) { - struct pci_controller* hose; + struct pci_controller *hose; hose = pcibios_alloc_controller(); if (!hose) @@ -463,8 +412,9 @@ /* Check that please. This must be the root of the OF * PCI tree (the root host bridge */ - hose->arch_data = find_devices("pci"); + hose->arch_data = dev = find_devices("pci"); setup_grackle(hose, 0x20000); + pci_process_bridge_OF_ranges(hose, dev, 1); return; } @@ -485,25 +435,22 @@ /* Check that please. This must be the root of the OF * PCI tree (the root host bridge */ - hose->arch_data = find_devices("pci"); + hose->arch_data = dev = find_devices("pci"); name = get_property(find_path_device("/"), "name", NULL); if (!strncmp("IBM,7043-150", name, 12) || !strncmp("IBM,7046-155", name, 12) || !strncmp("IBM,7046-B50", name, 12) ) { setup_grackle(hose, 0x01000000); - isa_mem_base = 0x80000000; + pci_process_bridge_OF_ranges(hose, dev, 1); return; } /* LongTrail */ hose->ops = &gg2_pci_ops; pci_dram_offset = 0; - isa_mem_base = 0xf7000000; - hose->io_base_phys = (unsigned long) 0xf8000000; - hose->io_base_virt = ioremap(hose->io_base_phys, 0x10000); - isa_io_base = (unsigned long) hose->io_base_virt; - ppc_md.pcibios_fixup = gg2_pcibios_fixup; - ppc_md.pcibios_fixup_bus = gg2_pcibios_fixup_bus; + pci_process_bridge_OF_ranges(hose, find_devices("pci"), 1); +// ppc_md.pcibios_fixup = gg2_pcibios_fixup; +// ppc_md.pcibios_fixup_bus = gg2_pcibios_fixup_bus; #endif /* CONFIG_POWER4 */ } diff -Nru a/arch/ppc/kernel/chrp_setup.c b/arch/ppc/kernel/chrp_setup.c --- a/arch/ppc/kernel/chrp_setup.c Wed May 16 06:00:21 2001 +++ b/arch/ppc/kernel/chrp_setup.c Wed May 16 06:00:21 2001 @@ -67,6 +67,7 @@ void rtas_indicator_progress(char *, unsigned short); void bootx_text_progress(char *, unsigned short); +extern unsigned long pmac_find_end_of_memory(void); extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode); extern int pckbd_getkeycode(unsigned int scancode); extern int pckbd_translate(unsigned char scancode, unsigned char *keycode, @@ -194,37 +195,36 @@ u8 type) { u8 level0, type0, active; - struct device_node *root; - - root = find_path_device("/"); - if (root && - !strncmp(get_property(root, "model", NULL), "IBM,LongTrail", 13 ) ) - { - /* select logical device */ - sio_write(device, 0x07); - active = sio_read(0x30); - level0 = sio_read(0x70); - type0 = sio_read(0x71); - printk("sio: %s irq level %d, type %d, %sactive: ", name, level0, type0, - !active ? "in" : ""); - if (level0 == level && type0 == type && active) - printk("OK\n"); - else { - printk("remapping to level %d, type %d, active\n", level, type); - sio_write(0x01, 0x30); - sio_write(level, 0x70); - sio_write(type, 0x71); - } - } + /* select logical device */ + sio_write(device, 0x07); + active = sio_read(0x30); + level0 = sio_read(0x70); + type0 = sio_read(0x71); + printk("sio: %s irq level %d, type %d, %sactive: ", name, level0, + type0, !active ? "in" : ""); + if (level0 == level && type0 == type && active) + printk("OK\n"); + else { + printk("remapping to level %d, type %d, active\n", level, + type); + sio_write(0x01, 0x30); + sio_write(level, 0x70); + sio_write(type, 0x71); + } } static void __init sio_init(void) { - /* logical device 0 (KBC/Keyboard) */ - sio_fixup_irq("keyboard", 0, 1, 2); - /* select logical device 1 (KBC/Mouse) */ - sio_fixup_irq("mouse", 1, 12, 2); + struct device_node *root; + + if ((root = find_path_device("/")) && + !strncmp(get_property(root, "model", NULL), "IBM,LongTrail", 13)) { + /* logical device 0 (KBC/Keyboard) */ + sio_fixup_irq("keyboard", 0, 1, 2); + /* select logical device 1 (KBC/Mouse) */ + sio_fixup_irq("mouse", 1, 12, 2); + } } @@ -263,16 +263,19 @@ #ifndef CONFIG_POWER4 /* Some IBM machines don't have the hydra -- Cort */ - if ( !OpenPIC_Addr ) - { + if (!OpenPIC_Addr) { + struct device_node *root; unsigned long *opprop; + int n; - opprop = (unsigned long *)get_property(find_path_device("/"), - "platform-open-pic", NULL); + root = find_path_device("/"); + opprop = (unsigned long *) get_property + (root, "platform-open-pic", NULL); + n = prom_n_addr_cells(root); if (opprop != 0) { printk("OpenPIC addrs: %lx %lx %lx\n", - opprop[0], opprop[1], opprop[2]); - OpenPIC_Addr = ioremap(opprop[0], 0x40000); + opprop[n-1], opprop[2*n-1], opprop[3*n-1]); + OpenPIC_Addr = ioremap(opprop[n-1], 0x40000); } } #endif @@ -281,6 +284,10 @@ * Fix the Super I/O configuration */ sio_init(); + + /* + * Setup the console operations + */ #ifdef CONFIG_DUMMY_CONSOLE conswitchp = &dummy_con; #endif @@ -356,7 +363,7 @@ { struct device_node *np; int i; - unsigned long *addrp; + unsigned int *addrp; unsigned char* chrp_int_ack_special = 0; unsigned char init_senses[NR_IRQS - NUM_8259_INTERRUPTS]; int nmi_irq = -1; @@ -365,11 +372,12 @@ #endif if (!(np = find_devices("pci")) - || !(addrp = (unsigned long *) + || !(addrp = (unsigned int *) get_property(np, "8259-interrupt-acknowledge", NULL))) printk("Cannot find pci to get ack address\n"); else - chrp_int_ack_special = (unsigned char *)ioremap(*addrp, 1); + chrp_int_ack_special = (unsigned char *) + ioremap(addrp[prom_n_addr_cells(np)-1], 1); /* hydra still sets OpenPIC_InitSenses to a static set of values */ if (OpenPIC_InitSenses == NULL) { prom_get_irq_senses(init_senses, NUM_8259_INTERRUPTS, NR_IRQS); @@ -553,11 +561,9 @@ #ifndef CONFIG_POWER4 ppc_md.init_IRQ = chrp_init_IRQ; ppc_md.get_irq = openpic_get_irq; - ppc_md.post_irq = NULL; #else ppc_md.init_IRQ = xics_init_IRQ; ppc_md.get_irq = xics_get_irq; - ppc_md.post_irq = NULL; #endif /* CONFIG_POWER4 */ ppc_md.init = chrp_init2; @@ -570,6 +576,8 @@ ppc_md.set_rtc_time = chrp_set_rtc_time; ppc_md.get_rtc_time = chrp_get_rtc_time; ppc_md.calibrate_decr = chrp_calibrate_decr; + + ppc_md.find_end_of_memory = pmac_find_end_of_memory; #ifdef CONFIG_VT /* these are adjusted in chrp_init2 if we have an ADB keyboard */ diff -Nru a/arch/ppc/kernel/chrp_time.c b/arch/ppc/kernel/chrp_time.c --- a/arch/ppc/kernel/chrp_time.c Wed May 16 06:00:18 2001 +++ b/arch/ppc/kernel/chrp_time.c Wed May 16 06:00:18 2001 @@ -29,6 +29,8 @@ #include #include +extern spinlock_t rtc_lock; + static int nvram_as1 = NVRAM_AS1; static int nvram_as0 = NVRAM_AS0; static int nvram_data = NVRAM_DATA; @@ -74,6 +76,7 @@ unsigned char save_control, save_freq_select; struct rtc_time tm; + spin_lock(&rtc_lock); to_tm(nowtime, &tm); save_control = chrp_cmos_clock_read(RTC_CONTROL); /* tell the clock it's being set */ @@ -112,6 +115,7 @@ if ( (time_state == TIME_ERROR) || (time_state == TIME_BAD) ) time_state = TIME_OK; + spin_unlock(&rtc_lock); return 0; } diff -Nru a/arch/ppc/kernel/cpc700.h b/arch/ppc/kernel/cpc700.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/kernel/cpc700.h Wed May 16 06:00:33 2001 @@ -0,0 +1,107 @@ +/* + * include/asm-ppc/cpc700.h + * + * Header file for IBM CPC700 Host Bridge, et. al. + * + * Author: Mark A. Greer + * mgreer@mvista.com + * + * Copyright 2000 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * This file contains the defines and macros for the IBM CPC700 host bridge, + * memory controller, PIC, UARTs, IIC, and Timers. + */ + +#ifndef _ASMPPC_CPC700_H +#define _ASMPPC_CPC700_H + +#include +#include +#include + +#define CPC700_OUT_32(a,d) (*(u_int *)a = d) +#define CPC700_IN_32(a) (*(u_int *)a) + +/* + * PCI Section + */ +#define CPC700_PCI_CONFIG_ADDR 0xfec00000 +#define CPC700_PCI_CONFIG_DATA 0xfec00004 + +#define CPC700_PMM0_LOCAL 0xff400000 +#define CPC700_PMM0_MASK_ATTR 0xff400004 +#define CPC700_PMM0_PCI_LOW 0xff400008 +#define CPC700_PMM0_PCI_HIGH 0xff40000c +#define CPC700_PMM1_LOCAL 0xff400010 +#define CPC700_PMM1_MASK_ATTR 0xff400014 +#define CPC700_PMM1_PCI_LOW 0xff400018 +#define CPC700_PMM1_PCI_HIGH 0xff40001c +#define CPC700_PMM2_LOCAL 0xff400020 +#define CPC700_PMM2_MASK_ATTR 0xff400024 +#define CPC700_PMM2_PCI_LOW 0xff400028 +#define CPC700_PMM2_PCI_HIGH 0xff40002c +#define CPC700_PTM1_MEMSIZE 0xff400030 +#define CPC700_PTM1_LOCAL 0xff400034 +#define CPC700_PTM2_MEMSIZE 0xff400038 +#define CPC700_PTM2_LOCAL 0xff40003c + +/* + * PIC Section + * + * IBM calls the CPC700's programmable interrupt controller the Universal + * Interrupt Controller or UIC. + */ + +/* + * UIC Register Addresses. + */ +#define CPC700_UIC_UICSR 0xff500880 /* Status Reg (Rd/Clr)*/ +#define CPC700_UIC_UICSRS 0xff500884 /* Status Reg (Set) */ +#define CPC700_UIC_UICER 0xff500888 /* Enable Reg */ +#define CPC700_UIC_UICCR 0xff50088c /* Critical Reg */ +#define CPC700_UIC_UICPR 0xff500890 /* Polarity Reg */ +#define CPC700_UIC_UICTR 0xff500894 /* Trigger Reg */ +#define CPC700_UIC_UICMSR 0xff500898 /* Masked Status Reg */ +#define CPC700_UIC_UICVR 0xff50089c /* Vector Reg */ +#define CPC700_UIC_UICVCR 0xff5008a0 /* Vector Config Reg */ + +#define CPC700_UIC_UICER_ENABLE 0x00000001 /* Enable an IRQ */ + +#define CPC700_UIC_UICVCR_31_HI 0x00000000 /* IRQ 31 hi priority */ +#define CPC700_UIC_UICVCR_0_HI 0x00000001 /* IRQ 0 hi priority */ +#define CPC700_UIC_UICVCR_BASE_MASK 0xfffffffc +#define CPC700_UIC_UICVCR_ORDER_MASK 0x00000001 + +/* Specify value of a bit for an IRQ. */ +#define CPC700_UIC_IRQ_BIT(i) ((0x00000001) << (31 - (i))) + +/* + * UIC Exports... + */ +extern struct hw_interrupt_type cpc700_pic; + +void __init cpc700_pic_init(void); + +#endif /* _ASMPPC_CPC700_H */ diff -Nru a/arch/ppc/kernel/cpc710.h b/arch/ppc/kernel/cpc710.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/kernel/cpc710.h Wed May 16 06:00:33 2001 @@ -0,0 +1,59 @@ +/* + * arch/ppc/kernel/cpc710.h + * + * Definitions for the IBM CPC710 PCI Host Bridge + * + * Author: Matt Porter + * + * Copyright 2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __PPC_KERNEL_CPC710_H +#define __PPC_KERNEL_CPC710_H + +/* General bridge and memory controller registers */ +#define PIDR 0xff000008 +#define CNFR 0xff00000c +#define RSTR 0xff000010 +#define UCTL 0xff001000 +#define MPSR 0xff001010 +#define SIOC 0xff001020 +#define ABCNTL 0xff001030 +#define SRST 0xff001040 +#define ERRC 0xff001050 +#define SESR 0xff001060 +#define SEAR 0xff001070 +#define PGCHP 0xff001100 +#define GPDIR 0xff001130 +#define ATAS 0xff001160 +#define AVDG 0xff001170 +#define MCCR 0xff001200 +#define MESR 0xff001220 +#define MEAR 0xff001230 +#define MCER0 0xff001300 +#define MCER1 0xff001310 +#define MCER2 0xff001320 +#define MCER3 0xff001330 +#define MCER4 0xff001340 +#define MCER5 0xff001350 +#define MCER6 0xff001360 +#define MCER7 0xff001370 + +/* System standard configuration registers space */ +#define DCR 0xff200000 +#define DID 0xff200004 +#define BAR 0xff200018 + +/* Device specific configuration space */ +#define PCIENB 0xff201000 + +/* Configuration space registers */ +#define CPC710_BUS_NUMBER 0x40 +#define CPC710_SUB_BUS_NUMBER 0x41 + +#endif /* __PPC_KERNEL_CPC710_H */ diff -Nru a/arch/ppc/kernel/entry.S b/arch/ppc/kernel/entry.S --- a/arch/ppc/kernel/entry.S Wed May 16 06:00:21 2001 +++ b/arch/ppc/kernel/entry.S Wed May 16 06:00:21 2001 @@ -30,7 +30,6 @@ #include #include #include -#include "mol.h" #undef SHOW_SYSCALLS #undef SHOW_SYSCALLS_TASK @@ -315,21 +314,12 @@ lwz r5,_MSR(r1) andi. r5,r5,MSR_EE beq 2f - .globl lost_irq_ret -lost_irq_ret: -3: lis r4,ppc_n_lost_interrupts@ha - lwz r4,ppc_n_lost_interrupts@l(r4) - cmpi 0,r4,0 - beq+ 1f - addi r3,r1,STACK_FRAME_OVERHEAD - bl do_IRQ - b 3b -1: lis r4,irq_stat@ha /* &softirq_active for cpu 0 */ + lis r4,irq_stat@ha /* &softirq_active for cpu 0 */ addi r4,r4,irq_stat@l #ifdef CONFIG_SMP /* get processor # */ lwz r3,PROCESSOR(r2) - slwi r3,r3,5 + slwi r3,r3,LG_CACHE_LINE_SIZE add r4,r4,r3 #endif /* CONFIG_SMP */ lwz r5,0(r4) /* softirq_active */ @@ -351,7 +341,6 @@ beq+ do_signal_ret li r3,0 addi r4,r1,STACK_FRAME_OVERHEAD - MOL_HOOK_MMU(8,r8) bl do_signal .globl do_signal_ret do_signal_ret: @@ -391,7 +380,6 @@ stw r0,THREAD+KSP(r2) /* save kernel stack pointer */ tophys(r8,r1) CLR_TOP32(r8) - MOL_HOOK_MMU(9, r4) /* mod. r0,r2-r7, lr, ctr */ mtspr SPRG2,r8 /* phys exception stack pointer */ 1: lwz r3,_CTR(r1) @@ -412,29 +400,6 @@ lwz r1,GPR1(r1) SYNC RFI - -/* - * Fake an interrupt from kernel mode. - * This is used when enable_irq loses an interrupt. - * We only fill in the stack frame minimally. - */ -_GLOBAL(fake_interrupt) - mflr r0 - stw r0,4(r1) - stwu r1,-INT_FRAME_SIZE(r1) - stw r0,_NIP(r1) - stw r0,_LINK(r1) - mfmsr r3 - stw r3,_MSR(r1) - li r0,0x0fac - stw r0,TRAP(r1) - addi r3,r1,STACK_FRAME_OVERHEAD - li r4,1 - bl do_IRQ - addi r1,r1,INT_FRAME_SIZE - lwz r0,4(r1) - mtlr r0 - blr /* diff -Nru a/arch/ppc/kernel/feature.c b/arch/ppc/kernel/feature.c --- a/arch/ppc/kernel/feature.c Wed May 16 06:00:24 2001 +++ b/arch/ppc/kernel/feature.c Wed May 16 06:00:24 2001 @@ -2,17 +2,13 @@ * arch/ppc/kernel/feature.c * * Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au) - * Ben. Herrenschmidt (bh40@calva.net) + * Ben. Herrenschmidt (benh@kernel.crashing.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. * - * BenH: Changed implementation to work on multiple registers - * polarity is also taken into account. Removed delay (now - * responsibility of the caller). Added spinlocks. - * */ #include #include @@ -29,11 +25,12 @@ #include #include #include +#include +#include #undef DEBUG_FEATURE #define MAX_FEATURE_CONTROLLERS 2 -#define MAX_FEATURE_OFFSET 0x100 #define FREG(c,r) (&(((c)->reg)[(r)>>2])) /* Keylargo reg. access. */ @@ -56,9 +53,7 @@ unsigned int mask; /* bit mask */ } fbit; -/* I don't have an OHare machine to test with, so I left those as they - * were. Someone with such a machine chould check out what OF says and - * try too see if they match the heathrow ones and should be changed too +/* Those features concern for OHare-based PowerBooks (2400, 3400, 3500) */ static fbit feature_bits_ohare_pbook[] = { {0x38,0,0}, /* FEATURE_null */ @@ -159,11 +154,12 @@ /* * Those bits are from a 1999 G3 PowerBook, with a paddington chip. - * Mostly the same as the heathrow. + * Mostly the same as the heathrow. They are used on both PowerBooks + * and desktop machines using the paddington chip */ static fbit feature_bits_paddington[] = { {0x38,0,0}, /* FEATURE_null */ - {0x38,0,0}, /* FEATURE_Serial_reset */ + {0x38,0,PADD_RESET_SCC}, /* FEATURE_Serial_reset */ {0x38,0,HRW_SCC_ENABLE}, /* FEATURE_Serial_enable */ {0x38,0,HRW_SCCA_IO}, /* FEATURE_Serial_IO_A */ {0x38,0,HRW_SCCB_IO}, /* FEATURE_Serial_IO_B */ @@ -192,6 +188,7 @@ }; /* Those bits are for Core99 machines (iBook,G4,iMacSL/DV,Pismo,...). + * Note: Different sets may be needed for iBook, especially for sound */ static fbit feature_bits_keylargo[] = { {0x38,0,0}, /* FEATURE_null */ @@ -201,13 +198,13 @@ {0x38,0,KL0_SCC_B_INTF_ENABLE}, /* FEATURE_Serial_IO_B */ {0x38,0,0}, /* FEATURE_SWIM3_enable */ {0x38,0,0}, /* FEATURE_MESH_enable */ - {0x3c,0,0}, /* FEATURE_IDE0_enable */ + {0x3c,0,KL1_EIDE0_ENABLE}, /* FEATURE_IDE0_enable */ {0x3c,1,KL1_EIDE0_RESET_N}, /* FEATURE_IDE0_reset */ {0x38,0,0}, /* FEATURE_IOBUS_enable */ - {0x34,1,0x00000200}, /* FEATURE_Mediabay_reset */ - {0x34,1,0x00000400}, /* FEATURE_Mediabay_power */ + {0x34,1,KL_MBCR_MB0_DEV_RESET}, /* FEATURE_Mediabay_reset */ + {0x34,1,KL_MBCR_MB0_DEV_POWER}, /* FEATURE_Mediabay_power */ {0x38,0,0}, /* FEATURE_Mediabay_PCI_enable */ - {0x3c,0,0x0}, /* FEATURE_IDE1_enable */ + {0x3c,0,KL1_EIDE1_ENABLE}, /* FEATURE_IDE1_enable */ {0x3c,1,KL1_EIDE1_RESET_N}, /* FEATURE_IDE1_reset */ {0x38,0,0}, /* FEATURE_Mediabay_floppy_enable */ {0x38,0,0}, /* FEATURE_BMac_reset */ @@ -216,10 +213,10 @@ {0x38,0,0}, /* FEATURE_Slow_SCC_PCLK */ {0x38,0,0}, /* FEATURE_Sound_Power */ {0x38,0,0}, /* FEATURE_Sound_CLK_Enable */ - {0x38,0,0}, /* FEATURE_IDE2_enable */ + {0x3c,0,KL1_UIDE_ENABLE}, /* FEATURE_IDE2_enable */ {0x3c,1,KL1_UIDE_RESET_N}, /* FEATURE_IDE2_reset */ - {0x34,0,KL_MBCR_MBDEV_ENABLE}, /* FEATURE_Mediabay_IDE_switch */ - {0x34,0,0x00000100}, /* FEATURE_Mediabay_content */ + {0x34,0,KL_MBCR_MB0_DEV_ENABLE},/* FEATURE_Mediabay_IDE_switch */ + {0x34,0,KL_MBCR_MB0_ENABLE}, /* FEATURE_Mediabay_content */ {0x40,1,KL2_AIRPORT_RESET_N}, /* FEATURE_Airport_reset */ }; @@ -238,6 +235,8 @@ static struct feature_controller* feature_lookup_controller(struct device_node *device); +static void uninorth_init(void); +static void keylargo_init(void); #ifdef CONFIG_PMAC_PBOOK static void heathrow_prepare_for_sleep(struct feature_controller* ctrler); static void heathrow_wakeup(struct feature_controller* ctrler); @@ -245,32 +244,80 @@ static void core99_wake_up(struct feature_controller* ctrler); #endif /* CONFIG_PMAC_PBOOK */ -static void keylargo_init(void); -static void uninorth_init(void); - /* static variables */ static struct feature_controller controllers[MAX_FEATURE_CONTROLLERS]; static int controller_count = 0; /* Core99 stuffs */ -static volatile u32* uninorth_base = NULL; -static volatile u32* keylargo_base = NULL; +/*static*/ volatile u32* uninorth_base; +static volatile u32* keylargo_base; +static struct feature_controller* keylargo; static int uninorth_rev; static int keylargo_rev; +static u32 board_features; +static u8 airport_pwr_regs[5]; +static int airport_pwr_state; +static struct device_node* airport_dev; + +#define FTR_NEED_OPENPIC_TWEAK 0x00000001 +#define FTR_CAN_NAP 0x00000002 +#define FTR_HAS_FW_POWER 0x00000004 +#define FTR_CAN_SLEEP 0x00000008 + +static struct board_features_t { + char* compatible; + u32 features; +} board_features_datas[] __init = +{ + { "AAPL,PowerMac G3", 0 }, /* Beige G3 */ + { "iMac,1", 0 }, /* First iMac (gossamer) */ + { "PowerMac1,1", 0 }, /* B&W G3 / Yikes */ + { "PowerMac1,2", 0 }, /* B&W G3 / Yikes */ + { "PowerMac2,1", FTR_CAN_SLEEP }, /* r128 based iMac */ + { "PowerMac2,2", FTR_HAS_FW_POWER|FTR_CAN_SLEEP }, /* Summer 2000 iMac */ + { "PowerMac4,1", FTR_CAN_SLEEP }, /* iMac "Flower Power" */ + { "PowerMac3,1", FTR_NEED_OPENPIC_TWEAK }, /* Sawtooth (G4) */ + { "PowerMac3,2", 0 }, /* G4/Dual G4 */ + { "PowerMac3,3", FTR_NEED_OPENPIC_TWEAK }, /* G4/Dual G4 */ + { "PowerMac5,1", 0 }, /* Cube */ + { "AAPL,3400/2400", FTR_CAN_SLEEP }, /* 2400/3400 PowerBook */ + { "AAPL,3500", FTR_CAN_SLEEP }, /* 3500 PowerBook (G3) */ + { "AAPL,PowerBook1998", FTR_CAN_SLEEP }, /* Wallstreet PowerBook */ + { "PowerBook1,1", FTR_CAN_SLEEP }, /* 101 (Lombard) PowerBook */ + { "PowerBook2,1", FTR_CAN_SLEEP }, /* iBook */ + { "PowerBook2,2", FTR_CAN_SLEEP /*| FTR_CAN_NAP*/ }, /* iBook FireWire */ + { "PowerBook3,1", FTR_CAN_SLEEP|FTR_CAN_NAP| /* PowerBook 2000 (Pismo) */ + FTR_HAS_FW_POWER }, + { "PowerBook3,2", FTR_CAN_NAP|FTR_CAN_SLEEP }, /* PowerBook Titanium */ + { "PowerBook4,1", FTR_CAN_NAP|FTR_CAN_SLEEP }, /* New polycarbonate iBook */ + { NULL, 0 } +}; + +extern unsigned long powersave_nap; -/* - * WARNING ! This function is called early in setup_arch, neither the IO base - * nor the udelay calibration have been done yet - */ void feature_init(void) { struct device_node *np; u32 *rev; - + int i; + if (_machine != _MACH_Pmac) return; + /* Figure out motherboard type & options */ + for(i=0;board_features_datas[i].compatible;i++) { + if (machine_is_compatible(board_features_datas[i].compatible)) { + board_features = board_features_datas[i].features; + break; + } + } + + /* Set default value of powersave_nap on machines that support it */ + if (board_features & FTR_CAN_NAP) + powersave_nap = 1; + + /* Track those poor mac-io's */ np = find_devices("mac-io"); while (np != NULL) { /* KeyLargo contains several (5 ?) FCR registers in mac-io, @@ -280,13 +327,25 @@ struct feature_controller* ctrler = feature_add_controller(np, feature_bits_keylargo); if (ctrler) { + keylargo = ctrler; keylargo_base = ctrler->reg; rev = (u32 *)get_property(ctrler->device, "revision-id", NULL); if (rev) keylargo_rev = *rev; + + rev = (u32 *)get_property(ctrler->device, "device-id", NULL); + if (rev && (*rev) == 0x0025) + keylargo_rev |= KL_PANGEA_REV; } } else if (device_is_compatible(np, "paddington")) { feature_add_controller(np, feature_bits_paddington); + /* We disable the modem power bit on Yikes as it can + * do bad things (it's the nvram power) + */ + if (machine_is_compatible("PowerMac1,1") || + machine_is_compatible("PowerMac1,2")) { + feature_bits_paddington[FEATURE_Modem_power].mask = 0; + } } else if (machine_is_compatible("AAPL,PowerBook1998")) { feature_add_controller(np, feature_bits_wallstreet); } else { @@ -311,11 +370,12 @@ } } - /* Handle core99 Uni-N */ + /* Locate core99 Uni-N */ np = find_devices("uni-n"); if (np && np->n_addrs > 0) { uninorth_base = ioremap(np->addrs[0].address, 0x1000); uninorth_rev = in_be32(UN_REG(UNI_N_VERSION)); + printk("Uninorth at 0x%08x\n", np->addrs[0].address); } if (uninorth_base && keylargo_base) printk("Uni-N revision: %d, KeyLargo revision: %d\n", @@ -360,8 +420,12 @@ return NULL; } + /* We remap the entire mac-io here. Normally, this will just + * give us back our already existing BAT mapping + */ controller->reg = (volatile u32 *)ioremap( - controller_device->addrs[0].address, MAX_FEATURE_OFFSET); + controller_device->addrs[0].address, + controller_device->addrs[0].size); if (bits == NULL) { printk(KERN_INFO "Twiddling the magic ohare bits\n"); @@ -495,6 +559,12 @@ return bit->polarity ? (value == 0) : (value == bit->mask); } +int +feature_can_sleep(void) +{ + return ((board_features & FTR_CAN_SLEEP) != 0); +} + /* * Core99 functions * @@ -506,53 +576,220 @@ void feature_set_gmac_power(struct device_node* device, int power) { - if (!uninorth_base) + unsigned long flags; + + if (!uninorth_base || !keylargo) return; + + /* TODO: Handle save/restore of PCI config space here + */ + + spin_lock_irqsave(&keylargo->lock, flags); if (power) UN_BIS(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_GMAC); else UN_BIC(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_GMAC); + spin_unlock_irqrestore(&keylargo->lock, flags); udelay(20); } void -feature_set_gmac_phy_reset(struct device_node* device, int reset) +feature_gmac_phy_reset(struct device_node* device) { - if (!keylargo_base) + unsigned long flags; + + if (!keylargo_base || !keylargo) return; - out_8((volatile u8 *)KL_FCR(KL_GPIO_ETH_PHY_RESET), reset); + + spin_lock_irqsave(&keylargo->lock, flags); + out_8((volatile u8 *)KL_FCR(KL_GPIO_ETH_PHY_RESET), + KEYLARGO_GPIO_OUTPUT_ENABLE); + (void)in_8((volatile u8 *)KL_FCR(KL_GPIO_ETH_PHY_RESET)); + spin_unlock_irqrestore(&keylargo->lock, flags); + mdelay(10); + spin_lock_irqsave(&keylargo->lock, flags); + out_8((volatile u8 *)KL_FCR(KL_GPIO_ETH_PHY_RESET), + KEYLARGO_GPIO_OUTPUT_ENABLE | KEYLARGO_GPIO_OUTOUT_DATA); (void)in_8((volatile u8 *)KL_FCR(KL_GPIO_ETH_PHY_RESET)); + spin_unlock_irqrestore(&keylargo->lock, flags); + mdelay(10); } /* Pass the node of the correct controller, please */ void feature_set_usb_power(struct device_node* device, int power) { + char* prop; + int number; + u32 reg; + + unsigned long flags; + + if (!keylargo_base || !keylargo) + return; + + prop = (char *)get_property(device, "AAPL,clock-id", NULL); + if (!prop) + return; + if (strncmp(prop, "usb0u048", strlen("usb0u048")) == 0) + number = 0; + else if (strncmp(prop, "usb1u148", strlen("usb1u148")) == 0) + number = 2; + else + return; + + spin_lock_irqsave(&keylargo->lock, flags); + if (power) { + /* Turn ON */ + + if (number == 0) { + KL_BIC(KEYLARGO_FCR0, (KL0_USB0_PAD_SUSPEND0 | KL0_USB0_PAD_SUSPEND1)); + mdelay(1); + KL_BIS(KEYLARGO_FCR0, KL0_USB0_CELL_ENABLE); + } else { + KL_BIC(KEYLARGO_FCR0, (KL0_USB1_PAD_SUSPEND0 | KL0_USB1_PAD_SUSPEND1)); + mdelay(1); + KL_BIS(KEYLARGO_FCR0, KL0_USB1_CELL_ENABLE); + } + reg = KL_IN(KEYLARGO_FCR4); + reg &= ~(KL4_SET_PORT_ENABLE(number) | KL4_SET_PORT_RESUME(number) | + KL4_SET_PORT_CONNECT(number) | KL4_SET_PORT_DISCONNECT(number)); + reg &= ~(KL4_SET_PORT_ENABLE(number+1) | KL4_SET_PORT_RESUME(number+1) | + KL4_SET_PORT_CONNECT(number+1) | KL4_SET_PORT_DISCONNECT(number+1)); + KL_OUT(KEYLARGO_FCR4, reg); + (void)KL_IN(KEYLARGO_FCR4); + udelay(10); + } else { + /* Turn OFF */ + + reg = KL_IN(KEYLARGO_FCR4); + reg |= KL4_SET_PORT_ENABLE(number) | KL4_SET_PORT_RESUME(number) | + KL4_SET_PORT_CONNECT(number) | KL4_SET_PORT_DISCONNECT(number); + reg |= KL4_SET_PORT_ENABLE(number+1) | KL4_SET_PORT_RESUME(number+1) | + KL4_SET_PORT_CONNECT(number+1) | KL4_SET_PORT_DISCONNECT(number+1); + KL_OUT(KEYLARGO_FCR4, reg); + (void)KL_IN(KEYLARGO_FCR4); + udelay(1); + if (number == 0) { + KL_BIC(KEYLARGO_FCR0, KL0_USB0_CELL_ENABLE); + (void)KL_IN(KEYLARGO_FCR0); + udelay(1); + KL_BIS(KEYLARGO_FCR0, (KL0_USB0_PAD_SUSPEND0 | KL0_USB0_PAD_SUSPEND1)); + (void)KL_IN(KEYLARGO_FCR0); + } else { + KL_BIC(KEYLARGO_FCR0, KL0_USB1_CELL_ENABLE); + (void)KL_IN(KEYLARGO_FCR0); + udelay(1); + KL_BIS(KEYLARGO_FCR0, (KL0_USB1_PAD_SUSPEND0 | KL0_USB1_PAD_SUSPEND1)); + (void)KL_IN(KEYLARGO_FCR0); + } + udelay(1); + } + spin_unlock_irqrestore(&keylargo->lock, flags); } -/* Not yet implemented */ void feature_set_firewire_power(struct device_node* device, int power) { + unsigned long flags; + + /* TODO: Handle save/restore of PCI config space here + */ + if (!uninorth_base) return; + spin_lock_irqsave(&keylargo->lock, flags); if (power) UN_BIS(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_FW); else UN_BIC(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_FW); udelay(20); + spin_unlock_irqrestore(&keylargo->lock, flags); +} + +/* Warning: will kill the PHY.. */ +void +feature_set_firewire_cable_power(struct device_node* device, int power) +{ + unsigned long flags; + u8 gpioValue = power ? 0 : 4; + + if (!keylargo_base || !(board_features & FTR_HAS_FW_POWER)) + return; + spin_lock_irqsave(&keylargo->lock, flags); + out_8((volatile u8 *)KL_FCR(KL_GPIO_FW_CABLE_POWER), gpioValue); + (void)in_8((volatile u8 *)KL_FCR(KL_GPIO_FW_CABLE_POWER)); + spin_unlock_irqrestore(&keylargo->lock, flags); } #ifdef CONFIG_SMP void -feature_core99_kick_cpu1(void) +feature_core99_kick_cpu(int cpu_nr) { - out_8((volatile u8 *)KL_FCR(KL_GPIO_KICK_CPU1), KL_GPIO_KICK_CPU1_UP); +#if 1 /* New way */ + const int reset_lines[] = { KL_GPIO_RESET_CPU0, + KL_GPIO_RESET_CPU1, + KL_GPIO_RESET_CPU2, + KL_GPIO_RESET_CPU3 }; + volatile u8* reset_io; + + if (!keylargo_base || cpu_nr > 3) + return; + reset_io = (volatile u8*)KL_FCR(reset_lines[cpu_nr]); + out_8(reset_io, KEYLARGO_GPIO_OUTPUT_ENABLE); udelay(1); - out_8((volatile u8 *)KL_FCR(KL_GPIO_KICK_CPU1), KL_GPIO_KICK_CPU1_DOWN); + out_8(reset_io, KEYLARGO_GPIO_OUTPUT_ENABLE | KEYLARGO_GPIO_OUTOUT_DATA); +#else + out_8((volatile u8 *)KL_FCR(KL_GPIO_EXTINT_CPU1), KL_GPIO_EXTINT_CPU1_ASSERT); + udelay(1); + out_8((volatile u8 *)KL_FCR(KL_GPIO_EXTINT_CPU1), KL_GPIO_EXTINT_CPU1_RELEASE); +#endif } #endif /* CONFIG_SMP */ +void +feature_set_airport_power(struct device_node* device, int power) +{ + if (!keylargo_base || !airport_dev || airport_dev != device) + return; + if (airport_pwr_state == power) + return; + if (power) { + /* Some if this is from Darwin code, some is from tracing of + * MacOS driver with Macsbug. Some real bit definitions would + * really help here... + */ + out_8((volatile u8*)KL_FCR(KL_GPIO_AIRPORT_0), airport_pwr_regs[0]); + out_8((volatile u8*)KL_FCR(KL_GPIO_AIRPORT_1), airport_pwr_regs[1]); + out_8((volatile u8*)KL_FCR(KL_GPIO_AIRPORT_2), airport_pwr_regs[2]); + out_8((volatile u8*)KL_FCR(KL_GPIO_AIRPORT_3), airport_pwr_regs[3]); + out_8((volatile u8*)KL_FCR(KL_GPIO_AIRPORT_4), airport_pwr_regs[4]); + udelay(20); + out_8((volatile u8*)KL_FCR(KL_GPIO_AIRPORT_4), 5); + udelay(20); + out_8((volatile u8*)KL_FCR(KL_GPIO_AIRPORT_4), 4); + mdelay(20); + KL_BIC(KEYLARGO_FCR2, KL2_AIRPORT_RESET_N); + udelay(10); + out_8((volatile u8*)KL_FCR(0x1a3e0), 0x41); + udelay(10); + KL_BIS(KEYLARGO_FCR2, KL2_AIRPORT_RESET_N); + udelay(10); + } else { + airport_pwr_regs[0] = in_8((volatile u8*)KL_FCR(KL_GPIO_AIRPORT_0)); + airport_pwr_regs[1] = in_8((volatile u8*)KL_FCR(KL_GPIO_AIRPORT_1)); + airport_pwr_regs[2] = in_8((volatile u8*)KL_FCR(KL_GPIO_AIRPORT_2)); + airport_pwr_regs[3] = in_8((volatile u8*)KL_FCR(KL_GPIO_AIRPORT_3)); + airport_pwr_regs[4] = in_8((volatile u8*)KL_FCR(KL_GPIO_AIRPORT_4)); + out_8((volatile u8*)KL_FCR(KL_GPIO_AIRPORT_0), 0); + out_8((volatile u8*)KL_FCR(KL_GPIO_AIRPORT_1), 0); + out_8((volatile u8*)KL_FCR(KL_GPIO_AIRPORT_2), 0); + out_8((volatile u8*)KL_FCR(KL_GPIO_AIRPORT_3), 0); + out_8((volatile u8*)KL_FCR(KL_GPIO_AIRPORT_4), 0); + } + airport_pwr_state = power; +} + /* Initialize the Core99 UniNorth host bridge and memory controller */ static void @@ -563,51 +800,106 @@ /* Set the arbitrer QAck delay according to what Apple does */ - actrl = in_be32(UN_REG(UNI_N_ARB_CTRL)) & ~UNI_N_ARB_CTRL_QACK_DELAY_MASK; - actrl |= ((uninorth_rev < 3) ? UNI_N_ARB_CTRL_QACK_DELAY105 : UNI_N_ARB_CTRL_QACK_DELAY) - << UNI_N_ARB_CTRL_QACK_DELAY_SHIFT; - UN_OUT(UNI_N_ARB_CTRL, actrl); + if (uninorth_rev < 0x10) { + actrl = UN_IN(UNI_N_ARB_CTRL) & ~UNI_N_ARB_CTRL_QACK_DELAY_MASK; + actrl |= ((uninorth_rev < 3) ? UNI_N_ARB_CTRL_QACK_DELAY105 : + UNI_N_ARB_CTRL_QACK_DELAY) << UNI_N_ARB_CTRL_QACK_DELAY_SHIFT; + UN_OUT(UNI_N_ARB_CTRL, actrl); + } - /* - * Turns OFF the gmac clock. The gmac driver will turn - * it back ON when the interface is enabled. This save - * power on portables. - * - * Note: We could also try to turn OFF the PHY. Since this - * has to be done by both the gmac driver and this code, - * I'll probably end-up moving some of this out of the - * modular gmac driver into a non-modular stub containing - * some basic PHY management and power management stuffs + /* Enable GMAC for now for PCI probing. It will be disabled + * later on after PCI probe */ gmac = find_devices("ethernet"); - while(gmac) { if (device_is_compatible(gmac, "gmac")) break; gmac = gmac->next; } if (gmac) - feature_set_gmac_power(gmac, 0); + feature_set_gmac_power(gmac, 1); - /* Kludge (enable FW before PCI probe) */ + /* Enable FW before PCI probe. Will be disabled later on + */ fw = find_devices("firewire"); if (fw && device_is_compatible(fw, "pci106b,18")) feature_set_firewire_power(fw, 1); } -/* Initialize the Core99 KeyLargo ASIC. Currently, we just make sure - * OpenPIC is enabled +/* Initialize the Core99 KeyLargo ASIC. */ static void keylargo_init(void) { + struct device_node* np; + KL_BIS(KEYLARGO_FCR2, KL2_MPIC_ENABLE); + + /* Lookup for an airport card, and disable it if found + * to save power (will be re-enabled by driver if used) + */ + np = find_devices("radio"); + if (np && np->parent == keylargo->device) + airport_dev = np; + + if (airport_dev) { + airport_pwr_state = 1; + feature_set_airport_power(airport_dev, 0); + } + } #ifdef CONFIG_PMAC_PBOOK +void +feature_prepare_for_sleep(void) +{ + /* We assume gatwick is second */ + struct feature_controller* ctrler = &controllers[0]; + + if (controller_count > 1 && + device_is_compatible(ctrler->device, "gatwick")) + ctrler = &controllers[1]; + + if (ctrler->bits == feature_bits_heathrow || + ctrler->bits == feature_bits_paddington) { + heathrow_prepare_for_sleep(ctrler); + return; + } + if (ctrler->bits == feature_bits_keylargo) { + core99_prepare_for_sleep(ctrler); + return; + } +} + + +void +feature_wake_up(void) +{ + struct feature_controller* ctrler = &controllers[0]; + + if (controller_count > 1 && + device_is_compatible(ctrler->device, "gatwick")) + ctrler = &controllers[1]; + + if (ctrler->bits == feature_bits_heathrow || + ctrler->bits == feature_bits_paddington) { + heathrow_wakeup(ctrler); + return; + } + if (ctrler->bits == feature_bits_keylargo) { + core99_wake_up(ctrler); + return; + } +} static u32 save_fcr[5]; static u32 save_mbcr; +static u32 save_gpio_levels[2]; +static u8 save_gpio_extint[KEYLARGO_GPIO_EXTINT_CNT]; +static u8 save_gpio_normal[KEYLARGO_GPIO_CNT]; +static u32 save_unin_clock_ctl; +static struct dbdma_regs save_dbdma[13]; + static void heathrow_prepare_for_sleep(struct feature_controller* ctrler) @@ -631,60 +923,226 @@ } static void -core99_prepare_for_sleep(struct feature_controller* ctrler) +turn_off_keylargo(void) { - /* Not yet implemented */ + u32 temp; + + /* For now, suspending the USB ref cause the machine to die on + * wakeup -- BenH + */ +#if 0 + mdelay(1); + KL_BIS(KEYLARGO_FCR0, KL0_USB_REF_SUSPEND); + (void)KL_IN(KEYLARGO_FCR0); + mdelay(1500); +#endif + + KL_BIC(KEYLARGO_FCR0, KL0_SCCA_ENABLE | KL0_SCCB_ENABLE | + KL0_SCC_CELL_ENABLE | + KL0_IRDA_ENABLE | KL0_IRDA_CLK32_ENABLE | + KL0_IRDA_CLK19_ENABLE); + + (void)KL_IN(KEYLARGO_FCR0); udelay(10); + KL_BIS(KEYLARGO_MBCR, KL_MBCR_MB0_DEV_ENABLE); + (void)KL_IN(KEYLARGO_MBCR); udelay(10); + + KL_BIC(KEYLARGO_FCR1, + KL1_AUDIO_SEL_22MCLK | KL1_AUDIO_CLK_ENABLE_BIT | + KL1_AUDIO_CLK_OUT_ENABLE | KL1_AUDIO_CELL_ENABLE | + KL1_I2S0_CELL_ENABLE | KL1_I2S0_CLK_ENABLE_BIT | + KL1_I2S0_ENABLE | KL1_I2S1_CELL_ENABLE | + KL1_I2S1_CLK_ENABLE_BIT | KL1_I2S1_ENABLE | + KL1_EIDE0_ENABLE | KL1_EIDE0_RESET_N | + KL1_EIDE1_ENABLE | KL1_EIDE1_RESET_N | + KL1_UIDE_ENABLE); + (void)KL_IN(KEYLARGO_FCR1); udelay(10); + + KL_BIS(KEYLARGO_FCR2, KL2_MODEM_POWER_N); + udelay(10); + KL_BIC(KEYLARGO_FCR2, KL2_IOBUS_ENABLE); + udelay(10); + temp = KL_IN(KEYLARGO_FCR3); + if (keylargo_rev >= 2) + temp |= (KL3_SHUTDOWN_PLL2X | KL3_SHUTDOWN_PLL_TOTAL); + + temp |= KL3_SHUTDOWN_PLLKW6 | KL3_SHUTDOWN_PLLKW4 | + KL3_SHUTDOWN_PLLKW35 | KL3_SHUTDOWN_PLLKW12; + temp &= ~(KL3_CLK66_ENABLE | KL3_CLK49_ENABLE | KL3_CLK45_ENABLE + | KL3_CLK31_ENABLE | KL3_TIMER_CLK18_ENABLE | KL3_I2S1_CLK18_ENABLE + | KL3_I2S0_CLK18_ENABLE | KL3_VIA_CLK16_ENABLE); + KL_OUT(KEYLARGO_FCR3, temp); + (void)KL_IN(KEYLARGO_FCR3); udelay(10); } static void -core99_wake_up(struct feature_controller* ctrler) +turn_off_pangea(void) { - /* Not yet implemented */ + u32 temp; + + KL_BIC(KEYLARGO_FCR0, KL0_SCCA_ENABLE | KL0_SCCB_ENABLE | + KL0_SCC_CELL_ENABLE | + KL0_USB0_CELL_ENABLE | KL0_USB1_CELL_ENABLE); + + (void)KL_IN(KEYLARGO_FCR0); udelay(10); + KL_BIS(KEYLARGO_MBCR, KL_MBCR_MB0_DEV_ENABLE); + (void)KL_IN(KEYLARGO_MBCR); udelay(10); + + KL_BIC(KEYLARGO_FCR1, + KL1_AUDIO_SEL_22MCLK | KL1_AUDIO_CLK_ENABLE_BIT | + KL1_AUDIO_CLK_OUT_ENABLE | KL1_AUDIO_CELL_ENABLE | + KL1_I2S0_CELL_ENABLE | KL1_I2S0_CLK_ENABLE_BIT | + KL1_I2S0_ENABLE | KL1_I2S1_CELL_ENABLE | + KL1_I2S1_CLK_ENABLE_BIT | KL1_I2S1_ENABLE | + KL1_UIDE_ENABLE); + (void)KL_IN(KEYLARGO_FCR1); udelay(10); + + KL_BIS(KEYLARGO_FCR2, KL2_MODEM_POWER_N); + udelay(10); + temp = KL_IN(KEYLARGO_FCR3); + temp |= KL3_SHUTDOWN_PLLKW6 | KL3_SHUTDOWN_PLLKW4 | + KL3_SHUTDOWN_PLLKW35; + temp &= ~(KL3_CLK49_ENABLE | KL3_CLK45_ENABLE + | KL3_CLK31_ENABLE | KL3_TIMER_CLK18_ENABLE | KL3_I2S1_CLK18_ENABLE + | KL3_I2S0_CLK18_ENABLE | KL3_VIA_CLK16_ENABLE); + KL_OUT(KEYLARGO_FCR3, temp); + (void)KL_IN(KEYLARGO_FCR3); udelay(10); } -void -feature_prepare_for_sleep(void) +static void +core99_prepare_for_sleep(struct feature_controller* ctrler) { - /* We assume gatwick is second */ - struct feature_controller* ctrler = &controllers[0]; + int i; + u8* base8; + + /* + * Save various bits of KeyLargo + */ - if (!ctrler) - return; - if (controller_count > 1 && - device_is_compatible(ctrler->device, "gatwick")) - ctrler = &controllers[1]; + /* We power off the wireless slot in case it was not done + * by the driver. We don't power it on automatically however + */ + feature_set_airport_power(airport_dev, 0); - if (ctrler->bits == feature_bits_heathrow || - ctrler->bits == feature_bits_paddington) { - heathrow_prepare_for_sleep(ctrler); - return; + /* We power off the FW cable. Should be done by the driver... */ + feature_set_firewire_cable_power(NULL, 0); + + /* Save the state of the various GPIOs */ + save_gpio_levels[0] = KL_IN(KEYLARGO_GPIO_LEVELS0); + save_gpio_levels[1] = KL_IN(KEYLARGO_GPIO_LEVELS1); + base8 = (u8 *)KL_FCR(KEYLARGO_GPIO_EXTINT_0); + for (i=0; i>2)); + save_dbdma[i].cmdptr_hi = in_le32(&chan->cmdptr_hi); + save_dbdma[i].cmdptr = in_le32(&chan->cmdptr); + save_dbdma[i].intr_sel = in_le32(&chan->intr_sel); + save_dbdma[i].br_sel = in_le32(&chan->br_sel); + save_dbdma[i].wait_sel = in_le32(&chan->wait_sel); } - if (ctrler->bits == feature_bits_keylargo) { - core99_prepare_for_sleep(ctrler); - return; + + /* + * Turn off as much as we can + */ + if (keylargo_rev & KL_PANGEA_REV) + turn_off_pangea(); + else + turn_off_keylargo(); + + /* + * Put the host bridge to sleep + */ + + save_unin_clock_ctl = UN_IN(UNI_N_CLOCK_CNTL); + UN_OUT(UNI_N_CLOCK_CNTL, save_unin_clock_ctl & + ~(UNI_N_CLOCK_CNTL_GMAC|UNI_N_CLOCK_CNTL_FW/*|UNI_N_CLOCK_CNTL_PCI*/)); + udelay(100); + UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_SLEEPING); + UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_SLEEP); + + /* + * FIXME: A bit of black magic with OpenPIC (don't ask me why) + */ + if (board_features & FTR_NEED_OPENPIC_TWEAK) { + KL_BIS(0x506e0, 0x00400000); + KL_BIS(0x506e0, 0x80000000); } } -void -feature_wake_up(void) +static void +core99_wake_up(struct feature_controller* ctrler) { - struct feature_controller* ctrler = &controllers[0]; + int i; + u8* base8; - if (!ctrler) - return; - if (controller_count > 1 && - device_is_compatible(ctrler->device, "gatwick")) - ctrler = &controllers[1]; + /* + * Wakeup the host bridge + */ + UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_NORMAL); + udelay(10); + UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_RUNNING); + udelay(10); - if (ctrler->bits == feature_bits_heathrow || - ctrler->bits == feature_bits_paddington) { - heathrow_wakeup(ctrler); - return; + /* + * Restore KeyLargo + */ + + KL_OUT(KEYLARGO_MBCR, save_mbcr); + (void)KL_IN(KEYLARGO_MBCR); udelay(10); + KL_OUT(KEYLARGO_FCR0, save_fcr[0]); + (void)KL_IN(KEYLARGO_FCR0); udelay(10); + KL_OUT(KEYLARGO_FCR1, save_fcr[1]); + (void)KL_IN(KEYLARGO_FCR1); udelay(10); + KL_OUT(KEYLARGO_FCR2, save_fcr[2]); + (void)KL_IN(KEYLARGO_FCR2); udelay(10); + KL_OUT(KEYLARGO_FCR3, save_fcr[3]); + (void)KL_IN(KEYLARGO_FCR3); udelay(10); + KL_OUT(KEYLARGO_FCR4, save_fcr[4]); + (void)KL_IN(KEYLARGO_FCR4); udelay(10); + + for (i=0; i<13; i++) { + volatile struct dbdma_regs* chan = (volatile struct dbdma_regs*) + (keylargo_base + ((0x8000+i*0x100)>>2)); + out_le32(&chan->control, (ACTIVE|DEAD|WAKE|FLUSH|PAUSE|RUN)<<16); + while (in_le32(&chan->status) & ACTIVE) + mb(); + out_le32(&chan->cmdptr_hi, save_dbdma[i].cmdptr_hi); + out_le32(&chan->cmdptr, save_dbdma[i].cmdptr); + out_le32(&chan->intr_sel, save_dbdma[i].intr_sel); + out_le32(&chan->br_sel, save_dbdma[i].br_sel); + out_le32(&chan->wait_sel, save_dbdma[i].wait_sel); } - if (ctrler->bits == feature_bits_keylargo) { - core99_wake_up(ctrler); - return; + + KL_OUT(KEYLARGO_GPIO_LEVELS0, save_gpio_levels[0]); + KL_OUT(KEYLARGO_GPIO_LEVELS1, save_gpio_levels[1]); + base8 = (u8 *)KL_FCR(KEYLARGO_GPIO_EXTINT_0); + for (i=0; i +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "pci.h" + +#define pci_config_addr(bus,dev,offset) \ + (0x80000000 | (bus<<16) | (dev<<8) | offset) + + +int +gemini_pcibios_read_config_byte(struct pci_dev *dev, int offset, u8 *val) +{ + unsigned long reg; + reg = grackle_read(pci_config_addr(dev->bus->number, dev->devfn, + (offset & ~(0x3)))); + *val = ((reg >> ((offset & 0x3) << 3)) & 0xff); + return PCIBIOS_SUCCESSFUL; +} + +int +gemini_pcibios_read_config_word(struct pci_dev *dev, int offset, u16 *val) +{ + unsigned long reg; + reg = grackle_read(pci_config_addr(dev->bus->number, dev->devfn, + (offset & ~(0x3)))); + *val = ((reg >> ((offset & 0x3) << 3)) & 0xffff); + return PCIBIOS_SUCCESSFUL; +} + +int +gemini_pcibios_read_config_dword(struct pci_dev *dev, int offset, u32 *val) +{ + *val = grackle_read(pci_config_addr(dev->bus->number, dev->devfn, + (offset & ~(0x3)))); + return PCIBIOS_SUCCESSFUL; +} + +int +gemini_pcibios_write_config_byte(struct pci_dev *dev, int offset, u8 val) +{ + unsigned long reg; + int shifts = offset & 0x3; + unsigned int addr = pci_config_addr(dev->bus->number, dev->devfn, + (offset & ~(0x3))); + + reg = grackle_read(addr); + reg = (reg & ~(0xff << (shifts << 3))) | (val << (shifts << 3)); + grackle_write(addr, reg ); + return PCIBIOS_SUCCESSFUL; +} + +int +gemini_pcibios_write_config_word(struct pci_dev *dev, int offset, u16 val) +{ + unsigned long reg; + int shifts = offset & 0x3; + unsigned int addr = pci_config_addr(dev->bus->number, dev->devfn, + (offset & ~(0x3))); + + reg = grackle_read(addr); + reg = (reg & ~(0xffff << (shifts << 3))) | (val << (shifts << 3)); + grackle_write(addr, reg ); + return PCIBIOS_SUCCESSFUL; +} + +int +gemini_pcibios_write_config_dword(struct pci_dev *dev, int offset, u32 val) +{ + grackle_write(pci_config_addr(dev->bus->number, dev->devfn, + (offset & ~(0x3))), val); + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops gemini_pci_ops = +{ + gemini_pcibios_read_config_byte, + gemini_pcibios_read_config_word, + gemini_pcibios_read_config_dword, + gemini_pcibios_write_config_byte, + gemini_pcibios_write_config_word, + gemini_pcibios_write_config_dword +}; + +void __init gemini_pcibios_fixup(void) +{ + int i; + struct pci_dev *dev; + + pci_for_each_dev(dev) { + for(i = 0; i < 6; i++) { + if (dev->resource[i].flags & IORESOURCE_IO) { + dev->resource[i].start |= (0xfe << 24); + dev->resource[i].end |= (0xfe << 24); + } + } + } +} + + +/* The "bootloader" for Synergy boards does none of this for us, so we need to + lay it all out ourselves... --Dan */ +void __init gemini_find_bridges(void) +{ + struct pci_controller* hose; + + ppc_md.pcibios_fixup = gemini_pcibios_fixup; + + hose = pcibios_alloc_controller(); + if (!hose) + return; + hose->ops = &gemini_pci_ops; +} diff -Nru a/arch/ppc/kernel/gemini_prom.S b/arch/ppc/kernel/gemini_prom.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/kernel/gemini_prom.S Wed May 16 06:00:33 2001 @@ -0,0 +1,96 @@ +/* + * arch/ppc/kernel/gemini_prom.S + * + * Not really prom support code (yet), but sort of anti-prom code. The current + * bootloader does a number of things it shouldn't and doesn't do things that it + * should. The stuff in here is mainly a hodge-podge collection of setup code + * to get the board up and running. + * ---Dan + */ + +#include "ppc_asm.tmpl" +#include "ppc_defs.h" +#include +#include +#include +#include + +#define HID0_ABE (1<<3) + +/* + * On 750's the MMU is on when Linux is booted, so we need to clear out the + * bootloader's BAT settings, make sure we're in supervisor state (gotcha!), + * and turn off the MMU. + * + */ + +_GLOBAL(gemini_prom_init) +#ifdef CONFIG_SMP + /* Since the MMU's on, get stuff in rom space that we'll need */ + lis r4,GEMINI_CPUSTAT@h + ori r4,r4,GEMINI_CPUSTAT@l + lbz r5,0(r4) + andi. r5,r5,3 + mr r24,r5 /* cpu # used later on */ +#endif + mfmsr r4 + li r3,MSR_PR /* ensure supervisor! */ + ori r3,r3,MSR_IR|MSR_DR + andc r4,r4,r3 + mtmsr r4 + isync +#if 0 + /* zero out the bats now that the MMU is off */ +prom_no_mmu: + li r3,0 + mtspr IBAT0U,r3 + mtspr IBAT0L,r3 + mtspr IBAT1U,r3 + mtspr IBAT1L,r3 + mtspr IBAT2U,r3 + mtspr IBAT2L,r3 + mtspr IBAT3U,r3 + mtspr IBAT3L,r3 + + mtspr DBAT0U,r3 + mtspr DBAT0L,r3 + mtspr DBAT1U,r3 + mtspr DBAT1L,r3 + mtspr DBAT2U,r3 + mtspr DBAT2L,r3 + mtspr DBAT3U,r3 + mtspr DBAT3L,r3 +#endif + + /* the bootloader (as far as I'm currently aware) doesn't mess with page + tables, but since we're already here, might as well zap these, too */ + li r4,0 + mtspr SDR1,r4 + + li r4,16 + mtctr r4 + li r3,0 + li r4,0 +3: mtsrin r3,r4 + addi r3,r3,1 + bdnz 3b + +#ifdef CONFIG_SMP + /* The 750 book (and Mot/IBM support) says that this will "assist" snooping + when in SMP. Not sure yet whether this should stay or leave... */ + mfspr r4,HID0 + ori r4,r4,HID0_ABE + mtspr HID0,r4 + sync +#endif /* CONFIG_SMP */ + blr + +/* apparently, SMon doesn't pay attention to HID0[SRST]. Disable the MMU and + branch to 0xfff00100 */ +_GLOBAL(_gemini_reboot) + lis r5,GEMINI_BOOT_INIT@h + ori r5,r5,GEMINI_BOOT_INIT@l + li r6,MSR_IP + mtspr SRR0,r5 + mtspr SRR1,r6 + rfi diff -Nru a/arch/ppc/kernel/gemini_setup.c b/arch/ppc/kernel/gemini_setup.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/kernel/gemini_setup.c Wed May 16 06:00:34 2001 @@ -0,0 +1,537 @@ +/* + * linux/arch/ppc/kernel/setup.c + * + * Copyright (C) 1995 Linus Torvalds + * Adapted from 'alpha' version by Gary Thomas + * Modified by Cort Dougan (cort@cs.nmt.edu) + * Synergy Microsystems board support by Dan Cox (dan@synergymicro.com) + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "local_irq.h" +#include "open_pic.h" + +void gemini_find_bridges(void); +static int gemini_get_clock_speed(void); +extern void gemini_pcibios_fixup(void); + +static char *gemini_board_families[] = { + "VGM", "VSS", "KGM", "VGR", "VCM", "VCS", "KCM", "VCR" +}; +static int gemini_board_count = sizeof(gemini_board_families) / + sizeof(gemini_board_families[0]); + +static unsigned int cpu_7xx[16] = { + 0, 15, 14, 0, 0, 13, 5, 9, 6, 11, 8, 10, 16, 12, 7, 0 +}; +static unsigned int cpu_6xx[16] = { + 0, 0, 14, 0, 0, 13, 5, 9, 6, 11, 8, 10, 0, 12, 7, 0 +}; + +int chrp_get_irq(struct pt_regs *); +void chrp_post_irq(struct pt_regs* regs, int); + +static inline unsigned long _get_HID1(void) +{ + unsigned long val; + + __asm__ __volatile__("mfspr %0,1009" : "=r" (val)); + return val; +} + +/* + * prom_init is the Gemini version of prom.c:prom_init. We only need + * the BSS clearing code, so I copied that out of prom.c. This is a + * lot simpler than hacking prom.c so it will build with Gemini. -VAL + */ + +#define PTRRELOC(x) ((typeof(x))((unsigned long)(x) + offset)) + +unsigned long +prom_init(void) +{ + unsigned long offset = reloc_offset(); + unsigned long phys; + extern char __bss_start, _end; + + /* First zero the BSS -- use memset, some arches don't have + * caches on yet */ + memset_io(PTRRELOC(&__bss_start),0 , &_end - &__bss_start); + + /* Default */ + phys = offset + KERNELBASE; + + gemini_prom_init(); + + return phys; +} + +int +gemini_get_cpuinfo(char *buffer) +{ + int len; + unsigned char reg, rev; + char *family; + unsigned int type; + + reg = readb(GEMINI_FEAT); + family = gemini_board_families[((reg>>4) & 0xf)]; + if (((reg>>4) & 0xf) > gemini_board_count) + printk(KERN_ERR "cpuinfo(): unable to determine board family\n"); + + reg = readb(GEMINI_BREV); + type = (reg>>4) & 0xf; + rev = reg & 0xf; + + reg = readb(GEMINI_BECO); + + len = sprintf( buffer, "machine\t\t: Gemini %s%d, rev %c, eco %d\n", + family, type, (rev + 'A'), (reg & 0xf)); + + len = sprintf(buffer, "board\t\t: Gemini %s", family); + if (type > 9) + len += sprintf(buffer+len, "%c", (type - 10) + 'A'); + else + len += sprintf(buffer+len, "%d", type); + + len += sprintf(buffer+len, ", rev %c, eco %d\n", + (rev + 'A'), (reg & 0xf)); + + len += sprintf(buffer+len, "clock\t\t: %dMhz\n", + gemini_get_clock_speed()); + + return len; +} + +static u_char gemini_openpic_initsenses[] = { + 1, + 1, + 1, + 1, + 0, + 0, + 1, /* remainder are level-triggered */ +}; + +#define GEMINI_MPIC_ADDR (0xfcfc0000) +#define GEMINI_MPIC_PCI_CFG (0x80005800) + +void __init gemini_openpic_init(void) +{ + + OpenPIC_Addr = (volatile struct OpenPIC *) + grackle_read(GEMINI_MPIC_PCI_CFG + 0x10); + OpenPIC_InitSenses = gemini_openpic_initsenses; + OpenPIC_NumInitSenses = sizeof( gemini_openpic_initsenses ); + + ioremap( GEMINI_MPIC_ADDR, OPENPIC_SIZE); +} + + +extern unsigned long loops_per_jiffy; +extern int root_mountflags; +extern char cmd_line[]; + +void +gemini_heartbeat(void) +{ + static unsigned long led = GEMINI_LEDBASE+(4*8); + static char direction = 8; + *(char *)led = 0; + if ( (led + direction) > (GEMINI_LEDBASE+(7*8)) || + (led + direction) < (GEMINI_LEDBASE+(4*8)) ) + direction *= -1; + led += direction; + *(char *)led = 0xff; + ppc_md.heartbeat_count = ppc_md.heartbeat_reset; +} + +void __init gemini_setup_arch(void) +{ + extern char cmd_line[]; + + + loops_per_jiffy = 50000000/HZ; + +#ifdef CONFIG_BLK_DEV_INITRD + /* bootable off CDROM */ + if (initrd_start) + ROOT_DEV = MKDEV(SCSI_CDROM_MAJOR, 0); + else +#endif + ROOT_DEV = to_kdev_t(0x0801); + + /* nothing but serial consoles... */ + sprintf(cmd_line, "%s console=ttyS0", cmd_line); + + printk("Boot arguments: %s\n", cmd_line); + + ppc_md.heartbeat = gemini_heartbeat; + ppc_md.heartbeat_reset = HZ/8; + ppc_md.heartbeat_count = 1; + + /* Lookup PCI hosts */ + gemini_find_bridges(); + /* take special pains to map the MPIC, since it isn't mapped yet */ + gemini_openpic_init(); + /* start the L2 */ + gemini_init_l2(); +} + + +int +gemini_get_clock_speed(void) +{ + unsigned long hid1, pvr = _get_PVR(); + int clock; + + hid1 = (_get_HID1() >> 28) & 0xf; + if (PVR_VER(pvr) == 8 || + PVR_VER(pvr) == 12) + hid1 = cpu_7xx[hid1]; + else + hid1 = cpu_6xx[hid1]; + + switch((readb(GEMINI_BSTAT) & 0xc) >> 2) { + + case 0: + default: + clock = (hid1*100)/3; + break; + + case 1: + clock = (hid1*125)/3; + break; + + case 2: + clock = (hid1*50); + break; + } + + return clock; +} + +void __init gemini_init_l2(void) +{ + unsigned char reg, brev, fam, creg; + unsigned long cache; + unsigned long pvr = _get_PVR(); + + reg = readb(GEMINI_L2CFG); + brev = readb(GEMINI_BREV); + fam = readb(GEMINI_FEAT); + + switch(PVR_VER(pvr)) { + + case 8: + if (reg & 0xc0) + cache = (((reg >> 6) & 0x3) << 28); + else + cache = 0x3 << 28; + +#ifdef CONFIG_SMP + /* Pre-3.0 processor revs had snooping errata. Leave + their L2's disabled with SMP. -- Dan */ + if (PVR_CFG(pvr) < 3) { + printk("Pre-3.0 750; L2 left disabled!\n"); + return; + } +#endif /* CONFIG_SMP */ + + /* Special case: VGM5-B's came before L2 ratios were set on + the board. Processor speed shouldn't be too high, so + set L2 ratio to 1:1.5. */ + if ((brev == 0x51) && ((fam & 0xa0) >> 4) == 0) + reg |= 1; + + /* determine best cache ratio based upon what the board + tells us (which sometimes _may_ not be true) and + the processor speed. */ + else { + if (gemini_get_clock_speed() > 250) + reg = 2; + } + break; + case 12: + { + static unsigned long l2_size_val = 0; + + if (!l2_size_val) + l2_size_val = _get_L2CR(); + cache = l2_size_val; + break; + } + case 4: + case 9: + creg = readb(GEMINI_CPUSTAT); + if (((creg & 0xc) >> 2) != 1) + printk("Dual-604 boards don't support the use of L2\n"); + else + writeb(1, GEMINI_L2CFG); + return; + default: + printk("Unknown processor; L2 left disabled\n"); + return; + } + + cache |= ((1<>2)&0x3) { + case 0: + default: + freq = 66667; + break; + case 1: + freq = 83000; + break; + case 2: + freq = 100000; + break; + } + + freq *= 1000; + divisor = 4; + tb_ticks_per_jiffy = freq / HZ / divisor; + tb_to_us = mulhwu_scale_factor(freq/divisor, 1000000); +} + +unsigned long __init gemini_find_end_of_memory(void) +{ + unsigned long total; + unsigned char reg; + + reg = readb(GEMINI_MEMCFG); + total = ((1<<((reg & 0x7) - 1)) * + (8<<((reg >> 3) & 0x7))); + total *= (1024*1024); + return total; +} + +void __init gemini_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + int i; + int chrp_get_irq( struct pt_regs * ); + + for(i = 0; i < GEMINI_LEDS; i++) + gemini_led_off(i); + + ISA_DMA_THRESHOLD = 0; + DMA_MODE_READ = 0; + DMA_MODE_WRITE = 0; + +#ifdef CONFIG_BLK_DEV_INITRD + if ( r4 ) + { + initrd_start = r4 + KERNELBASE; + initrd_end = r5 + KERNELBASE; + } +#endif + + ppc_md.setup_arch = gemini_setup_arch; + ppc_md.setup_residual = NULL; + ppc_md.get_cpuinfo = gemini_get_cpuinfo; + ppc_md.irq_cannonicalize = NULL; + ppc_md.init_IRQ = gemini_init_IRQ; + ppc_md.get_irq = openpic_get_irq; + ppc_md.init = NULL; + + ppc_md.restart = gemini_restart; + ppc_md.power_off = gemini_power_off; + ppc_md.halt = gemini_halt; + + ppc_md.time_init = gemini_time_init; + ppc_md.set_rtc_time = gemini_set_rtc_time; + ppc_md.get_rtc_time = gemini_get_rtc_time; + ppc_md.calibrate_decr = gemini_calibrate_decr; + + ppc_md.find_end_of_memory = gemini_find_end_of_memory; + + /* no keyboard/mouse/video stuff yet.. */ + ppc_md.kbd_setkeycode = NULL; + ppc_md.kbd_getkeycode = NULL; + ppc_md.kbd_translate = NULL; + ppc_md.kbd_unexpected_up = NULL; + ppc_md.kbd_leds = NULL; + ppc_md.kbd_init_hw = NULL; +#ifdef CONFIG_MAGIC_SYSRQ + ppc_md.ppc_kbd_sysrq_xlate = NULL; +#endif + ppc_md.pcibios_fixup_bus = gemini_pcibios_fixup; +} diff -Nru a/arch/ppc/kernel/hashtable.S b/arch/ppc/kernel/hashtable.S --- a/arch/ppc/kernel/hashtable.S Wed May 16 06:00:23 2001 +++ b/arch/ppc/kernel/hashtable.S Wed May 16 06:00:23 2001 @@ -27,7 +27,6 @@ #include #include #include -#include "mol.h" /* * Load a PTE into the hash table, if possible. @@ -609,11 +608,6 @@ * flush_hash_page(unsigned context, unsigned long va) */ _GLOBAL(flush_hash_page) -#ifdef CONFIG_MOL - mflr r10 - MOL_HOOK_MMU(10, r6) - mtlr r10 -#endif lis r6,Hash@ha lwz r6,Hash@l(r6) /* hash table base */ cmpwi 0,r6,0 /* hash table in use? */ diff -Nru a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S --- a/arch/ppc/kernel/head.S Wed May 16 06:00:23 2001 +++ b/arch/ppc/kernel/head.S Wed May 16 06:00:23 2001 @@ -31,24 +31,11 @@ #include #include #include -#include "mol.h" #ifdef CONFIG_APUS #include #endif -#ifndef CONFIG_PPC64BRIDGE -CACHELINE_BYTES = 32 -LG_CACHELINE_BYTES = 5 -CACHELINE_MASK = 0x1f -CACHELINE_WORDS = 8 -#else -CACHELINE_BYTES = 128 -LG_CACHELINE_BYTES = 7 -CACHELINE_MASK = 0x7f -CACHELINE_WORDS = 32 -#endif /* CONFIG_PPC64BRIDGE */ - #ifdef CONFIG_PPC64BRIDGE #define LOAD_BAT(n, reg, RA, RB) \ ld RA,(n*32)+0(reg); \ @@ -161,6 +148,7 @@ bl fix_mem_constants #endif /* CONFIG_APUS */ +#ifndef CONFIG_GEMINI /* Switch MMU off, clear BATs and flush TLB. At this point, r3 contains * the physical address we are running at, returned by prom_init() */ @@ -168,6 +156,7 @@ __after_mmu_off: bl clear_bats bl flush_tlbs +#endif #ifndef CONFIG_POWER4 /* POWER4 doesn't have BATs */ @@ -294,21 +283,14 @@ .long hdlr; \ .long ret_from_except -#define STD_MOL_EXCEPTION(n, label, hdlr, hook) \ - . = n; \ -label: \ - EXCEPTION_PROLOG; \ - MOL_HOOK(hook); \ - addi r3,r1,STACK_FRAME_OVERHEAD; \ - li r20,MSR_KERNEL; \ - bl transfer_to_handler; \ -i##n: \ - .long hdlr; \ - .long ret_from_except - /* System reset */ -#ifdef CONFIG_SMP /* MVME/MTX start the secondary here */ +#ifdef CONFIG_SMP /* MVME/MTX and gemini start the secondary here */ +#ifdef CONFIG_GEMINI + . = 0x100 + b __secondary_start_gemini +#else /* CONFIG_GEMINI */ STD_EXCEPTION(0x100, Reset, __secondary_start_psurge) +#endif /* CONFIG_GEMINI */ #else STD_EXCEPTION(0x100, Reset, UnknownException) #endif @@ -325,7 +307,6 @@ DataAccess: EXCEPTION_PROLOG #endif /* CONFIG_PPC64BRIDGE */ - MOL_HOOK(0) mfspr r20,DSISR andis. r0,r20,0xa470 /* weird error? */ bne 1f /* if not, try to put a PTE */ @@ -369,7 +350,6 @@ InstructionAccess: EXCEPTION_PROLOG #endif /* CONFIG_PPC64BRIDGE */ - MOL_HOOK(1) andis. r0,r23,0x4000 /* no pte found? */ beq 1f /* if so, try to put a PTE */ mr r3,r22 /* into the hash table */ @@ -436,7 +416,6 @@ . = 0x700 ProgramCheck: EXCEPTION_PROLOG - MOL_HOOK(2) addi r3,r1,STACK_FRAME_OVERHEAD li r20,MSR_KERNEL rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */ @@ -449,7 +428,6 @@ . = 0x800 FPUnavailable: EXCEPTION_PROLOG - MOL_HOOK_RESTORE(3) bne load_up_fpu /* if from user, just load it up */ li r20,MSR_KERNEL bl transfer_to_handler /* if from kernel, take a trap */ @@ -460,7 +438,6 @@ . = 0x900 Decrementer: EXCEPTION_PROLOG - MOL_HOOK(4) addi r3,r1,STACK_FRAME_OVERHEAD li r20,MSR_KERNEL bl transfer_to_handler @@ -484,7 +461,7 @@ .long ret_from_except /* Single step - not used on 601 */ - STD_MOL_EXCEPTION(0xd00, SingleStep, SingleStepException, 5) + STD_EXCEPTION(0xd00, SingleStep, SingleStepException) STD_EXCEPTION(0xe00, Trap_0e, UnknownException) /* @@ -514,7 +491,6 @@ */ . = 0x1000 InstructionTLBMiss: - MOL_HOOK_TLBMISS( 14 ) /* * r0: stored ctr * r1: linux style pte ( later becomes ppc hardware pte ) @@ -586,7 +562,6 @@ */ . = 0x1100 DataLoadTLBMiss: - MOL_HOOK_TLBMISS( 15 ) /* * r0: stored ctr * r1: linux style pte ( later becomes ppc hardware pte ) @@ -657,7 +632,6 @@ */ . = 0x1200 DataStoreTLBMiss: - MOL_HOOK_TLBMISS( 16 ) /* * r0: stored ctr * r1: linux style pte ( later becomes ppc hardware pte ) @@ -704,7 +678,7 @@ mtcrf 0x80,r3 rfi - STD_MOL_EXCEPTION(0x1300, Trap_13, InstructionBreakpoint, 11) + STD_EXCEPTION(0x1300, Trap_13, InstructionBreakpoint) STD_EXCEPTION(0x1400, SMI, SMIException) STD_EXCEPTION(0x1500, Trap_15, UnknownException) STD_EXCEPTION(0x1600, Trap_16, UnknownException) @@ -717,7 +691,7 @@ STD_EXCEPTION(0x1d00, Trap_1d, UnknownException) STD_EXCEPTION(0x1e00, Trap_1e, UnknownException) STD_EXCEPTION(0x1f00, Trap_1f, UnknownException) - STD_MOL_EXCEPTION(0x2000, RunMode, RunModeException, 5) + STD_EXCEPTION(0x2000, RunMode, RunModeException) STD_EXCEPTION(0x2100, Trap_21, UnknownException) STD_EXCEPTION(0x2200, Trap_22, UnknownException) STD_EXCEPTION(0x2300, Trap_23, UnknownException) @@ -739,7 +713,6 @@ #ifdef CONFIG_ALTIVEC AltiVecUnavailable: EXCEPTION_PROLOG - MOL_HOOK_RESTORE(12) bne load_up_altivec /* if from user, just load it up */ li r20,MSR_KERNEL bl transfer_to_handler /* if from kernel, take a trap */ @@ -805,7 +778,6 @@ lwz r24,0(r23) /* virtual address of handler */ lwz r23,4(r23) /* where to go when done */ FIX_SRR1(r20,r22) - MOL_HOOK(6) mtspr SRR0,r24 mtspr SRR1,r20 mtlr r23 @@ -1016,11 +988,6 @@ .globl giveup_altivec giveup_altivec: -#ifdef CONFIG_MOL - mflr r4 - MOL_HOOK_MMU(13, r5) - mtlr r4 -#endif mfmsr r5 oris r5,r5,MSR_VEC@h SYNC @@ -1057,11 +1024,6 @@ */ .globl giveup_fpu giveup_fpu: -#ifdef CONFIG_MOL - mflr r4 - MOL_HOOK_MMU(7, r5) - mtlr r4 -#endif mfmsr r5 ori r5,r5,MSR_FP SYNC @@ -1116,7 +1078,7 @@ copy_and_flush: addi r5,r5,-4 addi r6,r6,-4 -4: li r0,CACHELINE_WORDS +4: li r0,CACHE_LINE_SIZE/4 mtctr r0 3: addi r6,r6,4 /* copy a cache line */ lwzx r0,r6,r4 @@ -1127,6 +1089,7 @@ icbi r6,r3 /* flush the icache line */ cmplw 0,r6,r5 blt 4b + sync /* additional sync needed on g4 */ isync addi r5,r5,4 addi r6,r6,4 @@ -1165,6 +1128,7 @@ icbi r0,r14 /* flush the icache line */ cmpw r12,r13 bne 1b + sync /* additional sync needed on g4 */ isync /* @@ -1199,6 +1163,7 @@ cmpw r12,r13 bne 1b + sync /* additional sync needed on g4 */ isync /* No speculative loading until now */ blr @@ -1266,6 +1231,20 @@ #endif /* CONFIG_APUS */ #ifdef CONFIG_SMP +#ifdef CONFIG_GEMINI + .globl __secondary_start_gemini +__secondary_start_gemini: + mfspr r4,HID0 + ori r4,r4,HID0_ICFI + li r3,0 + ori r3,r3,HID0_ICE + andc r4,r4,r3 + mtspr HID0,r4 + sync + bl prom_init + b __secondary_start +#endif /* CONFIG_GEMINI */ + .globl __secondary_start_psurge __secondary_start_psurge: li r24,1 /* cpu # */ @@ -1536,6 +1515,7 @@ * -- Cort */ clear_bats: +#if !defined(CONFIG_GEMINI) li r20,0 mfspr r9,PVR rlwinm r9,r9,16,16,31 /* r9 = 1 for 601, 4 for 604 */ @@ -1559,8 +1539,10 @@ mtspr IBAT2L,r20 mtspr IBAT3U,r20 mtspr IBAT3L,r20 +#endif /* !defined(CONFIG_GEMINI) */ blr +#ifndef CONFIG_GEMINI flush_tlbs: lis r20, 0x40 1: addic. r20, r20, -0x1000 @@ -1579,6 +1561,7 @@ mtspr SRR1,r3 sync RFI +#endif #ifndef CONFIG_POWER4 /* @@ -1688,17 +1671,6 @@ 2: mtlr r4 blr -#endif - -#ifdef CONFIG_MOL -/* - * Mac-on-linux hook_table. Don't put this in the data section - - * the base address must be within the first 32KB of RAM. - */ - .globl mol_interface -mol_interface: - .long MOL_INTERFACE_VERSION - .fill 24,4,0 /* space for 24 hooks */ #endif diff -Nru a/arch/ppc/kernel/head_8xx.S b/arch/ppc/kernel/head_8xx.S --- a/arch/ppc/kernel/head_8xx.S Wed May 16 06:00:16 2001 +++ b/arch/ppc/kernel/head_8xx.S Wed May 16 06:00:16 2001 @@ -30,13 +30,6 @@ #include #include #include - -/* XXX need definitions here for 16 byte cachelines on some/all 8xx - -- paulus */ -CACHELINE_BYTES = 32 -LG_CACHELINE_BYTES = 5 -CACHELINE_MASK = 0x1f -CACHELINE_WORDS = 8 .text .globl _stext @@ -757,7 +750,7 @@ copy_and_flush: addi r5,r5,-4 addi r6,r6,-4 -4: li r0,CACHELINE_WORDS +4: li r0,CACHE_LINE_SIZE/4 mtctr r0 3: addi r6,r6,4 /* copy a cache line */ lwzx r0,r6,r4 diff -Nru a/arch/ppc/kernel/idle.c b/arch/ppc/kernel/idle.c --- a/arch/ppc/kernel/idle.c Wed May 16 06:00:19 2001 +++ b/arch/ppc/kernel/idle.c Wed May 16 06:00:19 2001 @@ -56,6 +56,7 @@ case 7: /* 603ev */ case 8: /* 750 */ case 12: /* 7400 */ + case 0x800c: /* 7410 */ do_power_save = 1; } diff -Nru a/arch/ppc/kernel/irq.c b/arch/ppc/kernel/irq.c --- a/arch/ppc/kernel/irq.c Wed May 16 06:00:21 2001 +++ b/arch/ppc/kernel/irq.c Wed May 16 06:00:21 2001 @@ -176,9 +176,19 @@ return 0; } -/* This could be promoted to a real free_irq() ... */ -static int -do_free_irq(int irq, void* dev_id) +#if (defined(CONFIG_8xx) || defined(CONFIG_8260)) +/* Name change so we can catch standard drivers that potentially mess up + * the internal interrupt controller on 8xx and 8260. Just bear with me, + * I don't like this either and I am searching a better solution. For + * now, this is what I need. -- Dan + */ +#define request_irq request_8xxirq +#elif defined(CONFIG_APUS) +#define request_irq request_sysirq +#define free_irq sys_free_irq +#endif + +void free_irq(unsigned int irq, void* dev_id) { irq_desc_t *desc; struct irqaction **p; @@ -209,27 +219,15 @@ barrier(); #endif irq_kfree(action); - return 0; + return; } printk("Trying to free free IRQ%d\n",irq); spin_unlock_irqrestore(&desc->lock,flags); break; } - return -ENOENT; + return; } -#if (defined(CONFIG_8xx) || defined(CONFIG_8260)) -/* Name change so we can catch standard drivers that potentially mess up - * the internal interrupt controller on 8xx and 8260. Just bear with me, - * I don't like this either and I am searching a better solution. For - * now, this is what I need. -- Dan - */ -#define request_irq request_8xxirq -#elif defined(CONFIG_APUS) -#define request_irq request_sysirq -#define free_irq sys_free_irq -#endif - int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long irqflags, const char * devname, void *dev_id) { @@ -239,8 +237,17 @@ if (irq >= NR_IRQS) return -EINVAL; if (!handler) - /* We could implement really free_irq() instead of that... */ - return do_free_irq(irq, dev_id); + { + /* + * free_irq() used to be implemented as a call to + * request_irq() with handler being NULL. Now we have + * a real free_irq() but need to allow the old behavior + * for old code that hasn't caught up yet. + * -- Cort + */ + free_irq(irq, dev_id); + return 0; + } action = (struct irqaction *) irq_kmalloc(sizeof(struct irqaction), GFP_KERNEL); @@ -266,11 +273,6 @@ return 0; } -void free_irq(unsigned int irq, void *dev_id) -{ - request_irq(irq, NULL, 0, NULL, dev_id); -} - /* * Generic enable/disable code: this just calls * down into the PIC-specific version for the actual @@ -524,7 +526,7 @@ spin_unlock(&desc->lock); } -int do_IRQ(struct pt_regs *regs, int isfake) +int do_IRQ(struct pt_regs *regs) { int cpu = smp_processor_id(); int irq; @@ -546,10 +548,7 @@ goto out; } ppc_irq_dispatch_handler( regs, irq ); - if (ppc_md.post_irq) - ppc_md.post_irq( regs, irq ); - - out: +out: hardirq_exit( cpu ); return 1; /* lets ret_from_int know we can do checks */ } @@ -851,15 +850,18 @@ } #endif /* CONFIG_SMP */ -static struct proc_dir_entry * root_irq_dir; -static struct proc_dir_entry * irq_dir [NR_IRQS]; -static struct proc_dir_entry * smp_affinity_entry [NR_IRQS]; +static struct proc_dir_entry *root_irq_dir; +static struct proc_dir_entry *irq_dir[NR_IRQS]; +static struct proc_dir_entry *smp_affinity_entry[NR_IRQS]; #ifdef CONFIG_IRQ_ALL_CPUS -unsigned int irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = 0xffffffff}; -#else /* CONFIG_IRQ_ALL_CPUS */ -unsigned int irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = 0x00000000}; -#endif /* CONFIG_IRQ_ALL_CPUS */ +#define DEFAULT_CPU_AFFINITY 0xffffffff +#else +#define DEFAULT_CPU_AFFINITY 0x00000001 +#endif + +unsigned int irq_affinity [NR_IRQS] = + { [0 ... NR_IRQS-1] = DEFAULT_CPU_AFFINITY }; #define HEX_DIGITS 8 @@ -919,16 +921,18 @@ err = parse_hex_value(buffer, count, &new_value); -/* Why is this disabled ? --BenH */ -#if 0/*CONFIG_SMP*/ /* * Do not allow disabling IRQs completely - it's a too easy * way to make the system unusable accidentally :-) At least * one online CPU still has to be targeted. + * + * We assume a 1-1 logical<->physical cpu mapping here. If + * we assume that the cpu indices in /proc/irq/../smp_affinity + * are actually logical cpu #'s then we have no problem. + * -- Cort */ if (!(new_value & cpu_online_map)) return -EINVAL; -#endif irq_affinity[irq] = new_value; irq_desc[irq].handler->set_affinity(irq, new_value); diff -Nru a/arch/ppc/kernel/k2.h b/arch/ppc/kernel/k2.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/kernel/k2.h Wed May 16 06:00:34 2001 @@ -0,0 +1,89 @@ +/* + * arch/ppc/kernel/k2.h + * + * Definitions for SBS K2 board support + * + * Author: Matt Porter + * + * Copyright 2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __PPC_KERNEL_K2_H +#define __PPC_KERNEL_K2_H + +#include "m1543c.h" + +/* + * SBS K2 definitions + */ + +#define K2_PCI64_BAR 0xff400000 +#define K2_PCI32_BAR 0xff500000 + +#define K2_PCI64_CONFIG_ADDR (K2_PCI64_BAR + 0x000f8000) +#define K2_PCI64_CONFIG_DATA (K2_PCI64_BAR + 0x000f8010) + +#define K2_PCI32_CONFIG_ADDR (K2_PCI32_BAR + 0x000f8000) +#define K2_PCI32_CONFIG_DATA (K2_PCI32_BAR + 0x000f8010) + +#define K2_PCI64_MEM_BASE 0xc8000000 +#define K2_PCI64_IO_BASE 0x88000000 + +#define K2_PCI32_MEM_BASE 0xc0000000 +#define K2_PCI32_IO_BASE 0x80000000 + +#define K2_PCI32_SYS_MEM_BASE 0x80000000 + +#define K2_PCI32_LOWER_MEM 0x00000000 +#define K2_PCI32_UPPER_MEM 0x07ffffff +#define K2_PCI32_LOWER_IO 0x00000000 +#define K2_PCI32_UPPER_IO 0x07ffffff + +#define K2_PCI64_LOWER_MEM 0x08000000 +#define K2_PCI64_UPPER_MEM 0x0fffffff +#define K2_PCI64_LOWER_IO 0x08000000 +#define K2_PCI64_UPPER_IO 0x0fffffff + +#define K2_ISA_IO_BASE K2_PCI32_IO_BASE +#define K2_ISA_MEM_BASE K2_PCI32_MEM_BASE + +#define K2_ISAPNP_CONFIG (K2_ISA_IO_BASE + M1543C_ISAPNP_CONFIG_OFFSET) +#define K2_ISAPNP_INDEX K2_ISAPNP_CONFIG +#define K2_ISAPNP_DATA (K2_ISA_IO_BASE + M1543C_ISAPNP_DATA_OFFSET) + +#define K2_BOARD_ID_REG (K2_ISA_IO_BASE + 0x800) +#define K2_MISC_REG (K2_ISA_IO_BASE + 0x804) +#define K2_MSIZ_GEO_REG (K2_ISA_IO_BASE + 0x808) +#define K2_HOT_SWAP_REG (K2_ISA_IO_BASE + 0x80c) +#define K2_PLD2_REG (K2_ISA_IO_BASE + 0x80e) +#define K2_PLD3_REG (K2_ISA_IO_BASE + 0x80f) + +#define K2_BUS_SPD(board_id) (board_id >> 2) & 3 + +#define K2_RTC_BASE_OFFSET 0x90000 +#define K2_RTC_BASE_ADDRESS (K2_PCI32_MEM_BASE + K2_RTC_BASE_OFFSET) +#define K2_RTC_SIZE 0x8000 + +#define K2_MEM_SIZE_MASK 0xe0 +#define K2_MEM_SIZE(size_reg) (size_reg & K2_MEM_SIZE_MASK) >> 5 +#define K2_MEM_SIZE_1GB 0x40000000 +#define K2_MEM_SIZE_512MB 0x20000000 +#define K2_MEM_SIZE_256MB 0x10000000 +#define K2_MEM_SIZE_128MB 0x08000000 + +#define K2_L2CACHE_MASK 0x03 /* Mask for 2 L2 Cache bits */ +#define K2_L2CACHE_512KB 0x00 /* 512KB */ +#define K2_L2CACHE_256KB 0x01 /* 256KB */ +#define K2_L2CACHE_1MB 0x02 /* 1MB */ +#define K2_L2CACHE_NONE 0x03 /* None */ + +#define K2_GEO_ADR_MASK 0x1f + +#define K2_SYS_SLOT_MASK 0x08 + +#endif /* __PPC_KERNEL_K2_H */ diff -Nru a/arch/ppc/kernel/k2_pci.c b/arch/ppc/kernel/k2_pci.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/kernel/k2_pci.c Wed May 16 06:00:34 2001 @@ -0,0 +1,264 @@ +/* + * arch/ppc/kernel/k2_pci.c + * + * PCI support for SBS K2 + * + * Author: Matt Porter + * + * Copyright 2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "pci.h" +#include "pci_auto.h" +#include "cpc710.h" +#include "k2.h" + +#undef DEBUG +#ifdef DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif /* DEBUG */ + +static inline int __init +k2_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) +{ + static char pci_irq_table[][4] = + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + { + {1, 0, 0, 0}, /* IDSEL 3 - Ethernet */ + {5, 5, 5, 5}, /* IDSEL 4 - PMC Site 1 */ + {6, 6, 6, 6}, /* IDSEL 5 - PMC Site 2 */ + {0, 0, 0, 0}, /* IDSEL 6 - unused */ + {0, 0, 0, 0}, /* IDSEL 7 - unused */ + {0, 0, 0, 0}, /* IDSEL 8 - PCI-ISA Bridge */ + {0, 0, 0, 0}, /* IDSEL 9 - unused */ + {0, 0, 0, 0}, /* IDSEL 10 - unused */ + {0, 0, 0, 0}, /* IDSEL 11 - unused */ + {0, 0, 0, 0}, /* IDSEL 12 - unused */ + {0, 0, 0, 0}, /* IDSEL 13 - unused */ + {0, 0, 0, 0}, /* IDSEL 14 - unused */ + {0, 0, 0, 0}, /* IDSEL 15 - unused */ + {0, 0, 0, 0}, /* IDSEL 16 - unused */ + {14, 0, 0, 0}, /* IDSEL 17 - M5229 IDE */ + }; + const long min_idsel = 3, max_idsel = 17, irqs_per_slot = 4; + return PCI_IRQ_TABLE_LOOKUP; +} + +/* Interrupt routes from cPCI bus (PCI-64 hose) */ +static unsigned char K2_CPCI_IRQ_routes[4] = {9, 10, 11, 12}; + +void +k2_route_cpci_int(struct pci_dev *dev) +{ + struct pci_bus *pbus; /* Parent bus structure pointer */ + struct pci_dev *tdev = dev; /* Temporary pci_dev pointer */ + unsigned int devnum; /* Accumulated device number */ + unsigned char intpin; /* PCI interrupt pin */ + struct pci_controller *hose; /* PCI controller */ + + /* Check for valid PCI dev pointer */ + if (dev == NULL) return; + + /* Get a pointer to our pci_controller descriptor */ + hose = pci_bus_to_hose(dev->bus->number); + + /* Initialize bridge IDSEL variable */ + devnum = PCI_SLOT(dev->devfn); + + /* Read the interrupt pin of the device */ + pcibios_read_config_byte(dev->bus->number, dev->devfn, + PCI_INTERRUPT_PIN, &intpin); + + /* If device doesn't request an interrupt, return */ + if ( (intpin < 1) || (intpin > 4) ) + return; + + /* Only loop if we are on a subordinate bus */ + if (dev->bus->number != hose->first_busno) + { + /* + * Walk up to the top bus, adjusting the interrupt pin for the + * standard PCI bus swizzle. + */ + do + { + intpin = bridge_swizzle(intpin, devnum); + pbus = tdev->bus; /* up one level */ + tdev = pbus->self; + devnum = PCI_SLOT(tdev->devfn); + } while(tdev->bus->number != hose->first_busno); + } + + /* + * devnum is reduced by 6 because the CPC710 + * addresses IDSELs differently than the PCI + * spec suggests. + */ + intpin = bridge_swizzle(intpin, devnum-6); + + /* + * For the second PCI hose, use the swizzled interrupt pin + * value to map to a CPCI interrupt input on the PIC + */ + dev->irq = K2_CPCI_IRQ_routes[intpin-1]; + + /* Write calculated interrupt value to header and device list */ + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); +} + +void k2_pcibios_fixup(void) +{ + struct pci_dev *dev; + + pci_for_each_dev(dev) + if (pci_bus_to_hose(dev->bus->number)->first_busno) + k2_route_cpci_int(dev); + +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) + { + /* + * Enable DMA support on hdc + */ + struct pci_dev *ide_dev; + unsigned long ide_dma_base; + + ide_dev = pci_find_device(PCI_VENDOR_ID_AL, + PCI_DEVICE_ID_AL_M5229, + NULL); + ide_dma_base = pci_resource_start(ide_dev, 4); + outb(0x00, ide_dma_base+0x2); + outb(0x20, ide_dma_base+0xa); + } +#endif + +} + +void k2_pcibios_fixup_resources(struct pci_dev *dev) +{ + int i; + + if ((dev->vendor == PCI_VENDOR_ID_IBM) && + (dev->device == PCI_DEVICE_ID_IBM_CPC710_PCI64)) + { + DBG("Fixup CPC710 resources\n"); + for (i=0; iresource[i].start = 0; + dev->resource[i].end = 0; + } + } +} + +void k2_find_bridges(void) +{ + struct pci_controller *hose_a, *hose_b; + + /* Setup PCI32 hose */ + hose_a = pcibios_alloc_controller(); + if (!hose_a) + return; + + hose_a->first_busno = 0; + hose_a->last_busno = 0xff; + hose_a->pci_mem_offset = K2_PCI32_MEM_BASE; + hose_a->io_space.start = K2_PCI32_LOWER_IO; + hose_a->io_space.end = K2_PCI32_UPPER_IO; + hose_a->mem_space.start = K2_PCI32_LOWER_MEM; + hose_a->mem_space.end = K2_PCI32_UPPER_MEM; + hose_a->io_base_virt = (void *)K2_ISA_IO_BASE; + + setup_indirect_pci(hose_a, K2_PCI32_CONFIG_ADDR, K2_PCI32_CONFIG_DATA); + + /* Initialize PCI32 bus registers */ + early_write_config_byte(hose_a, + hose_a->first_busno, + PCI_DEVFN(0, 0), + CPC710_BUS_NUMBER, + hose_a->first_busno); + early_write_config_byte(hose_a, + hose_a->first_busno, + PCI_DEVFN(0, 0), + CPC710_SUB_BUS_NUMBER, + hose_a->last_busno); + + hose_a->last_busno = pciauto_bus_scan(hose_a, hose_a->first_busno); + + /* Write out correct max subordinate bus number for hose A */ + early_write_config_byte(hose_a, + hose_a->first_busno, + PCI_DEVFN(0, 0), + CPC710_SUB_BUS_NUMBER, + hose_a->last_busno); + + /* Only setup PCI64 hose if we are in the system slot */ + if (!(readb(K2_MISC_REG) & K2_SYS_SLOT_MASK)) + { + /* Setup PCI64 hose */ + hose_b = pcibios_alloc_controller(); + if (!hose_b) + return; + + hose_b->first_busno = hose_a->last_busno + 1; + hose_b->last_busno = 0xff; + /* Reminder: quit changing the following, it is correct. */ + hose_b->pci_mem_offset = K2_PCI32_MEM_BASE; + hose_b->io_space.start = K2_PCI64_LOWER_IO; + hose_b->io_space.end = K2_PCI64_UPPER_IO; + hose_b->mem_space.start = K2_PCI64_LOWER_MEM; + hose_b->mem_space.end = K2_PCI64_UPPER_MEM; + hose_b->io_base_virt = (void *)K2_ISA_IO_BASE; + + setup_indirect_pci(hose_b, + K2_PCI64_CONFIG_ADDR, + K2_PCI64_CONFIG_DATA); + + /* Initialize PCI64 bus registers */ + early_write_config_byte(hose_b, + 0, + PCI_DEVFN(0, 0), + CPC710_SUB_BUS_NUMBER, + 0xff); + + early_write_config_byte(hose_b, + 0, + PCI_DEVFN(0, 0), + CPC710_BUS_NUMBER, + hose_b->first_busno); + + hose_b->last_busno = pciauto_bus_scan(hose_b, + hose_b->first_busno); + + /* Write out correct max subordinate bus number for hose B */ + early_write_config_byte(hose_b, + hose_b->first_busno, + PCI_DEVFN(0, 0), + CPC710_SUB_BUS_NUMBER, + hose_b->last_busno); + } + + ppc_md.pcibios_fixup = k2_pcibios_fixup; + ppc_md.pcibios_fixup_resources = k2_pcibios_fixup_resources; + ppc_md.pci_swizzle = common_swizzle; + ppc_md.pci_map_irq = k2_map_irq; +} diff -Nru a/arch/ppc/kernel/k2_pic.c b/arch/ppc/kernel/k2_pic.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/kernel/k2_pic.c Wed May 16 06:00:34 2001 @@ -0,0 +1,55 @@ +/* + * arch/ppc/kernel/k2_pic.c + * + * Interrupt controller support for SBS K2 + * + * Author: Matt Porter + * + * Copyright 2000 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include + +#include "local_irq.h" +#include "i8259.h" + +extern int i8259_irq(int); + +__init void +k2_init_IRQ(void) +{ + int i; + + for ( i = 0 ; i < 16 ; i++ ) + irq_desc[i].handler = &i8259_pic; + + i8259_init(); +} + +int +k2_get_irq(struct pt_regs *regs) +{ + int irq; + + if ( (irq = i8259_irq(0)) < 0 ) + { + printk(KERN_DEBUG "Bogus interrupt from PC = %lx\n", + regs->nip); + ppc_spurious_interrupts++; + return -1; + } + + ppc_irq_dispatch_handler( regs, irq ); + + return irq; +} diff -Nru a/arch/ppc/kernel/k2_setup.c b/arch/ppc/kernel/k2_setup.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/kernel/k2_setup.c Wed May 16 06:00:34 2001 @@ -0,0 +1,453 @@ +/* + * arch/ppc/kernel/k2_setup.c + * + * Board setup routines for SBS K2 + * + * Author: Matt Porter + * + * Copyright 2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "todc.h" +#include "k2.h" + +extern void k2_init_IRQ(void); +extern int k2_get_irq(struct pt_regs *); +extern void k2_find_bridges(void); +extern unsigned long loops_per_jiffy; + +static unsigned int k2_l2_cache_size; + +static unsigned int cpu_7xx[16] = { + 0, 15, 14, 0, 0, 13, 5, 9, 6, 11, 8, 10, 16, 12, 7, 0 +}; +static unsigned int cpu_6xx[16] = { + 0, 0, 14, 0, 0, 13, 5, 9, 6, 11, 8, 10, 0, 12, 7, 0 +}; + +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) +/* IDE functions */ +void +k2_ide_insw(ide_ioreg_t port, void *buf, int ns) +{ + ide_insw(((port)+(_IO_BASE)), buf, ns); +} + +void +k2_ide_outsw(ide_ioreg_t port, void *buf, int ns) +{ + ide_outsw(((port)+_IO_BASE), buf, ns); +} + +int +k2_ide_check_region(ide_ioreg_t from, unsigned int extent) +{ + return check_region(from, extent); +} + +void +k2_ide_request_region(ide_ioreg_t from, + unsigned int extent, + const char *name) +{ + request_region(from, extent, name); +} + +void +k2_ide_release_region(ide_ioreg_t from, + unsigned int extent) +{ + release_region(from, extent); +} + +void __init +k2_ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port, + ide_ioreg_t ctrl_port, int *irq) +{ + ide_ioreg_t reg = data_port; + int i = 8; + + for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) { + hw->io_ports[i] = reg; + reg += 1; + } + if (ctrl_port) + hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port; + else + hw->io_ports[IDE_CONTROL_OFFSET] = + hw->io_ports[IDE_DATA_OFFSET] + 0x206; + + if (irq != NULL) + *irq = 0; +} +#endif + +static inline unsigned long _get_HID1(void) +{ + unsigned long val; + + __asm__ __volatile__("mfspr %0,1009" : "=r" (val)); + return val; +} + +int +k2_get_bus_speed(void) +{ + int bus_speed; + unsigned char board_id; + + board_id = *(unsigned char *)K2_BOARD_ID_REG; + + switch( K2_BUS_SPD(board_id) ) { + + case 0: + default: + bus_speed = 100000000; + break; + + case 1: + bus_speed = 83333333; + break; + + case 2: + bus_speed = 75000000; + break; + + case 3: + bus_speed = 66666666; + break; + } + return bus_speed; +} + +int +k2_get_cpu_speed(void) +{ + unsigned long hid1; + int cpu_speed; + + hid1 = _get_HID1() >> 28; + + if ((_get_PVR()>>16) == 8) + hid1 = cpu_7xx[hid1]; + else + hid1 = cpu_6xx[hid1]; + + cpu_speed = k2_get_bus_speed()*hid1/2; + return cpu_speed; +} + +void __init k2_calibrate_decr(void) +{ + int freq, divisor = 4; + + /* determine processor bus speed */ + freq = k2_get_bus_speed(); + tb_ticks_per_jiffy = freq / HZ / divisor; + tb_to_us = mulhwu_scale_factor(freq/divisor, 1000000); +} + +void +k2_setup_l2_cache(void) +{ + switch ((*(unsigned char *)K2_BOARD_ID_REG) & K2_L2CACHE_MASK) + { + case K2_L2CACHE_512KB: + k2_l2_cache_size = L2CR_L2SIZ_512KB; + break; + + case K2_L2CACHE_256KB: + k2_l2_cache_size = L2CR_L2SIZ_256KB; + break; + + case K2_L2CACHE_1MB: + k2_l2_cache_size = L2CR_L2SIZ_1MB; + break; + + case K2_L2CACHE_NONE: + default: + k2_l2_cache_size = 0; + break; + } + + if (k2_l2_cache_size) + { + _set_L2CR(0); + _set_L2CR(L2CR_L2E | L2CR_L2PE | k2_l2_cache_size | + L2CR_L2CLK_DIV2 | L2CR_L2RAM_PIPE_LW | + L2CR_L2DO | L2CR_L2OH_1_0 | L2CR_L2DF); + } +} + +void +k2_get_l2_string(char *buffer) +{ + switch (k2_l2_cache_size) + { + case L2CR_L2SIZ_256KB: + sprintf(buffer, "256KB"); + break; + + case L2CR_L2SIZ_512KB: + sprintf(buffer, "512KB"); + break; + + case L2CR_L2SIZ_1MB: + sprintf(buffer, "1MB"); + break; + + default: + sprintf(buffer, "0KB"); + break; + } +} + +int +k2_get_cpuinfo(char *buffer) +{ + int len; + unsigned char k2_geo_bits, k2_system_slot; + char l2_string[10]; + + len = sprintf( buffer, "vendor\t\t: SBS\n"); + + len += sprintf( buffer+len, "machine\t\t: K2\n"); + + len += sprintf( buffer+len, "cpu speed\t: %dMhz\n", + k2_get_cpu_speed()/1000000); + + len += sprintf( buffer+len, "bus speed\t: %dMhz\n", + k2_get_bus_speed()/1000000); + + k2_get_l2_string(l2_string); + len += sprintf( buffer+len, "L2\t\t: %s\n", l2_string); + + len += sprintf( buffer+len, "memory type\t: SDRAM\n"); + + k2_geo_bits = readb(K2_MSIZ_GEO_REG) & K2_GEO_ADR_MASK; + k2_system_slot = !(readb(K2_MISC_REG) & K2_SYS_SLOT_MASK); + len += sprintf( buffer+len, + "backplane\t: %s slot board with geographical address %x\n", + k2_system_slot ? "System" : "Non system", + k2_geo_bits); + + len += sprintf(buffer+len, "\n"); + + return len; +} + +extern char cmd_line[]; + +void __init +k2_setup_arch(void) +{ + unsigned int cpu; + + /* Setup TODC access */ + todc_info = &m48t37_info; + todc_info->nvram_data = + (u_char *)ioremap(K2_RTC_BASE_ADDRESS, K2_RTC_SIZE); + + /* Configure and enable L2 cache */ + k2_setup_l2_cache(); + + /* init to some ~sane value until calibrate_delay() runs */ + loops_per_jiffy = 50000000/HZ; + + /* Setup PCI host bridges */ + k2_find_bridges(); + +#ifdef CONFIG_ROOT_NFS + /* bootable from nfsroot */ + ROOT_DEV = to_kdev_t(0x00FF); /* /dev/nfs pseudo device */ +#else + /* bootable from IDE secondary master */ + ROOT_DEV = to_kdev_t(0x1601); /* /dev/hdc1 */ +#endif + + /* Identify the system */ + printk("System Identification: SBS K2 - PowerPC 750 @ %d Mhz\n", k2_get_cpu_speed()/1000000); + printk("SBS K2 port (C) 2001 MontaVista Software, Inc. (source@mvista.com)\n"); + + /* Identify the CPU manufacturer */ + cpu = _get_PVR(); + printk("CPU manufacturer: %s [rev=%04x]\n", (cpu & (1<<15)) ? "IBM" : + "Motorola", (cpu & 0xffff)); +} + +void +k2_restart(char *cmd) +{ + __cli(); + /* SRR0 has system reset vector, SRR1 has default MSR value */ + /* rfi restores MSR from SRR1 and sets the PC to the SRR0 value */ + __asm__ __volatile__ + ("\n\ + lis 3,0xfff0 + ori 3,3,0x0100 + mtspr 26,3 + li 3,0 + mtspr 27,3 + rfi + "); + for(;;); +} + +void +k2_power_off(void) +{ + for(;;); +} + +void +k2_halt(void) +{ + k2_restart(NULL); +} + +/* + * Set BAT 3 to map 0x80000000. + */ +static __inline__ void +k2_set_bat(void) +{ + unsigned long bat3u, bat3l; + static int mapping_set = 0; + + if (!mapping_set) + { + __asm__ __volatile__( + " lis %0,0x8000\n \ + ori %1,%0,0x002a\n \ + ori %0,%0,0x1ffe\n \ + mtspr 0x21e,%0\n \ + mtspr 0x21f,%1\n \ + isync\n \ + sync " + :: "r" (bat3u), "r" (bat3l)); + + mapping_set = 1; + } + return; +} + +unsigned long __init k2_find_end_of_memory(void) +{ + unsigned long total; + unsigned char msize = 7; /* Default to 128MB */ + + k2_set_bat(); + + msize = K2_MEM_SIZE(readb(K2_MSIZ_GEO_REG)); + + switch (msize) + { + case 2: + total = K2_MEM_SIZE_1GB; + break; + total = K2_MEM_SIZE_1GB; + break; + case 3: + case 4: + total = K2_MEM_SIZE_512MB; + break; + case 5: + case 6: + total = K2_MEM_SIZE_256MB; + break; + case 7: + total = K2_MEM_SIZE_128MB; + break; + default: + printk("K2: Invalid memory size detected, defaulting to + 128MB\n"); + total = K2_MEM_SIZE_128MB; + break; + } + return total; +} + +void __init k2_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + +#ifdef CONFIG_BLK_DEV_INITRD + if ( r4 ) + { + initrd_start = r4 + KERNELBASE; + initrd_end = r5 + KERNELBASE; + } +#endif + + /* Copy cmd_line parameters */ + if ( r6 ) + { + *(char *)(r7 + KERNELBASE) = 0; + strcpy(cmd_line, (char *)(r6+KERNELBASE)); + } + + isa_io_base = K2_ISA_IO_BASE; + isa_mem_base = K2_ISA_MEM_BASE; + pci_dram_offset = K2_PCI32_SYS_MEM_BASE; + + ppc_md.setup_arch = k2_setup_arch; + ppc_md.setup_residual = NULL; + ppc_md.get_cpuinfo = k2_get_cpuinfo; + ppc_md.irq_cannonicalize = NULL; + ppc_md.init_IRQ = k2_init_IRQ; + ppc_md.get_irq = k2_get_irq; + ppc_md.init = NULL; + + ppc_md.find_end_of_memory = k2_find_end_of_memory; + + ppc_md.restart = k2_restart; + ppc_md.power_off = k2_power_off; + ppc_md.halt = k2_halt; + + ppc_md.time_init = todc_time_init; + ppc_md.set_rtc_time = todc_set_rtc_time; + ppc_md.get_rtc_time = todc_get_rtc_time; + ppc_md.calibrate_decr = k2_calibrate_decr; + + ppc_md.nvram_read_val = todc_direct_read_val; + ppc_md.nvram_write_val = todc_direct_write_val; + +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) + ppc_ide_md.insw = k2_ide_insw; + ppc_ide_md.outsw = k2_ide_outsw; + ppc_ide_md.ide_check_region = k2_ide_check_region; + ppc_ide_md.ide_request_region = k2_ide_request_region; + ppc_ide_md.ide_release_region = k2_ide_release_region; + ppc_ide_md.fix_driveid = ppc_generic_ide_fix_driveid; + ppc_ide_md.ide_init_hwif = k2_ide_init_hwif_ports; + ppc_ide_md.io_base = _IO_BASE; +#endif +} diff -Nru a/arch/ppc/kernel/m1543c.h b/arch/ppc/kernel/m1543c.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/kernel/m1543c.h Wed May 16 06:00:33 2001 @@ -0,0 +1,23 @@ +/* + * arch/ppc/kernel/m1543c.h + * + * ALI M1543C PCI-ISA bridge definitions + * + * Author: Matt Porter + * + * Copyright 2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __PPC_KERNEL_M1543C_H +#define __PPC_KERNEL_M1543C_H + +#define M1543C_ISAPNP_CONFIG_OFFSET 0x370 +#define M1543C_ISAPNP_INDEX_OFFSET M1543C_ISAPNP_CONFIG_OFFSET +#define M1543C_ISAPNP_DATA_OFFSET 0x371 + +#endif /* __PPC_KERNEL_M1543C_H */ diff -Nru a/arch/ppc/kernel/m8260_setup.c b/arch/ppc/kernel/m8260_setup.c --- a/arch/ppc/kernel/m8260_setup.c Wed May 16 06:00:24 2001 +++ b/arch/ppc/kernel/m8260_setup.c Wed May 16 06:00:24 2001 @@ -119,7 +119,7 @@ return(0); } -unsigned long __init +unsigned long m8260_get_rtc_time(void) { @@ -206,6 +206,18 @@ } +/* + * Same hack as 8xx + */ +unsigned long __init m8260_find_end_of_memory(void) +{ + bd_t *binfo; + extern unsigned char __res[]; + + binfo = (bd_t *)__res; + + return binfo->bi_memsize; +} void __init m8260_init(unsigned long r3, unsigned long r4, unsigned long r5, @@ -248,18 +260,8 @@ ppc_md.get_rtc_time = m8260_get_rtc_time; ppc_md.calibrate_decr = m8260_calibrate_decr; -#if 0 - ppc_md.kbd_setkeycode = pckbd_setkeycode; - ppc_md.kbd_getkeycode = pckbd_getkeycode; - ppc_md.kbd_pretranslate = pckbd_pretranslate; - ppc_md.kbd_translate = pckbd_translate; - ppc_md.kbd_unexpected_up = pckbd_unexpected_up; - ppc_md.kbd_leds = pckbd_leds; - ppc_md.kbd_init_hw = pckbd_init_hw; -#ifdef CONFIG_MAGIC_SYSRQ - ppc_md.kbd_sysrq_xlate = pckbd_sysrq_xlate; -#endif -#else + ppc_md.find_end_of_memory = m8260_find_end_of_memory; + ppc_md.kbd_setkeycode = NULL; ppc_md.kbd_getkeycode = NULL; ppc_md.kbd_translate = NULL; @@ -268,7 +270,6 @@ ppc_md.kbd_init_hw = NULL; #ifdef CONFIG_MAGIC_SYSRQ ppc_md.kbd_sysrq_xlate = NULL; -#endif #endif #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) diff -Nru a/arch/ppc/kernel/m8xx_setup.c b/arch/ppc/kernel/m8xx_setup.c --- a/arch/ppc/kernel/m8xx_setup.c Wed May 16 06:00:25 2001 +++ b/arch/ppc/kernel/m8xx_setup.c Wed May 16 06:00:25 2001 @@ -260,7 +260,7 @@ return(0); } -unsigned long __init +unsigned long m8xx_get_rtc_time(void) { /* Get time from the RTC. @@ -584,6 +584,25 @@ /* -------------------------------------------------------------------- */ +/* + * This is a big hack right now, but it may turn into something real + * someday. + * + * For the 8xx boards (at this time anyway), there is nothing to initialize + * associated the PROM. Rather than include all of the prom.c + * functions in the image just to get prom_init, all we really need right + * now is the initialization of the physical memory region. + */ +unsigned long __init m8xx_find_end_of_memory(void) +{ + bd_t *binfo; + extern unsigned char __res[]; + + binfo = (bd_t *)__res; + + return binfo->bi_memsize; +} + void __init m8xx_init(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7) @@ -629,18 +648,8 @@ ppc_md.get_rtc_time = m8xx_get_rtc_time; ppc_md.calibrate_decr = m8xx_calibrate_decr; -#if 0 - ppc_md.kbd_setkeycode = pckbd_setkeycode; - ppc_md.kbd_getkeycode = pckbd_getkeycode; - ppc_md.kbd_pretranslate = pckbd_pretranslate; - ppc_md.kbd_translate = pckbd_translate; - ppc_md.kbd_unexpected_up = pckbd_unexpected_up; - ppc_md.kbd_leds = pckbd_leds; - ppc_md.kbd_init_hw = pckbd_init_hw; -#ifdef CONFIG_MAGIC_SYSRQ - ppc_md.kbd_sysrq_xlate = pckbd_sysrq_xlate; -#endif -#else + ppc_md.find_end_of_memory = m8xx_find_end_of_memory; + ppc_md.kbd_setkeycode = NULL; ppc_md.kbd_getkeycode = NULL; ppc_md.kbd_translate = NULL; @@ -649,7 +658,6 @@ ppc_md.kbd_init_hw = NULL; #ifdef CONFIG_MAGIC_SYSRQ ppc_md.kbd_sysrq_xlate = NULL; -#endif #endif #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) diff -Nru a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S --- a/arch/ppc/kernel/misc.S Wed May 16 06:00:21 2001 +++ b/arch/ppc/kernel/misc.S Wed May 16 06:00:21 2001 @@ -21,20 +21,6 @@ #include #include "ppc_asm.h" -#if defined(CONFIG_4xx) || defined(CONFIG_8xx) -#define CACHE_LINE_SIZE 16 -#define LG_CACHE_LINE_SIZE 4 -#define MAX_COPY_PREFETCH 1 -#elif !defined(CONFIG_PPC64BRIDGE) -#define CACHE_LINE_SIZE 32 -#define LG_CACHE_LINE_SIZE 5 -#define MAX_COPY_PREFETCH 4 -#else -#define CACHE_LINE_SIZE 128 -#define LG_CACHE_LINE_SIZE 7 -#define MAX_COPY_PREFETCH 1 -#endif /* CONFIG_4xx || CONFIG_8xx */ - .text .align 5 @@ -60,14 +46,37 @@ mtlr r0 blr -/* void __no_use_save_flags(unsigned long *flags) */ -_GLOBAL(__no_use_save_flags) +/* void __save_flags_ptr(unsigned long *flags) */ +_GLOBAL(__save_flags_ptr) mfmsr r4 stw r4,0(r3) blr + /* + * Need these nops here for taking over save/restore to + * handle lost intrs + * -- Cort + */ + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop +_GLOBAL(__save_flags_ptr_end) -/* void __no_use_restore_flags(unsigned long flags) */ -_GLOBAL(__no_use_restore_flags) +/* void __restore_flags(unsigned long flags) */ +_GLOBAL(__restore_flags) /* * Just set/clear the MSR_EE bit through restore/flags but do not * change anything else. This is needed by the RT system and makes @@ -82,66 +91,95 @@ /* Check if things are setup the way we want _already_. */ cmpw 0,r3,r4 beqlr - /* are we enabling interrupts? */ - rlwinm. r0,r3,0,16,16 - beq 1f - /* if so, check if there are any lost interrupts */ - lis r7,ppc_n_lost_interrupts@ha - lwz r7,ppc_n_lost_interrupts@l(r7) - cmpi 0,r7,0 /* lost interrupts to process first? */ - bne- do_lost_interrupts 1: SYNC mtmsr r3 SYNC blr - -_GLOBAL(__no_use_cli) + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop +_GLOBAL(__restore_flags_end) + +_GLOBAL(__cli) mfmsr r0 /* Get current interrupt state */ rlwinm r3,r0,16+1,32-1,31 /* Extract old value of 'EE' */ rlwinm r0,r0,0,17,15 /* clear MSR_EE in r0 */ SYNC /* Some chip revs have problems here... */ mtmsr r0 /* Update machine state */ blr /* Done */ + /* + * Need these nops here for taking over save/restore to + * handle lost intrs + * -- Cort + */ + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop +_GLOBAL(__cli_end) -_GLOBAL(__no_use_sti) - lis r4,ppc_n_lost_interrupts@ha - lwz r4,ppc_n_lost_interrupts@l(r4) +_GLOBAL(__sti) mfmsr r3 /* Get current state */ ori r3,r3,MSR_EE /* Turn on 'EE' bit */ - cmpi 0,r4,0 /* lost interrupts to process first? */ - bne- do_lost_interrupts SYNC /* Some chip revs have problems here... */ mtmsr r3 /* Update machine state */ blr - -/* - * We were about to enable interrupts but we have to simulate - * some interrupts that were lost by enable_irq first. - */ -_GLOBAL(do_lost_interrupts) - stwu r1,-16(r1) - mflr r0 - stw r0,20(r1) - stw r3,8(r1) -1: bl fake_interrupt - lis r4,ppc_n_lost_interrupts@ha - lwz r4,ppc_n_lost_interrupts@l(r4) - cmpi 0,r4,0 - bne- 1b - lwz r3,8(r1) - SYNC - mtmsr r3 - lwz r0,20(r1) - mtlr r0 - addi r1,r1,16 - blr + /* + * Need these nops here for taking over save/restore to + * handle lost intrs + * -- Cort + */ + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop +_GLOBAL(__sti_end) /* * complement mask on the msr then "or" some values on. * _nmask_and_or_msr(nmask, value_to_or) */ - _GLOBAL(_nmask_and_or_msr) +_GLOBAL(_nmask_and_or_msr) mfmsr r0 /* Get current msr */ andc r0,r0,r3 /* And off the bits set in r3 (first parm) */ or r0,r0,r4 /* Or on the bits in r4 (second parm) */ @@ -267,6 +305,7 @@ 2: icbi 0,r6 addi r6,r6,CACHE_LINE_SIZE bdnz 2b + sync /* additional sync needed on g4 */ isync blr @@ -1055,6 +1094,49 @@ li r3,0 sc +#if defined(CONFIG_SPRUCE) +_GLOBAL(spruce_read_keyb_status) + addis r5,0,0xff50 + addi r6,0,0x88 + stw r6,0x8(r5) + eieio + + addis r6,0,0x300 + stw r6,0xc(r5) + eieio + + addis r7,0,0xff88 + ori r7,r7,0x8 + lswi r3,r7,0x8 + srwi r3,r3,0x18 + + addi r6,0,0 + stw r6,0xc(r5) + eieio + + blr + +_GLOBAL(spruce_read_keyb_data) + addis r5,0,0xff50 + addi r6,0,0x88 + stw r6,0x8(r5) + eieio + + addis r6,0,0x300 + stw r6,0xc(r5) + eieio + + addis r7,0,0xff88 + lswi r3,r7,0x8 + srwi r3,r3,0x18 + + addi r6,0,0 + stw r6,0xc(r5) + eieio + + blr +#endif + /* * This routine is just here to keep GCC happy - sigh... */ @@ -1283,7 +1365,7 @@ .long sys_vfork .long sys_getrlimit /* 190 */ .long sys_ni_syscall /* 191 */ /* Unused */ - .long sys_ni_syscall /* 192 - reserved - mmap2 */ + .long sys_mmap2 /* 192 */ .long sys_truncate64 /* 193 */ .long sys_ftruncate64 /* 194 */ .long sys_stat64 /* 195 */ diff -Nru a/arch/ppc/kernel/mol.h b/arch/ppc/kernel/mol.h --- a/arch/ppc/kernel/mol.h Wed May 16 06:00:17 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,68 +0,0 @@ -/* - * arch/ppc/kernel/mol.h - * - * - * - * Mac-on-Linux hook macros - * - * - * Copyright (C) 2000 Samuel Rydh (samuel@ibrium.se) - * - * 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 - * - */ - -#ifndef _PPC_KERNEL_MOL -#define _PPC_KERNEL_MOL - -#include - -#ifdef CONFIG_MOL -#define MOL_INTERFACE_VERSION 3 - -#define MOL_HOOK(hook_num) \ - lwz r0,(mol_interface + 4 * hook_num + 4)@l(0); \ - cmpwi cr1,r0,0; \ - beq+ cr1,777f; \ - mtctr r0; \ - bctrl; \ -777: lwz r0,GPR0(r21) - -#define MOL_HOOK_RESTORE(hook_num) \ - mfcr r2; \ - MOL_HOOK(hook_num); \ - mtcrf 0x80,r2; \ - lwz r2,_CTR(r21); \ - mtctr r2; \ - lwz r2,GPR2(r21) - -#define MOL_HOOK_MMU(hook_num, scr) \ - lis scr,(mol_interface + 4 * hook_num + 4)@ha; \ - lwz scr,(mol_interface + 4 * hook_num + 4)@l(scr); \ - cmpwi cr1,scr,0; \ - beq+ cr1,778f; \ - mtctr scr; \ - bctrl; \ -778: - -#define MOL_HOOK_TLBMISS(hook_num) \ - lwz r0,(mol_interface + 4 * hook_num + 4)@l(0); \ - cmpwi r0,0; \ - beq+ 779f; \ - mflr r3; \ - mtlr r0; \ - blrl; \ - mtlr r3; \ -779: - -#else -#define MOL_HOOK(num) -#define MOL_HOOK_RESTORE(num) -#define MOL_HOOK_MMU(num, scr) -#define MOL_HOOK_TLBMISS(num) -#endif - - -#endif /* _PPC_KERNEL_MOL */ diff -Nru a/arch/ppc/kernel/mvme5100.h b/arch/ppc/kernel/mvme5100.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/kernel/mvme5100.h Wed May 16 06:00:34 2001 @@ -0,0 +1,67 @@ +/* + * arch/ppc/kernel/mvme5100.h + * + * Definitions for Motorola MVME5100. + * + * Author: Matt Porter + * + * Copyright 2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __PPC_KERNEL_MVME5100_H +#define __PPC_KERNEL_MVME5100_H + +#define MVME5100_HAWK_SMC_BASE 0xfef80000 + +#define MVME5100_PCI_CONFIG_ADDR 0xfe000cf8 +#define MVME5100_PCI_CONFIG_DATA 0xfe000cfc + +#define MVME5100_PCI_IO_BASE 0xfe000000 +#define MVME5100_PCI_MEM_BASE 0x80000000 + +#define MVME5100_PCI_MEM_OFFSET 0x00000000 + +#define MVME5100_PCI_DRAM_OFFSET 0x00000000 +#define MVME5100_ISA_MEM_BASE 0x00000000 +#define MVME5100_ISA_IO_BASE MVME5100_PCI_IO_BASE + +/* MVME5100 board register addresses. */ +#define MVME5100_BOARD_STATUS_REG 0xfef88080 +#define MVME5100_BOARD_MODFAIL_REG 0xfef88090 +#define MVME5100_BOARD_MODRST_REG 0xfef880a0 +#define MVME5100_BOARD_TBEN_REG 0xfef880c0 +#define MVME5100_BOARD_SW_READ_REG 0xfef880e0 +#define MVME5100_BOARD_GEO_ADDR_REG 0xfef880e8 +#define MVME5100_BOARD_EXT_FEATURE1_REG 0xfef880f0 +#define MVME5100_BOARD_EXT_FEATURE2_REG 0xfef88100 + +/* Define the NVRAM/RTC address strobe & data registers */ +#define MVME5100_PHYS_NVRAM_AS0 0xfef880c8 +#define MVME5100_PHYS_NVRAM_AS1 0xfef880d0 +#define MVME5100_PHYS_NVRAM_DATA 0xfef880d8 + +#define MVME5100_NVRAM_AS0 (MVME5100_PHYS_NVRAM_AS0 - MVME5100_ISA_IO_BASE) +#define MVME5100_NVRAM_AS1 (MVME5100_PHYS_NVRAM_AS1 - MVME5100_ISA_IO_BASE) +#define MVME5100_NVRAM_DATA (MVME5100_PHYS_NVRAM_DATA - MVME5100_ISA_IO_BASE) + +/* UART clock, addresses, and irq */ +#define MVME5100_BASE_BAUD 1843200 +#define MVME5100_SERIAL_1 0xfef88000 +#define MVME5100_SERIAL_2 0xfef88200 +#ifdef CONFIG_MVME5100_IPMC761_PRESENT +#define MVME5100_SERIAL_IRQ 17 +#else +#define MVME5100_SERIAL_IRQ 1 +#endif + +#define MVME5100_WINBOND_DEVFN 0x58 +#define MVME5100_WINBOND_VIDDID 0x056510ad + +extern void mvme5100_find_bridges(void); + +#endif /* __PPC_KERNEL_MVME5100_H */ diff -Nru a/arch/ppc/kernel/mvme5100_pci.c b/arch/ppc/kernel/mvme5100_pci.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/kernel/mvme5100_pci.c Wed May 16 06:00:33 2001 @@ -0,0 +1,107 @@ +/* + * arch/ppc/kernel/mvme5100_pci.c + * + * PCI setup routines for the Motorola MVME5100. + * + * Author: Matt Porter + * + * Copyright 2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "pci.h" +#include "pplus.h" +#include "mvme5100.h" + +static inline int +mvme5100_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) +{ + int irq; + + static char pci_irq_table[][4] = + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + { + { 0, 0, 0, 0 }, /* IDSEL 11 - Winbond */ + { 0, 0, 0, 0 }, /* IDSEL 12 - unused */ + { 21, 22, 23, 24 }, /* IDSEL 13 - Universe II */ + { 18, 0, 0, 0 }, /* IDSEL 14 - Enet 1 */ + { 0, 0, 0, 0 }, /* IDSEL 15 - unused */ + { 25, 26, 27, 28 }, /* IDSEL 16 - PMC Slot 1 */ + { 28, 25, 26, 27 }, /* IDSEL 17 - PMC Slot 2 */ + { 0, 0, 0, 0 }, /* IDSEL 18 - unused */ + { 29, 0, 0, 0 }, /* IDSEL 19 - Enet 2 */ + { 0, 0, 0, 0 }, /* IDSEL 20 - PMCSPAN */ + }; + + const long min_idsel = 11, max_idsel = 20, irqs_per_slot = 4; + irq = PCI_IRQ_TABLE_LOOKUP; + /* If lookup is zero, always return 0 */ + if (!irq) + return 0; + else +#ifdef CONFIG_MVME5100_IPMC761_PRESENT + /* If IPMC761 present, return table value */ + return irq; +#else + /* If IPMC761 not present, we don't have an i8259 so adjust */ + return (irq - NUM_8259_INTERRUPTS); +#endif +} + +void mvme5100_pcibios_fixup_resources(struct pci_dev *dev) +{ + int i; + + if ((dev->vendor == PCI_VENDOR_ID_MOTOROLA) && + (dev->device == PCI_DEVICE_ID_MOTOROLA_HAWK)) + for (i=0; iresource[i].start = 0; + dev->resource[i].end = 0; + } +} + +void __init +mvme5100_find_bridges(void) +{ + struct pci_controller* hose; + + hose = pcibios_alloc_controller(); + + if (!hose) + return; + + hose->first_busno = 0; + hose->last_busno = 0xff; + hose->pci_mem_offset = MVME5100_PCI_MEM_OFFSET; + hose->io_base_virt = (void *)MVME5100_ISA_IO_BASE; + + /* Use indirect method of Hawk */ + setup_indirect_pci(hose, + MVME5100_PCI_CONFIG_ADDR, + MVME5100_PCI_CONFIG_DATA); + + ppc_md.pcibios_fixup_resources = mvme5100_pcibios_fixup_resources; + ppc_md.pci_swizzle = common_swizzle; + ppc_md.pci_map_irq = mvme5100_map_irq; + + return; +} diff -Nru a/arch/ppc/kernel/mvme5100_setup.c b/arch/ppc/kernel/mvme5100_setup.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/kernel/mvme5100_setup.c Wed May 16 06:00:34 2001 @@ -0,0 +1,331 @@ +/* + * arch/ppc/kernel/mvme5100_setup.c + * + * Board setup routines for the Motorola MVME5100. + * + * Author: Matt Porter + * + * Copyright 2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pci.h" +#include "local_irq.h" +#include "open_pic.h" +#include "i8259.h" +#include "pplus.h" +#include "todc.h" +#include "mvme5100.h" + +/* + * If you want "progress" messages, define this macro below. + */ +#undef CONFIG_MVME5100_DEBUG + +extern char cmd_line[]; + +static u_char mvme5100_openpic_initsenses[] __initdata = { + 0, /* 16: i8259 cascade (active high) */ + 1, /* 17: TL16C550 UART 1,2 */ + 1, /* 18: Enet 1 (front panel or P2) */ + 1, /* 19: Hawk Watchdog 1,2 */ + 1, /* 20: DS1621 thermal alarm */ + 1, /* 21: Universe II LINT0# */ + 1, /* 22: Universe II LINT1# */ + 1, /* 23: Universe II LINT2# */ + 1, /* 24: Universe II LINT3# */ + 1, /* 25: PMC1 INTA#, PMC2 INTB# */ + 1, /* 26: PMC1 INTB#, PMC2 INTC# */ + 1, /* 27: PMC1 INTC#, PMC2 INTD# */ + 1, /* 28: PMC1 INTD#, PMC2 INTA# */ + 1, /* 29: Enet 2 (front panel) */ + 1, /* 30: Abort Switch */ + 1, /* 31: RTC Alarm */ +}; + +static void __init +mvme5100_setup_arch(void) +{ + extern char cmd_line[]; + + if ( ppc_md.progress ) + ppc_md.progress("mvme5100_setup_arch: enter", 0); + + loops_per_jiffy = 50000000 / HZ; + +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) + ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0); + else +#endif +#ifdef CONFIG_ROOT_NFS + ROOT_DEV = to_kdev_t(0x00FF); /* /dev/nfs pseudo device */ +#else + ROOT_DEV = to_kdev_t(0x0802); /* /dev/sda2 SCSI disk */ +#endif + + if ( ppc_md.progress ) + ppc_md.progress("mvme5100_setup_arch: find_bridges", 0); + + /* Lookup PCI host bridges */ + mvme5100_find_bridges(); + + /* Find and map our OpenPIC */ + pplus_mpic_init(MVME5100_PCI_MEM_OFFSET); + OpenPIC_InitSenses = mvme5100_openpic_initsenses; + OpenPIC_NumInitSenses = sizeof(mvme5100_openpic_initsenses); + + printk("MVME5100 port (C) 2001 MontaVista Software, Inc. \n"); + + if ( ppc_md.progress ) + ppc_md.progress("mvme5100_setup_arch: exit", 0); + + return; +} + +static void __init +mvme5100_init2(void) +{ +#ifdef CONFIG_MVME5100_IPMC761_PRESENT + request_region(0x00,0x20,"dma1"); + request_region(0x20,0x20,"pic1"); + request_region(0x40,0x20,"timer"); + request_region(0x80,0x10,"dma page reg"); + request_region(0xa0,0x20,"pic2"); + request_region(0xc0,0x20,"dma2"); +#endif + return; +} + +/* + * Interrupt setup and service. + * Have MPIC on HAWK and cascaded 8259s on Winbond cascaded to MPIC. + */ +static void __init +mvme5100_init_IRQ(void) +{ +#ifdef CONFIG_MVME5100_IPMC761_PRESENT + int i; +#endif + + if ( ppc_md.progress ) + ppc_md.progress("init_irq: enter", 0); + +#ifdef CONFIG_MVME5100_IPMC761_PRESENT + openpic_init(1, NUM_8259_INTERRUPTS, NULL, -1); + + for(i=0; i < NUM_8259_INTERRUPTS; i++) + irq_desc[i].handler = &i8259_pic; + + i8259_init(); +#else + openpic_init(1, 0, NULL, -1); +#endif + + if ( ppc_md.progress ) + ppc_md.progress("init_irq: exit", 0); + + return; +} + +/* + * Set BAT 3 to map 0xf0000000 to end of physical memory space. + */ +static __inline__ void +mvme5100_set_bat(void) +{ + unsigned long bat3u, bat3l; + static int mapping_set = 0; + + if (!mapping_set) { + + __asm__ __volatile__( + " lis %0,0xf000\n \ + ori %1,%0,0x002a\n \ + ori %0,%0,0x1ffe\n \ + mtspr 0x21e,%0\n \ + mtspr 0x21f,%1\n \ + isync\n \ + sync " + :: "r" (bat3u), "r" (bat3l)); + + mapping_set = 1; + } + + return; +} + +unsigned long __init +mvme5100_find_end_of_memory(void) +{ + mvme5100_set_bat(); + return pplus_get_mem_size(MVME5100_HAWK_SMC_BASE); +} + +static void +mvme5100_reset_board(void) +{ + __cli(); + + /* Set exception prefix high - to the firmware */ + _nmask_and_or_msr(0, MSR_IP); + + out_8((u_char *)MVME5100_BOARD_MODRST_REG, 0x01); + + return; +} + +static void +mvme5100_restart(char *cmd) +{ + volatile ulong i = 10000000; + + mvme5100_reset_board(); + + while (i-- > 0); + panic("restart failed\n"); +} + +static void +mvme5100_halt(void) +{ + __cli(); + while (1); +} + +static void +mvme5100_power_off(void) +{ + mvme5100_halt(); +} + +static int +mvme5100_get_cpuinfo(char *buffer) +{ + int len; + uint pvid; + + pvid = _get_PVR(); + + len = sprintf( buffer, "vendor\t\t: Motorola\n"); + + len += sprintf( buffer+len, "machine\t\t: MVME5100\n"); + + return len; +} + +#ifdef CONFIG_MVME5100_DEBUG +#include "../boot/include/ns16550.h" +void +mvme5100_progress(char *s, unsigned short hex) +{ + volatile char c; + volatile struct NS16550 *com_port; + + mvme5100_set_bat(); + + com_port = (volatile struct NS16550 *)(COM1); + while ((c = *s++) != 0) { + while ((com_port->lsr & LSR_THRE) == 0) ; + com_port->thr = c; + if (c == '\n') { + while ((com_port->lsr & LSR_THRE) == 0) ; + com_port->thr = '\r'; + } + } + + while ((com_port->lsr & LSR_THRE) == 0) ; + com_port->thr = '\n'; + while ((com_port->lsr & LSR_THRE) == 0) ; + com_port->thr = '\r'; + + return; +} +#endif /* CONFIG_MVME5100_DEBUG */ + +void __init +mvme5100_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ +#ifdef CONFIG_BLK_DEV_INITRD + if ( r4 ) + { + initrd_start = r4 + KERNELBASE; + initrd_end = r5 + KERNELBASE; + } +#endif + + /* Copy cmd_line parameters */ + if ( r6 && (((char *) r6) != '\0')) { + *(char *)(r7 + KERNELBASE) = 0; + strcpy(cmd_line, (char *)(r6 + KERNELBASE)); + } + + todc_info = &m48t37_info; + todc_info->nvram_as0 = (u_char *)MVME5100_NVRAM_AS0; + todc_info->nvram_as1 = (u_char *)MVME5100_NVRAM_AS1; + todc_info->nvram_data = (u_char *)MVME5100_NVRAM_DATA; + + isa_io_base = MVME5100_ISA_IO_BASE; + isa_mem_base = MVME5100_ISA_MEM_BASE; + pci_dram_offset = MVME5100_PCI_DRAM_OFFSET; + + ppc_md.setup_arch = mvme5100_setup_arch; + ppc_md.setup_residual = NULL; + ppc_md.get_cpuinfo = mvme5100_get_cpuinfo; + ppc_md.init_IRQ = mvme5100_init_IRQ; + ppc_md.get_irq = openpic_get_irq; + ppc_md.post_irq = NULL; + ppc_md.init = mvme5100_init2; + + ppc_md.restart = mvme5100_restart; + ppc_md.power_off = mvme5100_power_off; + ppc_md.halt = mvme5100_halt; + + ppc_md.find_end_of_memory = mvme5100_find_end_of_memory; + + ppc_md.time_init = todc_time_init; + ppc_md.set_rtc_time = todc_set_rtc_time; + ppc_md.get_rtc_time = todc_get_rtc_time; + ppc_md.calibrate_decr = todc_calibrate_decr; + +#ifdef CONFIG_MVME5100_DEBUG + ppc_md.progress = mvme5100_progress; +#else /* CONFIG_MVME5100_DEBUG */ + ppc_md.progress = NULL; +#endif /* CONFIG_MVME5100_DEBUG */ + + ppc_md.nvram_read_val = todc_m48txx_read_val; + ppc_md.nvram_write_val = todc_m48txx_write_val; + + return; +} diff -Nru a/arch/ppc/kernel/open_pic.c b/arch/ppc/kernel/open_pic.c --- a/arch/ppc/kernel/open_pic.c Wed May 16 06:00:22 2001 +++ b/arch/ppc/kernel/open_pic.c Wed May 16 06:00:22 2001 @@ -775,11 +775,17 @@ int openpic_get_irq(struct pt_regs *regs) { +/* + * Clean up needed. -VAL + */ +#ifndef CONFIG_GEMINI extern int i8259_irq(int cpu); - +#endif int irq = openpic_irq(); /* Management of the cascade should be moved out of here */ + + /* Yep - because openpic !=> i8259, for one thing. -VAL */ if (open_pic_irq_offset && irq == open_pic_irq_offset) { /* @@ -787,8 +793,10 @@ */ if ( chrp_int_ack_special ) irq = *chrp_int_ack_special; +#ifndef CONFIG_GEMINI else irq = i8259_irq( smp_processor_id() ); +#endif openpic_eoi(); } if (irq == OPENPIC_VEC_SPURIOUS + open_pic_irq_offset) { diff -Nru a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c --- a/arch/ppc/kernel/pci.c Wed May 16 06:00:24 2001 +++ b/arch/ppc/kernel/pci.c Wed May 16 06:00:24 2001 @@ -26,7 +26,7 @@ #include "pci.h" -#define DEBUG +#undef DEBUG #ifdef DEBUG #define DBG(x...) printk(x) @@ -38,11 +38,10 @@ unsigned long isa_mem_base = 0; unsigned long pci_dram_offset = 0; -static u8* pci_to_OF_bus_map; - static void pcibios_fixup_resources(struct pci_dev* dev); #ifdef CONFIG_ALL_PPC static void pcibios_fixup_cardbus(struct pci_dev* dev); +static u8* pci_to_OF_bus_map; #endif /* By default, we don't re-assign bus numbers. We do this only on @@ -131,6 +130,10 @@ res->start - offs, res->start); } } + + /* Call machine specific resource fixup */ + if (ppc_md.pcibios_fixup_resources) + ppc_md.pcibios_fixup_resources(dev); } #ifdef CONFIG_ALL_PPC @@ -343,6 +346,10 @@ (!ppc_md.pcibios_enable_device_hook || !ppc_md.pcibios_enable_device_hook(dev, 1))) pci_assign_resource(dev, idx); + if (!r->start && r->end && + (!ppc_md.pcibios_enable_device_hook || + !ppc_md.pcibios_enable_device_hook(dev, 1))) + pci_assign_resource(dev, idx); } if (0) { /* don't assign ROMs */ @@ -399,6 +406,10 @@ return hose; } +#ifdef CONFIG_ALL_PPC +/* + * Functions below are used on OpenFirmware machines. + */ static void make_one_node_map(struct device_node* node, u8 pci_bus) { @@ -579,6 +590,95 @@ } void __init +pci_process_bridge_OF_ranges(struct pci_controller *hose, + struct device_node *dev, int primary) +{ + unsigned int *ranges, *prev; + int rlen = 0; + int memno = 0; + struct resource *res; + int np, na = prom_n_addr_cells(dev); + np = na + 5; + + /* First we try to merge ranges to fix a problem with some pmacs + * that can have more than 3 ranges, fortunately using contiguous + * addresses -- BenH + */ + ranges = (unsigned int *) get_property(dev, "ranges", &rlen); + prev = NULL; + while ((rlen -= np * sizeof(unsigned int)) >= 0) { + if (prev) { + if (prev[0] == ranges[0] && prev[1] == ranges[1] && + (prev[2] + prev[na+4]) == ranges[2] && + (prev[na+2] + prev[na+4]) == ranges[na+2]) { + prev[na+4] += ranges[na+4]; + ranges[0] = 0; + ranges += np; + continue; + } + } + prev = ranges; + ranges += np; + } + + /* + * The ranges property is laid out as an array of elements, + * each of which comprises: + * cells 0 - 2: a PCI address + * cells 3 or 3+4: a CPU physical address + * (size depending on dev->n_addr_cells) + * cells 4+5 or 5+6: the size of the range + */ + rlen = 0; + hose->io_base_phys = 0; + ranges = (unsigned int *) get_property(dev, "ranges", &rlen); + while ((rlen -= np * sizeof(unsigned int)) >= 0) { + res = NULL; + switch (ranges[0] >> 24) { + case 1: /* I/O space */ + if (ranges[2] != 0) + break; + hose->io_base_phys = ranges[na+2]; + hose->io_base_virt = ioremap(ranges[na+2], ranges[na+4]); + if (primary) + isa_io_base = (unsigned long) hose->io_base_virt; + res = &hose->io_resource; + res->flags = IORESOURCE_IO; + res->start = ranges[2]; + break; + case 2: /* memory space */ + memno = 0; + if (ranges[1] == 0 && ranges[2] == 0 + && ranges[na+4] <= (16 << 20)) { + /* 1st 16MB, i.e. ISA memory area */ + if (primary) + isa_mem_base = ranges[na+2]; + memno = 1; + } + while (memno < 3 && hose->mem_resources[memno].flags) + ++memno; + if (memno == 0) + hose->pci_mem_offset = ranges[na+2] - ranges[2]; + if (memno < 3) { + res = &hose->mem_resources[memno]; + res->flags = IORESOURCE_MEM; + res->start = ranges[na+2]; + } + break; + } + if (res != NULL) { + res->name = dev->full_name; + res->end = res->start + ranges[na+4] - 1; + res->parent = NULL; + res->sibling = NULL; + res->child = NULL; + } + ranges += np; + } +} +#endif /* CONFIG_ALL_PPC */ + +void __init pcibios_init(void) { struct pci_controller *hose; @@ -617,7 +717,11 @@ */ if (pci_assign_all_busses && have_of) pcibios_make_OF_bus_map(); - + + /* Do machine dependent PCI interrupt routing */ + if (ppc_md.pci_swizzle && ppc_md.pci_map_irq) + pci_fixup_irqs(ppc_md.pci_swizzle, ppc_md.pci_map_irq); + /* Call machine dependant fixup */ if (ppc_md.pcibios_fixup) ppc_md.pcibios_fixup(); @@ -632,9 +736,6 @@ /* OF fails to initialize IDE controllers on macs * (and maybe other machines) * - * This late fixup is done here since I want it to happen after - * resource assignement, and there's no "late-init" arch hook - * * Ideally, this should be moved to the IDE layer, but we need * to check specifically with Andre Hedrick how to do it cleanly * since the common IDE code seem to care about the fact that the @@ -651,6 +752,9 @@ } } #endif /* CONFIG_BLK_DEV_IDE */ + + if (ppc_md.pcibios_after_init) + ppc_md.pcibios_after_init(); } int __init @@ -659,6 +763,25 @@ return pci_assign_all_busses; } +unsigned char __init +common_swizzle(struct pci_dev *dev, unsigned char *pinp) +{ + struct pci_controller *hose = dev->sysdata; + + if (dev->bus->number != hose->first_busno) { + u8 pin = *pinp; + do { + pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn)); + /* Move up the chain of bridges. */ + dev = dev->bus->self; + } while (dev->bus->self); + *pinp = pin; + + /* The slot is the idsel of the last bridge. */ + } + return PCI_SLOT(dev->devfn); +} + void __init pcibios_fixup_pbus_ranges(struct pci_bus * bus, struct pbus_set_ranges_data * ranges) { @@ -794,14 +917,14 @@ #ifdef CONFIG_POWER4 unsigned long offset = pci_address_offset(pdev->bus->number, res->flags); return res->start - offset; -#else /* CONFIG_POWER4 */ +#else /* !CONFIG_POWER4 */ struct pci_controller* hose = (struct pci_controller *)pdev->sysdata; if (hose && res->flags & IORESOURCE_MEM) return res->start - hose->pci_mem_offset; /* We may want to do something with IOs here... */ return res->start; -#endif +#endif /* CONFIG_POWER4 */ } /* Obsolete functions. Should be removed once the symbios driver @@ -838,12 +961,12 @@ { #ifdef CONFIG_POWER4 return pa - pci_address_offset(busnr, IORESOURCE_MEM); -#else /* CONFIG_POWER4 */ +#else /* !CONFIG_POWER4 */ struct pci_controller* hose = pci_bus_to_hose(busnr); if (!hose) return pa; return pa - hose->pci_mem_offset; -#endif +#endif /* CONFIG_POWER4 */ } unsigned long @@ -851,12 +974,12 @@ { #ifdef CONFIG_POWER4 return ba + pci_address_offset(dev->bus->number, IORESOURCE_MEM); -#else /* CONFIG_POWER4 */ +#else /* !CONFIG_POWER4 */ struct pci_controller* hose = pci_bus_to_hose(busnr); if (!hose) return ba; return ba + hose->pci_mem_offset; -#endif +#endif /* CONFIG_POWER4 */ } /* Provide information on locations of various I/O regions in physical diff -Nru a/arch/ppc/kernel/pci.h b/arch/ppc/kernel/pci.h --- a/arch/ppc/kernel/pci.h Wed May 16 06:00:16 2001 +++ b/arch/ppc/kernel/pci.h Wed May 16 06:00:16 2001 @@ -21,4 +21,30 @@ u32 cfg_addr, u32 cfg_data); extern void setup_grackle(struct pci_controller *hose, unsigned io_space_size); +extern unsigned char common_swizzle(struct pci_dev *, unsigned char *); + +/* + * The following code swizzles for exactly one bridge. The routine + * common_swizzle below handles multiple bridges. But there are a + * some boards that don't follow the PCI spec's suggestion so we + * break this piece out separately. + */ +static inline unsigned char bridge_swizzle(unsigned char pin, + unsigned char idsel) +{ + return (((pin-1) + idsel) % 4) + 1; +} + +/* + * The following macro is used to lookup irqs in a standard table + * format for those PPC systems that do not already have PCI + * interrupts properly routed. + */ +/* FIXME - double check this */ +#define PCI_IRQ_TABLE_LOOKUP \ +({ long _ctl_ = -1; \ + if (idsel >= min_idsel && idsel <= max_idsel && pin <= irqs_per_slot) \ + _ctl_ = pci_irq_table[idsel - min_idsel][pin-1]; \ + _ctl_; }) + #endif /* __PPC_KERNEL_PCI_H__ */ diff -Nru a/arch/ppc/kernel/pci_auto.c b/arch/ppc/kernel/pci_auto.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/kernel/pci_auto.c Wed May 16 06:00:25 2001 @@ -0,0 +1,339 @@ +/* + * arch/ppc/kernel/pci_auto.c + * + * PCI autoconfiguration library + * + * Author: Matt Porter + * + * Copyright 2000 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include + +#include + +#include "pci.h" +#include "pci_auto.h" + +#undef DEBUG +#ifdef DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif /* DEBUG */ + +static int pciauto_upper_iospc; +static int pciauto_upper_memspc; + +void pciauto_setup_bars(struct pci_controller *hose, + int current_bus, + int pci_devfn) +{ + int bar_response, bar_size, bar_value; + int bar, addr_mask, bar_nr = 0; + int * upper_limit; + int found_mem64 = 0; + + DBG("PCI Autoconfig: Found Bus %d, Device %d, Function %d\n", + current_bus, PCI_SLOT(pci_devfn), PCI_FUNC(pci_devfn) ); + + for (bar = PCI_BASE_ADDRESS_0; bar <= PCI_BASE_ADDRESS_5; bar+=4) + { + /* Tickle the BAR and get the response */ + early_write_config_dword(hose, + current_bus, + pci_devfn, + bar, + 0xffffffff); + early_read_config_dword(hose, + current_bus, + pci_devfn, + bar, + &bar_response); + + /* If BAR is not implemented go to the next BAR */ + if (!bar_response) + continue; + + /* Check the BAR type and set our address mask */ + if (bar_response & PCI_BASE_ADDRESS_SPACE) + { + addr_mask = PCI_BASE_ADDRESS_IO_MASK; + upper_limit = &pciauto_upper_iospc; + DBG("PCI Autoconfig: BAR %d, I/O, ", bar_nr); + } + else + { + if ( (bar_response & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == + PCI_BASE_ADDRESS_MEM_TYPE_64) + found_mem64 = 1; + + addr_mask = PCI_BASE_ADDRESS_MEM_MASK; + upper_limit = &pciauto_upper_memspc; + DBG("PCI Autoconfig: BAR %d, Mem, ", bar_nr); + } + + /* Calculate requested size */ + bar_size = ~(bar_response & addr_mask) + 1; + + /* Allocate a base address */ + bar_value = (*upper_limit - bar_size) & ~(bar_size - 1); + + /* Write it out and update our limit */ + early_write_config_dword(hose, + current_bus, + pci_devfn, + bar, + bar_value); + + *upper_limit = bar_value; + + /* + * If we are a 64-bit decoder then increment to the + * upper 32 bits of the bar and force it to locate + * in the lower 4GB of memory. + */ + if (found_mem64) + { + bar += 4; + early_write_config_dword(hose, + current_bus, + pci_devfn, + bar, + 0x00000000); + } + + bar_nr++; + + DBG("size=0x%x, address=0x%x\n", + bar_size, bar_value); + } + +} + +void pciauto_prescan_setup_bridge(struct pci_controller *hose, + int current_bus, + int pci_devfn, + int sub_bus) +{ + int cmdstat; + + /* Configure bus number registers */ + early_write_config_byte(hose, + current_bus, + pci_devfn, + PCI_PRIMARY_BUS, + current_bus); + early_write_config_byte(hose, + current_bus, + pci_devfn, + PCI_SECONDARY_BUS, + sub_bus + 1); + early_write_config_byte(hose, + current_bus, + pci_devfn, + PCI_SUBORDINATE_BUS, + 0xff); + + /* Round memory allocator to 1MB boundary */ + pciauto_upper_memspc &= ~(0x100000 - 1); + + /* Round I/O allocator to 4KB boundary */ + pciauto_upper_iospc &= ~(0x1000 - 1); + + /* Set up memory and I/O filter limits, assume 32-bit I/O space */ + early_write_config_word(hose, + current_bus, + pci_devfn, + PCI_MEMORY_LIMIT, + ((pciauto_upper_memspc - 1) & 0xfff00000) >> 16); + early_write_config_byte(hose, + current_bus, + pci_devfn, + PCI_IO_LIMIT, + ((pciauto_upper_iospc - 1) & 0x0000f000) >> 8); + early_write_config_word(hose, + current_bus, + pci_devfn, + PCI_IO_LIMIT_UPPER16, + ((pciauto_upper_iospc - 1) & 0xffff0000) >> 16); + + /* We don't support prefetchable memory for now, so disable */ + early_write_config_word(hose, + current_bus, + pci_devfn, + PCI_PREF_MEMORY_BASE, + 0x1000); + early_write_config_word(hose, + current_bus, + pci_devfn, + PCI_PREF_MEMORY_LIMIT, + 0x1000); + + /* Enable memory and I/O accesses, enable bus master */ + early_read_config_dword(hose, + current_bus, + pci_devfn, + PCI_COMMAND, + &cmdstat); + early_write_config_dword(hose, + current_bus, + pci_devfn, + PCI_COMMAND, + cmdstat | + PCI_COMMAND_IO | + PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER); +} + +void pciauto_postscan_setup_bridge(struct pci_controller *hose, + int current_bus, + int pci_devfn, + int sub_bus) +{ + /* Configure bus number registers */ + early_write_config_byte(hose, + current_bus, + pci_devfn, + PCI_SUBORDINATE_BUS, + sub_bus); + + /* Round memory allocator to 1MB boundary */ + pciauto_upper_memspc &= ~(0x100000 - 1); + early_write_config_word(hose, + current_bus, + pci_devfn, + PCI_MEMORY_BASE, + pciauto_upper_memspc >> 16); + + /* Round I/O allocator to 4KB boundary */ + pciauto_upper_iospc &= ~(0x1000 - 1); + early_write_config_byte(hose, + current_bus, + pci_devfn, + PCI_IO_BASE, + (pciauto_upper_iospc & 0x0000f000) >> 8); + early_write_config_word(hose, + current_bus, + pci_devfn, + PCI_IO_BASE_UPPER16, + pciauto_upper_iospc >> 16); +} + +int pciauto_bus_scan(struct pci_controller *hose, int current_bus) +{ + int sub_bus, pci_devfn, pci_class, cmdstat, found_multi=0; + unsigned short vid; + unsigned char header_type; + + /* + * Fetch our I/O and memory space upper boundaries used + * to allocated base addresses on this hose. + */ + if (current_bus == hose->first_busno) + { + pciauto_upper_iospc = hose->io_space.end + 1; + pciauto_upper_memspc = hose->mem_space.end + 1; + } + + sub_bus = current_bus; + + for (pci_devfn=0; pci_devfn<0xff; pci_devfn++) + { + /* Skip our host bridge */ + if ( (current_bus == hose->first_busno) && (pci_devfn == 0) ) + continue; + + if (PCI_FUNC(pci_devfn) && !found_multi) + continue; + + early_read_config_byte(hose, + current_bus, + pci_devfn, + PCI_HEADER_TYPE, + &header_type); + + if (!PCI_FUNC(pci_devfn)) + found_multi = header_type & 0x80; + + early_read_config_word(hose, + current_bus, + pci_devfn, + PCI_VENDOR_ID, + &vid); + + if (vid != 0xffff) + { + early_read_config_dword(hose, + current_bus, + pci_devfn, + PCI_CLASS_REVISION, &pci_class); + if ( (pci_class >> 16) == PCI_CLASS_BRIDGE_PCI ) + { + DBG("PCI Autoconfig: Found P2P bridge, device %d\n", PCI_SLOT(pci_devfn)); + pciauto_prescan_setup_bridge(hose, + current_bus, + pci_devfn, + sub_bus); + sub_bus = pciauto_bus_scan(hose, sub_bus+1); + pciauto_postscan_setup_bridge(hose, + current_bus, + pci_devfn, + sub_bus); + } + else + { + if ((pci_class >> 16) == PCI_CLASS_STORAGE_IDE) + { + unsigned char prg_iface; + + early_read_config_byte(hose, + current_bus, + pci_devfn, + PCI_CLASS_PROG, + &prg_iface); + if (!(prg_iface & PCIAUTO_IDE_MODE_MASK)) + { + DBG("PCI Autoconfig: Skipping legacy mode IDE controller\n"); + continue; + } + } + /* + * Found a peripheral, enable some standard + * settings + */ + early_read_config_dword(hose, + current_bus, + pci_devfn, + PCI_COMMAND, + &cmdstat); + early_write_config_dword(hose, + current_bus, + pci_devfn, + PCI_COMMAND, + cmdstat | + PCI_COMMAND_IO | + PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER); + early_write_config_byte(hose, + current_bus, + pci_devfn, + PCI_LATENCY_TIMER, + 0x80); + + /* Allocate PCI I/O and/or memory space */ + pciauto_setup_bars(hose, + current_bus, + pci_devfn); + } + } + } + return sub_bus; +} diff -Nru a/arch/ppc/kernel/pci_auto.h b/arch/ppc/kernel/pci_auto.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/kernel/pci_auto.h Wed May 16 06:00:34 2001 @@ -0,0 +1,25 @@ +/* + * arch/ppc/kernel/pci_auto.h + * + * PCI autoconfiguration library definitions + * + * Author: Matt Porter + * + * Copyright 2000 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef _PPC_KERNEL_PCI_AUTO_H +#define _PPC_KERNEL_PCI_AUTO_H + +#include + +extern int pciauto_bus_scan(struct pci_controller *, int); + +#define PCIAUTO_IDE_MODE_MASK 0x05 + +#endif /* _PPC_KERNEL_PCI_AUTO_H */ diff -Nru a/arch/ppc/kernel/pmac_pci.c b/arch/ppc/kernel/pmac_pci.c --- a/arch/ppc/kernel/pmac_pci.c Wed May 16 06:00:25 2001 +++ b/arch/ppc/kernel/pmac_pci.c Wed May 16 06:00:25 2001 @@ -24,13 +24,12 @@ #include #include #include +#include #include "pci.h" #undef DEBUG -extern void process_bridge_ranges(struct pci_controller *hose, - struct device_node *dev, int primary); static void add_bridges(struct device_node *dev); /* XXX Could be per-controller, but I don't think we risk anything by @@ -382,17 +381,6 @@ hose->ops = ¯isc_pci_ops; hose->cfg_addr = ioremap(addr->address + 0x800000, 0x1000); hose->cfg_data = ioremap(addr->address + 0xc00000, 0x1000); -#if 0 /* done in process_bridge_ranges now - paulus */ - hose->io_base_phys = addr->address; - /* is 0x10000 enough for io space ? */ - hose->io_base_virt = (void *)ioremap(addr->address, 0x10000); - - /* XXX This is the bridge with the PCI expansion bus. We route - * legacy IOs to it. - */ - if (addr->address == 0xf2000000) - isa_io_base = (unsigned long)hose->io_base_virt; -#endif /* We "know" that the bridge at f2000000 has the PCI slots. */ return addr->address == 0xf2000000; } @@ -405,10 +393,6 @@ ioremap(addr->address + 0x800000, 0x1000); hose->cfg_data = (volatile unsigned char *) ioremap(addr->address + 0xc00000, 0x1000); -#if 0 /* done in process_bridge_ranges now - paulus */ - hose->io_base_phys = addr->address; - hose->io_base_virt = (void *) ioremap(addr->address, 0x10000); -#endif init_bandit(hose); } @@ -421,23 +405,12 @@ ioremap(addr->address + 0x800000, 0x1000); hose->cfg_data = (volatile unsigned char *) ioremap(addr->address + 0xc00000, 0x1000); -#if 0 /* done in process_bridge_ranges now - paulus */ - hose->io_base_phys = addr->address; - hose->io_base_virt = (void *) ioremap(addr->address, 0x10000); -#endif } void __init setup_grackle(struct pci_controller *hose, unsigned io_space_size) { setup_indirect_pci(hose, 0xfec00000, 0xfee00000); -#if 0 /* done in process_bridge_ranges now - paulus */ - hose->io_base_phys = 0xfe000000; - hose->io_base_virt = (void *) ioremap(0xfe000000, io_space_size); - pci_dram_offset = 0; - isa_mem_base = 0xfd000000; - isa_io_base = (unsigned long) hose->io_base_virt; -#endif if (machine_is_compatible("AAPL,PowerBook1998")) grackle_set_loop_snoop(hose, 1); #if 0 /* Disabled for now, HW problems ??? */ @@ -505,7 +478,7 @@ /* Interpret the "ranges" property */ /* This also maps the I/O region and sets isa_io/mem_base */ - process_bridge_ranges(hose, dev, primary); + pci_process_bridge_OF_ranges(hose, dev, primary); /* Fixup "bus-range" OF property */ fixup_bus_range(dev); @@ -557,19 +530,56 @@ pcibios_fixup_OF_interrupts(); } -/* We don't want to enable USB controllers absent from the OF tree - * (iBook second controller) - */ int pmac_pci_enable_device_hook(struct pci_dev *dev, int initial) { + struct device_node* node; + + node = pci_device_to_OF_node(dev); + + /* We don't want to enable USB controllers absent from the OF tree + * (iBook second controller) + */ if (dev->vendor == PCI_VENDOR_ID_APPLE - && dev->device == PCI_DEVICE_ID_APPLE_KL_USB) { - struct device_node* node; - node = pci_device_to_OF_node(dev); - if (!node) - return -EINVAL; + && dev->device == PCI_DEVICE_ID_APPLE_KL_USB && !node) + return -EINVAL; + + /* Firewire was disabled after PCI probe, the driver is claiming it, + * so we must re-enable it now, at least until the driver can do it + * itself. + */ + if (node && !strcmp(node->name, "firewire") && + device_is_compatible(node, "pci106b,18")) { + feature_set_firewire_cable_power(node, 1); + feature_set_firewire_power(node, 1); } + return 0; +} + +/* We power down some devices after they have been probed. They'll + * be powered back on later on + */ +void +pmac_pcibios_after_init(void) +{ + struct device_node* nd; + + nd = find_devices("firewire"); + while (nd) { + if (nd->parent && device_is_compatible(nd, "pci106b,18") + && device_is_compatible(nd->parent, "uni-north")) { + feature_set_firewire_power(nd, 0); + feature_set_firewire_cable_power(nd, 0); + } + nd = nd->next; + } + nd = find_devices("ethernet"); + while (nd) { + if (nd->parent && device_is_compatible(nd, "gmac") + && device_is_compatible(nd->parent, "uni-north")) + feature_set_gmac_power(nd, 0); + nd = nd->next; + } } diff -Nru a/arch/ppc/kernel/pmac_pic.c b/arch/ppc/kernel/pmac_pic.c --- a/arch/ppc/kernel/pmac_pic.c Wed May 16 06:00:18 2001 +++ b/arch/ppc/kernel/pmac_pic.c Wed May 16 06:00:18 2001 @@ -10,6 +10,7 @@ #include #include #include +#include #include "pmac_pic.h" #include "open_pic.h" @@ -44,10 +45,12 @@ * since it can lose interrupts (see pmac_set_irq_mask). * -- Cort */ -void __pmac __no_use_set_lost(unsigned long irq_nr) +void __pmac __set_lost(unsigned long irq_nr) { - if (!test_and_set_bit(irq_nr, ppc_lost_interrupts)) + if (!test_and_set_bit(irq_nr, ppc_lost_interrupts)) { atomic_inc(&ppc_n_lost_interrupts); + set_dec(1); + } } static void __pmac pmac_mask_and_ack_irq(unsigned int irq_nr) @@ -373,7 +376,6 @@ irqctrler = NULL; } - int_control.int_set_lost = __no_use_set_lost; /* * G3 powermacs and 1999 G3 PowerBooks have 64 interrupts, * 1998 G3 Series PowerBooks have 128, diff -Nru a/arch/ppc/kernel/pmac_setup.c b/arch/ppc/kernel/pmac_setup.c --- a/arch/ppc/kernel/pmac_setup.c Wed May 16 06:00:18 2001 +++ b/arch/ppc/kernel/pmac_setup.c Wed May 16 06:00:18 2001 @@ -66,6 +66,7 @@ #include #include "local_irq.h" #include "pmac_pic.h" +#include "../mm/mem_pieces.h" #undef SHOW_GATWICK_IRQS @@ -102,6 +103,9 @@ extern void pmac_nvram_update(void); extern int pmac_pci_enable_device_hook(struct pci_dev *dev, int initial); +extern void pmac_pcibios_after_init(void); + +struct device_node *memory_node; unsigned char drive_info; @@ -470,7 +474,7 @@ char *p; /* Do nothing if the root has been set already. */ - if ((goodness < current_root_goodness) && + if ((goodness <= current_root_goodness) && (ROOT_DEV != to_kdev_t(DEFAULT_ROOT_DEVICE))) return; p = strstr(saved_command_line, "root="); @@ -635,6 +639,88 @@ #endif #endif +/* + * Read in a property describing some pieces of memory. + */ + +static void __init get_mem_prop(char *name, struct mem_pieces *mp) +{ + struct reg_property *rp; + int i, s; + unsigned int *ip; + int nac = prom_n_addr_cells(memory_node); + int nsc = prom_n_size_cells(memory_node); + + ip = (unsigned int *) get_property(memory_node, name, &s); + if (ip == NULL) { + printk(KERN_ERR "error: couldn't get %s property on /memory\n", + name); + abort(); + } + s /= (nsc + nac) * 4; + rp = mp->regions; + for (i = 0; i < s; ++i, ip += nac+nsc) { + if (nac >= 2 && ip[nac-2] != 0) + continue; + rp->address = ip[nac-1]; + if (nsc >= 2 && ip[nac+nsc-2] != 0) + rp->size = ~0U; + else + rp->size = ip[nac+nsc-1]; + ++rp; + } + mp->n_regions = rp - mp->regions; + + /* Make sure the pieces are sorted. */ + mem_pieces_sort(mp); + mem_pieces_coalesce(mp); +} + +/* + * On systems with Open Firmware, collect information about + * physical RAM and which pieces are already in use. + * At this point, we have (at least) the first 8MB mapped with a BAT. + * Our text, data, bss use something over 1MB, starting at 0. + * Open Firmware may be using 1MB at the 4MB point. + */ +unsigned long __init pmac_find_end_of_memory(void) +{ + unsigned long a, total; + struct mem_pieces phys_mem; + + memory_node = find_devices("memory"); + if (memory_node == NULL) { + printk(KERN_ERR "can't find memory node\n"); + abort(); + } + + /* + * Find out where physical memory is, and check that it + * starts at 0 and is contiguous. It seems that RAM is + * always physically contiguous on Power Macintoshes. + * + * Supporting discontiguous physical memory isn't hard, + * it just makes the virtual <-> physical mapping functions + * more complicated (or else you end up wasting space + * in mem_map). + */ + get_mem_prop("reg", &phys_mem); + if (phys_mem.n_regions == 0) + panic("No RAM??"); + a = phys_mem.regions[0].address; + if (a != 0) + panic("RAM doesn't start at physical address 0"); + total = phys_mem.regions[0].size; + + if (phys_mem.n_regions > 1) { + printk("RAM starting at 0x%x is not contiguous\n", + phys_mem.regions[1].address); + printk("Using RAM from 0 to 0x%lx\n", total-1); + } + + return total; +} + void __init pmac_init(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7) @@ -656,6 +742,7 @@ ppc_md.pcibios_fixup = pmac_pcibios_fixup; ppc_md.pcibios_enable_device_hook = pmac_pci_enable_device_hook; + ppc_md.pcibios_after_init = pmac_pcibios_after_init; ppc_md.restart = pmac_restart; ppc_md.power_off = pmac_power_off; @@ -665,6 +752,8 @@ ppc_md.set_rtc_time = pmac_set_rtc_time; ppc_md.get_rtc_time = pmac_get_rtc_time; ppc_md.calibrate_decr = pmac_calibrate_decr; + + ppc_md.find_end_of_memory = pmac_find_end_of_memory; #ifdef CONFIG_VT #ifdef CONFIG_INPUT diff -Nru a/arch/ppc/kernel/ppc8260_pic.h b/arch/ppc/kernel/ppc8260_pic.h --- a/arch/ppc/kernel/ppc8260_pic.h Wed May 16 06:00:25 2001 +++ b/arch/ppc/kernel/ppc8260_pic.h Wed May 16 06:00:25 2001 @@ -8,8 +8,7 @@ void m8260_pic_init(void); void m8260_do_IRQ(struct pt_regs *regs, - int cpu, - int isfake); + int cpu); int m8260_get_irq(struct pt_regs *regs); #endif /* _PPC_KERNEL_PPC8260_H */ diff -Nru a/arch/ppc/kernel/ppc8xx_pic.c b/arch/ppc/kernel/ppc8xx_pic.c --- a/arch/ppc/kernel/ppc8xx_pic.c Wed May 16 06:00:18 2001 +++ b/arch/ppc/kernel/ppc8xx_pic.c Wed May 16 06:00:18 2001 @@ -67,8 +67,7 @@ #if 0 void m8xx_do_IRQ(struct pt_regs *regs, - int cpu, - int isfake) + int cpu) { int irq; unsigned long bits = 0; @@ -158,13 +157,15 @@ */ switch (irq) { #ifdef IDE0_INTERRUPT - case IDE0_INTERRUPT: /* fall through */ + case IDE0_INTERRUPT: /* IDE0 */ + return (request_8xxirq(irq, handler, irqflags, devname, + dev_id)); #endif #ifdef IDE1_INTERRUPT - case IDE1_INTERRUPT: /* fall through */ + case IDE1_INTERRUPT: /* IDE1 */ + return (request_8xxirq(irq, handler, irqflags, devname, + dev_id)); #endif - return (request_8xxirq(irq, handler, irqflags, devname, dev_id)); - default: /* unknown IRQ -> panic */ panic("request_irq"); } diff -Nru a/arch/ppc/kernel/ppc8xx_pic.h b/arch/ppc/kernel/ppc8xx_pic.h --- a/arch/ppc/kernel/ppc8xx_pic.h Wed May 16 06:00:23 2001 +++ b/arch/ppc/kernel/ppc8xx_pic.h Wed May 16 06:00:23 2001 @@ -8,8 +8,7 @@ void m8xx_pic_init(void); void m8xx_do_IRQ(struct pt_regs *regs, - int cpu, - int isfake); + int cpu); int m8xx_get_irq(struct pt_regs *regs); #ifdef CONFIG_MBX diff -Nru a/arch/ppc/kernel/ppc_asm.h b/arch/ppc/kernel/ppc_asm.h --- a/arch/ppc/kernel/ppc_asm.h Wed May 16 06:00:24 2001 +++ b/arch/ppc/kernel/ppc_asm.h Wed May 16 06:00:24 2001 @@ -130,3 +130,22 @@ #define MTMSRD(r) mtmsr r #define CLR_TOP32(r) #endif /* CONFIG_PPC64BRIDGE */ + +/* + * Defines for cache-line size etc. + */ +#if defined(CONFIG_4xx) || defined(CONFIG_8xx) +#define CACHE_LINE_SIZE 16 +#define LG_CACHE_LINE_SIZE 4 +#define MAX_COPY_PREFETCH 1 + +#elif !defined(CONFIG_PPC64BRIDGE) +#define CACHE_LINE_SIZE 32 +#define LG_CACHE_LINE_SIZE 5 +#define MAX_COPY_PREFETCH 4 + +#else +#define CACHE_LINE_SIZE 128 +#define LG_CACHE_LINE_SIZE 7 +#define MAX_COPY_PREFETCH 1 +#endif /* CONFIG_4xx || CONFIG_8xx */ diff -Nru a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c --- a/arch/ppc/kernel/ppc_ksyms.c Wed May 16 06:00:22 2001 +++ b/arch/ppc/kernel/ppc_ksyms.c Wed May 16 06:00:22 2001 @@ -55,12 +55,11 @@ extern void transfer_to_handler(void); extern void syscall_trace(void); -extern void do_IRQ(struct pt_regs *regs, int isfake); +extern void do_IRQ(struct pt_regs *regs); extern void MachineCheckException(struct pt_regs *regs); extern void AlignmentException(struct pt_regs *regs); extern void ProgramCheckException(struct pt_regs *regs); extern void SingleStepException(struct pt_regs *regs); -extern void do_lost_interrupts(unsigned long); extern int do_signal(sigset_t *, struct pt_regs *); extern int pmac_newworld; extern int sys_sigreturn(struct pt_regs *regs); @@ -83,7 +82,6 @@ EXPORT_SYMBOL(sys_sigreturn); EXPORT_SYMBOL(ppc_n_lost_interrupts); EXPORT_SYMBOL(ppc_lost_interrupts); -EXPORT_SYMBOL(do_lost_interrupts); EXPORT_SYMBOL(enable_irq); EXPORT_SYMBOL(disable_irq); EXPORT_SYMBOL(disable_irq_nosync); @@ -216,9 +214,6 @@ EXPORT_SYMBOL(synchronize_irq); #endif -#ifndef CONFIG_MACH_SPECIFIC -EXPORT_SYMBOL(_machine); -#endif EXPORT_SYMBOL(ppc_md); #ifdef CONFIG_ADB @@ -249,11 +244,10 @@ EXPORT_SYMBOL(set_backlight_enable); EXPORT_SYMBOL(register_backlight_controller); #endif /* CONFIG_PMAC_BACKLIGHT */ -#ifndef CONFIG_MACH_SPECIFIC -EXPORT_SYMBOL_NOVERS(have_of); -#endif /* CONFIG_MACH_SPECIFIC */ #if defined(CONFIG_ALL_PPC) +EXPORT_SYMBOL_NOVERS(have_of); EXPORT_SYMBOL_NOVERS(sys_ctrler); +EXPORT_SYMBOL(_machine); EXPORT_SYMBOL(find_devices); EXPORT_SYMBOL(find_type_devices); EXPORT_SYMBOL(find_compatible_devices); @@ -277,9 +271,11 @@ EXPORT_SYMBOL(feature_clear); EXPORT_SYMBOL(feature_test); EXPORT_SYMBOL(feature_set_gmac_power); -EXPORT_SYMBOL(feature_set_gmac_phy_reset); +EXPORT_SYMBOL(feature_gmac_phy_reset); EXPORT_SYMBOL(feature_set_usb_power); EXPORT_SYMBOL(feature_set_firewire_power); +EXPORT_SYMBOL(feature_set_firewire_cable_power); +EXPORT_SYMBOL(feature_set_airport_power); #endif /* defined(CONFIG_ALL_PPC) */ #if defined(CONFIG_BOOTX_TEXT) EXPORT_SYMBOL(bootx_update_display); @@ -314,7 +310,14 @@ #endif EXPORT_SYMBOL(__delay); -EXPORT_SYMBOL(int_control); +EXPORT_SYMBOL(__sti); +EXPORT_SYMBOL(__sti_end); +EXPORT_SYMBOL(__cli); +EXPORT_SYMBOL(__cli_end); +EXPORT_SYMBOL(__save_flags_ptr); +EXPORT_SYMBOL(__save_flags_ptr_end); +EXPORT_SYMBOL(__restore_flags); +EXPORT_SYMBOL(__restore_flags_end); EXPORT_SYMBOL(timer_interrupt_intercept); EXPORT_SYMBOL(timer_interrupt); EXPORT_SYMBOL(do_IRQ_intercept); @@ -331,9 +334,6 @@ EXPORT_SYMBOL(__up); EXPORT_SYMBOL(__down); EXPORT_SYMBOL(__down_interruptible); -EXPORT_SYMBOL(__down_trylock); -EXPORT_SYMBOL(down_read_failed); -EXPORT_SYMBOL(down_write_failed); #if defined(CONFIG_KGDB) || defined(CONFIG_XMON) extern void (*debugger)(struct pt_regs *regs); @@ -362,6 +362,8 @@ EXPORT_SYMBOL(next_mmu_context); EXPORT_SYMBOL(set_context); EXPORT_SYMBOL(mmu_context_overflow); +EXPORT_SYMBOL(flush_hash_page); /* For MOL */ +EXPORT_SYMBOL(handle_mm_fault); /* For MOL */ EXPORT_SYMBOL_NOVERS(disarm_decr); #if !defined(CONFIG_8xx) && !defined(CONFIG_4xx) extern long *intercept_table; @@ -369,17 +371,3 @@ #endif extern long *ret_from_intercept; EXPORT_SYMBOL(ret_from_intercept); - -#ifdef CONFIG_MOL -extern ulong mol_interface[]; -extern PTE *Hash; -extern unsigned long Hash_mask; -extern void (*ret_from_except)(void); -extern struct task_struct *last_task_used_altivec; -EXPORT_SYMBOL_NOVERS(mol_interface); -EXPORT_SYMBOL(Hash); -EXPORT_SYMBOL(Hash_mask); -EXPORT_SYMBOL(handle_mm_fault); -EXPORT_SYMBOL(last_task_used_math); -EXPORT_SYMBOL(ret_from_except); -#endif /* CONFIG_MOL */ diff -Nru a/arch/ppc/kernel/ppc_stubs.c b/arch/ppc/kernel/ppc_stubs.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/kernel/ppc_stubs.c Wed May 16 06:00:34 2001 @@ -0,0 +1,72 @@ +/* + * arch/ppc/kernel/ppc_stubs.c + * + * Call stubs to allow linking without pulling in CHRP/PMAC/PREP objects + * on 6xx/7xx/74xx systems + * + * Author: Matt Porter + * + * Copyright 2000 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * prom_init() is called very early on, before the kernel text + * and data have been mapped to KERNELBASE. At this point the code + * is running at whatever address it has been loaded at, so + * references to extern and static variables must be relocated + * explicitly. The procedure reloc_offset() returns the address + * we're currently running at minus the address we were linked at. + * (Note that strings count as static variables.) + */ +extern unsigned long reloc_offset(void); +#define PTRRELOC(x) ((typeof(x))((unsigned long)(x) + offset)) + +EXPORT_SYMBOL(get_property); + +__init +unsigned long +prom_init(int r3, int r4, prom_entry dummy) +{ + unsigned long offset = reloc_offset(); + unsigned long phys; + extern char __bss_start, _end; + + /* First zero the BSS -- use memset, some arches don't have + * caches on yet */ + memset_io(PTRRELOC(&__bss_start),0 , &_end - &__bss_start); + + /* Default */ + phys = offset + KERNELBASE; + + /* We are done. + */ + return phys; +} + +__openfirmware +struct device_node * +find_path_device(const char *path) +{ + return NULL; +} + +__openfirmware +unsigned char * +get_property(struct device_node *np, const char *name, int *lenp) +{ + return NULL; +} diff -Nru a/arch/ppc/kernel/pplus.h b/arch/ppc/kernel/pplus.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/kernel/pplus.h Wed May 16 06:00:34 2001 @@ -0,0 +1,91 @@ +/* + * arch/ppc/kernel/pplus.h + * + * Definitions for Motorola MCG Falcon/Raven & HAWK North Bridge & Memory ctlr. + * + * Author: Mark A. Greer + * mgreer@mvista.com + * + * Copyright 2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __ASMPPC_PPLUS_H +#define __ASMPPC_PPLUS_H + +#include + +/* + * The Falcon/Raven and HAWK have 4 sets of registers: + * 1) PPC Registers which define the mappings from PPC bus to PCI bus, + * etc. + * 2) PCI Registers which define the mappings from PCI bus to PPC bus and the + * MPIC base address. + * 3) MPIC registers + * 4) System Memory Controller (SMC) registers. + */ + +#define PPLUS_RAVEN_VEND_DEV_ID 0x48011057 +#define PPLUS_HAWK_VEND_DEV_ID 0x48031057 + +#define PPLUS_MPIC_SIZE 0x00030000U +#define PPLUS_SMC_SIZE 0x00001000U + +/* + * Define PPC register offsets. + */ +#define PPLUS_PPC_XSADD0_OFF 0x40 +#define PPLUS_PPC_XSOFF0_OFF 0x44 +#define PPLUS_PPC_XSADD1_OFF 0x48 +#define PPLUS_PPC_XSOFF1_OFF 0x4c +#define PPLUS_PPC_XSADD2_OFF 0x50 +#define PPLUS_PPC_XSOFF2_OFF 0x54 +#define PPLUS_PPC_XSADD3_OFF 0x58 +#define PPLUS_PPC_XSOFF3_OFF 0x5c + +/* + * Define PCI register offsets. + */ +#define PPLUS_PCI_PSADD0_OFF 0x80 +#define PPLUS_PCI_PSOFF0_OFF 0x84 +#define PPLUS_PCI_PSADD1_OFF 0x88 +#define PPLUS_PCI_PSOFF1_OFF 0x8c +#define PPLUS_PCI_PSADD2_OFF 0x90 +#define PPLUS_PCI_PSOFF2_OFF 0x94 +#define PPLUS_PCI_PSADD3_OFF 0x98 +#define PPLUS_PCI_PSOFF3_OFF 0x9c + +/* + * Define the System Memory Controller (SMC) register offsets. + */ +#define PPLUS_SMC_RAM_A_SIZE_REG_OFF 0x10 +#define PPLUS_SMC_RAM_B_SIZE_REG_OFF 0x11 +#define PPLUS_SMC_RAM_C_SIZE_REG_OFF 0x12 +#define PPLUS_SMC_RAM_D_SIZE_REG_OFF 0x13 +#define PPLUS_SMC_RAM_E_SIZE_REG_OFF 0xc0 /* HAWK Only */ +#define PPLUS_SMC_RAM_F_SIZE_REG_OFF 0xc1 /* HAWK Only */ +#define PPLUS_SMC_RAM_G_SIZE_REG_OFF 0xc2 /* HAWK Only */ +#define PPLUS_SMC_RAM_H_SIZE_REG_OFF 0xc3 /* HAWK Only */ + +#define PPLUS_FALCON_SMC_REG_COUNT 4 +#define PPLUS_HAWK_SMC_REG_COUNT 8 + + + +int pplus_init(struct pci_controller *hose, + uint ppc_reg_base, + ulong processor_pci_mem_start, + ulong processor_pci_mem_end, + ulong processor_pci_io_start, + ulong processor_pci_io_end, + ulong processor_mpic_base); + +unsigned long pplus_get_mem_size(uint smc_base); + +int pplus_mpic_init(unsigned int pci_mem_offset); + +#endif /* __ASMPPC_PPLUS_H */ diff -Nru a/arch/ppc/kernel/pplus_common.c b/arch/ppc/kernel/pplus_common.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/kernel/pplus_common.c Wed May 16 06:00:34 2001 @@ -0,0 +1,297 @@ +/* + * arch/ppc/kernel/pplus_common.c + * + * Common Motorola PowerPlus Platform--really Falcon/Raven or HAWK. + * + * Author: Mark A. Greer + * mgreer@mvista.com + * + * Copyright 2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "pci.h" +#include "open_pic.h" +#include "pplus.h" + +/* + * The Falcon/Raven and HAWK has 4 sets of registers: + * 1) PPC Registers which define the mappings from PPC bus to PCI bus, + * etc. + * 2) PCI Registers which define the mappings from PCI bus to PPC bus and the + * MPIC base address. + * 3) MPIC registers. + * 4) System Memory Controller (SMC) registers. + */ + +/* + * Initialize the Motorola MCG Raven or HAWK host bridge. + * + * This means setting up the PPC bus to PCI memory and I/O space mappings, + * setting the PCI memory space address of the MPIC (mapped straight + * through), and ioremap'ing the mpic registers. + * 'OpenPIC_Addr' will be set correctly by this routine. + * This routine will not change the PCI_CONFIG_ADDR or PCI_CONFIG_DATA + * addresses and assumes that the mapping of PCI memory space back to system + * memory is set up correctly by PPCBug. + */ +int __init +pplus_init(struct pci_controller *hose, + uint ppc_reg_base, + ulong processor_pci_mem_start, + ulong processor_pci_mem_end, + ulong processor_pci_io_start, + ulong processor_pci_io_end, + ulong processor_mpic_base) +{ + uint addr, offset; + + /* + * Some sanity checks... + */ + if (((processor_pci_mem_start&0xffff0000) != processor_pci_mem_start) || + ((processor_pci_io_start &0xffff0000) != processor_pci_io_start)) { + printk("pplus_init: %s\n", + "PPC to PCI mappings must start on 64 MB boundaries"); + return -1; + } + + if (((processor_pci_mem_end &0x0000ffff) != 0x0000ffff) || + ((processor_pci_io_end &0x0000ffff) != 0x0000ffff)) { + printk("pplus_init: PPC to PCI mappings %s\n", + "must end just before a 64 MB boundaries"); + return -1; + } + + if (((processor_pci_mem_end - processor_pci_mem_start) != + (hose->mem_space.end - hose->mem_space.start)) || + ((processor_pci_io_end - processor_pci_io_start) != + (hose->io_space.end - hose->io_space.start))) { + printk("pplus_init: %s\n", + "PPC and PCI memory or I/O space sizes don't match"); + return -1; + } + + if ((processor_mpic_base & 0xfffc0000) != processor_mpic_base) { + printk("pplus_init: %s\n", + "MPIC address must start on 256 MB boundary"); + return -1; + } + + if ((pci_dram_offset & 0xffff0000) != pci_dram_offset) { + printk("pplus_init: %s\n", + "pci_dram_offset must be multiple of 64 MB"); + return -1; + } + + /* + * Program the XSADD/XSOFF registers to set up the PCI Mem & I/O + * space mappings. These are the mappings going from the processor to + * the PCI bus. + * + * Note: Don't need to 'AND' start/end addresses with 0xffff0000 + * because sanity check above ensures that they are properly + * aligned. + */ + + /* Set up PPC->PCI Mem mapping */ + addr = processor_pci_mem_start | (processor_pci_mem_end >> 16); + offset = (hose->mem_space.start - processor_pci_mem_start) | 0xd2; + out_be32((uint *)(ppc_reg_base + PPLUS_PPC_XSADD0_OFF), addr); + out_be32((uint *)(ppc_reg_base + PPLUS_PPC_XSOFF0_OFF), offset); + + /* Set up PPC->PCI I/O mapping -- Contiguous I/O space */ + addr = processor_pci_io_start | (processor_pci_io_end >> 16); + offset = (hose->io_space.start - processor_pci_io_start) | 0xc0; + out_be32((uint *)(ppc_reg_base + PPLUS_PPC_XSADD1_OFF), addr); + out_be32((uint *)(ppc_reg_base + PPLUS_PPC_XSOFF1_OFF), offset); + + /* Set up PPC->MPIC mapping on the bridge--mapped straight through */ + addr = processor_mpic_base | + (((processor_mpic_base + PPLUS_MPIC_SIZE) >> 16) - 1); + offset = 0xc2; /* No write posting for this PCI Mem space */ + out_be32((uint *)(ppc_reg_base + PPLUS_PPC_XSADD2_OFF), addr); + out_be32((uint *)(ppc_reg_base + PPLUS_PPC_XSOFF2_OFF), offset); + + /* + * Disable MPIC response to PCI I/O space (BAR 0). + * Make MPIC respond to PCI Mem space at specified address. + * (BAR 1). + */ + early_write_config_dword(hose, + 0, + PCI_DEVFN(0,0), + PCI_BASE_ADDRESS_0, + 0x00000000 | 0x1); + + early_write_config_dword(hose, + 0, + PCI_DEVFN(0,0), + PCI_BASE_ADDRESS_1, + processor_mpic_base | 0x0); + + /* Map MPIC into vitual memory */ + OpenPIC_Addr = ioremap(processor_mpic_base, PPLUS_MPIC_SIZE); + + return 0; +} + +/* + * Find the amount of RAM present. + * This assumes that PPCBug has initialized the memory controller (SMC) + * on the Falcon/HAWK correctly (i.e., it does no sanity checking). + * It also assumes that the memory base registers are set to configure the + * memory as contigous starting with "RAM A BASE", "RAM B BASE", etc. + * however, RAM base registers can be skipped (e.g. A, B, C are set, + * D is skipped but E is set is okay). + */ +#define MB (1024*1024) + +static uint __init reg_offset_table[] = { + PPLUS_SMC_RAM_A_SIZE_REG_OFF, + PPLUS_SMC_RAM_B_SIZE_REG_OFF, + PPLUS_SMC_RAM_C_SIZE_REG_OFF, + PPLUS_SMC_RAM_D_SIZE_REG_OFF, + PPLUS_SMC_RAM_E_SIZE_REG_OFF, + PPLUS_SMC_RAM_F_SIZE_REG_OFF, + PPLUS_SMC_RAM_G_SIZE_REG_OFF, + PPLUS_SMC_RAM_H_SIZE_REG_OFF +}; + +static uint __init falcon_size_table[] = { + 0 * MB, /* 0 ==> 0 MB */ + 16 * MB, /* 1 ==> 16 MB */ + 32 * MB, /* 2 ==> 32 MB */ + 64 * MB, /* 3 ==> 64 MB */ + 128 * MB, /* 4 ==> 128 MB */ + 256 * MB, /* 5 ==> 256 MB */ + 1024 * MB, /* 6 ==> 1024 MB (1 GB) */ +}; + +static uint __init hawk_size_table[] = { + 0 * MB, /* 0 ==> 0 MB */ + 32 * MB, /* 1 ==> 32 MB */ + 64 * MB, /* 2 ==> 64 MB */ + 64 * MB, /* 3 ==> 64 MB */ + 128 * MB, /* 4 ==> 128 MB */ + 128 * MB, /* 5 ==> 128 MB */ + 128 * MB, /* 6 ==> 128 MB */ + 256 * MB, /* 7 ==> 256 MB */ + 256 * MB, /* 8 ==> 256 MB */ + 512 * MB, /* 9 ==> 512 MB */ +}; + +/* + * *** WARNING: You MUST have a BAT set up to map in the SMC regs *** + * + * Read the memory controller's registers to determine the amount of system + * memory. Assumes that the memory controller registers are already mapped + * into virtual memory--too early to use ioremap(). + */ +unsigned long __init +pplus_get_mem_size(uint smc_base) +{ + unsigned long total; + int i, size_table_entries, reg_limit; + uint vend_dev_id; + uint *size_table; + u_char val; + + + vend_dev_id = in_be32((uint *)smc_base + PCI_VENDOR_ID); + + if (((vend_dev_id & 0xffff0000) >> 16) != PCI_VENDOR_ID_MOTOROLA) { + printk("pplus_get_mem_size: %s (0x%x)\n", + "Not a Motorola Memory Controller", vend_dev_id); + return 0; + } + + vend_dev_id &= 0x0000ffff; + + if (vend_dev_id == PCI_DEVICE_ID_MOTOROLA_FALCON) { + size_table = falcon_size_table; + size_table_entries = sizeof(falcon_size_table) / + sizeof(falcon_size_table[0]); + + reg_limit = PPLUS_FALCON_SMC_REG_COUNT; + } + else if (vend_dev_id == PCI_DEVICE_ID_MOTOROLA_HAWK) { + size_table = hawk_size_table; + size_table_entries = sizeof(hawk_size_table) / + sizeof(hawk_size_table[0]); + reg_limit = PPLUS_HAWK_SMC_REG_COUNT; + } + else { + printk("pplus_get_mem_size: %s (0x%x)\n", + "Not a Falcon or HAWK", vend_dev_id); + return 0; + } + + total = 0; + + /* Check every reg because PPCBug may skip some */ + for (i=0; iTotalMemory; +#else + total = 0; +#endif + + if (total == 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"); + total = 0x02000000; + printk("Ramsize default to be %ldM\n", total>>20); + } + + return (total); +} + unsigned long *MotSave_SmpIar; unsigned char *MotSave_CpusState[2]; @@ -750,7 +781,8 @@ { if ( !strncmp(res->VitalProductData.PrintableModel,"IBM",3) ) _prep_type = _PREP_IBM; - _prep_type = _PREP_Motorola; + else + _prep_type = _PREP_Motorola; } else /* assume motorola if no residual (netboot?) */ #endif @@ -783,6 +815,8 @@ ppc_md.calibrate_decr = mk48t59_calibrate_decr; ppc_md.time_init = mk48t59_init; } + + ppc_md.find_end_of_memory = prep_find_end_of_memory; #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) ppc_ide_md.insw = prep_ide_insw; diff -Nru a/arch/ppc/kernel/prep_time.c b/arch/ppc/kernel/prep_time.c --- a/arch/ppc/kernel/prep_time.c Wed May 16 06:00:21 2001 +++ b/arch/ppc/kernel/prep_time.c Wed May 16 06:00:21 2001 @@ -30,6 +30,8 @@ #include +extern spinlock_t rtc_lock; + /* * The motorola uses the m48t18 rtc (includes DS1643) whose registers * are at a higher end of nvram (1ff8-1fff) than the ibm mc146818 @@ -55,6 +57,7 @@ unsigned char save_control, save_freq_select; struct rtc_time tm; + spin_lock(&rtc_lock); to_tm(nowtime, &tm); /* tell the clock it's being set */ @@ -92,6 +95,7 @@ */ CMOS_WRITE(save_control, RTC_CONTROL); CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); + spin_unlock(&rtc_lock); return 0; } @@ -149,7 +153,7 @@ unsigned char save_control; struct rtc_time tm; - + spin_lock(&rtc_lock); to_tm(nowtime, &tm); /* tell the clock it's being written */ @@ -175,6 +179,7 @@ /* Turn off the write bit. */ ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, save_control); + spin_unlock(&rtc_lock); return 0; } diff -Nru a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c --- a/arch/ppc/kernel/process.c Wed May 16 06:00:20 2001 +++ b/arch/ppc/kernel/process.c Wed May 16 06:00:20 2001 @@ -378,45 +378,6 @@ } /* - * 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) @@ -425,7 +386,6 @@ regs->nip = nip; regs->gpr[1] = sp; regs->msr = MSR_USER; - shove_aux_table(sp); if (last_task_used_math == current) last_task_used_math = 0; if (last_task_used_altivec == current) diff -Nru a/arch/ppc/kernel/prom.c b/arch/ppc/kernel/prom.c --- a/arch/ppc/kernel/prom.c Wed May 16 06:00:23 2001 +++ b/arch/ppc/kernel/prom.c Wed May 16 06:00:23 2001 @@ -757,14 +757,9 @@ setup_disp_fake_bi(RELOC(prom_disp_node)); #endif - /* If pmac, then use quiesce call. We can't rely on prom_version - * since some old iMacs appear to have an incorrect /openprom/model - * entry in the device tree - */ - if (!chrp) { - prom_print(RELOC("Calling quiesce ...\n")); - call_prom(RELOC("quiesce"), 0, 0); - } + /* Use quiesce call to get OF to shut down any devices it's using */ + prom_print(RELOC("Calling quiesce ...\n")); + call_prom(RELOC("quiesce"), 0, 0); #ifdef CONFIG_BOOTX_TEXT if (!chrp && RELOC(disp_bi)) { @@ -839,7 +834,7 @@ __asm__ __volatile__ ("mfspr %0, 1008" : "=r" (flags)); prom_drawhex(flags); } - if (pvr == 8 || pvr == 12) { + if (pvr == 8 || pvr == 12 || pvr == 0x800c) { prom_drawstring(RELOC("\nICTC : 0x")); __asm__ __volatile__ ("mfspr %0, 1019" : "=r" (flags)); prom_drawhex(flags); @@ -986,9 +981,11 @@ prom_print(RELOC("... failed\n")); } else { prom_print(RELOC("... ok\n")); - - /* Setup a useable color table when the appropriate - * method is available. Should update this to set-colors */ + /* + * Setup a usable color table when the appropriate + * method is available. + * Should update this to use set-colors. + */ for (i = 0; i < 32; i++) if (prom_set_color(ih, i, RELOC(default_colors)[i*3], RELOC(default_colors)[i*3+1], @@ -1267,7 +1264,10 @@ np->name = get_property(np, "name", 0); np->type = get_property(np, "device_type", 0); - +#if 0 + np->n_addr_cells = naddrc; + np->n_size_cells = nsizec; +#endif /* get the device addresses and interrupts */ if (ifunc != NULL) { mem_start = ifunc(np, mem_start, naddrc, nsizec); @@ -1283,6 +1283,16 @@ ip = (int *) get_property(np, "#size-cells", 0); if (ip != NULL) nsizec = *ip; +#if 0 + if (np->parent == NULL) { + /* + * Set the n_addr/size_cells on the root to its + * own values, rather than 0. + */ + np->n_addr_cells = naddrc; + np->n_size_cells = nsizec; + } +#endif /* the f50 sets the name to 'display' and 'compatible' to what we * expect for the name -- Cort @@ -1497,6 +1507,34 @@ } } +int +prom_n_addr_cells(struct device_node* np) +{ + int* ip; + do { + if (np->parent) + np = np->parent; + ip = (int *) get_property(np, "#address-cells", 0); + if (ip != NULL) + return *ip; + } while(np->parent); + return 0; +} + +int +prom_n_size_cells(struct device_node* np) +{ + int* ip; + do { + if (np->parent) + np = np->parent; + ip = (int *) get_property(np, "#size-cells", 0); + if (ip != NULL) + return *ip; + } while(np->parent); + return 0; +} + __init static unsigned long interpret_pci_props(struct device_node *np, unsigned long mem_start, @@ -1566,6 +1604,8 @@ } ip = (int *) get_property(np, "AAPL,interrupts", &l); + if (ip == 0 && np->parent) + ip = (int *) get_property(np->parent, "AAPL,interrupts", &l); if (ip == 0) ip = (int *) get_property(np, "interrupts", &l); if (ip != 0) { @@ -1761,7 +1801,7 @@ i = 0; adr = (struct address_range *) mem_start; while ((l -= rpsize) >= 0) { - adr[i].space = 0; + adr[i].space = (naddrc >= 2? rp[naddrc-2]: 0); adr[i].address = rp[naddrc - 1]; adr[i].size = rp[naddrc + nsizec - 1]; ++i; @@ -1978,12 +2018,13 @@ { struct property *pp; - for (pp = np->properties; pp != 0; pp = pp->next) - if (strcmp(pp->name, name) == 0) { + for (pp = np->properties; pp != 0; pp = pp->next) { + if (name && strcmp(pp->name, name) == 0) { if (lenp != 0) *lenp = pp->length; return pp->value; } + } return 0; } @@ -2161,9 +2202,10 @@ { if (disp_bi == 0) return; - /* check it's the same frame buffer (within 16MB) */ - if ((phys ^ (unsigned long)disp_bi->dispDeviceBase) & 0xff000000) + /* check it's the same frame buffer (within 64MB) */ + if ((phys ^ (unsigned long)disp_bi->dispDeviceBase) & 0xfc000000) { return; + } disp_bi->dispDeviceBase = (__u8 *) phys; disp_bi->dispDeviceRect[0] = 0; diff -Nru a/arch/ppc/kernel/prpmc750.h b/arch/ppc/kernel/prpmc750.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/kernel/prpmc750.h Wed May 16 06:00:33 2001 @@ -0,0 +1,56 @@ +/* + * include/asm-ppc/prpmc750.h + * + * Definitions for Motorola PrPMC750 board support + * + * Author: Matt Porter + * + * Copyright 2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __ASMPPC_PRPMC750_H +#define __ASMPPC_PRPMC750_H + +#include + +#define PRPMC750_PCI_CONFIG_ADDR 0x80000cf8 +#define PRPMC750_PCI_CONFIG_DATA 0x80000cfc + +#define PRPMC750_PCI_PHY_MEM_BASE 0xc0000000 +#define PRPMC750_PCI_MEM_BASE 0xf0000000 +#define PRPMC750_PCI_IO_BASE 0x80000000 + +#define PRPMC750_ISA_IO_BASE PRPMC750_PCI_IO_BASE +#define PRPMC750_ISA_MEM_BASE PRPMC750_PCI_MEM_BASE +#define PRPMC750_PCI_MEM_OFFSET PRPMC750_PCI_PHY_MEM_BASE + +#define PRPMC750_SYS_MEM_BASE 0x80000000 + +#define PRPMC750_HAWK_SMC_BASE 0xfef80000 + +#define PRPMC750_BASE_BAUD 1843200 +#define PRPMC750_SERIAL_0 0xfef88000 +#define PRPMC750_SERIAL_0_DLL (PRPMC750_SERIAL_0 + (UART_DLL << 4)) +#define PRPMC750_SERIAL_0_DLM (PRPMC750_SERIAL_0 + (UART_DLM << 4)) +#define PRPMC750_SERIAL_0_LCR (PRPMC750_SERIAL_0 + (UART_LCR << 4)) + +#define PRPMC750_STATUS_REG 0xfef88080 +#define PRPMC750_BAUDOUT_MASK 0x02 +#define PRPMC750_MONARCH_MASK 0x01 + +#define PRPMC750_MODRST_REG 0xfef880a0 +#define PRPMC750_MODRST_MASK 0x01 + +#define PRPMC750_PIRQ_REG 0xfef880b0 +#define PRPMC750_SEL1_MASK 0x02 +#define PRPMC750_SEL0_MASK 0x01 + +#define PRPMC750_TBEN_REG 0xfef880c0 +#define PRPMC750_TBEN_MASK 0x01 + +#endif /* __ASMPPC_PRPMC750_H */ diff -Nru a/arch/ppc/kernel/prpmc750_pci.c b/arch/ppc/kernel/prpmc750_pci.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/kernel/prpmc750_pci.c Wed May 16 06:00:33 2001 @@ -0,0 +1,138 @@ +/* + * arch/ppc/kernel/prpmc750_pci.c + * + * PCI support for Motorola PrPMC750 + * + * Author: Matt Porter + * + * Copyright 2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "pci.h" +#include "prpmc750.h" + +#undef DEBUG +#ifdef DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif /* DEBUG */ + +/* Motorola PrPMC750 in a PrPMCBASE */ +static inline int __init +prpmc_base_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) +{ + static char pci_irq_table[][4] = + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + { + {12, 0, 0, 0}, /* IDSEL 14 - Ethernet */ + {0, 0, 0, 0}, /* IDSEL 15 - unused */ + {10, 0, 0, 0}, /* IDSEL 16 - PMC1INTA */ + {0, 0, 0, 0}, /* IDSEL 17 - unused */ + {0, 0, 0, 0}, /* IDSEL 18 - unused */ + {0, 0, 0, 0}, /* IDSEL 19 - unused */ + {9, 0, 0, 0}, /* IDSEL 20 - DEC21554 */ + }; + const long min_idsel = 14, max_idsel = 20, irqs_per_slot = 4; + return PCI_IRQ_TABLE_LOOKUP; +}; + +/* Motorola PrPMC750 in a PrPMC-Carrier */ +static inline int __init +prpmc_carrier_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) +{ + static char pci_irq_table[][4] = + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + { + {10, 11, 12, 9}, /* IDSEL 16 - PMC A1 */ + {0, 0, 0, 0}, /* IDSEL 17 - unused */ + {0, 0, 0, 0}, /* IDSEL 18 - unused */ + {0, 0, 0, 0}, /* IDSEL 19 - unused */ + {9, 10, 11, 12}, /* IDSEL 20 - P2P Bridge */ + {11, 12, 9, 10}, /* IDSEL 21 - PMC A2 */ + }; + const long min_idsel = 16, max_idsel = 21, irqs_per_slot = 4; + return PCI_IRQ_TABLE_LOOKUP; +}; + +void __init +prpmc750_pcibios_fixup(void) +{ + struct pci_dev *dev; + unsigned short wtmp; + + /* + * Kludge to clean up after PPC6BUG which doesn't + * configure the CL5446 VGA card. Also the + * resource subsystem doesn't fixup the + * PCI mem resources on the CL5446. + */ + if ((dev = pci_find_device(PCI_VENDOR_ID_CIRRUS, + PCI_DEVICE_ID_CIRRUS_5446, 0))) + { + dev->resource[0].start += PRPMC750_PCI_PHY_MEM_BASE; + dev->resource[0].end += PRPMC750_PCI_PHY_MEM_BASE; + pci_read_config_word(dev, + PCI_COMMAND, + &wtmp); + pci_write_config_word(dev, + PCI_COMMAND, + wtmp|3); + /* Enable Color mode in MISC reg */ + outb(0x03, 0x3c2); + /* Select DRAM config reg */ + outb(0x0f, 0x3c4); + /* Set proper DRAM config */ + outb(0xdf, 0x3c5); + } +} + +void __init +prpmc750_find_bridges(void) +{ + struct pci_controller* hose; + + hose = pcibios_alloc_controller(); + if (!hose) + return; + + hose->first_busno = 0; + hose->last_busno = 0xff; + hose->pci_mem_offset = PRPMC750_PCI_PHY_MEM_BASE; + hose->io_base_virt = (void *)PRPMC750_ISA_IO_BASE; + + setup_indirect_pci(hose, + PRPMC750_PCI_CONFIG_ADDR, + PRPMC750_PCI_CONFIG_DATA); + + ppc_md.pcibios_fixup = prpmc750_pcibios_fixup; + ppc_md.pci_swizzle = common_swizzle; +#ifdef CONFIG_PRPMC_BASE + ppc_md.pci_map_irq = prpmc_base_map_irq; +#elif CONFIG_PRPMC_CARRIER + ppc_md.pci_map_irq = prpmc_carrier_map_irq; +#endif /* Carrier specific interrupt routing */ +} diff -Nru a/arch/ppc/kernel/prpmc750_setup.c b/arch/ppc/kernel/prpmc750_setup.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/kernel/prpmc750_setup.c Wed May 16 06:00:33 2001 @@ -0,0 +1,279 @@ +/* + * arch/ppc/kernel/prpmc750_setup.c + * + * Board setup routines for Motorola PrPMC750 + * + * Author: Matt Porter + * + * Copyright 2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "local_irq.h" +#include "open_pic.h" +#include "pplus.h" +#include "prpmc750.h" + +extern void prpmc750_find_bridges(void); +extern int mpic_init(void); +extern unsigned long loops_per_jiffy; + +static u_char prpmc750_openpic_initsenses[] __initdata = +{ + 1, /* PRPMC750_INT_HOSTINT0 */ + 1, /* PRPMC750_INT_UART */ + 1, /* PRPMC750_INT_DEBUGINT */ + 1, /* PRPMC750_INT_HAWK_WDT */ + 1, /* PRPMC750_INT_UNUSED */ + 1, /* PRPMC750_INT_ABORT */ + 1, /* PRPMC750_INT_HOSTINT1 */ + 1, /* PRPMC750_INT_HOSTINT2 */ + 1, /* PRPMC750_INT_HOSTINT3 */ + 1, /* PRPMC750_INT_PMC_INTA */ + 1, /* PRPMC750_INT_PMC_INTB */ + 1, /* PRPMC750_INT_PMC_INTC */ + 1, /* PRPMC750_INT_PMC_INTD */ + 1, /* PRPMC750_INT_UNUSED */ + 1, /* PRPMC750_INT_UNUSED */ + 1, /* PRPMC750_INT_UNUSED */ +}; + +int +prpmc750_get_cpuinfo(char *buffer) +{ + int len; + + len = sprintf(buffer,"machine\t\t: PrPMC750\n"); + + return len; +} + +void __init +prpmc750_setup_arch(void) +{ + extern char cmd_line[]; + + /* init to some ~sane value until calibrate_delay() runs */ + loops_per_jiffy = 100000000/HZ; + + /* Lookup PCI host bridges */ + prpmc750_find_bridges(); + +#ifdef CONFIG_ROOT_NFS + ROOT_DEV = to_kdev_t(0x00ff); /* /dev/nfs pseudo device */ +#else + ROOT_DEV = to_kdev_t(0x0802); /* /dev/sda2 */ +#endif + + /* Find and map our OpenPIC */ + pplus_mpic_init(PRPMC750_PCI_MEM_OFFSET); + OpenPIC_InitSenses = prpmc750_openpic_initsenses; + OpenPIC_NumInitSenses = sizeof(prpmc750_openpic_initsenses); + + printk("PrPMC750 port (C) 2001 MontaVista Software, Inc. \n"); + + return; +} + +/* + * Compute the PrPMC750's bus speed using the baud clock as a + * reference. + */ +unsigned long __init prpmc750_get_bus_speed(void) +{ + unsigned long tbl_start, tbl_end; + unsigned long current_state, old_state, bus_speed; + unsigned char lcr, dll, dlm; + int baud_divisor, count; + + /* Read the UART's baud clock divisor */ + lcr = readb(PRPMC750_SERIAL_0_LCR); + writeb(lcr | UART_LCR_DLAB, PRPMC750_SERIAL_0_LCR); + dll = readb(PRPMC750_SERIAL_0_DLL); + dlm = readb(PRPMC750_SERIAL_0_DLM); + writeb(lcr & ~UART_LCR_DLAB, PRPMC750_SERIAL_0_LCR); + baud_divisor = (dlm << 8) | dll; + + /* + * Use the baud clock divisor and base baud clock + * to determine the baud rate and use that as + * the number of baud clock edges we use for + * the time base sample. Make it half the baud + * rate. + */ + count = PRPMC750_BASE_BAUD / (baud_divisor * 16); + + /* Find the first edge of the baud clock */ + old_state = readb(PRPMC750_STATUS_REG) & PRPMC750_BAUDOUT_MASK; + do { + current_state = readb(PRPMC750_STATUS_REG) & + PRPMC750_BAUDOUT_MASK; + } while(old_state == current_state); + + old_state = current_state; + + /* Get the starting time base value */ + tbl_start = get_tbl(); + + /* + * Loop until we have found a number of edges equal + * to half the count (half the baud rate) + */ + do { + do { + current_state = readb(PRPMC750_STATUS_REG) & + PRPMC750_BAUDOUT_MASK; + } while(old_state == current_state); + old_state = current_state; + } while (--count); + + /* Get the ending time base value */ + tbl_end = get_tbl(); + + /* Compute bus speed */ + bus_speed = (tbl_end-tbl_start)*128; + + return bus_speed; +} + +void __init prpmc750_calibrate_decr(void) +{ + unsigned long freq; + int divisor = 4; + + freq = prpmc750_get_bus_speed(); + + tb_ticks_per_jiffy = freq / (HZ * divisor); + tb_to_us = mulhwu_scale_factor(freq/divisor, 1000000); +} + +void +prpmc750_restart(char *cmd) +{ + __cli(); + writeb(PRPMC750_MODRST_MASK, PRPMC750_MODRST_REG); + while(1); +} + +void +prpmc750_halt(void) +{ + __cli(); + while (1); +} + +void +prpmc750_power_off(void) +{ + prpmc750_halt(); +} + +/* Resolves the open_pic.c build without including i8259.c */ +int i8259_irq(int cpu) +{ + return 0; +} + +void __init +prpmc750_init_IRQ(void) +{ + openpic_init(1, 0, 0, -1); +} + +/* + * Set BAT 3 to map 0xf0000000 to end of physical memory space. + */ +static __inline__ void +prpmc750_set_bat(void) +{ + unsigned long bat3u, bat3l; + static int mapping_set = 0; + + if (!mapping_set) + { + __asm__ __volatile__( + " lis %0,0xf000\n \ + ori %1,%0,0x002a\n \ + ori %0,%0,0x1ffe\n \ + mtspr 0x21e,%0\n \ + mtspr 0x21f,%1\n \ + isync\n \ + sync " + :: "r" (bat3u), "r" (bat3l)); + + mapping_set = 1; + } + return; +} + +/* + * We need to read the Falcon/Hawk memory controller + * to properly determine this value + */ +unsigned long __init +prpmc750_find_end_of_memory(void) +{ + /* Cover the Hawk registers with a BAT */ + prpmc750_set_bat(); + + /* Read the memory size from the Hawk SMC */ + return pplus_get_mem_size(PRPMC750_HAWK_SMC_BASE); +} + +void __init +prpmc750_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + /* Copy cmd_line parameters */ + if ( r6) + { + *(char *)(r7 + KERNELBASE) = 0; + strcpy(cmd_line, (char *)(r6 + KERNELBASE)); + } + + isa_io_base = PRPMC750_ISA_IO_BASE; + isa_mem_base = PRPMC750_ISA_MEM_BASE; + pci_dram_offset = PRPMC750_SYS_MEM_BASE; + + ppc_md.setup_arch = prpmc750_setup_arch; + ppc_md.get_cpuinfo = prpmc750_get_cpuinfo; + ppc_md.init_IRQ = prpmc750_init_IRQ; + ppc_md.get_irq = openpic_get_irq; + + ppc_md.find_end_of_memory = prpmc750_find_end_of_memory; + + ppc_md.restart = prpmc750_restart; + ppc_md.power_off = prpmc750_power_off; + ppc_md.halt = prpmc750_halt; + + /* PrPMC750 has no timekeeper part */ + ppc_md.time_init = NULL; + ppc_md.get_rtc_time = NULL; + ppc_md.set_rtc_time = NULL; + ppc_md.calibrate_decr = prpmc750_calibrate_decr; diff -Nru a/arch/ppc/kernel/semaphore.c b/arch/ppc/kernel/semaphore.c --- a/arch/ppc/kernel/semaphore.c Wed May 16 06:00:20 2001 +++ b/arch/ppc/kernel/semaphore.c Wed May 16 06:00:20 2001 @@ -9,131 +9,122 @@ * 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. + * + * April 2001 - Reworked by Paul Mackerras + * to eliminate the SMP races in the old version between the updates + * of `count' and `waking'. Now we use negative `count' values to + * indicate that some process(es) are waiting for the semaphore. */ #include - +#include #include -#include /* - * Semaphores are implemented using a two-way counter: - * The "count" variable is decremented for each process - * that tries to sleep, while the "waking" variable is - * incremented when the "up()" code goes to wake up waiting - * processes. - * - * Notably, the inline "up()" and "down()" functions can - * efficiently test if they need to do any extra work (up - * needs to do something only if count was negative before - * the increment operation. - * - * waking_non_zero() (from asm/semaphore.h) must execute - * atomically. - * - * When __up() is called, the count was negative before - * incrementing it, and we need to wake up somebody. - * - * This routine adds one to the count of processes that need to - * wake up and exit. ALL waiting processes actually wake up but - * only the one that gets to the "waking" field first will gate - * through and acquire the semaphore. The others will go back - * to sleep. + * Atomically update sem->count. + * This does the equivalent of the following: * - * Note that these functions are only called when there is - * contention on the lock, and as such all this is the - * "non-critical" part of the whole semaphore business. The - * critical part is the inline stuff in - * where we want to avoid any extra jumps and calls. + * old_count = sem->count; + * tmp = MAX(old_count, 0) + incr; + * sem->count = tmp; + * return old_count; */ +static inline int __sem_update_count(struct semaphore *sem, int incr) +{ + int old_count, tmp; + + __asm__ __volatile__("\n" +"1: lwarx %0,0,%3\n" +" srawi %1,%0,31\n" +" andc %1,%0,%1\n" +" add %1,%1,%4\n" +" stwcx. %1,0,%3\n" +" bne 1b" + : "=&r" (old_count), "=&r" (tmp), "=m" (sem->count) + : "r" (&sem->count), "r" (incr), "m" (sem->count) + : "cc"); + + return old_count; +} + void __up(struct semaphore *sem) { - wake_one_more(sem); + /* + * Note that we incremented count in up() before we came here, + * but that was ineffective since the result was <= 0, and + * any negative value of count is equivalent to 0. + * This ends up setting count to 1, unless count is now > 0 + * (i.e. because some other cpu has called up() in the meantime), + * in which case we just increment count. + */ + __sem_update_count(sem, 1); wake_up(&sem->wait); } /* - * Perform the "down" function. Return zero for semaphore acquired, - * return negative for signalled out of the function. - * - * If called from __down, the return is ignored and the wait loop is - * not interruptible. This means that a task waiting on a semaphore - * using "down()" cannot be killed until someone does an "up()" on - * the semaphore. - * - * If called from __down_interruptible, the return value gets checked - * upon return. If the return value is negative then the task continues - * with the negative value in the return register (it can be tested by - * the caller). - * - * Either form may be used in conjunction with "up()". - * + * Note that when we come in to __down or __down_interruptible, + * we have already decremented count, but that decrement was + * ineffective since the result was < 0, and any negative value + * of count is equivalent to 0. + * Thus it is only when we decrement count from some value > 0 + * that we have actually got the semaphore. */ +void __down(struct semaphore *sem) +{ + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); -#define DOWN_VAR \ - struct task_struct *tsk = current; \ - wait_queue_t wait; \ - init_waitqueue_entry(&wait, tsk); - -#define DOWN_HEAD(task_state) \ - \ - \ - tsk->state = (task_state); \ - add_wait_queue(&sem->wait, &wait); \ - \ - /* \ - * Ok, we're set up. sem->count is known to be less than zero \ - * so we must wait. \ - * \ - * We can let go the lock for purposes of waiting. \ - * We re-acquire it after awaking so as to protect \ - * all semaphore operations. \ - * \ - * If "up()" is called before we call waking_non_zero() then \ - * we will catch it right away. If it is called later then \ - * we will have to go through a wakeup cycle to catch it. \ - * \ - * Multiple waiters contend for the semaphore lock to see \ - * who gets to gate through and who has to wait some more. \ - */ \ - for (;;) { - -#define DOWN_TAIL(task_state) \ - tsk->state = (task_state); \ - } \ - tsk->state = TASK_RUNNING; \ + tsk->state = TASK_UNINTERRUPTIBLE; + add_wait_queue_exclusive(&sem->wait, &wait); + smp_wmb(); + + /* + * Try to get the semaphore. If the count is > 0, then we've + * got the semaphore; we decrement count and exit the loop. + * If the count is 0 or negative, we set it to -1, indicating + * that we are asleep, and then sleep. + */ + while (__sem_update_count(sem, -1) <= 0) { + schedule(); + tsk->state = TASK_UNINTERRUPTIBLE; + } remove_wait_queue(&sem->wait, &wait); + tsk->state = TASK_RUNNING; -void __down(struct semaphore * sem) -{ - DOWN_VAR - DOWN_HEAD(TASK_UNINTERRUPTIBLE) - if (waking_non_zero(sem)) - break; - schedule(); - DOWN_TAIL(TASK_UNINTERRUPTIBLE) + /* + * If there are any more sleepers, wake one of them up so + * that it can either get the semaphore, or set count to -1 + * indicating that there are still processes sleeping. + */ + wake_up(&sem->wait); } int __down_interruptible(struct semaphore * sem) { - int ret = 0; - DOWN_VAR - DOWN_HEAD(TASK_INTERRUPTIBLE) - - ret = waking_non_zero_interruptible(sem, tsk); - if (ret) - { - if (ret == 1) - /* ret != 0 only if we get interrupted -arca */ - ret = 0; - break; + int retval = 0; + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); + + tsk->state = TASK_INTERRUPTIBLE; + add_wait_queue_exclusive(&sem->wait, &wait); + smp_wmb(); + + while (__sem_update_count(sem, -1) <= 0) { + if (signal_pending(current)) { + /* + * A signal is pending - give up trying. + * Set sem->count to 0 if it is negative, + * since we are no longer sleeping. + */ + __sem_update_count(sem, 0); + retval = -EINTR; + break; + } + schedule(); + tsk->state = TASK_INTERRUPTIBLE; } - schedule(); - DOWN_TAIL(TASK_INTERRUPTIBLE) - return ret; -} - -int __down_trylock(struct semaphore * sem) -{ - return waking_non_zero_trylock(sem); + tsk->state = TASK_RUNNING; + remove_wait_queue(&sem->wait, &wait); + wake_up(&sem->wait); + return retval; } diff -Nru a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c --- a/arch/ppc/kernel/setup.c Wed May 16 06:00:19 2001 +++ b/arch/ppc/kernel/setup.c Wed May 16 06:00:19 2001 @@ -43,7 +43,7 @@ #include "oak_setup.h" #endif /* CONFIG_OAK */ -extern void pmac_init(unsigned long r3, +extern void apus_init(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, @@ -55,24 +55,54 @@ unsigned long r6, unsigned long r7); -extern void prep_init(unsigned long r3, +extern void gemini_init(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7); +extern void k2_init(unsigned long r3, + unsigned long r4, + unsigned long r5, + unsigned long r6, + unsigned long r7); + +extern void mvme5100_init(unsigned long r3, + unsigned long r4, + unsigned long r5, + unsigned long r6, + unsigned long r7); + extern void m8xx_init(unsigned long r3, - unsigned long r4, - unsigned long r5, - unsigned long r6, - unsigned long r7); + unsigned long r4, + unsigned long r5, + unsigned long r6, + unsigned long r7); -extern void apus_init(unsigned long r3, +extern void pmac_init(unsigned long r3, + unsigned long r4, + unsigned long r5, + unsigned long r6, + unsigned long r7); + +extern void prep_init(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7); +extern void prpmc750_init(unsigned long r3, + unsigned long r4, + unsigned long r5, + unsigned long r6, + unsigned long r7); + +extern void spruce_init(unsigned long r3, + unsigned long r4, + unsigned long r5, + unsigned long r6, + unsigned long r7); + #ifdef CONFIG_XMON extern void xmon_map_scc(void); #endif @@ -80,23 +110,16 @@ extern boot_infos_t *boot_infos; char saved_command_line[256]; unsigned char aux_device_present; -struct int_control_struct int_control = -{ - __no_use_cli, - __no_use_sti, - __no_use_restore_flags, - __no_use_save_flags -}; struct ide_machdep_calls ppc_ide_md; int parse_bootinfo(void); unsigned long ISA_DMA_THRESHOLD; unsigned long DMA_MODE_READ, DMA_MODE_WRITE; -#ifndef CONFIG_MACH_SPECIFIC +#ifdef CONFIG_ALL_PPC int _machine = 0; int have_of = 0; -#endif /* CONFIG_MACH_SPECIFIC */ +#endif /* CONFIG_ALL_PPC */ #ifdef CONFIG_MAGIC_SYSRQ unsigned long SYSRQ_KEY; @@ -412,7 +435,7 @@ return len; } -#ifndef CONFIG_MACH_SPECIFIC +#ifdef CONFIG_ALL_PPC void __init intuit_machine_type(void) { @@ -434,7 +457,7 @@ } } } -#endif /* CONFIG_MACH_SPECIFIC */ +#endif /* CONFIG_ALL_PPC */ /* * Find out what kind of machine we're on and save any data we need @@ -448,36 +471,26 @@ if ( ppc_md.progress ) ppc_md.progress("id mach(): start", 0x100); -#if !defined(CONFIG_4xx) && !defined(CONFIG_8xx) && !defined(CONFIG_8260) -#ifndef CONFIG_MACH_SPECIFIC +#if defined(CONFIG_ALL_PPC) /* if we didn't get any bootinfo telling us what we are... */ if ( _machine == 0 ) { - /* boot loader will tell us if we're APUS */ - if ( r3 == 0x61707573 ) - { - _machine = _MACH_apus; - r3 = 0; - } /* prep boot loader tells us if we're prep or not */ - else if ( *(unsigned long *)(KERNELBASE) == (0xdeadc0de) ) + if ( *(unsigned long *)(KERNELBASE) == (0xdeadc0de) ) { _machine = _MACH_prep; } else have_of = 1; } -#endif /* CONFIG_MACH_SPECIFIC */ if ( have_of ) { /* prom_init has already been called from __start */ if (boot_infos) relocate_nodes(); -#ifndef CONFIG_MACH_SPECIFIC /* we need to set _machine before calling finish_device_tree */ if (_machine == 0) intuit_machine_type(); -#endif /* CONFIG_MACH_SPECIFIC */ finish_device_tree(); /* * If we were booted via quik, r3 points to the physical @@ -489,16 +502,18 @@ * are used for initrd_start and initrd_size, * otherwise they contain 0xdeadbeef. */ - cmd_line[0] = 0; if (r3 >= 0x4000 && r3 < 0x800000 && r4 == 0) { + cmd_line[0] = 0; strncpy(cmd_line, (char *)r3 + KERNELBASE, sizeof(cmd_line)); } else if (boot_infos != 0) { /* booted by BootX - check for ramdisk */ - if (boot_infos->kernelParamsOffset != 0) + if (boot_infos->kernelParamsOffset != 0) { + cmd_line[0] = 0; strncpy(cmd_line, (char *) boot_infos + boot_infos->kernelParamsOffset, sizeof(cmd_line)); + } #ifdef CONFIG_BLK_DEV_INITRD if (boot_infos->ramDisk) { initrd_start = (unsigned long) boot_infos @@ -522,17 +537,20 @@ initrd_below_start_ok = 1; } #endif - cmd_line[0] = 0; chosen = find_devices("chosen"); if (chosen != NULL) { p = get_property(chosen, "bootargs", NULL); - if (p != NULL) + if (p && *p) { + cmd_line[0] = 0; strncpy(cmd_line, p, sizeof(cmd_line)); + } } } cmd_line[sizeof(cmd_line) - 1] = 0; } +#endif /* CONFIG_ALL_PPC */ +#if defined(CONFIG_ALL_PPC) switch (_machine) { case _MACH_Pmac: @@ -544,31 +562,36 @@ case _MACH_chrp: chrp_init(r3, r4, r5, r6, r7); break; -#ifdef CONFIG_APUS - case _MACH_apus: - apus_init(r3, r4, r5, r6, r7); - break; -#endif default: - printk("Unknown machine type in identify_machine!\n"); + printk("Unknown machine type in identify_machine()!\n"); } - - /* Check for nobats option (used in mapin_ram). */ - if (strstr(cmd_line, "nobats")) { - extern int __map_without_bats; - __map_without_bats = 1; - } -#else -#if defined(CONFIG_4xx) +#elif defined(CONFIG_APUS) + apus_init(r3, r4, r5, r6, r7); +#elif defined(CONFIG_GEMINI) + gemini_init(r3, r4, r5, r6, r7); +#elif defined(CONFIG_K2) + k2_init(r3, r4, r5, r6, r7); +#elif defined(CONFIG_MVME5100) + mvme5100_init(r3, r4, r5, r6, r7); +#elif defined(CONFIG_PRPMC750) + prpmc750_init(r3, r4, r5, r6, r7); +#elif defined(CONFIG_SPRUCE) + spruce_init(r3, r4, r5, r6, r7); +#elif defined(CONFIG_4xx) oak_init(r3, r4, r5, r6, r7); #elif defined(CONFIG_8xx) m8xx_init(r3, r4, r5, r6, r7); #elif defined(CONFIG_8260) m8260_init(r3, r4, r5, r6, r7); #else -#error "No board type has been defined for identify_machine()!" -#endif /* CONFIG_4xx */ -#endif /* !CONFIG_4xx && !CONFIG_8xx */ +#error "No board/machine type has been identified for identify_machine()!" +#endif + + /* Check for nobats option (used in mapin_ram). */ + if (strstr(cmd_line, "nobats")) { + extern int __map_without_bats; + __map_without_bats = 1; + } /* Look for mem= option on command line */ if (strstr(cmd_line, "mem=")) { @@ -600,6 +623,13 @@ return 0; } +#if defined(CONFIG_SPRUCE) +int boot_mem_size; /* Used with the BI_MEMSIZE bootinfo parameter to + * store the memory size value reported by the boot + * loader. + */ +#endif + int parse_bootinfo(void) { struct bi_record *rec; @@ -639,12 +669,17 @@ initrd_end = data[0] + rec->size; break; #endif /* CONFIG_BLK_DEV_INITRD */ -#ifndef CONFIG_MACH_SPECIFIC +#ifdef CONFIG_ALL_PPC case BI_MACHTYPE: _machine = data[0]; have_of = data[1]; break; -#endif /* CONFIG_MACH_SPECIFIC */ +#endif /* CONFIG_ALL_PPC */ +#ifdef CONFIG_SPRUCE + case BI_MEMSIZE: + boot_mem_size = data[0]; + break; +#endif /* CONFIG_SPRUCE */ } } diff -Nru a/arch/ppc/kernel/sleep.S b/arch/ppc/kernel/sleep.S --- a/arch/ppc/kernel/sleep.S Wed May 16 06:00:16 2001 +++ b/arch/ppc/kernel/sleep.S Wed May 16 06:00:16 2001 @@ -1,6 +1,6 @@ /* * This file contains sleep low-level functions for PowerBook G3. - * Copyright (C) 1999 Benjamin Herrenschmidt (bh40@calva.net) + * Copyright (C) 1999 Benjamin Herrenschmidt (benh@kernel.crashing.org) * and Paul Mackerras (paulus@cs.anu.edu.au). * * This program is free software; you can redistribute it and/or diff -Nru a/arch/ppc/kernel/smp.c b/arch/ppc/kernel/smp.c --- a/arch/ppc/kernel/smp.c Wed May 16 06:00:18 2001 +++ b/arch/ppc/kernel/smp.c Wed May 16 06:00:18 2001 @@ -40,6 +40,7 @@ #include #include #include +#include #include "open_pic.h" int smp_threads_ready; @@ -55,7 +56,7 @@ unsigned int prof_counter[NR_CPUS]; cycles_t cacheflush_time; static int max_cpus __initdata = NR_CPUS; - +unsigned long cpu_online_map; int smp_hw_index[NR_CPUS]; /* all cpu mappings are 1-1 -- Cort */ @@ -452,32 +453,48 @@ static void smp_core99_kick_cpu(int nr) { - unsigned long save_int; + unsigned long save_vector, new_vector; unsigned long flags; +#if 1 /* New way... */ + volatile unsigned long *vector + = ((volatile unsigned long *)(KERNELBASE+0x100)); + if (nr < 1 || nr > 3) + return; +#else volatile unsigned long *vector = ((volatile unsigned long *)(KERNELBASE+0x500)); - if (nr != 1) return; +#endif if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu", 0x346); local_irq_save(flags); local_irq_disable(); - /* Save EE vector */ - save_int = *vector; + /* Save reset vector */ + save_vector = *vector; - /* Setup fake EE vector that does + /* Setup fake reset vector that does * b __secondary_start_psurge - KERNELBASE - */ - *vector = 0x48000002 + - ((unsigned long)__secondary_start_psurge - KERNELBASE); + */ + switch(nr) { + case 1: + new_vector = (unsigned long)__secondary_start_psurge; + break; + case 2: + new_vector = (unsigned long)__secondary_start_psurge2; + break; + case 3: + new_vector = (unsigned long)__secondary_start_psurge3; + break; + } + *vector = 0x48000002 + new_vector - KERNELBASE; /* flush data cache and inval instruction cache */ flush_icache_range((unsigned long) vector, (unsigned long) vector + 4); /* Put some life in our friend */ - feature_core99_kick_cpu1(); + feature_core99_kick_cpu(nr); /* FIXME: We wait a bit for the CPU to take the exception, I should * instead wait for the entry code to set something for me. Well, @@ -487,11 +504,11 @@ mdelay(1); /* Restore our exception vector */ - *vector = save_int; + *vector = save_vector; flush_icache_range((unsigned long) vector, (unsigned long) vector + 4); local_irq_restore(flags); - if (ppc_md.progress) ppc_md.progress("smp_core99_probe done", 0x347); + if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu done", 0x347); } static void @@ -628,6 +645,43 @@ do_openpic_setup_cpu(); } +#ifdef CONFIG_GEMINI +static int +smp_gemini_probe(void) +{ + int i, nr; + + nr = (readb(GEMINI_CPUSTAT) & GEMINI_CPU_COUNT_MASK) >> 2; + if (nr == 0) + nr = 4; + + if (nr > 1) { + openpic_request_IPIs(); + for (i = 1; i < nr; ++i) + smp_hw_index[i] = i; + } + + return nr; +} + +static void +smp_gemini_kick_cpu(int nr) +{ + openpic_init_processor( 1< 0) + gemini_init_l2(); +} +#endif /* CONFIG_GEMINI */ + + static struct smp_ops_t { void (*message_pass)(int target, int msg, unsigned long data, int wait); int (*probe)(void); @@ -685,6 +739,16 @@ smp_prep_setup_cpu, }; +#ifdef CONFIG_GEMINI +/* Gemini */ +static struct smp_ops_t gemini_smp_ops = { + smp_openpic_message_pass, + smp_gemini_probe, + smp_gemini_kick_cpu, + smp_gemini_setup_cpu, +}; +#endif /* CONFIG_GEMINI */ + /* * Common functions */ @@ -925,6 +989,11 @@ case _MACH_prep: smp_ops = &prep_smp_ops; break; +#ifdef CONFIG_GEMINI + case _MACH_gemini: + smp_ops = &gemini_smp_ops; + break; +#endif /* CONFIG_GEMINI */ default: printk("SMP not supported on this machine.\n"); return; @@ -946,6 +1015,19 @@ /* create a process for the processor */ /* we don't care about the values in regs since we'll never reschedule the forked task. */ + /* We DO care about one bit in the pt_regs we + pass to do_fork. That is the MSR_FP bit in + regs.msr. If that bit is on, then do_fork + (via copy_thread) will call giveup_fpu. + giveup_fpu will get a pointer to our (current's) + last register savearea via current->thread.regs + and using that pointer will turn off the MSR_FP, + MSR_FE0 and MSR_FE1 bits. At this point, this + pointer is pointing to some arbitrary point within + our stack. */ + + memset(®s, 0, sizeof(struct pt_regs)); + if (do_fork(CLONE_VM|CLONE_PID, 0, ®s, 0) < 0) panic("failed fork for CPU %d", i); p = init_task.prev_task; @@ -1114,8 +1196,18 @@ init_idle(); + /* + * This cpu is now "online". Only set them online + * before they enter the loop below since write access + * to the below variable is _not_ guaranteed to be + * atomic. + * -- Cort + */ + cpu_online_map |= 1UL << smp_processor_id(); + while(!smp_commenced) barrier(); + /* see smp_commence for more info */ if (!smp_tb_synchronized && smp_num_cpus == 2) { smp_software_tb_sync(cpu); diff -Nru a/arch/ppc/kernel/spruce_pci.c b/arch/ppc/kernel/spruce_pci.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/kernel/spruce_pci.c Wed May 16 06:00:33 2001 @@ -0,0 +1,174 @@ +/* + * arch/ppc/kernel/spruce_pci.c + * + * PCI support for IBM Spruce + * + * Author: Johnnie Peters + * jpeters@mvista.com + * + * Copyright 2000 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "cpc700.h" +#include "pci_auto.h" +#include "pci.h" + +static inline int __init +spruce_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) +{ + static char pci_irq_table[][4] = + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + { + {0, 0, 0, 0}, /* IDSEL 0 - unused */ + {23, 24, 25, 26}, /* IDSEL 1 - PCI slot 3 */ + {24, 25, 26, 23}, /* IDSEL 2 - PCI slot 2 */ + {25, 26, 23, 24}, /* IDSEL 3 - PCI slot 1 */ + {26, 23, 24, 25}, /* IDSEL 4 - PCI slot 0 */ + {0, 0, 0, 0}, /* IDSEL 5 - unused */ + {0, 0, 0, 0}, /* IDSEL 6 - unused */ + {0, 0, 0, 0}, /* IDSEL 7 - unused */ + {0, 0, 0, 0}, /* IDSEL 8 - unused */ + {0, 0, 0, 0}, /* IDSEL 9 - unused */ + {0, 0, 0, 0}, /* IDSEL 10 - unused */ + {0, 0, 0, 0}, /* IDSEL 11 - unused */ + {1, 0, 0, 0}, /* IDSEL 12 - ATM */ + {0, 0, 0, 0}, /* IDSEL 13 - Ethernet */ + {0, 0, 0, 0}, /* IDSEL 14 - Drawbridge */ + {6, 7, 7, 7}, /* IDSEL 15 - PMC Site */ + }; + + const long min_idsel = 0, max_idsel = 15, irqs_per_slot = 4; + return PCI_IRQ_TABLE_LOOKUP; +} + +void +spruce_route_non0(struct pci_dev *dev) +{ + struct pci_bus *pbus; /* Parent bus structure pointer */ + struct pci_dev *tdev = dev; /* Temporary pci_dev pointer */ + unsigned int devnum; /* Accumulated device number */ + unsigned char intpin; /* PCI interrupt pin */ + struct pci_controller *hose; /* PCI controller */ + + /* Check for valid PCI dev pointer */ + if (dev == NULL) return; + + /* Get a pointer to our pci_controller descriptor */ + hose = pci_bus_to_hose(dev->bus->number); + /* Initialize bridge IDSEL variable */ + devnum = PCI_SLOT(dev->devfn); + + /* Read the interrupt pin of the device */ + pcibios_read_config_byte(dev->bus->number, dev->devfn, + PCI_INTERRUPT_PIN, &intpin); + + /* If device doesn't request an interrupt, return */ + if ( (intpin < 1) || (intpin > 4) ) + return; + + intpin--; + + /* + * Walk up to the top bus, adjusting the interrupt pin for the + *standard PCI bus swizzle. + */ + do { + intpin = bridge_swizzle(intpin, devnum); + pbus = tdev->bus; /* up one level */ + tdev = pbus->self; + devnum = PCI_SLOT(tdev->devfn); + } while(tdev->bus->number != hose->first_busno); + + dev->irq = spruce_map_irq(pbus->self, devnum, intpin); + + /* Write calculated interrupt value to header and device list */ + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); +} + +void spruce_pcibios_fixup(void) +{ + struct pci_dev * dev; + + pci_for_each_dev(dev) { + if (pci_bus_to_hose(dev->bus->number)->first_busno) + spruce_route_non0(dev); + } +} + +void spruce_pcibios_fixup_resources(struct pci_dev *dev) +{ + int i; + + if ((dev->vendor == PCI_VENDOR_ID_IBM) && + (dev->device == PCI_DEVICE_ID_IBM_CPC710_PCI64)) + { + for (i=0; iresource[i].start = 0; + dev->resource[i].end = 0; + } + } +} + + +void spruce_find_bridges(void) +{ + struct pci_controller *hose_a; + + /* Setup PCI32 hose */ + hose_a = pcibios_alloc_controller(); + if (!hose_a) + return; + + hose_a->first_busno = 0; + hose_a->last_busno = 0xff; + hose_a->pci_mem_offset = SPRUCE_PCI_PHY_MEM_BASE; + hose_a->io_space.start = SPRUCE_PCI_LOWER_IO; + hose_a->io_space.end = SPRUCE_PCI_UPPER_IO; + hose_a->mem_space.start = SPRUCE_PCI_LOWER_MEM; + hose_a->mem_space.end = SPRUCE_PCI_UPPER_MEM; + hose_a->io_base_virt = (void *)SPRUCE_ISA_IO_BASE; + + setup_indirect_pci(hose_a, SPRUCE_PCI_CONFIG_ADDR, SPRUCE_PCI_CONFIG_DATA); + + hose_a->last_busno = pciauto_bus_scan(hose_a, hose_a->first_busno); + + ppc_md.pcibios_fixup = spruce_pcibios_fixup; + ppc_md.pcibios_fixup_resources = spruce_pcibios_fixup_resources; + ppc_md.pci_swizzle = common_swizzle; + ppc_md.pci_map_irq = spruce_map_irq; +} diff -Nru a/arch/ppc/kernel/spruce_pic.c b/arch/ppc/kernel/spruce_pic.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/kernel/spruce_pic.c Wed May 16 06:00:34 2001 @@ -0,0 +1,246 @@ +/* + * arch/ppc/kernel/spruce_pic.c + * + * Interrupt controller support for IBM Spruce + * + * Authors: Matt Porter and Johnnie Peters + * mporter@mvista.com + * jpeters@mvista.com + * + * Copyright 2000 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include "local_irq.h" +#include "cpc700.h" +#include + +void spruce_unmask_irq(unsigned int); +void spruce_mask_irq(unsigned int); +void spruce_mask_and_ack_irq(unsigned int); +static void spruce_end_irq(unsigned int); + +void cpc700_pic_init_irq(unsigned int); +int cpc700_pic_get_irq(void); + +struct hw_interrupt_type spruce_pic = { + "CPC700 PIC", + NULL, + NULL, + spruce_unmask_irq, + spruce_mask_irq, + spruce_mask_and_ack_irq, + NULL, + NULL +}; + +/* + * Table used to ensure proper programming of IRQs 0-16. + * + * First entry is the sensitivity (level/edge), second is the polarity. + */ +static u_int cpc700_irq_assigns[27][2] = { + { 1, 1 }, /* IRQ 0: ECC Correctable Error - rising edge */ + { 1, 1 }, /* IRQ 1: PCI Write Mem Range - rising edge */ + { 0, 1 }, /* IRQ 2: PCI Write Command Reg - active high */ + { 0, 1 }, /* IRQ 3: UART 0 - active high */ + { 0, 1 }, /* IRQ 4: UART 1 - active high */ + { 0, 1 }, /* IRQ 5: ICC 0 - active high */ + { 0, 1 }, /* IRQ 6: ICC 1 - active high */ + { 0, 1 }, /* IRQ 7: GPT Compare 0 - active high */ + { 0, 1 }, /* IRQ 8: GPT Compare 1 - active high */ + { 0, 1 }, /* IRQ 9: GPT Compare 2 - active high */ + { 0, 1 }, /* IRQ 10: GPT Compare 3 - active high */ + { 0, 1 }, /* IRQ 11: GPT Compare 4 - active high */ + { 0, 1 }, /* IRQ 12: GPT Capture 0 - active high */ + { 0, 1 }, /* IRQ 13: GPT Capture 1 - active high */ + { 0, 1 }, /* IRQ 14: GPT Capture 2 - active high */ + { 0, 1 }, /* IRQ 15: GPT Capture 3 - active high */ + { 0, 1 }, /* IRQ 16: GPT Capture 4 - active high */ + { 0, 0 }, /* IRQ 17: Reserved */ + { 0, 0 }, /* IRQ 18: Reserved */ + { 0, 0 }, /* IRQ 19: Reserved */ + { 0, 1 }, /* IRQ 20: FPGA EXT_IRQ0 - active high */ + { 1, 1 }, /* IRQ 21: Mouse - rising edge */ + { 1, 1 }, /* IRQ 22: Keyboard - rising edge */ + { 0, 0 }, /* IRQ 23: PCI Slot 3 - active low */ + { 0, 0 }, /* IRQ 24: PCI Slot 2 - active low */ + { 0, 0 }, /* IRQ 25: PCI Slot 1 - active low */ + { 0, 0 }, /* IRQ 26: PCI Slot 0 - active low */ +}; + +void +spruce_unmask_irq(unsigned int irq) +{ + unsigned int tr_bits; + + /* + * IRQ 31 is largest IRQ supported. + * IRQs 17-19 are reserved. + */ + if ((irq <= 31) && ((irq < 17) || (irq > 19))) { + tr_bits = CPC700_IN_32(CPC700_UIC_UICTR); + + if ((tr_bits & (1 << (31 - irq))) == 0) { + /* level trigger interrupt, clear bit in status + * register */ + CPC700_OUT_32(CPC700_UIC_UICSR, 1 << (31 - irq)); + } + + /* Know IRQ fits in entry 0 of ppc_cached_irq_mask[] */ + ppc_cached_irq_mask[0] |= CPC700_UIC_IRQ_BIT(irq); + + CPC700_OUT_32(CPC700_UIC_UICER, ppc_cached_irq_mask[0]); + } + return; +} + +void +spruce_mask_irq(unsigned int irq) +{ + /* + * IRQ 31 is largest IRQ supported. + * IRQs 17-19 are reserved. + */ + if ((irq <= 31) && ((irq < 17) || (irq > 19))) { + /* Know IRQ fits in entry 0 of ppc_cached_irq_mask[] */ + ppc_cached_irq_mask[0] &= + ~CPC700_UIC_IRQ_BIT(irq); + + CPC700_OUT_32(CPC700_UIC_UICER, ppc_cached_irq_mask[0]); + } + return; +} + +void +spruce_mask_and_ack_irq(unsigned int irq) +{ + u_int bit; + + /* + * IRQ 31 is largest IRQ supported. + * IRQs 17-19 are reserved. + */ + if ((irq <= 31) && ((irq < 17) || (irq > 19))) { + /* Know IRQ fits in entry 0 of ppc_cached_irq_mask[] */ + bit = CPC700_UIC_IRQ_BIT(irq); + + ppc_cached_irq_mask[0] &= ~bit; + CPC700_OUT_32(CPC700_UIC_UICER, ppc_cached_irq_mask[0]); + CPC700_OUT_32(CPC700_UIC_UICSR, bit); /* Write 1 clears IRQ */ + } + return; +} + +__init void +spruce_init_IRQ(void) +{ + int i; + + ppc_cached_irq_mask[0] = 0; + CPC700_OUT_32(CPC700_UIC_UICER, 0x00000000); /* Disable all irq's */ + CPC700_OUT_32(CPC700_UIC_UICSR, 0xffffffff); /* Clear cur intrs */ + CPC700_OUT_32(CPC700_UIC_UICCR, 0xffffffff); /* Gen INT not MCP */ + CPC700_OUT_32(CPC700_UIC_UICPR, 0x00000000); /* Active low */ + CPC700_OUT_32(CPC700_UIC_UICTR, 0x00000000); /* Level Sensitive */ + CPC700_OUT_32(CPC700_UIC_UICVR, CPC700_UIC_UICVCR_0_HI); + /* IRQ 0 is highest */ + + for (i = 0; i < 17; i++) { + irq_desc[i].handler = &spruce_pic; + cpc700_pic_init_irq(i); + } + + for (i = 20; i < 27; i++) { + irq_desc[i].handler = &spruce_pic; + cpc700_pic_init_irq(i); + } + + return; +} + +void +cpc700_pic_init_irq(unsigned int irq) +{ + unsigned int tmp; + + /* Set interrupt sense */ + tmp = CPC700_IN_32(CPC700_UIC_UICTR); + if (cpc700_irq_assigns[irq][0] == 0) { + tmp &= ~CPC700_UIC_IRQ_BIT(irq); + } else { + tmp |= CPC700_UIC_IRQ_BIT(irq); + } + CPC700_OUT_32(CPC700_UIC_UICTR, tmp); + + /* Set interrupt polarity */ + tmp = CPC700_IN_32(CPC700_UIC_UICPR); + if (cpc700_irq_assigns[irq][1]) { + tmp |= CPC700_UIC_IRQ_BIT(irq); + } else { + tmp &= ~CPC700_UIC_IRQ_BIT(irq); + } + CPC700_OUT_32(CPC700_UIC_UICPR, tmp); + + /* Set interrupt critical */ + tmp = CPC700_IN_32(CPC700_UIC_UICCR); + tmp |= CPC700_UIC_IRQ_BIT(irq); + CPC700_OUT_32(CPC700_UIC_UICCR, tmp); + + return; +} + +/* + * Find the highest IRQ that generating an interrupt, if any. + */ +int +spruce_get_irq(void) +{ + int irq = 0; + u_int irq_status, irq_test = 1; + + irq_status = CPC700_IN_32(CPC700_UIC_UICMSR); + + do + { + if (irq_status & irq_test) + break; + irq++; + irq_test <<= 1; + } while (irq < NR_IRQS); + + + if (irq == NR_IRQS) + irq = 33; + + return (31 - irq); +} diff -Nru a/arch/ppc/kernel/spruce_setup.c b/arch/ppc/kernel/spruce_setup.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/kernel/spruce_setup.c Wed May 16 06:00:33 2001 @@ -0,0 +1,240 @@ +/* + * arch/ppc/kernel/spruce_setup.c + * + * Board setup routines for IBM Spruce + * + * Author: Johnnie Peters + * jpeters@mvista.com + * + * Copyright 2000 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +extern void spruce_init_IRQ(void); +extern int spruce_get_irq(struct pt_regs *); +extern void spruce_find_bridges(void); +extern void spruce_setup_pci_ptrs(void); + + +extern int pckbd_setkeycode(unsigned int, unsigned int); +extern int pckbd_getkeycode(unsigned int); +extern int pckbd_translate(unsigned char, unsigned char *, char); +extern char pckbd_unexpected_up(unsigned char); +extern void pckbd_leds(unsigned char); +extern void pckbd_init_hw(void); +extern unsigned char pckbd_sysrq_xlate[128]; + +int +spruce_set_rtc_time( unsigned long now ) +{ + return 0; +} + +unsigned long +spruce_get_rtc_time(void) +{ + return 0; +} + +void __init spruce_calibrate_decr(void) +{ + int freq, divisor = 4; + + /* determine processor bus speed */ + freq = SPRUCE_BUS_SPEED; + tb_ticks_per_jiffy = freq / HZ / divisor; + tb_to_us = mulhwu_scale_factor(freq/divisor, 1000000); +} + +int +spruce_get_cpuinfo(char *buffer) +{ + int len; + + len = sprintf( buffer, "vendor\t\t: IBM\n"); + + len += sprintf( buffer+len, "machine\t\t: Spruce\n"); + + len += sprintf( buffer+len, "L2\t\t: 256 Kb\n"); + + len += sprintf( buffer+len, "memory type\t: SDRAM\n"); + + len += sprintf(buffer+len, "\n"); + + return len; +} + +extern char cmd_line[]; + +void __init +spruce_setup_arch(void) +{ + unsigned int cpu; + extern char cmd_line[]; + + /* init to some ~sane value until calibrate_delay() runs */ + loops_per_jiffy = 50000000 / HZ; + + /* Setup PCI host bridges */ + spruce_find_bridges(); + +#ifdef CONFIG_ROOT_NFS + /* bootable from nfsroot */ + ROOT_DEV = to_kdev_t(0x00FF); /* /dev/nfs pseudo device */ +#else + /* bootable from SCSI */ + ROOT_DEV = to_kdev_t(0x0801); /* /dev/sda1 */ +#endif + + printk("Boot arguments: %s\n", cmd_line); + + /* Identify the system */ + printk("System Identification: IBM Spruce\n"); + printk("IBM Spruce port (C) 2001 MontaVista Software, Inc. (source@mvista.com)\n"); + + /* Identify the CPU manufacturer */ + cpu = _get_PVR(); + printk("CPU manufacturer: IBM [rev=%04x]\n", cpu & 0xffff); + _set_L2CR(0x80000000); +} + +void +spruce_restart(char *cmd) +{ + __cli(); + + /* SRR0 has system reset vector, SRR1 has default MSR value */ + /* rfi restores MSR from SRR1 and sets the PC to the SRR0 value */ + __asm__ __volatile__ + ("\n\ + lis 3,0xfff0 + ori 3,3,0x0100 + mtspr 26,3 + li 3,0 + mtspr 27,3 + rfi + "); + for(;;); +} + +void +spruce_power_off(void) +{ + for(;;); +} + +void +spruce_halt(void) +{ + spruce_restart(NULL); +} + +extern int boot_mem_size; + +unsigned long __init +spruce_find_end_of_memory(void) +{ + return boot_mem_size; +} + +void __init +spruce_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ +#ifdef CONFIG_BLK_DEV_INITRD + if ( r4 ) + { + initrd_start = r4 + KERNELBASE; + initrd_end = r5 + KERNELBASE; + } +#endif + + /* take care of cmd line */ + if ( r6 && (((char *) r6) != '\0')) + { + *(char *)(r7+KERNELBASE) = 0; + strcpy(cmd_line, (char *)(r6+KERNELBASE)); + } + + isa_io_base = SPRUCE_ISA_IO_BASE; + isa_mem_base = SPRUCE_ISA_MEM_BASE; + pci_dram_offset = SPRUCE_PCI_SYS_MEM_BASE; + + ppc_md.setup_arch = spruce_setup_arch; + ppc_md.setup_residual = NULL; + ppc_md.get_cpuinfo = spruce_get_cpuinfo; + ppc_md.irq_cannonicalize = NULL; + ppc_md.init_IRQ = spruce_init_IRQ; + ppc_md.get_irq = spruce_get_irq; + ppc_md.init = NULL; + + ppc_md.find_end_of_memory = spruce_find_end_of_memory; + + ppc_md.restart = spruce_restart; + ppc_md.power_off = spruce_power_off; + ppc_md.halt = spruce_halt; + + /* Spruce has a DS9034? */ + ppc_md.time_init = NULL; + ppc_md.set_rtc_time = spruce_set_rtc_time; + ppc_md.get_rtc_time = spruce_get_rtc_time; + ppc_md.calibrate_decr = spruce_calibrate_decr; + +#ifdef CONFIG_VT + /* Spruce has a PS2 styke keyboard */ + ppc_md.kbd_setkeycode = pckbd_setkeycode; + ppc_md.kbd_getkeycode = pckbd_getkeycode; + ppc_md.kbd_translate = pckbd_translate; + ppc_md.kbd_unexpected_up = pckbd_unexpected_up; + ppc_md.kbd_leds = pckbd_leds; + ppc_md.kbd_init_hw = pckbd_init_hw; +#ifdef CONFIG_MAGIC_SYSRQ + ppc_md.kbd_sysrq_xlate = pckbd_sysrq_xlate; + SYSRQ_KEY = 0x54; +#endif +#endif +} diff -Nru a/arch/ppc/kernel/syscalls.c b/arch/ppc/kernel/syscalls.c --- a/arch/ppc/kernel/syscalls.c Wed May 16 06:00:25 2001 +++ b/arch/ppc/kernel/syscalls.c Wed May 16 06:00:25 2001 @@ -185,9 +185,10 @@ return error; } -unsigned long sys_mmap(unsigned long addr, size_t len, - unsigned long prot, unsigned long flags, - unsigned long fd, off_t offset) +static inline unsigned long +do_mmap2(unsigned long addr, size_t len, + unsigned long prot, unsigned long flags, + unsigned long fd, unsigned long pgoff) { struct file * file = NULL; int ret = -EBADF; @@ -199,12 +200,33 @@ } down_write(¤t->mm->mmap_sem); - ret = do_mmap(file, addr, len, prot, flags, offset); + ret = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); up_write(¤t->mm->mmap_sem); if (file) fput(file); out: return ret; +} + +unsigned long sys_mmap2(unsigned long addr, size_t len, + unsigned long prot, unsigned long flags, + unsigned long fd, unsigned long pgoff) +{ + return do_mmap2(addr, len, prot, flags, fd, pgoff); +} + +unsigned long sys_mmap(unsigned long addr, size_t len, + unsigned long prot, unsigned long flags, + unsigned long fd, off_t offset) +{ + int err = -EINVAL; + + if (offset & ~PAGE_MASK) + goto out; + + err = do_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT); +out: + return err; } extern int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *); diff -Nru a/arch/ppc/kernel/time.c b/arch/ppc/kernel/time.c --- a/arch/ppc/kernel/time.c Wed May 16 06:00:16 2001 +++ b/arch/ppc/kernel/time.c Wed May 16 06:00:16 2001 @@ -50,6 +50,7 @@ #include #include #include +#include #include #include #include @@ -91,6 +92,10 @@ static long time_offset; +spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED; + +EXPORT_SYMBOL(rtc_lock); + /* Timer interrupt helper function */ static inline int tb_delta(unsigned *jiffy_stamp) { int delta; @@ -144,14 +149,20 @@ int next_dec; unsigned long cpu = smp_processor_id(); unsigned jiffy_stamp = last_jiffy_stamp(cpu); + extern void do_IRQ(struct pt_regs *); + + if (atomic_read(&ppc_n_lost_interrupts) != 0) + do_IRQ(regs); hardirq_enter(cpu); - if (!user_mode(regs)) - ppc_do_profile(instruction_pointer(regs)); - do { + while ((next_dec = tb_ticks_per_jiffy - tb_delta(&jiffy_stamp)) < 0) { jiffy_stamp += tb_ticks_per_jiffy; - if (smp_processor_id()) continue; + if (!user_mode(regs)) + ppc_do_profile(instruction_pointer(regs)); + if (smp_processor_id()) + continue; + /* We are in an interrupt, no need to save/restore flags */ write_lock(&xtime_lock); tb_last_stamp = jiffy_stamp; @@ -184,7 +195,7 @@ last_rtc_update += 60; } write_unlock(&xtime_lock); - } while((next_dec = tb_ticks_per_jiffy - tb_delta(&jiffy_stamp)) < 0); + } if ( !disarm_decr[smp_processor_id()] ) set_dec(next_dec); last_jiffy_stamp(cpu) = jiffy_stamp; @@ -337,6 +348,8 @@ tz.tz_dsttime = 0; do_sys_settimeofday(NULL, &tz); } + + do_get_fast_time = do_gettimeofday; } #define TICK_SIZE tick diff -Nru a/arch/ppc/kernel/todc.h b/arch/ppc/kernel/todc.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/kernel/todc.h Wed May 16 06:00:34 2001 @@ -0,0 +1,104 @@ +/* + * include/asm-ppc/todc.h + * + * Definitions for the M48Txx and mc146818 series of Time of day/Real Time + * Clock chips. + * + * Author: Mark A. Greer + * mgreer@mvista.com + * + * Copyright 2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +/* + * Support for the M48T37/M48T59/.../mc146818 Real Time Clock chips. + * Purpose is to make one generic file that handles all of these chips instead + * of every platform implementing the same code over & over again. + */ + +#ifndef __PPC_KERNEL_TODC_H +#define __PPC_KERNEL_TODC_H + +typedef struct { + uint rtc_type; /* your particular chip */ + + /* + * Following are the addresses of the AS0, AS1, and DATA registers + * of these chips. Note that these are board-specific. + */ + u_char *nvram_as0; + u_char *nvram_as1; + u_char *nvram_data; + + /* + * Following is the number of AS0 address bits. This is normally + * 8 but some bad hardware routes address lines incorrectly. + */ + int as0_bits; + + /* Following are the register offsets for the particular chip */ + int year; + int month; + int day_of_month; + int day_of_week; + int hours; + int minutes; + int seconds; + int control_b; + int control_a; + int watchdog; + int interrupts; + int alarm_date; + int alarm_hour; + int alarm_minutes; + int alarm_seconds; + int century; + int flags; +} todc_info_t; + +/* + * Define the types of TODC/RTC variants that are supported in + * arch/ppc/kernel/todc_time.c + * Make a new one of these for any chip somehow differs from what's already + * defined. That way, if you ever need to put in code to touch those + * bits/registers in todc_time.c, you can put it inside an + * 'if (todc_info->rtc_type == TODC_TYPE_XXX)' so you won't break + * anyone else. + */ +#define TODC_TYPE_MK48T35 1 +#define TODC_TYPE_MK48T37 2 +#define TODC_TYPE_MK48T59 3 +#define TODC_TYPE_MC146818 100 /* Leave room for more m48txx's */ + +#ifndef BCD_TO_BIN +#define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10) +#endif + +#ifndef BIN_TO_BCD +#define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10) +#endif + +extern todc_info_t *todc_info; +extern todc_info_t m48t35_info; +extern todc_info_t m48t37_info; +extern todc_info_t m48t59_info; +extern todc_info_t mc146818_info; + +u_char todc_direct_read_val(int addr); +void todc_direct_write_val(int addr, unsigned char val); +u_char todc_m48txx_read_val(int addr); +void todc_m48txx_write_val(int addr, unsigned char val); +u_char todc_mc146818_read_val(int addr); +void todc_mc146818_write_val(int addr, unsigned char val); + +long todc_time_init(void); +unsigned long todc_get_rtc_time(void); +int todc_set_rtc_time(unsigned long nowtime); +void todc_calibrate_decr(void); + +#endif /* __PPC_KERNEL_TODC_H */ diff -Nru a/arch/ppc/kernel/todc_time.c b/arch/ppc/kernel/todc_time.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/kernel/todc_time.c Wed May 16 06:00:33 2001 @@ -0,0 +1,502 @@ +/* + * arch/ppc/kernel/todc_time.c + * + * Time of Day Clock support for the M48T35, M48T37, M48T59, and MC146818 + * Real Time Clocks/Timekeepers. + * + * Author: Mark A. Greer + * mgreer@mvista.com + * + * Copyright 2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include "todc.h" + +/* + * Depending on the hardware on your board and your board design, the + * RTC/NVRAM may be accessed either directly (like normal memory) or via + * address/data registers. If your board uses the direct method, set + * 'nvram_data' to the base address of your nvram and leave 'nvram_as0' and + * 'nvram_as1' NULL. If your board uses address/data regs to access nvram, + * set 'nvram_as0' to the address of the lower byte, set 'nvram_as1' to the + * address of the upper byte (leave NULL if using mv146818), and set + * 'nvram_data' to the address of the 8-bit data register. + * + * You also need to set 'ppc_md.nvram_read_val' and 'ppc_md.nvram_write_val' to + * the proper routines. There are standard ones defined further down in + * this file that you can use. + * + * There is a built in assumption that the RTC and NVRAM are accessed by the + * same mechanism (i.e., ppc_md.nvram_read_val, etc works for both). + */ + +/* + * 'todc_info' should be initialized in your *_setup.c file to + * point to a fully initialized 'todc_info_t' structure. + * This structure holds all the register offsets for your particular + * TODC/RTC chip. + */ +todc_info_t *todc_info = NULL; + +/* + * Allocate & initialize sample 'todc_info_t' structures for the M48T35, M48T37, + * M48T59, and M146818. You can use these ones, add others, or you can make + * your own in your *_setup.c file. + */ +todc_info_t m48t35_info = { + TODC_TYPE_MK48T35, /* rtc_type */ + + (u_char *)0, /* nvram_as0 -- board specific */ + (u_char *)0, /* nvram_as1 -- board specific */ + (u_char *)0, /* nvram_data -- board specific */ + + 8, /* as0_bits */ + + 0x7fff, /* year */ + 0x7ffe, /* month */ + 0x7ffd, /* day_of_month */ + 0x7ffc, /* day_of_week */ + 0x7ffb, /* hours */ + 0x7ffa, /* minutes */ + 0x7ff9, /* seconds */ + 0x7ff9, /* control_b */ + 0x7ff8, /* control_a */ + 0xffff, /* watchdog -- not used */ + 0xffff, /* interrupts -- not used */ + 0xffff, /* alarm_date -- not used */ + 0xffff, /* alarm_hour -- not used */ + 0xffff, /* alarm_minutes -- not used */ + 0xffff, /* alarm_seconds -- not used */ + 0xffff, /* century -- not used */ + 0xffff /* flags -- not used */ +}; + +todc_info_t m48t37_info = { + TODC_TYPE_MK48T37, /* rtc_type */ + + (u_char *)0, /* nvram_as0 -- board specific */ + (u_char *)0, /* nvram_as1 -- board specific */ + (u_char *)0, /* nvram_data -- board specific */ + + 8, /* as0_bits */ + + 0x7fff, /* year */ + 0x7ffe, /* month */ + 0x7ffd, /* day_of_month */ + 0x7ffc, /* day_of_week */ + 0x7ffb, /* hours */ + 0x7ffa, /* minutes */ + 0x7ff9, /* seconds */ + 0x7ff9, /* control_b */ + 0x7ff8, /* control_a */ + 0x7ff7, /* watchdog */ + 0x7ff6, /* interrupts */ + 0x7ff5, /* alarm_date */ + 0x7ff4, /* alarm_hour */ + 0x7ff3, /* alarm_minutes */ + 0x7ff2, /* alarm_seconds */ + 0x7ff1, /* century */ + 0x7ff0 /* flags */ +}; + +todc_info_t m48t59_info = { + TODC_TYPE_MK48T59, /* rtc_type */ + + (u_char *)0, /* nvram_as0 -- board specific */ + (u_char *)0, /* nvram_as1 -- board specific */ + (u_char *)0, /* nvram_data -- board specific */ + + 8, /* as0_bits */ + + 0x1fff, /* year */ + 0x1ffe, /* month */ + 0x1ffd, /* day_of_month */ + 0x1ffc, /* day_of_week */ + 0x1ffb, /* hours */ + 0x1ffa, /* minutes */ + 0x1ff9, /* seconds */ + 0x1ff9, /* control_b */ + 0x1ff8, /* control_a */ + 0x1ff7, /* watchdog */ + 0x1ff6, /* interrupts */ + 0x1ff5, /* alarm_date */ + 0x1ff4, /* alarm_hour */ + 0x1ff3, /* alarm_minutes */ + 0x1ff2, /* alarm_seconds */ + 0x1ff1, /* century */ + 0x1ff0 /* flags */ +}; + +todc_info_t mc146818_info = { + TODC_TYPE_MC146818, /* rtc_type */ + + (u_char *)0x70, /* nvram_as0 -- ISA address, can modify */ + (u_char *)0, /* nvram_as1 -- not used */ + (u_char *)0x71, /* nvram_data -- ISA address, can modify */ + + 8, /* as0_bits */ + + 0x09, /* year */ + 0x08, /* month */ + 0x07, /* day_of_month */ + 0x06, /* day_of_week */ + 0x04, /* hours */ + 0x02, /* minutes */ + 0x00, /* seconds */ + 0x0a, /* control_b -- used for Register A */ + 0x0b, /* control_a -- used for Register B */ + 0x0c, /* watchdog -- used for Register C */ + 0x0d, /* interrupts -- used for Register D */ + 0xff, /* alarm_date -- not used */ + 0x05, /* alarm_hour */ + 0x03, /* alarm_minutes */ + 0x01, /* alarm_seconds */ + 0xff, /* century -- not used */ + 0xff /* flags -- not used */ +}; + +#ifdef RTC_FREQ_SELECT +#undef RTC_FREQ_SELECT +#define RTC_FREQ_SELECT control_b /* Register A */ +#endif + +#ifdef RTC_CONTROL +#undef RTC_CONTROL +#define RTC_CONTROL control_a /* Register B */ +#endif + +#ifdef RTC_INTR_FLAGS +#undef RTC_INTR_FLAGS +#define RTC_INTR_FLAGS watchdog /* Register C */ +#endif + +#ifdef RTC_VALID +#undef RTC_VALID +#define RTC_VALID interrupts /* Register D */ +#endif + +/* Access routines when RTC accessed directly (like normal memory) */ +u_char +todc_direct_read_val(int addr) +{ + return readb(todc_info->nvram_data + addr); +} + +void +todc_direct_write_val(int addr, unsigned char val) +{ + writeb(val, todc_info->nvram_data + addr); + return; +} + +/* Access routines for accessing m48txx type chips via addr/data regs */ +u_char +todc_m48txx_read_val(int addr) +{ + outb(addr, todc_info->nvram_as0); + outb(addr>>todc_info->as0_bits, todc_info->nvram_as1); + return inb(todc_info->nvram_data); +} + +void +todc_m48txx_write_val(int addr, unsigned char val) +{ + outb(addr, todc_info->nvram_as0); + outb(addr>>todc_info->as0_bits, todc_info->nvram_as1); + outb(val, todc_info->nvram_data); + return; +} + +/* Access routines for accessing mc146818 type chips via addr/data regs */ +u_char +todc_mc146818_read_val(int addr) +{ + outb(addr, todc_info->nvram_as0); + return inb(todc_info->nvram_data); +} + +void +todc_mc146818_write_val(int addr, unsigned char val) +{ + outb(addr, todc_info->nvram_as0); + outb(val, todc_info->nvram_data); + return; +} + +/* + * TODC routines + * + * There is some ugly stuff in that there are assumptions for the mc146818. + * + * Assumptions: + * - todc_info->control_a has the offset as mc146818 Register B reg + * - todc_info->control_b has the offset as mc146818 Register A reg + * - m48txx control reg's write enable or 'W' bit is same as + * mc146818 Register B 'SET' bit (i.e., 0x80) + * + * These assumptions were made to make the code simpler. + */ +long __init +todc_time_init(void) +{ + u_char cntl_b; + static u_char not_initialized = 1; + + /* Make sure clocks are running */ + if (not_initialized) { + cntl_b = ppc_md.nvram_read_val(todc_info->control_b); + + if (todc_info->rtc_type == TODC_TYPE_MC146818) { + if ((cntl_b & 0x70) != 0x20) { + printk(KERN_INFO "TODC %s %s\n", + "real-time-clock was stopped.", + "Now starting..."); + cntl_b &= ~0x70; + cntl_b |= 0x20; + } + } + else { /* must be a m48txx type */ + u_char val; + + /* Check & clear STOP bit in control B register */ + if (cntl_b & MK48T59_RTC_CB_STOP) { + printk(KERN_INFO "TODC %s %s\n", + "real-time-clock was stopped.", + "Now starting..."); + cntl_b &= ~MK48T59_RTC_CB_STOP; + } + + /* Make sure READ & WRITE bits are cleared. */ + val = ppc_md.nvram_read_val(todc_info->control_a); + val &= ~(MK48T59_RTC_CA_WRITE | MK48T59_RTC_CA_READ); + ppc_md.nvram_write_val(todc_info->control_a, val); + } + + ppc_md.nvram_write_val(todc_info->control_b, cntl_b); + not_initialized = 0; + } + + return 0; +} + +/* + * There is some ugly stuff in that there are assumptions that for a mc146818, + * the todc_info->control_a has the offset of the mc146818 Register B reg and + * that the register'ss 'SET' bit is the same as the m48txx's write enable + * bit in the control register of the m48txx (i.e., 0x80). + * + * It was done to make the code look simpler. + */ +ulong +todc_get_rtc_time(void) +{ + uint year, mon, day, hour, min, sec; + uint limit, i; + u_char save_control, uip; + + save_control = ppc_md.nvram_read_val(todc_info->control_a); + + if (todc_info->rtc_type != TODC_TYPE_MC146818) { + limit = 1; + ppc_md.nvram_write_val(todc_info->control_a, + (save_control | MK48T59_RTC_CA_READ)); + } + else { + limit = 100000000; + } + + for (i=0; irtc_type == TODC_TYPE_MC146818) { + uip = ppc_md.nvram_read_val(todc_info->RTC_FREQ_SELECT); + } + + sec = ppc_md.nvram_read_val(todc_info->seconds); + min = ppc_md.nvram_read_val(todc_info->minutes); + hour = ppc_md.nvram_read_val(todc_info->hours); + day = ppc_md.nvram_read_val(todc_info->day_of_month); + mon = ppc_md.nvram_read_val(todc_info->month); + year = ppc_md.nvram_read_val(todc_info->year); + + if (todc_info->rtc_type == TODC_TYPE_MC146818) { + uip |= ppc_md.nvram_read_val( + todc_info->RTC_FREQ_SELECT); + if ((uip & RTC_UIP) == 0) break; + } + } + + if (todc_info->rtc_type != TODC_TYPE_MC146818) { + save_control &= ~MK48T59_RTC_CA_READ; /* in case it was set */ + ppc_md.nvram_write_val(todc_info->control_a, save_control); + } + + if ((todc_info->rtc_type != TODC_TYPE_MC146818) || + ((save_control & RTC_DM_BINARY) == 0) || + RTC_ALWAYS_BCD) { + + BCD_TO_BIN(sec); + BCD_TO_BIN(min); + BCD_TO_BIN(hour); + BCD_TO_BIN(day); + BCD_TO_BIN(mon); + BCD_TO_BIN(year); + } + + year = year + 1900; + if (year < 1970) { + year += 100; + } + + return mktime(year, mon, day, hour, min, sec); +} + +int +todc_set_rtc_time(unsigned long nowtime) +{ + struct rtc_time tm; + u_char save_control, save_freq_select; + + to_tm(nowtime, &tm); + + save_control = ppc_md.nvram_read_val(todc_info->control_a); + + /* Assuming MK48T59_RTC_CA_WRITE & RTC_SET are equal */ + ppc_md.nvram_write_val(todc_info->control_a, + (save_control | MK48T59_RTC_CA_WRITE)); + save_control &= ~MK48T59_RTC_CA_WRITE; /* in case it was set */ + + if (todc_info->rtc_type == TODC_TYPE_MC146818) { + save_freq_select = + ppc_md.nvram_read_val(todc_info->RTC_FREQ_SELECT); + ppc_md.nvram_write_val(todc_info->RTC_FREQ_SELECT, + save_freq_select | RTC_DIV_RESET2); + } + + + tm.tm_year = (tm.tm_year - 1900) % 100; + + if ((todc_info->rtc_type != TODC_TYPE_MC146818) || + ((save_control & RTC_DM_BINARY) == 0) || + RTC_ALWAYS_BCD) { + + BIN_TO_BCD(tm.tm_sec); + BIN_TO_BCD(tm.tm_min); + BIN_TO_BCD(tm.tm_hour); + BIN_TO_BCD(tm.tm_mon); + BIN_TO_BCD(tm.tm_mday); + BIN_TO_BCD(tm.tm_year); + } + + ppc_md.nvram_write_val(todc_info->seconds, tm.tm_sec); + ppc_md.nvram_write_val(todc_info->minutes, tm.tm_min); + ppc_md.nvram_write_val(todc_info->hours, tm.tm_hour); + ppc_md.nvram_write_val(todc_info->month, tm.tm_mon); + ppc_md.nvram_write_val(todc_info->day_of_month, tm.tm_mday); + ppc_md.nvram_write_val(todc_info->year, tm.tm_year); + + ppc_md.nvram_write_val(todc_info->control_a, save_control); + + if (todc_info->rtc_type == TODC_TYPE_MC146818) { + ppc_md.nvram_write_val(todc_info->RTC_FREQ_SELECT, + save_freq_select); + } + + return 0; +} + +/* + * Manipulates read bit to reliably read seconds at a high rate. + */ +unsigned char todc_read_timereg(int addr) +{ + unsigned char save_control, val; + + save_control = ppc_md.nvram_read_val(todc_info->control_a); + if (todc_info->rtc_type != TODC_TYPE_MC146818) { + ppc_md.nvram_write_val(todc_info->control_a, + (save_control | MK48T59_RTC_CA_READ)); + } + val = ppc_md.nvram_read_val(addr); + if (todc_info->rtc_type != TODC_TYPE_MC146818) { + save_control &= ~MK48T59_RTC_CA_READ; /* in case it was set */ + ppc_md.nvram_write_val(todc_info->control_a, save_control); + } + return val; +} + +/* + * This was taken from prep_setup.c + * Use the NVRAM RTC to time a second to calibrate the decrementer. + */ +void __init +todc_calibrate_decr(void) +{ + ulong freq; + ulong tbl, tbu; + long i, loop_count; + u_char sec; + + todc_time_init(); + + /* + * Actually this is bad for precision, we should have a loop in + * which we only read the seconds counter. nvram_read_val writes + * the address bytes on every call and this takes a lot of time. + * Perhaps an nvram_wait_change method returning a time + * stamp with a loop count as parameter would be the solution. + */ + /* + * Need to make sure the tbl doesn't roll over so if tbu increments + * during this test, we need to do it again. + */ + loop_count = 0; + + sec = todc_read_timereg(todc_info->seconds); + + do { + tbu = get_tbu(); + + for (i = 0 ; i < 10000000 ; i++) {/* may take up to 1 second */ + tbl = get_tbl(); + + if (todc_read_timereg(todc_info->seconds) != sec) { + break; + } + } + + sec = todc_read_timereg(todc_info->seconds); + + for (i = 0 ; i < 10000000 ; i++) { /* Should take 1 second */ + freq = get_tbl(); + + if (todc_read_timereg(todc_info->seconds) != sec) { + break; + } + } + + freq -= tbl; + } while ((get_tbu() != tbu) && (++loop_count < 2)); + + printk("time_init: decrementer frequency = %lu.%.6lu MHz\n", + freq/1000000, freq%1000000); + + tb_ticks_per_jiffy = freq / HZ; + tb_to_us = mulhwu_scale_factor(freq, 1000000); + + return; +} diff -Nru a/arch/ppc/lib/Makefile b/arch/ppc/lib/Makefile --- a/arch/ppc/lib/Makefile Wed May 16 06:00:20 2001 +++ b/arch/ppc/lib/Makefile Wed May 16 06:00:20 2001 @@ -2,8 +2,7 @@ # Makefile for ppc-specific library files.. # -.S.o: - $(CC) $(AFLAGS) -c $< -o $*.o +USE_STANDARD_AS_RULE := true O_TARGET := lib.o diff -Nru a/arch/ppc/mbxboot/Makefile b/arch/ppc/mbxboot/Makefile --- a/arch/ppc/mbxboot/Makefile Wed May 16 06:00:21 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,124 +0,0 @@ -# -# arch/ppc/mbxboot/Makefile -# -# This file is subject to the terms and conditions of the GNU General Public -# License. See the file "COPYING" in the main directory of this archive -# for more details. -# -# Copyright (C) 1994 by Linus Torvalds -# Adapted for PowerPC by Gary Thomas -# modified by Cort (cort@cs.nmt.edu) -# -.c.s: - $(CC) $(CFLAGS) -S -o $*.s $< -.s.o: - $(AS) -o $*.o $< -.c.o: - $(CC) $(CFLAGS) -DINITRD_OFFSET=$(IOFF) -DINITRD_SIZE=$(ISZ) -DZIMAGE_OFFSET=$(ZOFF) -DZIMAGE_SIZE=$(ZSZ) -c -o $*.o $< -.S.s: - $(CPP) $(AFLAGS) -traditional -o $*.o $< -.S.o: - $(CC) $(AFLAGS) -traditional -c -o $*.o $< - -ZOFF = 0 -ZSZ = 0 -IOFF = 0 -ISZ = 0 - -TFTPIMAGE=/tftpboot/zImage.embedded - -ifdef CONFIG_8xx -ZLINKFLAGS = -T ../vmlinux.lds -Ttext 0x00180000 -OBJECTS := head.o misc.o ../coffboot/zlib.o m8xx_tty.o -CFLAGS = $(CPPFLAGS) -O2 -DSTDC_HEADERS -fno-builtin -DCONFIG_8xx -endif - -ifdef CONFIG_8260 -ZLINKFLAGS = -T ../vmlinux.lds -Ttext 0x00400000 -OBJECTS := head_8260.o misc.o ../coffboot/zlib.o m8260_tty.o embed_config.o -CFLAGS = $(CPPFLAGS) -O2 -DSTDC_HEADERS -fno-builtin -DCONFIG_8260 -endif - -OBJCOPY_ARGS = -O elf32-powerpc - -ifeq ($(CONFIG_MBX),y) -OBJECTS += pci.o qspan_pci.o -CFLAGS += -DCONFIG_MBX -endif -ifeq ($(CONFIG_RPXLITE),y) -CFLAGS += -DCONFIG_RPXLITE -OBJECTS += iic.o embed_config.o -endif -ifeq ($(CONFIG_RPXCLASSIC),y) -CFLAGS += -DCONFIG_RPXCLASSIC -OBJECTS += iic.o embed_config.o pci.o qspan_pci.o -endif -ifeq ($(CONFIG_BSEIP),y) -CFLAGS += -DCONFIG_BSEIP -OBJECTS += iic.o embed_config.o -endif - -all: zImage - -zvmlinux.initrd: zvmlinux - $(LD) $(ZLINKFLAGS) -o zvmlinux.initrd.tmp1 $(OBJECTS) - $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ - --add-section=initrd=ramdisk.image.gz \ - --add-section=image=../coffboot/vmlinux.gz \ - zvmlinux.initrd.tmp1 zvmlinux.initrd1 - $(CC) $(CFLAGS) -DINITRD_OFFSET=`sh offset $(OBJDUMP) zvmlinux.initrd1 initrd` \ - -DINITRD_SIZE=`sh size $(OBJDUMP) zvmlinux.initrd1 initrd` \ - -DZIMAGE_OFFSET=`sh offset $(OBJDUMP) zvmlinux.initrd1 image` \ - -DZIMAGE_SIZE=`sh size $(OBJDUMP) zvmlinux.initrd1 image` \ - -c -o misc.o misc.c - $(LD) $(ZLINKFLAGS) -o zvmlinux.initrd.tmp $(OBJECTS) - $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ - --add-section=initrd=ramdisk.image.gz \ - --add-section=image=../coffboot/vmlinux.gz \ - zvmlinux.initrd.tmp $@ - -zImage: zvmlinux - ln -sf zvmlinux zImage - -zImage.initrd: zvmlinux.initrd - ln -sf zvmlinux.initrd zImage.initrd - -zvmlinux: $(OBJECTS) ../coffboot/vmlinux.gz -# -# build the boot loader image and then compute the offset into it -# for the kernel image -# - $(LD) $(ZLINKFLAGS) -o zvmlinux.tmp $(OBJECTS) - $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment --add-section=image=../coffboot/vmlinux.gz \ - zvmlinux.tmp $@ -# -# then with the offset rebuild the bootloader so we know where the kernel is -# - $(CC) $(CFLAGS) -DINITRD_OFFSET=0 -DINITRD_SIZE=0 \ - -DZIMAGE_OFFSET=`sh offset $(OBJDUMP) zvmlinux image` \ - -DZIMAGE_SIZE=`sh size $(OBJDUMP) zvmlinux image` \ - -c -o misc.o misc.c - $(LD) $(ZLINKFLAGS) -o zvmlinux.tmp $(OBJECTS) - $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment --add-section=image=../coffboot/vmlinux.gz \ - zvmlinux.tmp $@ - rm zvmlinux.tmp - -znetboot : zImage - cp zImage $(TFTPIMAGE) - -znetboot.initrd : zImage.initrd - cp zImage.initrd $(TFTPIMAGE) - -clean: - rm -f vmlinux* zvmlinux* zImage* - -fastdep: - $(TOPDIR)/scripts/mkdep *.[Sch] > .depend - -dep: - $(CPP) $(CPPFLAGS) -M *.S *.c > .depend - -# just here to match coffboot/Makefile -vmlinux.coff: - -vmlinux.coff.initrd: diff -Nru a/arch/ppc/mbxboot/embed_config.c b/arch/ppc/mbxboot/embed_config.c --- a/arch/ppc/mbxboot/embed_config.c Wed May 16 06:00:18 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,253 +0,0 @@ - -/* Board specific functions for those embedded 8xx boards that do - * not have boot monitor support for board information. - */ -#include -#include -#ifdef CONFIG_8xx -#include -#endif -#ifdef CONFIG_8260 -#include -#endif - - -/* IIC functions. - * These are just the basic master read/write operations so we can - * examine serial EEPROM. - */ -extern void iic_read(uint devaddr, u_char *buf, uint offset, uint count); -extern u_char aschex_to_byte(u_char *cp); - -/* Supply a default Ethernet address for those eval boards that don't - * ship with one. This is an address from the MBX board I have, so - * it is unlikely you will find it on your network. - */ -static ushort def_enet_addr[] = { 0x0800, 0x3e26, 0x1559 }; - -#if defined(CONFIG_RPXLITE) || defined(CONFIG_RPXCLASSIC) - -static void rpx_eth(bd_t *bd, u_char *cp); -static void rpx_brate(bd_t *bd, u_char *cp); -static void rpx_memsize(bd_t *bd, u_char *cp); -static void rpx_cpuspeed(bd_t *bd, u_char *cp); - -/* Read the EEPROM on the RPX-Lite board. -*/ -void -rpx_cfg(bd_t *bd) -{ - u_char eebuf[256], *cp; - - /* Read the first 256 bytes of the EEPROM. I think this - * is really all there is, and I hope if it gets bigger the - * info we want is still up front. - */ -#if 1 - iic_read(0xa8, eebuf, 0, 128); - iic_read(0xa8, &eebuf[128], 128, 128); - { - int i; - cp = (u_char *)0xfa000000; - - for (i=0; i<256; i++) - *cp++ = eebuf[i]; - } - - /* We look for two things, the Ethernet address and the - * serial baud rate. The records are separated by - * newlines. - */ - cp = eebuf; - for (;;) { - if (*cp == 'E') { - cp++; - if (*cp == 'A') { - cp += 2; - rpx_eth(bd, cp); - } - } - if (*cp == 'S') { - cp++; - if (*cp == 'B') { - cp += 2; - rpx_brate(bd, cp); - } - } - if (*cp == 'D') { - cp++; - if (*cp == '1') { - cp += 2; - rpx_memsize(bd, cp); - } - } - if (*cp == 'H') { - cp++; - if (*cp == 'Z') { - cp += 2; - rpx_cpuspeed(bd, cp); - } - } - - /* Scan to the end of the record. - */ - while ((*cp != '\n') && (*cp != 0xff)) - cp++; - - /* If the next character is a 0 or ff, we are done. - */ - cp++; - if ((*cp == 0) || (*cp == 0xff)) - break; - } - bd->bi_memstart = 0; - -#else - /* For boards without initialized EEPROM. - */ - bd->bi_memstart = 0; - bd->bi_memsize = (8 * 1024 * 1024); - bd->bi_intfreq = 48; - bd->bi_busfreq = 48; - bd->bi_baudrate = 9600; -#endif -} - -static void -rpx_eth(bd_t *bd, u_char *cp) -{ - int i; - - for (i=0; i<6; i++) { - bd->bi_enetaddr[i] = aschex_to_byte(cp); - cp += 2; - } -} - -static void -rpx_brate(bd_t *bd, u_char *cp) -{ - uint rate; - - rate = 0; - - while (*cp != '\n') { - rate *= 10; - rate += (*cp) - '0'; - cp++; - } - - bd->bi_baudrate = rate * 100; -} - -static void -rpx_memsize(bd_t *bd, u_char *cp) -{ - uint size; - - size = 0; - - while (*cp != '\n') { - size *= 10; - size += (*cp) - '0'; - cp++; - } - - bd->bi_memsize = size * 1024 * 1024; -} - -static void -rpx_cpuspeed(bd_t *bd, u_char *cp) -{ - uint num, den; - - num = den = 0; - - while (*cp != '\n') { - num *= 10; - num += (*cp) - '0'; - cp++; - if (*cp == '/') { - cp++; - den = (*cp) - '0'; - break; - } - } - - /* I don't know why the RPX just can't state the actual - * CPU speed..... - */ - if (den) { - num /= den; - num *= den; - } - bd->bi_intfreq = bd->bi_busfreq = num; - - /* The 8xx can only run a maximum 50 MHz bus speed (until - * Motorola changes this :-). Greater than 50 MHz parts - * run internal/2 for bus speed. - */ - if (num > 50) - bd->bi_busfreq /= 2; -} -#endif /* RPXLITE || RPXCLASSIC */ - -#ifdef CONFIG_BSEIP -/* Build a board information structure for the BSE ip-Engine. - * There is more to come since we will add some environment - * variables and a function to read them. - */ -void -bseip_cfg(bd_t *bd) -{ - u_char *cp; - int i; - - /* Baud rate and processor speed will eventually come - * from the environment variables. - */ - bd->bi_baudrate = 9600; - - /* Get the Ethernet station address from the Flash ROM. - */ - cp = (u_char *)0xfe003ffa; - for (i=0; i<6; i++) { - bd->bi_enetaddr[i] = *cp++; - } - - /* The rest of this should come from the environment as well. - */ - bd->bi_memstart = 0; - bd->bi_memsize = (16 * 1024 * 1024); - bd->bi_intfreq = 48; - bd->bi_busfreq = 48; -} -#endif /* BSEIP */ - -#ifdef CONFIG_EST8260 -void -embed_config(bd_t *bd) -{ - u_char *cp; - int i; - -#if 0 - /* This is actually provided by my boot rom. I have it - * here for those people that may load the kernel with - * a JTAG/COP tool and not the rom monitor. - */ - bd->bi_baudrate = 115200; - bd->bi_intfreq = 200; - bd->bi_busfreq = 66; - bd->bi_cpmfreq = 66; - bd->bi_brgfreq = 33; - bd->bi_memsize = 16 * 1024 * 1024; -#endif - - cp = (u_char *)def_enet_addr; - for (i=0; i<6; i++) { - bd->bi_enetaddr[i] = *cp++; - } -} -#endif /* EST8260 */ - diff -Nru a/arch/ppc/mbxboot/gzimage.c b/arch/ppc/mbxboot/gzimage.c --- a/arch/ppc/mbxboot/gzimage.c Wed May 16 06:00:19 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,8 +0,0 @@ -/* - * gzimage.c - * - * Dummy file to allow a compressed zImage to be added - * into a linker section, accessed by the boot coode - */ - -char dummy_for_gzimage; diff -Nru a/arch/ppc/mbxboot/head.S b/arch/ppc/mbxboot/head.S --- a/arch/ppc/mbxboot/head.S Wed May 16 06:00:21 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,249 +0,0 @@ -#include -#include "../kernel/ppc_defs.h" -#include "../kernel/ppc_asm.tmpl" -#include -#include - - .text - -/* - * $Id: head.S,v 1.6 1999/09/15 00:02:25 dmalek Exp $ - * - * This code is loaded by the ROM loader at some arbitrary location. - * Move it to high memory so that it can load the kernel at 0x0000. - * - * This is a three step process that will also work when booting from - * a Flash PROM normally located in high memory. - * - * First, the entire image is loaded into some high memory address. - * This is usually at or above 0x02000000. This is done by a network - * boot function supported by the board or a debugger over BDM port. - * - * Second, the start up function here will relocate the decompress - * function to run at the link address of 0x01000000. - * - * Last, the decompression function will reloate the initrd, zImage, and - * the residual data to locations under 8 Meg. This is necessary because - * the embedded kernel start up uses 8 Meg translations to access physical - * space before the MMU is enabled. Finally, the zImage is uncompressed - * to location 0 and we jump to it. - * - * On the MBX, - * R1 - Stack pointer at a high memory address. - * R3 - Pointer to Board Information Block. - * R4 - Pointer to argument string. - * Interrupts masked, cache and MMU disabled. - * - * ...and the first and second functions listed above are - * done for us (it knows ELF images). - * - * For other embedded boards we build the Board Information Block. - */ - - .globl start -start: - bl start_ -start_: -#ifndef CONFIG_MBX - lis r11, local_bd_info@h - ori r11, r11, local_bd_info@l -#else - mr r11, r3 -#endif - - mfmsr r3 /* Turn off interrupts */ - li r4,0 - ori r4,r4,MSR_EE - andc r3,r3,r4 - mtmsr r3 - -/* check if we need to relocate ourselves to the link addr or were we - loaded there to begin with -- Cort */ - lis r4,start@h - ori r4,r4,start@l - mflr r3 - subi r3,r3,4 /* we get the nip, not the ip of the branch */ - mr r8,r3 -#if 0 - cmp 0,r3,r4 - beq start_ldr /* Branch if loaded OK */ -#endif - -/* - * no matter where we're loaded, move ourselves to -Ttext address - * This computes the sizes we need to determine other things. - */ - lis r5,end@h - ori r5,r5,end@l - addi r5,r5,3 /* Round up - just in case */ - sub r5,r5,r4 /* Compute # longwords to move */ - srwi r5,r5,2 - mtctr r5 - mr r7,r5 - li r6,0 - subi r3,r3,4 /* Set up for loop */ - subi r4,r4,4 -00: lwzu r5,4(r3) - stwu r5,4(r4) - xor r6,r6,r5 - bdnz 00b - - lis r3,start_ldr@h - ori r3,r3,start_ldr@l - mtlr r3 /* Easiest way to do an absolute jump */ - blr - -start_ldr: -/* Most 8xx boards don't boot up with the I-cache enabled. Do that - * now because the decompress runs much faster that way. - */ - lis r3, IDC_INVALL@h - mtspr IC_CST, r3 - lis r3, IDC_ENABLE@h - mtspr IC_CST, r3 - -/* Clear all of BSS */ - lis r3,edata@h - ori r3,r3,edata@l - lis r4,end@h - ori r4,r4,end@l - subi r3,r3,4 - subi r4,r4,4 - li r0,0 -50: stwu r0,4(r3) - cmp 0,r3,r4 - bne 50b - - lis r1,.stack@h - ori r1,r1,.stack@l - addi r1,r1,4096*2 - subi r1,r1,256 - li r2,0x000F /* Mask pointer to 16-byte boundary */ - andc r1,r1,r2 - - /* Perform configuration of the various boards. This is done - * by reading some configuration data from EEPROM and building - * the board information structure. - */ - mr r3, r11 - mr r21, r11 - mr r22, r8 - mr r23, r7 - mr r24, r6 - -#if defined(CONFIG_RPXLITE) || defined(CONFIG_RPXCLASSIC) - bl rpx_cfg - mr r3, r21 -#endif -#ifdef CONFIG_BSEIP - bl bseip_cfg - mr r3, r21 -#endif - bl serial_init /* Init MBX serial port */ - - mr r11, r21 - mr r8, r22 - mr r7, r23 - mr r6, r24 - -#ifdef CONFIG_MBX - lis r18, 0xfa200000@h /* Disable Ethernet SCC */ - li r0, 0 - stw r0, 0x0a00(r18) - - /* On the MBX (or anything that will TFTP load an ELF image), - * we have to find the intermediate address. The ELF loader - * only moves the Linux boostrap/decompress, not the zImage. - */ -#define ILAP_ADDRESS 0xfa000020 - lis r8, ILAP_ADDRESS@h - lwz r8, ILAP_ADDRESS@l(r8) - addis r8, r8, 1 /* Add 64K */ -#endif - - mr r3,r8 /* Load point */ - mr r4,r7 /* Program length */ - mr r5,r6 /* Checksum */ - mr r6,r11 /* Residual data */ - bl decompress_kernel - - /* changed to use r3 (as firmware does) for kernel - as ptr to residual -- Cort*/ - lis r6,cmd_line@h - ori r6,r6,cmd_line@l - lwz r6, 0(r6) - subi r7,r6,1 -00: lbzu r2,1(r7) - 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) - - /* The world starts from the beginning. - */ - li r9,0x0 - mtlr r9 - - /* Invalidate the instruction cache because we just copied a - * bunch of kernel instructions. - */ - lis r9, IDC_INVALL@h - mtspr IC_CST, r9 - - blr -hang: - b hang - -/* - * Delay for a number of microseconds - * -- Use the BUS timer (assumes 66MHz) - */ - .globl udelay -udelay: - 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 - -.globl _get_MSR -_get_MSR: - mfmsr r3 - blr - -.globl _put_MSR -_put_MSR: - mtmsr r3 - blr - - .comm .stack,4096*2,4 -#ifndef CONFIG_MBX -local_bd_info: - .long 0 - .long 0x01000000 - .long 64 - .long 64 - .long 0 - .long 0 - .long 0 -#endif diff -Nru a/arch/ppc/mbxboot/head_8260.S b/arch/ppc/mbxboot/head_8260.S --- a/arch/ppc/mbxboot/head_8260.S Wed May 16 06:00:16 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,258 +0,0 @@ -#include "../kernel/ppc_defs.h" -#include "../kernel/ppc_asm.tmpl" -#include -#include - - .text - -/* - * $Id: head.S,v 1.33 1999/09/08 01:06:58 cort Exp $ - * - * Boot loader philosophy: - * - * ROM loads us to some arbitrary location - * ROM loads these registers: - * - * R3 = Pointer to the board configuration data - * R5 = Pointer to Open Firmware data - * - * ROM jumps to start/start_ - * Move the boot code to the link address (4 MB) - * Call decompress_kernel() - * Relocate the initrd, zimage and residual data to 4 MB - * Decompress the kernel to 0 - * Jump to the kernel entry - * -- Cort - */ - .globl start -start: - bl start_ -start_: - mr r11,r3 /* Save pointer to residual/board data */ - mr r25,r5 /* Save OFW pointer */ - li r3,MSR_IP /* Establish default MSR value */ - mtmsr r3 - -/* check if we need to relocate ourselves to the link addr or were we - loaded there to begin with -- Cort */ - lis r4,start@h - ori r4,r4,start@l - mflr r3 - subi r3,r3,4 /* we get the nip, not the ip of the branch */ - mr r8,r3 - cmp 0,r3,r4 - bne 1010f -/* compute size of whole image in words. this should be moved to - * start_ldr() -- Cort - */ - lis r4,start@h - ori r4,r4,start@l - lis r5,end@h - ori r5,r5,end@l - addi r5,r5,3 /* round up */ - sub r5,r5,r4 - srwi r5,r5,2 - mr r7,r5 - b start_ldr -1010: -/* - * no matter where we're loaded, move ourselves to -Ttext address - */ -relocate: - mflr r3 /* Compute code bias */ - subi r3,r3,4 - mr r8,r3 - lis r4,start@h - ori r4,r4,start@l - lis r5,end@h - ori r5,r5,end@l - addi r5,r5,3 /* Round up - just in case */ - sub r5,r5,r4 /* Compute # longwords to move */ - srwi r5,r5,2 - mtctr r5 - mr r7,r5 - li r6,0 - subi r3,r3,4 /* Set up for loop */ - subi r4,r4,4 -00: lwzu r5,4(r3) - stwu r5,4(r4) - xor r6,r6,r5 - bdnz 00b - lis r3,start_ldr@h - ori r3,r3,start_ldr@l - mtlr r3 /* Easiest way to do an absolute jump */ - blr -start_ldr: -/* Clear all of BSS */ - lis r3,edata@h - ori r3,r3,edata@l - lis r4,end@h - ori r4,r4,end@l - subi r3,r3,4 - subi r4,r4,4 - li r0,0 -50: stwu r0,4(r3) - cmp 0,r3,r4 - bne 50b -90: mr r9,r1 /* Save old stack pointer (in case it matters) */ - lis r1,.stack@h - ori r1,r1,.stack@l - addi r1,r1,4096*2 - subi r1,r1,256 - li r2,0x000F /* Mask pointer to 16-byte boundary */ - andc r1,r1,r2 - - /* Speed us up a little. - */ - bl flush_instruction_cache - -/* Run loader */ - mr r3,r8 /* Load point */ - mr r4,r7 /* Program length */ - mr r5,r6 /* Checksum */ - mr r6,r11 /* Residual data */ - mr r7,r25 /* OFW interfaces */ - bl decompress_kernel - - /* changed to use r3 (as firmware does) for kernel - as ptr to residual -- Cort*/ - lis r6,cmd_line@h - ori r6,r6,cmd_line@l - lwz r6, 0(r6) - subi r7,r6,1 -00: lbzu r2,1(r7) - 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) - - /* tell kernel we're prep */ - /* - * get start address of kernel code which is stored as a coff - * entry. see boot/head.S -- Cort - */ - li r9,0x4 - mtlr r9 - lis r10,0xdeadc0de@h - ori r10,r10,0xdeadc0de@l - li r9,0 - stw r10,0(r9) -/* - * The Radstone firmware maps PCI memory at 0xc0000000 using BAT2 - * so disable BATs before setting this to avoid a clash - */ - li r8,0 - mtspr DBAT0U,r8 - mtspr DBAT1U,r8 - mtspr DBAT2U,r8 - mtspr DBAT3U,r8 - mtspr IBAT0U,r8 - mtspr IBAT1U,r8 - mtspr IBAT2U,r8 - mtspr IBAT3U,r8 - - blr -hang: - b hang - -/* - * 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 - -.globl _get_HID0 -_get_HID0: - mfspr r3,HID0 - blr - -.globl _put_HID0 -_put_HID0: - mtspr HID0,r3 - blr - -.globl _get_MSR -_get_MSR: - mfmsr r3 - blr - -.globl _put_MSR -_put_MSR: - mtmsr r3 - blr - -/* - * Flush instruction cache - * *** I'm really paranoid here! - */ -_GLOBAL(flush_instruction_cache) - mflr r5 - bl flush_data_cache - mfspr r3,HID0 /* Caches are controlled by this register */ - li r4,0 - ori r4,r4,(HID0_ICE|HID0_ICFI) - or r3,r3,r4 /* Need to enable+invalidate to clear */ - mtspr HID0,r3 - andc r3,r3,r4 - ori r3,r3,HID0_ICE /* Enable cache */ - mtspr HID0,r3 - mtlr r5 - blr - -#define NUM_CACHE_LINES 128*8 -#define CACHE_LINE_SIZE 32 -#define cache_flush_buffer 0x1000 - -/* - * Flush data cache - * *** I'm really paranoid here! - */ -_GLOBAL(flush_data_cache) - lis r3,cache_flush_buffer@h - ori r3,r3,cache_flush_buffer@l - li r4,NUM_CACHE_LINES - mtctr r4 -00: lwz r4,0(r3) - addi r3,r3,CACHE_LINE_SIZE /* Next line, please */ - bdnz 00b -10: blr - .comm .stack,4096*2,4 diff -Nru a/arch/ppc/mbxboot/iic.c b/arch/ppc/mbxboot/iic.c --- a/arch/ppc/mbxboot/iic.c Wed May 16 06:00:25 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,259 +0,0 @@ - -/* Minimal support functions to read configuration from IIC EEPROMS - * on MPC8xx boards. Originally written for RPGC RPX-Lite. - * Dan Malek (dmalek@jlc.net). - */ -#include -#include -#include "asm/mpc8xx.h" -#include "../8xx_io/commproc.h" - - -/* IIC functions. - * These are just the basic master read/write operations so we can - * examine serial EEPROM. - */ -void iic_read(uint devaddr, u_char *buf, uint offset, uint count); -u_char aschex_to_byte(u_char *cp); - -static int iic_init_done; - -static void -iic_init() -{ - volatile iic_t *iip; - volatile i2c8xx_t *i2c; - volatile cbd_t *tbdf, *rbdf; - volatile cpm8xx_t *cp; - volatile immap_t *immap; - uint dpaddr; - - immap = (immap_t *)IMAP_ADDR; - cp = (cpm8xx_t *)&(immap->im_cpm); - - /* Reset the CPM. This is necessary on the 860 processors - * that may have started the SCC1 ethernet without relocating - * the IIC. - * This also stops the Ethernet in case we were loaded by a - * BOOTP rom monitor. - */ - cp->cp_cpcr = (CPM_CR_RST | CPM_CR_FLG); - - /* Wait for it. - */ - while (cp->cp_cpcr & (CPM_CR_RST | CPM_CR_FLG)); - - /* Remove any microcode patches. We will install our own - * later. - */ - cp->cp_cpmcr1 = 0; - cp->cp_cpmcr2 = 0; - cp->cp_cpmcr3 = 0; - cp->cp_cpmcr4 = 0; - cp->cp_rccr = 0; - - iip = (iic_t *)&cp->cp_dparam[PROFF_IIC]; - i2c = (i2c8xx_t *)&(immap->im_i2c); - - /* Initialize Port B IIC pins. - */ - cp->cp_pbpar |= 0x00000030; - cp->cp_pbdir |= 0x00000030; - cp->cp_pbodr |= 0x00000030; - - /* Initialize the parameter ram. - */ - - /* Allocate space for a two transmit and one receive buffer - * descriptor in the DP ram. - * For now, this address seems OK, but it may have to - * change with newer versions of the firmware. - */ - dpaddr = 0x0840; - - /* Set up the IIC parameters in the parameter ram. - */ - iip->iic_tbase = dpaddr; - iip->iic_rbase = dpaddr + (2 * sizeof(cbd_t)); - - iip->iic_tfcr = SMC_EB; - iip->iic_rfcr = SMC_EB; - - /* This should really be done by the reader/writer. - */ - iip->iic_mrblr = 128; - - /* Initialize Tx/Rx parameters. - */ - cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_I2C, CPM_CR_INIT_TRX) | CPM_CR_FLG; - while (cp->cp_cpcr & CPM_CR_FLG); - - /* Select an arbitrary address. Just make sure it is unique. - */ - i2c->i2c_i2add = 0x34; - - /* Make clock run maximum slow. - */ - i2c->i2c_i2brg = 7; - - /* Disable interrupts. - */ - i2c->i2c_i2cmr = 0; - i2c->i2c_i2cer = 0xff; - - /* Enable SDMA. - */ - immap->im_siu_conf.sc_sdcr = 1; - - iic_init_done = 1; -} - -/* Read from IIC. - * Caller provides device address, memory buffer, and byte count. - */ -static u_char iitemp[32]; - -void -iic_read(uint devaddr, u_char *buf, uint offset, uint count) -{ - volatile iic_t *iip; - volatile i2c8xx_t *i2c; - volatile cbd_t *tbdf, *rbdf; - volatile cpm8xx_t *cp; - volatile immap_t *immap; - u_char *tb; - uint dpaddr, temp; - - /* If the interface has not been initialized, do that now. - */ - if (!iic_init_done) - iic_init(); - - immap = (immap_t *)IMAP_ADDR; - cp = (cpm8xx_t *)&(immap->im_cpm); - - iip = (iic_t *)&cp->cp_dparam[PROFF_IIC]; - i2c = (i2c8xx_t *)&(immap->im_i2c); - - tbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_tbase]; - rbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_rbase]; - - /* Send a "dummy write" operation. This is a write request with - * only the offset sent, followed by another start condition. - * This will ensure we start reading from the first location - * of the EEPROM. - */ - tb = iitemp; - tb = (u_char *)(((uint)tb + 15) & ~15); - tbdf->cbd_bufaddr = tb; - *tb = devaddr & 0xfe; /* Device address */ - *(tb+1) = offset; /* Offset */ - tbdf->cbd_datlen = 2; /* Length */ - tbdf->cbd_sc = - BD_SC_READY | BD_SC_LAST | BD_SC_WRAP | BD_IIC_START; - - i2c->i2c_i2mod = 1; /* Enable */ - i2c->i2c_i2cer = 0xff; - i2c->i2c_i2com = 0x81; /* Start master */ - - /* Wait for IIC transfer. - */ -#if 0 - while ((i2c->i2c_i2cer & 3) == 0); - - if (tbdf->cbd_sc & BD_SC_READY) - printf("IIC ra complete but tbuf ready\n"); -#else - temp = 10000000; - while ((tbdf->cbd_sc & BD_SC_READY) && (temp != 0)) - temp--; -#if 0 - /* We can't do this...there is no serial port yet! - */ - if (temp == 0) { - printf("Timeout reading EEPROM\n"); - return; - } -#endif -#endif - - /* Chip errata, clear enable. - */ - i2c->i2c_i2mod = 0; - - /* To read, we need an empty buffer of the proper length. - * All that is used is the first byte for address, the remainder - * is just used for timing (and doesn't really have to exist). - */ - tbdf->cbd_bufaddr = tb; - *tb = devaddr | 1; /* Device address */ - rbdf->cbd_bufaddr = (uint)buf; /* Desination buffer */ - tbdf->cbd_datlen = rbdf->cbd_datlen = count + 1; /* Length */ - tbdf->cbd_sc = BD_SC_READY | BD_SC_LAST | BD_SC_WRAP | BD_IIC_START; - rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP; - - /* Chip bug, set enable here. - */ - i2c->i2c_i2mod = 1; /* Enable */ - i2c->i2c_i2cer = 0xff; - i2c->i2c_i2com = 0x81; /* Start master */ - - /* Wait for IIC transfer. - */ -#if 0 - while ((i2c->i2c_i2cer & 1) == 0); - - if (rbdf->cbd_sc & BD_SC_EMPTY) - printf("IIC read complete but rbuf empty\n"); -#else - temp = 10000000; - while ((tbdf->cbd_sc & BD_SC_READY) && (temp != 0)) - temp--; -#endif - - /* Chip errata, clear enable. - */ - i2c->i2c_i2mod = 0; -} - -/* Because I didn't find anything that would do this....... -*/ -u_char -aschex_to_byte(u_char *cp) -{ - u_char byte, c; - - c = *cp++; - - if ((c >= 'A') && (c <= 'F')) { - c -= 'A'; - c += 10; - } - else if ((c >= 'a') && (c <= 'f')) { - c -= 'a'; - c += 10; - } - else { - c -= '0'; - } - - byte = c * 16; - - c = *cp; - - if ((c >= 'A') && (c <= 'F')) { - c -= 'A'; - c += 10; - } - else if ((c >= 'a') && (c <= 'f')) { - c -= 'a'; - c += 10; - } - else { - c -= '0'; - } - - byte += c; - - return(byte); -} diff -Nru a/arch/ppc/mbxboot/m8260_tty.c b/arch/ppc/mbxboot/m8260_tty.c --- a/arch/ppc/mbxboot/m8260_tty.c Wed May 16 06:00:22 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,201 +0,0 @@ - - -/* Minimal serial functions needed to send messages out the serial - * port on SMC1. - */ -#include -#include "asm/mpc8260.h" -#include "asm/cpm_8260.h" - -uint no_print; -extern char *params[]; -extern int nparams; -static u_char cons_hold[128], *sgptr; -static int cons_hold_cnt; - -void -serial_init(bd_t *bd) -{ - volatile smc_t *sp; - volatile smc_uart_t *up; - volatile cbd_t *tbdf, *rbdf; - volatile immap_t *ip; - volatile iop8260_t *io; - volatile cpm8260_t *cp; - uint dpaddr, memaddr; - - ip = (immap_t *)IMAP_ADDR; - - sp = (smc_t*)&(ip->im_smc[0]); - *(ushort *)(&ip->im_dprambase[PROFF_SMC1_BASE]) = PROFF_SMC1; - up = (smc_uart_t *)&ip->im_dprambase[PROFF_SMC1]; - - cp = &ip->im_cpm; - io = &ip->im_ioport; - - /* Disable transmitter/receiver. - */ - sp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); - - /* Use Port D for SMC1 instead of other functions. - */ - io->iop_ppard |= 0x00c00000; - io->iop_pdird |= 0x00400000; - io->iop_pdird &= ~0x00800000; - io->iop_psord &= ~0x00c00000; - - /* Allocate space for two buffer descriptors in the DP ram. - * For now, this address seems OK, but it may have to - * change with newer versions of the firmware. - */ - dpaddr = 0x0800; - - /* Grab a few bytes from the top of memory. - */ -#if 1 - memaddr = (bd->bi_memsize - 256) & ~15; -#else - memaddr = 0x0f002c00; -#endif - - /* Set the physical address of the host memory buffers in - * the buffer descriptors. - */ - rbdf = (cbd_t *)&ip->im_dprambase[dpaddr]; - rbdf->cbd_bufaddr = memaddr; - rbdf->cbd_sc = 0; - tbdf = rbdf + 1; - tbdf->cbd_bufaddr = memaddr+128; - tbdf->cbd_sc = 0; - - /* Set up the uart parameters in the parameter ram. - */ - up->smc_rbase = dpaddr; - up->smc_tbase = dpaddr+sizeof(cbd_t); - up->smc_rfcr = CPMFCR_EB; - up->smc_tfcr = CPMFCR_EB; - up->smc_brklen = 0; - up->smc_brkec = 0; - up->smc_brkcr = 0; - - /* Set UART mode, 8 bit, no parity, one stop. - * Enable receive and transmit. - */ - sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART; - - /* Mask all interrupts and remove anything pending. - */ - sp->smc_smcm = 0; - sp->smc_smce = 0xff; - - /* Set up the baud rate generator. - */ - ip->im_clkrst.car_sccr = 0; /* DIV 4 BRG */ - ip->im_cpmux.cmx_smr = 0; - ip->im_brgc1 = - ((((bd->bi_brgfreq * 1000000)/16) / bd->bi_baudrate) << 1) | - CPM_BRG_EN; - - /* Make the first buffer the only buffer. - */ - tbdf->cbd_sc |= BD_SC_WRAP; - rbdf->cbd_sc |= BD_SC_EMPTY | BD_SC_WRAP; - -#if 0 - /* Single character receive. - */ - up->smc_mrblr = 1; - up->smc_maxidl = 0; -#else - up->smc_mrblr = 128; - up->smc_maxidl = 8; -#endif - - /* Initialize Tx/Rx parameters. - */ - cp->cp_cpcr = mk_cr_cmd(CPM_CR_SMC1_PAGE, CPM_CR_SMC1_SBLOCK, 0, CPM_CR_INIT_TRX) | CPM_CR_FLG; - while (cp->cp_cpcr & CPM_CR_FLG); - - /* Enable transmitter/receiver. - */ - sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN; -} - -void -serial_putchar(const char c) -{ - volatile cbd_t *tbdf; - volatile char *buf; - volatile smc_uart_t *up; - volatile immap_t *ip; - extern bd_t *board_info; - - ip = (immap_t *)IMAP_ADDR; - up = (smc_uart_t *)&(ip->im_dprambase[PROFF_SMC1]); - tbdf = (cbd_t *)&ip->im_dprambase[up->smc_tbase]; - - /* Wait for last character to go. - */ - buf = (char *)tbdf->cbd_bufaddr; - while (tbdf->cbd_sc & BD_SC_READY); - - *buf = c; - tbdf->cbd_datlen = 1; - tbdf->cbd_sc |= BD_SC_READY; -} - -char -serial_getc() -{ - char c; - - if (cons_hold_cnt <= 0) { - cons_hold_cnt = serial_readbuf(cons_hold); - sgptr = cons_hold; - } - c = *sgptr++; - cons_hold_cnt--; - - return(c); -} - -int -serial_readbuf(u_char *cbuf) -{ - volatile cbd_t *rbdf; - volatile char *buf; - volatile smc_uart_t *up; - volatile immap_t *ip; - int i, nc; - - ip = (immap_t *)IMAP_ADDR; - - up = (smc_uart_t *)&(ip->im_dprambase[PROFF_SMC1]); - rbdf = (cbd_t *)&ip->im_dprambase[up->smc_rbase]; - - /* Wait for character to show up. - */ - buf = (char *)rbdf->cbd_bufaddr; - while (rbdf->cbd_sc & BD_SC_EMPTY); - nc = rbdf->cbd_datlen; - for (i=0; icbd_sc |= BD_SC_EMPTY; - - return(nc); -} - -int -serial_tstc() -{ - volatile cbd_t *rbdf; - volatile smc_uart_t *up; - volatile immap_t *ip; - - ip = (immap_t *)IMAP_ADDR; - up = (smc_uart_t *)&(ip->im_dprambase[PROFF_SMC1]); - rbdf = (cbd_t *)&ip->im_dprambase[up->smc_rbase]; - - return(!(rbdf->cbd_sc & BD_SC_EMPTY)); -} - diff -Nru a/arch/ppc/mbxboot/m8xx_tty.c b/arch/ppc/mbxboot/m8xx_tty.c --- a/arch/ppc/mbxboot/m8xx_tty.c Wed May 16 06:00:23 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,276 +0,0 @@ - - -/* Minimal serial functions needed to send messages out the serial - * port on the MBX console. - * - * The MBX uxes SMC1 for the serial port. We reset the port and use - * only the first BD that EPPC-Bug set up as a character FIFO. - * - * Later versions (at least 1.4, maybe earlier) of the MBX EPPC-Bug - * use COM1 instead of SMC1 as the console port. This kinda sucks - * for the rest of the kernel, so here we force the use of SMC1 again. - */ -#include -#include -#include -#include -#include "../8xx_io/commproc.h" - -#ifdef CONFIG_MBX -#define MBX_CSR1 ((volatile u_char *)0xfa100000) -#define CSR1_COMEN (u_char)0x02 -#endif - -#ifdef TQM_SMC2_CONSOLE -#define PROFF_CONS PROFF_SMC2 -#define CPM_CR_CH_CONS CPM_CR_CH_SMC2 -#define SMC_INDEX 1 -static volatile iop8xx_t *iopp = (iop8xx_t *)&(((immap_t *)IMAP_ADDR)->im_ioport); -#else -#define PROFF_CONS PROFF_SMC1 -#define CPM_CR_CH_CONS CPM_CR_CH_SMC1 -#define SMC_INDEX 0 -#endif - -static cpm8xx_t *cpmp = (cpm8xx_t *)&(((immap_t *)IMAP_ADDR)->im_cpm); - -void -serial_init(bd_t *bd) -{ - volatile smc_t *sp; - volatile smc_uart_t *up; - volatile cbd_t *tbdf, *rbdf; - volatile cpm8xx_t *cp; - uint dpaddr, memaddr; - - cp = cpmp; - sp = (smc_t*)&(cp->cp_smc[SMC_INDEX]); - up = (smc_uart_t *)&cp->cp_dparam[PROFF_CONS]; - - /* Disable transmitter/receiver. - */ - sp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); - -#ifndef CONFIG_MBX - { - /* Initialize SMCx and use it for the console port. - */ - - /* Enable SDMA. - */ - ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sdcr = 1; - -#ifdef TQM_SMC2_CONSOLE - /* Use Port A for SMC2 instead of other functions. - */ - iopp->iop_papar |= 0x00c0; - iopp->iop_padir &= ~0x00c0; - iopp->iop_paodr &= ~0x00c0; -#else - /* Use Port B for SMCs instead of other functions. - */ - cp->cp_pbpar |= 0x00000cc0; - cp->cp_pbdir &= ~0x00000cc0; - cp->cp_pbodr &= ~0x00000cc0; -#endif - - /* Allocate space for two buffer descriptors in the DP ram. - * For now, this address seems OK, but it may have to - * change with newer versions of the firmware. - */ - dpaddr = 0x0800; - - /* Grab a few bytes from the top of memory for SMC FIFOs. - */ - memaddr = (bd->bi_memsize - 32) & ~15; - - /* Set the physical address of the host memory buffers in - * the buffer descriptors. - */ - rbdf = (cbd_t *)&cp->cp_dpmem[dpaddr]; - rbdf->cbd_bufaddr = memaddr; - rbdf->cbd_sc = 0; - tbdf = rbdf + 1; - tbdf->cbd_bufaddr = memaddr+4; - tbdf->cbd_sc = 0; - - /* Set up the uart parameters in the parameter ram. - */ - up->smc_rbase = dpaddr; - up->smc_tbase = dpaddr+sizeof(cbd_t); - up->smc_rfcr = SMC_EB; - up->smc_tfcr = SMC_EB; - - /* Set UART mode, 8 bit, no parity, one stop. - * Enable receive and transmit. - */ - sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART; - - /* Mask all interrupts and remove anything pending. - */ - sp->smc_smcm = 0; - sp->smc_smce = 0xff; - - /* Set up the baud rate generator. - * See 8xx_io/commproc.c for details. - * This wires BRG1 to SMC1 and BRG2 to SMC2; - */ - cp->cp_simode = 0x10000000; -#ifdef TQM_SMC2_CONSOLE - cp->cp_brgc2 = -#else - cp->cp_brgc1 = -#endif - ((((bd->bi_intfreq * 1000000)/16) / bd->bi_baudrate) << 1) | CPM_BRG_EN; - -#else /* CONFIG_MBX */ - if (*MBX_CSR1 & CSR1_COMEN) { - /* COM1 is enabled. Initialize SMC1 and use it for - * the console port. - */ - - /* Enable SDMA. - */ - ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sdcr = 1; - - /* Use Port B for SMCs instead of other functions. - */ - cp->cp_pbpar |= 0x00000cc0; - cp->cp_pbdir &= ~0x00000cc0; - cp->cp_pbodr &= ~0x00000cc0; - - /* Allocate space for two buffer descriptors in the DP ram. - * For now, this address seems OK, but it may have to - * change with newer versions of the firmware. - */ - dpaddr = 0x0800; - - /* Grab a few bytes from the top of memory. EPPC-Bug isn't - * running any more, so we can do this. - */ - memaddr = (bd->bi_memsize - 32) & ~15; - - /* Set the physical address of the host memory buffers in - * the buffer descriptors. - */ - rbdf = (cbd_t *)&cp->cp_dpmem[dpaddr]; - rbdf->cbd_bufaddr = memaddr; - rbdf->cbd_sc = 0; - tbdf = rbdf + 1; - tbdf->cbd_bufaddr = memaddr+4; - tbdf->cbd_sc = 0; - - /* Set up the uart parameters in the parameter ram. - */ - up->smc_rbase = dpaddr; - up->smc_tbase = dpaddr+sizeof(cbd_t); - up->smc_rfcr = SMC_EB; - up->smc_tfcr = SMC_EB; - - /* Set UART mode, 8 bit, no parity, one stop. - * Enable receive and transmit. - */ - sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART; - - /* Mask all interrupts and remove anything pending. - */ - sp->smc_smcm = 0; - sp->smc_smce = 0xff; - - /* Set up the baud rate generator. - * See 8xx_io/commproc.c for details. - */ - cp->cp_simode = 0x10000000; - cp->cp_brgc1 = - ((((bd->bi_intfreq * 1000000)/16) / 9600) << 1) | CPM_BRG_EN; - - /* Enable SMC1 for console output. - */ - *MBX_CSR1 &= ~CSR1_COMEN; - } - else { -#endif /* ndef CONFIG_MBX */ - /* SMCx is used as console port. - */ - tbdf = (cbd_t *)&cp->cp_dpmem[up->smc_tbase]; - rbdf = (cbd_t *)&cp->cp_dpmem[up->smc_rbase]; - - /* Issue a stop transmit, and wait for it. - */ - cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_CONS, - CPM_CR_STOP_TX) | CPM_CR_FLG; - while (cp->cp_cpcr & CPM_CR_FLG); - } - - /* Make the first buffer the only buffer. - */ - tbdf->cbd_sc |= BD_SC_WRAP; - rbdf->cbd_sc |= BD_SC_EMPTY | BD_SC_WRAP; - - /* Single character receive. - */ - up->smc_mrblr = 1; - up->smc_maxidl = 0; - - /* Initialize Tx/Rx parameters. - */ - cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_CONS, CPM_CR_INIT_TRX) | CPM_CR_FLG; - while (cp->cp_cpcr & CPM_CR_FLG); - - /* Enable transmitter/receiver. - */ - sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN; -} - -void -serial_putchar(const char c) -{ - volatile cbd_t *tbdf; - volatile char *buf; - volatile smc_uart_t *up; - - up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_CONS]; - tbdf = (cbd_t *)&cpmp->cp_dpmem[up->smc_tbase]; - - /* Wait for last character to go. - */ - buf = (char *)tbdf->cbd_bufaddr; - while (tbdf->cbd_sc & BD_SC_READY); - - *buf = c; - tbdf->cbd_datlen = 1; - tbdf->cbd_sc |= BD_SC_READY; -} - -char -serial_getc() -{ - volatile cbd_t *rbdf; - volatile char *buf; - volatile smc_uart_t *up; - char c; - - up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_CONS]; - rbdf = (cbd_t *)&cpmp->cp_dpmem[up->smc_rbase]; - - /* Wait for character to show up. - */ - buf = (char *)rbdf->cbd_bufaddr; - while (rbdf->cbd_sc & BD_SC_EMPTY); - c = *buf; - rbdf->cbd_sc |= BD_SC_EMPTY; - - return(c); -} - -int -serial_tstc() -{ - volatile cbd_t *rbdf; - volatile smc_uart_t *up; - - up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_CONS]; - rbdf = (cbd_t *)&cpmp->cp_dpmem[up->smc_rbase]; - - return(!(rbdf->cbd_sc & BD_SC_EMPTY)); -} diff -Nru a/arch/ppc/mbxboot/misc.c b/arch/ppc/mbxboot/misc.c --- a/arch/ppc/mbxboot/misc.c Wed May 16 06:00:20 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,476 +0,0 @@ -/* - * misc.c - * - * $Id: misc.c,v 1.2 1999/09/14 05:55:29 dmalek Exp $ - * - * Adapted for PowerPC by Gary Thomas - * - * Rewritten by Cort Dougan (cort@cs.nmt.edu) - * One day to be replaced by a single bootloader for chrp/prep/pmac. -- Cort - */ - -#include -#include "../coffboot/zlib.h" -#include "asm/residual.h" -#include -#include -#include -#include -#include -#ifdef CONFIG_8xx -#include -#endif -#ifdef CONFIG_8260 -#include -#endif - -/* - * The following references are needed to cause the linker to pull in the - * gzimage.o and rdimage.o files. These object files are special, - * since they get placed into the .gzimage and .rdimage ELF sections - * of the zvmlinux and zvmlinux.initrd files. - */ -extern char dummy_for_gzimage; -extern char dummy_for_rdimage; - -/* - * Please send me load/board info and such data for hardware not - * listed here so I can keep track since things are getting tricky - * with the different load addrs with different firmware. This will - * help to avoid breaking the load/boot process. - * -- Cort - */ -char *avail_ram; -char *end_avail; - -/* See comment below..... -*/ -unsigned int initrd_offset, initrd_size; - -/* Because of the limited amount of memory on embedded, it presents - * loading problems. The biggest is that we load this boot program - * into a relatively low memory address, and the Linux kernel Bss often - * extends into this space when it get loaded. When the kernel starts - * and zeros the BSS space, it also writes over the information we - * save here and pass to the kernel (command line and board info). - * On these boards, we grab some known memory holes to hold this information. - */ -char cmd_buf[256]; -char *cmd_line = cmd_buf; - -char *root_string = "root=/dev/nfs rw"; -char *nfsaddrs_string = "nfsaddrs="; -char *nfsroot_string = "nfsroot="; -char *defroot_string = "/sys/mbxroot"; -char *ramroot_string = "root=/dev/ram"; -int do_ipaddrs(char **cmd_cp, int echo); -void do_nfsroot(char **cmd_cp, char *dp); -int strncmp(const char * cs,const char * ct,size_t count); -char *strrchr(const char * s, int c); - -bd_t hold_resid_buf; -bd_t *hold_residual = &hold_resid_buf; -unsigned long initrd_start = 0, initrd_end = 0; -char *zimage_start; -int zimage_size; - -void puts(const char *); -void putc(const char c); -void puthex(unsigned long val); -void _bcopy(char *src, char *dst, int len); -void * memcpy(void * __dest, __const void * __src, - int __n); -void gunzip(void *, int, unsigned char *, int *); - -void pause() -{ - puts("pause\n"); -} - -void exit() -{ - puts("exit\n"); - while(1); -} - -/* The MPC8xx is just the serial port. -*/ -tstc(void) -{ - return (serial_tstc()); -} - -getc(void) -{ - while (1) { - if (serial_tstc()) return (serial_getc()); - } -} - -void -putc(const char c) -{ - serial_putchar(c); -} - -void puts(const char *s) -{ - char c; - - while ( ( c = *s++ ) != '\0' ) { - serial_putchar(c); - if ( c == '\n' ) - serial_putchar('\r'); - } -} - -void * memcpy(void * __dest, __const void * __src, - int __n) -{ - int i; - char *d = (char *)__dest, *s = (char *)__src; - - for (i=0;i<__n;i++) d[i] = s[i]; -} - -int memcmp(__const void * __dest, __const void * __src, - int __n) -{ - int i; - char *d = (char *)__dest, *s = (char *)__src; - - for (i=0;i<__n;i++, d++, s++) - { - if (*d != *s) - { - return (*s - *d); - } - } - return (0); -} - -void error(char *x) -{ - puts("\n\n"); - puts(x); - puts("\n\n -- System halted"); - - while(1); /* Halt */ -} - -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) { - puts("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) { - puts("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) { - puts("gunzip: ran out of data in header\n"); - exit(); - } - - s.zalloc = zalloc; - s.zfree = zfree; - r = inflateInit2(&s, -MAX_WBITS); - if (r != Z_OK) { - puts("inflateInit2 returned %d\n"); - 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) { - puts("inflate returned "); - puthex(r); - puts("\n"); - exit(); - } - *lenp = s.next_out - (unsigned char *) dst; - inflateEnd(&s); -} - -unsigned char sanity[0x2000]; - -unsigned long -decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, bd_t *bp) -{ - int timer; - extern unsigned long start; - char *cp, ch; - unsigned long i; - char *dp; - -#ifdef CONFIG_8260 - /* I don't know why I didn't do it this way on the 8xx....... - */ - embed_config(bp); - serial_init(bp); -#endif - - /* These values must be variables. If not, the compiler optimizer - * will remove some code, causing the size of the code to vary - * when these values are zero. This is bad because we first - * compile with these zero to determine the size and offsets - * in an image, than compile again with these set to the proper - * discovered value.....Ya know, we used to read these from the - * header a long time ago..... - */ - initrd_offset = INITRD_OFFSET; - initrd_size = INITRD_SIZE; - - /* Grab some space for the command line and board info. Since - * we no longer use the ELF header, but it was loaded, grab - * that space. - */ -#ifdef CONFIG_MBX - cmd_line = (char *)(load_addr - 0x10000); - - /* To be like everyone else, we need one too, although this - * board information is passed from the boot rom. - */ - bp->bi_baudrate = 9600; -#else - cmd_line = (char *)(0x200000); -#endif - hold_residual = (bd_t *)(cmd_line + sizeof(cmd_buf)); - /* copy board data */ - if (bp) - memcpy(hold_residual,bp,sizeof(bd_t)); - - /* Set end of memory available to us. It is always the highest - * memory address provided by the board information. - */ - end_avail = (char *)(bp->bi_memsize); - - puts("loaded at: "); puthex(load_addr); - puts(" "); puthex((unsigned long)(load_addr + (4*num_words))); puts("\n"); - if ( (unsigned long)load_addr != (unsigned long)&start ) - { - puts("relocated to: "); puthex((unsigned long)&start); - puts(" "); - puthex((unsigned long)((unsigned long)&start + (4*num_words))); - puts("\n"); - } - - if ( bp ) - { - puts("board data at: "); puthex((unsigned long)bp); - puts(" "); - puthex((unsigned long)((unsigned long)bp + sizeof(bd_t))); - puts("\n"); - puts("relocated to: "); - puthex((unsigned long)hold_residual); - puts(" "); - puthex((unsigned long)((unsigned long)hold_residual + sizeof(bd_t))); - puts("\n"); - } - - /* we have to subtract 0x10000 here to correct for objdump including the - size of the elf header which we strip -- Cort */ - zimage_start = (char *)(load_addr - 0x10000 + ZIMAGE_OFFSET); - zimage_size = ZIMAGE_SIZE; - - if ( initrd_offset ) - initrd_start = load_addr - 0x10000 + initrd_offset; - else - initrd_start = 0; - initrd_end = initrd_size + initrd_start; - - /* - * setup avail_ram - this is the first part of ram usable - * by the uncompress code. -- Cort - */ - avail_ram = (char *)PAGE_ALIGN((unsigned long)zimage_start+zimage_size); - if ( ((load_addr+(num_words*4)) > (unsigned long) avail_ram) - && (load_addr <= 0x01000000) ) - avail_ram = (char *)(load_addr+(num_words*4)); - if ( (((unsigned long)&start+(num_words*4)) > (unsigned long) avail_ram) - && (load_addr <= 0x01000000) ) - avail_ram = (char *)((unsigned long)&start+(num_words*4)); - - /* relocate zimage */ - puts("zimage at: "); puthex((unsigned long)zimage_start); - puts(" "); puthex((unsigned long)(zimage_size+zimage_start)); puts("\n"); - /* - * There is no reason (yet) to relocate zImage for embedded boards. - * To support boot from flash rom on 8xx embedded boards, I - * assume if zimage start is over 16M we are booting from flash. - * In this case, avilable ram will start just above the space we - * have allocated for the command buffer and board information. - */ - if ((unsigned long)zimage_start > 0x01000000) - avail_ram = (char *)PAGE_ALIGN((unsigned long)hold_residual + sizeof(bd_t)); - - /* relocate initrd */ - if ( initrd_start ) - { - puts("initrd at: "); puthex(initrd_start); - puts(" "); puthex(initrd_end); puts("\n"); - - /* We only have to relocate initrd if we find it is in Flash - * rom. This is because the kernel thinks it can toss the - * pages into the free memory pool after it is done. Use - * the same 16M test. - */ - if ((unsigned long)initrd_start > 0x01000000) { - memcpy ((void *)PAGE_ALIGN(-PAGE_SIZE+(unsigned long)end_avail-INITRD_SIZE), - (void *)initrd_start, - initrd_size ); - initrd_start = PAGE_ALIGN(-PAGE_SIZE+(unsigned long)end_avail-INITRD_SIZE); - initrd_end = initrd_start + initrd_size; - end_avail = (char *)initrd_start; - puts("relocated to: "); puthex(initrd_start); - puts(" "); puthex(initrd_end); puts("\n"); - } - else { - avail_ram = (char *)PAGE_ALIGN((unsigned long)initrd_end); - } - } - - - puts("avail ram: "); puthex((unsigned long)avail_ram); puts(" "); - puthex((unsigned long)end_avail); puts("\n"); - - puts("\nLinux/PPC load: "); - timer = 0; - cp = cmd_line; - - while (timer++ < 5*1000) { - if (tstc()) { - while ((ch = getc()) != '\n' && ch != '\r') { - if (ch == '\b') { - if (cp != cmd_line) { - cp--; - puts("\b \b"); - } - } else { - *cp++ = ch; - putc(ch); - } - } - break; /* Exit 'timer' loop */ - } - udelay(1000); /* 1 msec */ - } - *cp = 0; - - /* If the command line is not filled in, we will automatically - * create the default boot. - */ - if (cmd_line[0] == 0) { - - /* An initrd on these boards means we booted from Flash - * ROM and want to use the ramdisk as the root file system. - * Otherwise, we perform a diskless NFS boot. - */ - if (initrd_start) - dp = ramroot_string; - else - dp = root_string; - while (*dp != 0) - *cp++ = *dp++; - *cp = 0; - } - - puts("\n"); - - puts("Uncompressing Linux..."); - - gunzip(0, 0x400000, zimage_start, &zimage_size); - puts("done.\n"); - puts("Now booting the kernel\n"); - return (unsigned long)hold_residual; -} - -void puthex(unsigned long val) -{ - unsigned char buf[10]; - int i; - for (i = 7; i >= 0; i--) - { - buf[i] = "0123456789ABCDEF"[val & 0x0F]; - val >>= 4; - } - buf[8] = '\0'; - puts(buf); -} - -/* - * PCI/ISA I/O support - */ - -volatile unsigned char *ISA_io = (unsigned char *)0x80000000; -volatile unsigned char *ISA_mem = (unsigned char *)0xC0000000; - -void -outb(int port, char val) -{ - /* Ensure I/O operations complete */ - __asm__ volatile("eieio"); - ISA_io[port] = val; -} - -unsigned char -inb(int port) -{ - /* Ensure I/O operations complete */ - __asm__ volatile("eieio"); - return (ISA_io[port]); -} - -unsigned long -local_to_PCI(unsigned long addr) -{ - return ((addr & 0x7FFFFFFF) | 0x80000000); -} - -void -_bcopy(char *src, char *dst, int len) -{ - while (len--) *dst++ = *src++; -} diff -Nru a/arch/ppc/mbxboot/offset b/arch/ppc/mbxboot/offset --- a/arch/ppc/mbxboot/offset Wed May 16 06:00:20 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,4 +0,0 @@ -#!/bin/bash - -OFFSET=`$1 -h $2 | grep $3 | grep -v zvmlinux| awk '{print $6}'` -echo "0x"$OFFSET diff -Nru a/arch/ppc/mbxboot/pci.c b/arch/ppc/mbxboot/pci.c --- a/arch/ppc/mbxboot/pci.c Wed May 16 06:00:22 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,252 +0,0 @@ -/* Stand alone funtions for QSpan Tundra support. - */ -#include -#include -#include -#include - -/* To map PCI devices, you first write 0xffffffff into the device - * base address registers. When the register is read back, the - * number of most significant '1' bits describes the amount of address - * space needed for mapping. If the most significant bit is not set, - * either the device does not use that address register, or it has - * a fixed address that we can't change. After the address is assigned, - * the command register has to be written to enable the card. - */ -typedef struct { - u_char pci_bus; - u_char pci_devfn; - ushort pci_command; - uint pci_addrs[6]; -} pci_map_t; - -/* We should probably dynamically allocate these structures. -*/ -#define MAX_PCI_DEVS 32 -int pci_dev_cnt; -pci_map_t pci_map[MAX_PCI_DEVS]; - -void pci_conf_write(int bus, int device, int func, int reg, uint writeval); -void pci_conf_read(int bus, int device, int func, int reg, void *readval); -void probe_addresses(int bus, int devfn); -void map_pci_addrs(void); - -/* This is a really stripped version of PCI bus scan. All we are - * looking for are devices that exist. - */ -pci_scanner(int addr_probe) -{ - unsigned int devfn, l, max, class, bus_number; - unsigned char cmd, irq, tmp, hdr_type, is_multi; - int reg; - - is_multi = 0; - bus_number = 0; - for (devfn = 0; devfn < 0xff; ++devfn) { - /* The device numbers are comprised of upper 5 bits of - * device number and lower 3 bits of multi-function number. - */ - if ((devfn & 7) && !is_multi) { - /* Don't scan multifunction addresses if this is - * not a multifunction device. - */ - continue; - } - - /* Read the header to determine card type. - */ - qs_pci_read_config_byte(bus_number, devfn, PCI_HEADER_TYPE, - &hdr_type); - - /* If this is a base device number, check the header to - * determine if it is mulifunction. - */ - if ((devfn & 7) == 0) - is_multi = hdr_type & 0x80; - - /* Check to see if the board is really in the slot. - */ - qs_pci_read_config_dword(bus_number, devfn, PCI_VENDOR_ID, &l); - /* some broken boards return 0 if a slot is empty: */ - if (l == 0xffffffff || l == 0x00000000 || l == 0x0000ffff || - l == 0xffff0000) { - /* Nothing there. - */ - is_multi = 0; - continue; - } - - /* If we are not performing an address probe, - * just simply print out some information. - */ - if (!addr_probe) { - qs_pci_read_config_dword(bus_number, devfn, - PCI_CLASS_REVISION, &class); - - class >>= 8; /* upper 3 bytes */ - -#if 0 - printf("Found (%3d:%d): vendor 0x%04x, device 0x%04x, class 0x%06x\n", - (devfn >> 3), (devfn & 7), - (l & 0xffff), (l >> 16) & 0xffff, class); -#else - puts("Found ("); puthex(devfn >> 3); - puts(":"); puthex(devfn & 7); - puts("): vendor "); puthex(l & 0xffff); - puts(", device "); puthex((l >> 16) & 0xffff); - puts(", class "); puthex(class); puts("\n"); -#endif - } - else { - /* If this is a "normal" device, build address list. - */ - if ((hdr_type & 0x7f) == PCI_HEADER_TYPE_NORMAL) - probe_addresses(bus_number, devfn); - } - } - - /* Now map the boards. - */ - if (addr_probe) - map_pci_addrs(); -} - -/* Probe addresses for the specified device. This is a destructive - * operation because it writes the registers. - */ -void -probe_addresses(bus, devfn) -{ - int i; - uint pciaddr; - ushort pcicmd; - pci_map_t *pm; - - if (pci_dev_cnt >= MAX_PCI_DEVS) { - puts("Too many PCI devices\n"); - return; - } - - pm = &pci_map[pci_dev_cnt++]; - - pm->pci_bus = bus; - pm->pci_devfn = devfn; - - for (i=0; i<6; i++) { - qs_pci_write_config_dword(bus, devfn, PCI_BASE_ADDRESS_0 + (i * 4), -1); - qs_pci_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0 + (i * 4), - &pciaddr); - pm->pci_addrs[i] = pciaddr; - qs_pci_read_config_word(bus, devfn, PCI_COMMAND, &pcicmd); - pm->pci_command = pcicmd; - } -} - -/* Map the cards into the PCI space. The PCI has separate memory - * and I/O spaces. In addition, some memory devices require mapping - * below 1M. The least significant 4 bits of the address register - * provide information. If this is an I/O device, only the LS bit - * is used to indicate that, so I/O devices can be mapped to a two byte - * boundard. Memory addresses can be mapped to a 32 byte boundary. - * The QSpan implementations usually have a 1Gbyte space for each - * memory and I/O spaces. - * - * This isn't a terribly fancy algorithm. I just map the spaces from - * the top starting with the largest address space. When finished, - * the registers are written and the card enabled. - * - * While the Tundra can map a large address space on most boards, we - * need to be careful because it may overlap other devices (like IMMR). - */ -#define MEMORY_SPACE_SIZE 0x20000000 -#define IO_SPACE_SIZE 0x20000000 - -void -map_pci_addrs() -{ - uint pci_mem_top, pci_mem_low; - uint pci_io_top; - uint addr_mask, reg_addr, space; - int i, j; - pci_map_t *pm; - - pci_mem_top = MEMORY_SPACE_SIZE; - pci_io_top = IO_SPACE_SIZE; - pci_mem_low = (1 * 1024 * 1024); /* Below one meg addresses */ - - /* We can't map anything more than the maximum space, but test - * for it anyway to catch devices out of range. - */ - addr_mask = 0x80000000; - - do { - space = (~addr_mask) + 1; /* Size of the space */ - for (i=0; ipci_addrs[j]; - if ((reg_addr & 0x80000000) == 0) - continue; - if (reg_addr & PCI_BASE_ADDRESS_SPACE_IO) { - if ((reg_addr & PCI_BASE_ADDRESS_IO_MASK) != addr_mask) - continue; - if (pci_io_top < space) { - puts("Out of PCI I/O space\n"); - } - else { - pci_io_top -= space; - pm->pci_addrs[j] = pci_io_top; - pm->pci_command |= PCI_COMMAND_IO; - } - } - else { - if ((reg_addr & PCI_BASE_ADDRESS_MEM_MASK) != addr_mask) - continue; - - /* Memory space. Test if below 1M. - */ - if (reg_addr & PCI_BASE_ADDRESS_MEM_TYPE_1M) { - if (pci_mem_low < space) { - puts("Out of PCI 1M space\n"); - } - else { - pci_mem_low -= space; - pm->pci_addrs[j] = pci_mem_low; - } - } - else { - if (pci_mem_top < space) { - puts("Out of PCI Mem space\n"); - } - else { - pci_mem_top -= space; - pm->pci_addrs[j] = pci_mem_top; - } - } - pm->pci_command |= PCI_COMMAND_MEMORY; - } - } - } - addr_mask >>= 1; - addr_mask |= 0x80000000; - } while (addr_mask != 0xfffffffe); - - /* Now, run the list one more time and map everything. - */ - for (i=0; ipci_bus, pm->pci_devfn, - PCI_BASE_ADDRESS_0 + (j * 4), pm->pci_addrs[j]); - } - - /* Enable memory or address mapping. - */ - qs_pci_write_config_word(pm->pci_bus, pm->pci_devfn, PCI_COMMAND, - pm->pci_command); - } -} - diff -Nru a/arch/ppc/mbxboot/qspan_pci.c b/arch/ppc/mbxboot/qspan_pci.c --- a/arch/ppc/mbxboot/qspan_pci.c Wed May 16 06:00:25 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,268 +0,0 @@ -/* - * LinuxPPC arch/ppc/kernel/qspan_pci.c Dan Malek (dmalek@jlc.net) - * - * QSpan Motorola bus to PCI bridge. The config address register - * is located 0x500 from the base of the bridge control/status registers. - * The data register is located at 0x504. - * This is a two step operation. First, the address register is written, - * then the data register is read/written as required. - * I don't know what to do about interrupts (yet). - */ - -#include -#include -#include -#include - -/* - * When reading the configuration space, if something does not respond - * the bus times out and we get a machine check interrupt. So, the - * good ol' exception tables come to mind to trap it and return some - * value. - * - * On an error we just return a -1, since that is what the caller wants - * returned if nothing is present. I copied this from __get_user_asm, - * with the only difference of returning -1 instead of EFAULT. - * There is an associated hack in the machine check trap code. - * - * The QSPAN is also a big endian device, that is it makes the PCI - * look big endian to us. This presents a problem for the Linux PCI - * functions, which assume little endian. For example, we see the - * first 32-bit word like this: - * ------------------------ - * | Device ID | Vendor ID | - * ------------------------ - * If we read/write as a double word, that's OK. But in our world, - * when read as a word, device ID is at location 0, not location 2 as - * the little endian PCI would believe. We have to switch bits in - * the PCI addresses given to us to get the data to/from the correct - * byte lanes. - * - * The QSPAN only supports 4 bits of "slot" in the dev_fn instead of 5. - * It always forces the MS bit to zero. Therefore, dev_fn values - * greater than 128 are returned as "no device found" errors. - * - * The QSPAN can only perform long word (32-bit) configuration cycles. - * The "offset" must have the two LS bits set to zero. Read operations - * require we read the entire word and then sort out what should be - * returned. Write operations other than long word require that we - * read the long word, update the proper word or byte, then write the - * entire long word back. - * - * PCI Bridge hack. We assume (correctly) that bus 0 is the primary - * PCI bus from the QSPAN. If we are called with a bus number other - * than zero, we create a Type 1 configuration access that a downstream - * PCI bridge will interpret. - */ - -#define __get_pci_config(x, addr, op) \ - __asm__ __volatile__( \ - "1: "op" %0,0(%1)\n" \ - " eieio\n" \ - "2:\n" \ - ".section .fixup,\"ax\"\n" \ - "3: li %0,-1\n" \ - " b 2b\n" \ - ".section __ex_table,\"a\"\n" \ - " .align 2\n" \ - " .long 1b,3b\n" \ - ".text" \ - : "=r"(x) : "r"(addr)) - -#define QS_CONFIG_ADDR ((volatile uint *)(PCI_CSR_ADDR + 0x500)) -#define QS_CONFIG_DATA ((volatile uint *)(PCI_CSR_ADDR + 0x504)) - -#define mk_config_addr(bus, dev, offset) \ - (((bus)<<16) | ((dev)<<8) | (offset & 0xfc)) - -#define mk_config_type1(bus, dev, offset) \ - mk_config_addr(bus, dev, offset) | 1; - -/* Initialize the QSpan device registers after power up. -*/ -qspan_init() -{ - uint *qptr; - - - - qptr = (uint *)PCI_CSR_ADDR; - - /* PCI Configuration/status. Upper bits written to clear - * pending interrupt or status. Lower bits enable QSPAN as - * PCI master, enable memory and I/O cycles, and enable PCI - * parity error checking. - * IMPORTANT: The last two bits of this word enable PCI - * master cycles into the QBus. The QSpan is broken and can't - * meet the timing specs of the PQ bus for this to work. Therefore, - * if you don't have external bus arbitration, you can't use - * this function. - */ -#ifdef EXTERNAL_PQ_ARB - qptr[1] = 0xf9000147; -#else - qptr[1] = 0xf9000144; -#endif - - /* PCI Misc configuration. Set PCI latency timer resolution - * of 8 cycles, set cache size to 4 x 32. - */ - qptr[3] = 0; - - /* Set up PCI Target address mapping. Enable, Posted writes, - * 2Gbyte space (processor memory controller determines actual size). - */ - qptr[64] = 0x8f000080; - - /* Map processor 0x80000000 to PCI 0x00000000. - * Processor address bit 1 determines I/O type access (0x80000000) - * or memory type access (0xc0000000). - */ - qptr[65] = 0x80000000; - - /* Enable error logging and clear any pending error status. - */ - qptr[80] = 0x90000000; - - qptr[512] = 0x000c0003; - - /* Set up Qbus slave image. - */ - qptr[960] = 0x01000000; - qptr[961] = 0x000000d1; - qptr[964] = 0x00000000; - qptr[965] = 0x000000d1; - -} - -/* Functions to support PCI bios-like features to read/write configuration - * space. If the function fails for any reason, a -1 (0xffffffff) value - * must be returned. - */ -#define DEVICE_NOT_FOUND (-1) -#define SUCCESSFUL 0 - -int qs_pci_read_config_byte(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned char *val) -{ - uint temp; - u_char *cp; - - if ((bus > 7) || (dev_fn > 127)) { - *val = 0xff; - return DEVICE_NOT_FOUND; - } - - if (bus == 0) - *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset); - else - *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset); - __get_pci_config(temp, QS_CONFIG_DATA, "lwz"); - - offset ^= 0x03; - cp = ((u_char *)&temp) + (offset & 0x03); - *val = *cp; - return SUCCESSFUL; -} - -int qs_pci_read_config_word(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned short *val) -{ - uint temp; - ushort *sp; - - if ((bus > 7) || (dev_fn > 127)) { - *val = 0xffff; - return DEVICE_NOT_FOUND; - } - - if (bus == 0) - *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset); - else - *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset); - __get_pci_config(temp, QS_CONFIG_DATA, "lwz"); - offset ^= 0x02; - - sp = ((ushort *)&temp) + ((offset >> 1) & 1); - *val = *sp; - return SUCCESSFUL; -} - -int qs_pci_read_config_dword(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned int *val) -{ - if ((bus > 7) || (dev_fn > 127)) { - *val = 0xffffffff; - return DEVICE_NOT_FOUND; - } - if (bus == 0) - *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset); - else - *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset); - __get_pci_config(*val, QS_CONFIG_DATA, "lwz"); - return SUCCESSFUL; -} - -int qs_pci_write_config_byte(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned char val) -{ - uint temp; - u_char *cp; - - if ((bus > 7) || (dev_fn > 127)) - return DEVICE_NOT_FOUND; - - qs_pci_read_config_dword(bus, dev_fn, offset, &temp); - - offset ^= 0x03; - cp = ((u_char *)&temp) + (offset & 0x03); - *cp = val; - - if (bus == 0) - *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset); - else - *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset); - *QS_CONFIG_DATA = temp; - - return SUCCESSFUL; -} - -int qs_pci_write_config_word(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned short val) -{ - uint temp; - ushort *sp; - - if ((bus > 7) || (dev_fn > 127)) - return DEVICE_NOT_FOUND; - - qs_pci_read_config_dword(bus, dev_fn, offset, &temp); - - offset ^= 0x02; - sp = ((ushort *)&temp) + ((offset >> 1) & 1); - *sp = val; - - if (bus == 0) - *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset); - else - *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset); - *QS_CONFIG_DATA = temp; - - return SUCCESSFUL; -} - -int qs_pci_write_config_dword(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned int val) -{ - if ((bus > 7) || (dev_fn > 127)) - return DEVICE_NOT_FOUND; - - if (bus == 0) - *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset); - else - *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset); - *(unsigned int *)QS_CONFIG_DATA = val; - - return SUCCESSFUL; -} - diff -Nru a/arch/ppc/mbxboot/rdimage.c b/arch/ppc/mbxboot/rdimage.c --- a/arch/ppc/mbxboot/rdimage.c Wed May 16 06:00:18 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,8 +0,0 @@ -/* - * rdimage.c - * - * Dummy file to allow a compressed initrd to be added - * into a linker section, accessed by the boot coode - */ - -char dummy_for_rdimage; diff -Nru a/arch/ppc/mbxboot/size b/arch/ppc/mbxboot/size --- a/arch/ppc/mbxboot/size Wed May 16 06:00:19 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,4 +0,0 @@ -#!/bin/bash - -OFFSET=`$1 -h $2 | grep $3 | grep -v zvmlinux | awk '{print $3}'` -echo "0x"$OFFSET diff -Nru a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c --- a/arch/ppc/mm/init.c Wed May 16 06:00:17 2001 +++ b/arch/ppc/mm/init.c Wed May 16 06:00:17 2001 @@ -46,7 +46,6 @@ #include #include #include -#include #include #ifdef CONFIG_8xx #include @@ -61,6 +60,8 @@ #include #include #include +#include +#include #include "mem_pieces.h" @@ -93,7 +94,6 @@ extern char __pmac_begin, __pmac_end; extern char __apus_begin, __apus_end; extern char __openfirmware_begin, __openfirmware_end; -struct device_node *memory_node; unsigned long ioremap_base; unsigned long ioremap_bot; unsigned long avail_start; @@ -111,19 +111,6 @@ void MMU_init(void); void *early_get_page(void); -unsigned long prep_find_end_of_memory(void); -unsigned long pmac_find_end_of_memory(void); -unsigned long apus_find_end_of_memory(void); -extern unsigned long find_end_of_memory(void); -#ifdef CONFIG_8xx -unsigned long m8xx_find_end_of_memory(void); -#endif /* CONFIG_8xx */ -#ifdef CONFIG_4xx -unsigned long oak_find_end_of_memory(void); -#endif -#ifdef CONFIG_8260 -unsigned long m8260_find_end_of_memory(void); -#endif /* CONFIG_8260 */ static void mapin_ram(void); int map_page(unsigned long va, unsigned long pa, int flags); void set_phys_avail(unsigned long total_ram); @@ -436,11 +423,9 @@ * Should check if it is a candidate for a BAT mapping */ - spin_lock(&init_mm.page_table_lock); err = 0; for (i = 0; i < size && err == 0; i += PAGE_SIZE) err = map_page(v+i, p+i, flags); - spin_unlock(&init_mm.page_table_lock); if (err) { if (mem_init_done) vfree((void *)v); @@ -487,17 +472,21 @@ { pmd_t *pd; pte_t *pg; + int err = -ENOMEM; + spin_lock(&init_mm.page_table_lock); /* Use upper 10 bits of VA to index the first level map */ pd = pmd_offset(pgd_offset_k(va), va); /* Use middle 10 bits of VA to index the second-level map */ pg = pte_alloc(&init_mm, pd, va); - if (pg == 0) - return -ENOMEM; - set_pte(pg, mk_pte_phys(pa & PAGE_MASK, __pgprot(flags))); - if (mem_init_done) - flush_hash_page(0, va); - return 0; + if (pg != 0) { + err = 0; + set_pte(pg, mk_pte_phys(pa & PAGE_MASK, __pgprot(flags))); + if (mem_init_done) + flush_hash_page(0, va); + } + spin_unlock(&init_mm.page_table_lock); + return err; } #ifndef CONFIG_8xx @@ -668,33 +657,6 @@ } #if !defined(CONFIG_4xx) && !defined(CONFIG_8xx) -static void get_mem_prop(char *, struct mem_pieces *); - -#if defined(CONFIG_ALL_PPC) -/* - * Read in a property describing some pieces of memory. - */ - -static void __init get_mem_prop(char *name, struct mem_pieces *mp) -{ - struct reg_property *rp; - int s; - - rp = (struct reg_property *) get_property(memory_node, name, &s); - if (rp == NULL) { - printk(KERN_ERR "error: couldn't get %s property on /memory\n", - name); - abort(); - } - mp->n_regions = s / sizeof(mp->regions[0]); - memcpy(mp->regions, rp, s); - - /* Make sure the pieces are sorted. */ - mem_pieces_sort(mp); - mem_pieces_coalesce(mp); -} -#endif /* CONFIG_ALL_PPC */ - /* * Set up one of the I/D BAT (block address translation) register pairs. * The parameters are not checked; in particular size must be a power @@ -877,14 +839,13 @@ #ifdef CONFIG_BLK_DEV_INITRD void free_initrd_mem(unsigned long start, unsigned long end) { - printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10); - for (; start < end; start += PAGE_SIZE) { ClearPageReserved(virt_to_page(start)); set_page_count(virt_to_page(start), 1); free_page(start); totalram_pages++; } + printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10); } #endif @@ -904,27 +865,28 @@ /* * The Zone Protection Register (ZPR) defines how protection will * be applied to every page which is a member of a given zone. At - * present, we utilize only two of the 4xx's zones. The first, zone - * 0, is set at '00b and only allows access in supervisor-mode based - * on the EX and WR bits. No user-mode access is allowed. The second, - * zone 1, is set at '10b and in supervisor-mode allows access - * without regard to the EX and WR bits. In user-mode, access is - * allowed based on the EX and WR bits. + * present, we utilize only two of the 4xx's zones. + * The zone index bits (of ZSEL) in the PTE are used for software + * indicators, except the LSB. For user access, zone 15 is used, + * for kernel access, zone 14 is used. We set all but zone 15 + * to zero, allowing only kernel access as indicated in the PTE. + * For zone 15, we set a 10 binary (I guess a 01 would work too) + * to allow user access as indicated in the PTE. This also allows + * kernel access as indicated in the PTE. */ - mtspr(SPRN_ZPR, 0x2aaaaaaa); + mtspr(SPRN_ZPR, 0x00000002); - /* Hardwire any TLB entries necessary here. */ - - PPC4xx_tlb_pin(KERNELBASE, 0, TLB_PAGESZ(PAGESZ_16M), 1); + flush_instruction_cache(); /* * Find the top of physical memory and map all of it in starting * at KERNELBASE. */ - total_memory = total_lowmem = oak_find_end_of_memory(); - end_of_DRAM = __va(total_memory); + total_memory = total_lowmem = ppc_md.find_end_of_memory(); + end_of_DRAM = __va(total_lowmem); + set_phys_avail(total_lowmem); mapin_ram(); /* @@ -943,70 +905,13 @@ mtspr(SPRN_ICCR, 0x80000000); /* 128 MB of instr. space at 0x0. */ } -#elif defined(CONFIG_8xx) +#else /* !CONFIG_4xx */ void __init MMU_init(void) { if ( ppc_md.progress ) ppc_md.progress("MMU:enter", 0x111); - total_memory = total_lowmem = m8xx_find_end_of_memory(); -#ifdef CONFIG_HIGHMEM - if (total_lowmem > MAX_LOW_MEM) { - total_lowmem = MAX_LOW_MEM; - mem_pieces_remove(&phys_avail, total_lowmem, - total_memory - total_lowmem, 0); - } -#endif /* CONFIG_HIGHMEM */ - end_of_DRAM = __va(total_lowmem); - set_phys_avail(total_lowmem); - - /* Map in all of RAM starting at KERNELBASE */ - mapin_ram(); + total_memory = ppc_md.find_end_of_memory(); - /* Now map in some of the I/O space that is generically needed - * or shared with multiple devices. - * All of this fits into the same 4Mbyte region, so it only - * requires one page table page. - */ - ioremap(IMAP_ADDR, IMAP_SIZE); -#ifdef CONFIG_MBX - ioremap(NVRAM_ADDR, NVRAM_SIZE); - ioremap(MBX_CSR_ADDR, MBX_CSR_SIZE); - ioremap(PCI_CSR_ADDR, PCI_CSR_SIZE); - - /* Map some of the PCI/ISA I/O space to get the IDE interface. - */ - ioremap(PCI_ISA_IO_ADDR, 0x4000); - ioremap(PCI_IDE_ADDR, 0x4000); -#endif -#ifdef CONFIG_RPXLITE - ioremap(RPX_CSR_ADDR, RPX_CSR_SIZE); - ioremap(HIOX_CSR_ADDR, HIOX_CSR_SIZE); -#endif -#ifdef CONFIG_RPXCLASSIC - ioremap(PCI_CSR_ADDR, PCI_CSR_SIZE); - ioremap(RPX_CSR_ADDR, RPX_CSR_SIZE); -#endif - if ( ppc_md.progress ) ppc_md.progress("MMU:exit", 0x211); -} - -#else /* not 4xx or 8xx */ -void __init MMU_init(void) -{ - if ( ppc_md.progress ) ppc_md.progress("MMU:enter", 0x111); - - if (have_of) - total_memory = pmac_find_end_of_memory(); -#ifdef CONFIG_APUS - else if (_machine == _MACH_apus ) - total_memory = apus_find_end_of_memory(); -#endif -#if defined(CONFIG_8260) - else - total_memory = m8260_find_end_of_memory(); -#else - else /* prep */ - total_memory = prep_find_end_of_memory(); -#endif if (__max_memory && total_memory > __max_memory) total_memory = __max_memory; total_lowmem = total_memory; @@ -1019,6 +924,7 @@ end_of_DRAM = __va(total_lowmem); set_phys_avail(total_lowmem); +#if !defined(CONFIG_8xx) if ( ppc_md.progress ) ppc_md.progress("MMU:hash init", 0x300); hash_init(); #ifndef CONFIG_PPC64BRIDGE @@ -1026,16 +932,49 @@ #endif ioremap_base = 0xf8000000; +#endif /* CONFIG_8xx */ if ( ppc_md.progress ) ppc_md.progress("MMU:mapin", 0x301); /* Map in all of RAM starting at KERNELBASE */ mapin_ram(); -#ifdef CONFIG_POWER4 +#if defined(CONFIG_POWER4) ioremap_base = ioremap_bot = 0xfffff000; isa_io_base = (unsigned long) ioremap(0xffd00000, 0x200000) + 0x100000; -#else /* CONFIG_POWER4 */ +#elif defined(CONFIG_8xx) + /* Now map in some of the I/O space that is generically needed + * or shared with multiple devices. + * All of this fits into the same 4Mbyte region, so it only + * requires one page table page. + */ + ioremap(IMAP_ADDR, IMAP_SIZE); +#ifdef CONFIG_MBX + ioremap(NVRAM_ADDR, NVRAM_SIZE); + ioremap(MBX_CSR_ADDR, MBX_CSR_SIZE); + ioremap(PCI_CSR_ADDR, PCI_CSR_SIZE); + + /* Map some of the PCI/ISA I/O space to get the IDE interface. + */ + ioremap(PCI_ISA_IO_ADDR, 0x4000); + ioremap(PCI_IDE_ADDR, 0x4000); +#endif +#if defined(CONFIG_RPXLITE) || defined(CONFIG_RPXCLASSIC) + ioremap(RPX_CSR_ADDR, RPX_CSR_SIZE); +#if !defined(CONFIG_PCI) + ioremap(_IO_BASE,_IO_BASE_SIZE); +#endif +#endif +#ifdef CONFIG_HTDMSOUND + ioremap(HIOX_CSR_ADDR, HIOX_CSR_SIZE); +#endif +#ifdef CONFIG_FADS + ioremap(BCSR_ADDR, BCSR_SIZE); +#endif +#ifdef CONFIG_PCI + ioremap(PCI_CSR_ADDR, PCI_CSR_SIZE); +#endif +#else /* !CONFIG_POWER4 && !CONFIG_8xx */ /* * Setup the bat mappings we're going to load that cover * the io areas. RAM was mapped by mapin_ram(). @@ -1069,6 +1008,33 @@ /* Map chip and ZorroII memory */ setbat(1, zTwoBase, 0x00000000, 0x01000000, IO_PAGE); break; + case _MACH_gemini: + setbat(0, 0xf0000000, 0xf0000000, 0x10000000, IO_PAGE); + setbat(1, 0x80000000, 0x80000000, 0x10000000, IO_PAGE); + break; + case _MACH_k2: + setbat(0, 0x80000000, 0x80000000, 0x10000000, IO_PAGE); + setbat(1, 0xff000000, 0xff000000, 0x01000000, IO_PAGE); + ioremap_base = 0xff000000; + break; + case _MACH_mvme5100: + setbat(0, 0xf0000000, 0xf0000000, 0x10000000, IO_PAGE); + setbat(1, 0x80000000, 0x80000000, 0x10000000, IO_PAGE); + ioremap_base = 0xf0000000; + break; + case _MACH_prpmc750: + setbat(0, 0x80000000, 0x80000000, 0x10000000, IO_PAGE); + setbat(1, 0xf0000000, 0xc0000000, 0x08000000, IO_PAGE); + setbat(3, 0xf8000000, 0xf8000000, 0x08000000, IO_PAGE); + ioremap_base = 0xf0000000; + break; + case _MACH_spruce: + setbat(0, SPRUCE_PCI_MEM_BASE, SPRUCE_PCI_PHY_MEM_BASE, + 0x10000000, IO_PAGE); + setbat(1, SPRUCE_PCI_IO_BASE, SPRUCE_PCI_PHY_IO_BASE, + 0x10000000, IO_PAGE); + ioremap_base = SPRUCE_PCI_PHY_MEM_BASE; + break; case _MACH_8260: /* Map the IMMR, plus anything else we can cover * in that upper space according to the memory controller @@ -1081,7 +1047,7 @@ break; } ioremap_bot = ioremap_base; -#endif /* CONFIG_POWER4 */ +#endif /* CONFIG_POWER4 || CONFIG_8xx */ if ( ppc_md.progress ) ppc_md.progress("MMU:exit", 0x211); #ifdef CONFIG_BOOTX_TEXT @@ -1257,155 +1223,6 @@ } #if !defined(CONFIG_4xx) && !defined(CONFIG_8xx) -#if defined(CONFIG_ALL_PPC) -/* - * On systems with Open Firmware, collect information about - * physical RAM and which pieces are already in use. - * At this point, we have (at least) the first 8MB mapped with a BAT. - * Our text, data, bss use something over 1MB, starting at 0. - * Open Firmware may be using 1MB at the 4MB point. - */ -unsigned long __init pmac_find_end_of_memory(void) -{ - unsigned long a, total; - struct mem_pieces phys_mem; - - memory_node = find_devices("memory"); - if (memory_node == NULL) { - printk(KERN_ERR "can't find memory node\n"); - abort(); - } - - /* - * Find out where physical memory is, and check that it - * starts at 0 and is contiguous. It seems that RAM is - * always physically contiguous on Power Macintoshes. - * - * Supporting discontiguous physical memory isn't hard, - * it just makes the virtual <-> physical mapping functions - * more complicated (or else you end up wasting space - * in mem_map). - */ - get_mem_prop("reg", &phys_mem); - if (phys_mem.n_regions == 0) - panic("No RAM??"); - a = phys_mem.regions[0].address; - if (a != 0) - panic("RAM doesn't start at physical address 0"); - total = phys_mem.regions[0].size; - - if (phys_mem.n_regions > 1) { - printk("RAM starting at 0x%x is not contiguous\n", - phys_mem.regions[1].address); - printk("Using RAM from 0 to 0x%lx\n", total-1); - } - - return total; -} -#endif /* CONFIG_ALL_PPC */ - -#if defined(CONFIG_ALL_PPC) -/* - * This finds the amount of physical ram and does necessary - * setup for prep. This is pretty architecture specific so - * this will likely stay separate from the pmac. - * -- Cort - */ -unsigned long __init prep_find_end_of_memory(void) -{ - unsigned long total; -#ifdef CONFIG_PREP_RESIDUAL - total = res->TotalMemory; -#else - total = 0; -#endif - - if (total == 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"); - total = 0x02000000; - printk("Ramsize default to be %ldM\n", total>>20); - } - - return (total); -} -#endif /* defined(CONFIG_ALL_PPC) */ - -#ifdef CONFIG_8260 -/* - * Same hack as 8xx. - */ -unsigned long __init m8260_find_end_of_memory(void) -{ - bd_t *binfo; - extern unsigned char __res[]; - - binfo = (bd_t *)__res; - - return binfo->bi_memsize; -} -#endif /* CONFIG_8260 */ - -#ifdef CONFIG_APUS -#define HARDWARE_MAPPED_SIZE (512*1024) -unsigned long __init apus_find_end_of_memory(void) -{ - int shadow = 0; - unsigned long total; - - /* The memory size reported by ADOS excludes the 512KB - reserved for PPC exception registers and possibly 512KB - containing a shadow of the ADOS ROM. */ - { - unsigned long size = memory[0].size; - - /* If 2MB aligned, size was probably user - specified. We can't tell anything about shadowing - in this case so skip shadow assignment. */ - if (0 != (size & 0x1fffff)){ - /* Align to 512KB to ensure correct handling - of both memfile and system specified - sizes. */ - size = ((size+0x0007ffff) & 0xfff80000); - /* If memory is 1MB aligned, assume - shadowing. */ - shadow = !(size & 0x80000); - } - - /* Add the chunk that ADOS does not see. by aligning - the size to the nearest 2MB limit upwards. */ - memory[0].size = ((size+0x001fffff) & 0xffe00000); - } - - total = memory[0].size; - - /* Remove the memory chunks that are controlled by special - Phase5 hardware. */ - - /* Remove the upper 512KB if it contains a shadow of - the ADOS ROM. FIXME: It might be possible to - disable this shadow HW. Check the booter - (ppc_boot.c) */ - if (shadow) - total -= HARDWARE_MAPPED_SIZE; - - /* Remove the upper 512KB where the PPC exception - vectors are mapped. */ - total -= HARDWARE_MAPPED_SIZE; - - /* Linux/APUS only handles one block of memory -- the one on - the PowerUP board. Other system memory is horrible slow in - comparison. The user can use other memory for swapping - using the z2ram device. */ - ram_phys_base = memory[0].addr; - return total; -} -#endif /* CONFIG_APUS */ - /* * Initialize the hash table and patch the instructions in head.S. */ @@ -1514,43 +1331,7 @@ } if ( ppc_md.progress ) ppc_md.progress("hash:done", 0x205); } -#elif defined(CONFIG_8xx) -/* - * This is a big hack right now, but it may turn into something real - * someday. - * - * For the 8xx boards (at this time anyway), there is nothing to initialize - * associated the PROM. Rather than include all of the prom.c - * functions in the image just to get prom_init, all we really need right - * now is the initialization of the physical memory region. - */ -unsigned long __init m8xx_find_end_of_memory(void) -{ - bd_t *binfo; - extern unsigned char __res[]; - - binfo = (bd_t *)__res; - - return binfo->bi_memsize; -} #endif /* !CONFIG_4xx && !CONFIG_8xx */ - -#ifdef CONFIG_OAK -/* - * Return the virtual address representing the top of physical RAM - * on the Oak board. - */ -unsigned long __init -oak_find_end_of_memory(void) -{ - extern unsigned char __res[]; - - unsigned long *ret; - bd_t *bip = (bd_t *)__res; - - return bip->bi_memsize; -} -#endif /* * Set phys_avail to the amount of physical memory, diff -Nru a/arch/ppc/treeboot/Makefile b/arch/ppc/treeboot/Makefile --- a/arch/ppc/treeboot/Makefile Wed May 16 06:00:21 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,57 +0,0 @@ -# -# Copyright (c) 1999 Grant Erickson -# -# Module name: Makefile -# -# Description: -# Makefile for the IBM "tree" evaluation board Linux kernel -# boot loaders. -# - -HOSTCFLAGS = -O -I$(TOPDIR)/include - -GZIP = gzip -vf9 -RM = rm -f -MKEVIMG = mkevimg -l -MKIRIMG = mkirimg - -CFLAGS = -O -fno-builtin -I$(TOPDIR)/include -LD_ARGS = -e _start -T ld.script -Ttext 0x00200000 -Bstatic - -OBJS = crt0.o main.o misc.o irSect.o ../coffboot/string.o ../coffboot/zlib.o -LIBS = - -treeboot: $(OBJS) ld.script - $(LD) -o $@ $(LD_ARGS) $(OBJS) $(LIBS) - -zImage: vmlinux.img - -zImage.initrd: vmlinux.initrd.img - -treeboot.image: treeboot vmlinux.gz - $(OBJCOPY) --add-section=image=vmlinux.gz treeboot $@ - -treeboot.initrd: treeboot.image ramdisk.image.gz - $(OBJCOPY) --add-section=initrd=ramdisk.image.gz treeboot.image $@ - -vmlinux.img: treeboot.image - $(OBJDUMP) --syms treeboot.image | grep irSectStart > irSectStart.txt - $(MKIRIMG) treeboot.image treeboot.image.out irSectStart.txt - $(MKEVIMG) treeboot.image.out $@ - $(RM) treeboot.image treeboot.image.out irSectStart.txt - -vmlinux.initrd.img: treeboot.initrd - $(OBJDUMP) --all-headers treeboot.initrd | grep irSectStart > irSectStart.txt - $(MKIRIMG) treeboot.initrd treeboot.initrd.out irSectStart.txt - $(MKEVIMG) treeboot.initrd.out $@ - $(RM) treeboot.initrd treeboot.initrd.out irSectStart.txt - -vmlinux.gz: $(TOPDIR)/vmlinux - $(OBJCOPY) -S -O binary $(TOPDIR)/vmlinux vmlinux - $(GZIP) vmlinux - -clean: - rm -f treeboot treeboot.image treeboot.initrd irSectStart.txt vmlinux.* *.o - -fastdep: - diff -Nru a/arch/ppc/treeboot/crt0.S b/arch/ppc/treeboot/crt0.S --- a/arch/ppc/treeboot/crt0.S Wed May 16 06:00:25 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,70 +0,0 @@ -/* - * Copyright (c) 1997 Paul Mackerras - * Initial Power Macintosh COFF version. - * Copyright (c) 1999 Grant Erickson - * Modifications for IBM PowerPC 400-class processor evaluation - * boards. - * - * Module name: crt0.S - * - * Description: - * Boot loader execution entry point. Clears out .bss section as per - * ANSI C requirements. Invalidates and flushes the caches over the - * range covered by the boot loader's .text section. Sets up a stack - * below the .text section entry point. - * - * 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 "../kernel/ppc_asm.tmpl" - - .text - - .globl _start -_start: - ## Clear out the BSS as per ANSI C requirements - - lis r7,_end@ha # - addi r7,r7,_end@l # r7 = &_end - lis r8,__bss_start@ha # - addi r8,r8,__bss_start@l # r8 = &_bss_start - - ## Determine how large an area, in number of words, to clear - - subf r7,r8,r7 # r7 = &_end - &_bss_start + 1 - addi r7,r7,3 # r7 += 3 - srwi. r7,r7,2 # r7 = size in words. - beq 2f # If the size is zero, do not bother - addi r8,r8,-4 # r8 -= 4 - mtctr r7 # SPRN_CTR = number of words to clear - li r0,0 # r0 = 0 -1: stwu r0,4(r8) # Clear out a word - bdnz 1b # If we are not done yet, keep clearing - - ## Flush and invalidate the caches for the range in memory covering - ## the .text section of the boot loader - -2: lis r9,_start@h # r9 = &_start - lis r8,_etext@ha # - addi r8,r8,_etext@l # r8 = &_etext -3: dcbf r0,r9 # Flush the data cache - icbi r0,r9 # Invalidate the instruction cache - addi r9,r9,0x10 # Increment by one cache line - cmplwi cr0,r9,r8 # Are we at the end yet? - blt 3b # No, keep flushing and invalidating - - ## Set up the stack - - lis r9,_start@h # r9 = &_start (text section entry) - addi r9,r9,_start@l - subi r1,r9,64 # Start the stack 64 bytes below _start - clrrwi r1,r1,4 # Make sure it is aligned on 16 bytes. - li r0,0 - stwu r0,-16(r1) - mtlr r9 - - b start # All done, start the real work. diff -Nru a/arch/ppc/treeboot/elf.pl b/arch/ppc/treeboot/elf.pl --- a/arch/ppc/treeboot/elf.pl Wed May 16 06:00:22 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,33 +0,0 @@ -# -# ELF header field numbers -# - -$e_ident = 0; # Identification bytes / magic number -$e_type = 1; # ELF file type -$e_machine = 2; # Target machine type -$e_version = 3; # File version -$e_entry = 4; # Start address -$e_phoff = 5; # Program header file offset -$e_shoff = 6; # Section header file offset -$e_flags = 7; # File flags -$e_ehsize = 8; # Size of ELF header -$e_phentsize = 9; # Size of program header -$e_phnum = 10; # Number of program header entries -$e_shentsize = 11; # Size of section header -$e_shnum = 12; # Number of section header entries -$e_shstrndx = 13; # Section header table string index - -# -# Section header field numbers -# - -$sh_name = 0; # Section name -$sh_type = 1; # Section header type -$sh_flags = 2; # Section header flags -$sh_addr = 3; # Virtual address -$sh_offset = 4; # File offset -$sh_size = 5; # Section size -$sh_link = 6; # Miscellaneous info -$sh_info = 7; # More miscellaneous info -$sh_addralign = 8; # Memory alignment -$sh_entsize = 9; # Entry size if this is a table diff -Nru a/arch/ppc/treeboot/irSect.c b/arch/ppc/treeboot/irSect.c --- a/arch/ppc/treeboot/irSect.c Wed May 16 06:00:25 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,36 +0,0 @@ -/* - * - * Copyright (c) 1999 Grant Erickson - * - * Module name: irSect.c - * - * Description: - * Defines variables to hold the absolute starting address and size - * of the Linux kernel "image" and the initial RAM disk "initrd" - * sections within the boot loader. - * - */ - -#include "irSect.h" - - -/* - * The order of globals below must not change. If more globals are added, - * you must change the script 'mkirimg' accordingly. - * - */ - -/* - * irSectStart must be at beginning of file - */ -unsigned int irSectStart = 0xdeadbeaf; - -unsigned int imageSect_start = 0; -unsigned int imageSect_size = 0; -unsigned int initrdSect_start = 0; -unsigned int initrdSect_size = 0; - -/* - * irSectEnd must be at end of file - */ -unsigned int irSectEnd = 0xdeadbeaf; diff -Nru a/arch/ppc/treeboot/irSect.h b/arch/ppc/treeboot/irSect.h --- a/arch/ppc/treeboot/irSect.h Wed May 16 06:00:24 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,32 +0,0 @@ -/* - * - * Copyright (c) 1999 Grant Erickson - * - * Module name: irSect.h - * - * Description: - * Defines variables to hold the absolute starting address and size - * of the Linux kernel "image" and the initial RAM disk "initrd" - * sections within the boot loader. - * - */ - -#ifndef __IRSECT_H__ -#define __IRSECT_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -extern unsigned int imageSect_start; -extern unsigned int imageSect_size; - -extern unsigned int initrdSect_start; -extern unsigned int initrdSect_size; - - -#ifdef __cplusplus -} -#endif - -#endif /* __IRSECT_H__ */ diff -Nru a/arch/ppc/treeboot/ld.script b/arch/ppc/treeboot/ld.script --- a/arch/ppc/treeboot/ld.script Wed May 16 06:00:16 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,68 +0,0 @@ -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 = .); -} - diff -Nru a/arch/ppc/treeboot/main.c b/arch/ppc/treeboot/main.c --- a/arch/ppc/treeboot/main.c Wed May 16 06:00:18 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,240 +0,0 @@ -/* - * Copyright (c) 1997 Paul Mackerras - * Initial Power Macintosh COFF version. - * Copyright (c) 1999 Grant Erickson - * Modifications for an ELF-based IBM evaluation board version. - * - * Module name: main.c - * - * Description: - * This module does most of the real work for the boot loader. It - * checks the variables holding the absolute start address and size - * of the Linux kernel "image" and initial RAM disk "initrd" sections - * and if they are present, moves them to their "proper" locations. - * - * For the Linux kernel, "proper" is physical address 0x00000000. - * For the RAM disk, "proper" is the image's size below the top - * of physical memory. The Linux kernel may be in either raw - * binary form or compressed with GNU zip (aka gzip). - * - * 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 - -#include "../coffboot/nonstdio.h" -#include "../coffboot/zlib.h" -#include "irSect.h" - - -/* Preprocessor Defines */ - -/* - * Location of the IBM boot ROM function pointer address for retrieving - * the board information structure. - */ - -#define BOARD_INFO_VECTOR 0xFFFE0B50 - -#define RAM_SIZE (4 * 1024 * 1024) - -#define RAM_PBASE 0x00000000 -#define RAM_PEND (RAM_PBASE + RAM_SIZE) - -#define RAM_VBASE 0xC0000000 -#define RAM_VEND (RAM_VBASE + RAM_SIZE) - -#define RAM_START RAM_PBASE -#define RAM_END RAM_PEND -#define RAM_FREE (imageSect_start + imageSect_size + initrdSect_size) - -#define PROG_START RAM_START - - -/* Function Macros */ - -#define ALIGN_UP(x, align) (((x) + ((align) - 1)) & ~((align) - 1)) - - -/* Global Variables */ - -/* Needed by zalloc and zfree for allocating memory */ - -char *avail_ram; /* Indicates start of RAM available for heap */ -char *end_avail; /* Indicates end of RAM available for heap */ - -bd_t board_info; - -/* - * XXX - Until either the IBM boot ROM provides a way of passing arguments to - * the program it launches or until I/O is working in the boot loader, - * this is a good spot to pass in command line arguments to the kernel - * (e.g. console=tty0). - */ - -static char *cmdline = ""; - - -/* Function Prototypes */ - -void *zalloc(void *x, unsigned items, unsigned size); -void zfree(void *x, void *addr, unsigned nb); - -void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp); - -void printf () {} -void pause () {} -void exit () {} - - -void start(void) -{ - void *options; - int ns, oh, i; - unsigned long sa, len; - void *dst; - unsigned char *im; - unsigned long initrd_start, initrd_size; - bd_t *(*get_board_info)(void) = - (bd_t *(*)(void))(*(unsigned long *)BOARD_INFO_VECTOR); - bd_t *bip = NULL; - - if ((bip = get_board_info()) != NULL) - memcpy(&board_info, bip, sizeof(bd_t)); - - /* setup_bats(RAM_START); */ - - /* Init RAM disk (initrd) section */ - - if (initrdSect_start != 0 && (initrd_size = initrdSect_size) != 0) { - initrd_start = (RAM_END - initrd_size) & ~0xFFF; - - printf("Initial RAM disk at 0x%08x (%u bytes)\n", - initrd_start, initrd_size); - - memcpy((char *)initrd_start, - (char *)(initrdSect_start), - initrdSect_size); - - end_avail = (char *)initrd_start; - } else { - initrd_start = initrd_size = 0; - end_avail = (char *)RAM_END; - } - - /* Linux kernel image section */ - - im = (unsigned char *)(imageSect_start); - len = imageSect_size; - dst = (void *)PROG_START; - - /* Check for the gzip archive magic numbers */ - - if (im[0] == 0x1f && im[1] == 0x8b) { - - /* The gunzip routine needs everything nice and aligned */ - - void *cp = (void *)ALIGN_UP(RAM_FREE, 8); - avail_ram = (void *)(cp + ALIGN_UP(len, 8)); - memcpy(cp, im, len); - - /* I'm not sure what the 0x200000 parameter is for, but it works. */ - - gunzip(dst, 0x200000, cp, (int *)&len); - } else { - memmove(dst, im, len); - } - - flush_cache(dst, len); - - sa = (unsigned long)dst; - - (*(void (*)())sa)(&board_info, - initrd_start, - initrd_start + initrd_size, - cmdline, - cmdline + strlen(cmdline)); - - pause(); -} - -void *zalloc(void *x, unsigned items, unsigned size) -{ - void *p = avail_ram; - - size *= items; - size = ALIGN_UP(size, 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(); - } - printf("done 1\n"); - 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; - printf("doing inflate\n"); - r = inflate(&s, Z_FINISH); - printf("done inflate\n"); - if (r != Z_OK && r != Z_STREAM_END) { - printf("inflate returned %d\n", r); - exit(); - } - *lenp = s.next_out - (unsigned char *) dst; - printf("doing end\n"); - inflateEnd(&s); -} diff -Nru a/arch/ppc/treeboot/misc.S b/arch/ppc/treeboot/misc.S --- a/arch/ppc/treeboot/misc.S Wed May 16 06:00:20 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,40 +0,0 @@ -/* - * 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 "../kernel/ppc_asm.tmpl" - - .text - -/* - * Flush the dcache and invalidate the icache for a range of addresses. - * - * flush_cache(addr, len) - */ - .global flush_cache -flush_cache: - mfpvr r5 # Get processor version register - extrwi r5,r5,16,0 # Get the version bits - cmpwi cr0,r5,0x0020 # Is this a 403-based processor? - beq 1f # Yes, it is - li r5,32 # It is not a 403, set to 32 bytes - addi r4,r4,32-1 # len += line_size - 1 - srwi. r4,r4,5 # Convert from bytes to lines - b 2f -1: li r5,16 # It is a 403, set to 16 bytes - addi r4,r4,16-1 # len += line_size - 1 - srwi. r4,r4,4 # Convert from bytes to lines -2: mtctr r4 # Set-up the counter register - beqlr # If it is 0, we are done -3: dcbf r0,r3 # Flush and invalidate the data line - icbi r0,r3 # Invalidate the instruction line - add r3,r3,r5 # Move to the next line - bdnz 3b # Are we done yet? - sync - isync - blr # Return to the caller diff -Nru a/arch/ppc/treeboot/mkevimg b/arch/ppc/treeboot/mkevimg --- a/arch/ppc/treeboot/mkevimg Wed May 16 06:00:17 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,437 +0,0 @@ -#!/usr/bin/perl - -# -# Copyright (c) 1998-1999 TiVo, Inc. -# All rights reserved. -# -# Copyright (c) 1999 Grant Erickson -# Major syntactic and usability rework. -# -# Module name: mkevimg -# -# Description: -# Converts an ELF output file from the linker into the format used by -# the IBM evaluation board ROM Monitor to load programs from a host -# onto the evaluation board. The ELF file must be an otherwise execut- -# able file (with the text and data addresses bound at link time) and -# have space reserved after the entry point for the load information -# block: -# -# typedef struct boot_block { -# unsigned long magic; 0x0052504F -# unsigned long dest; Target address of the image -# unsigned long num_512blocks; Size, rounded-up, in 512 byte blocks -# unsigned long debug_flag; Run the debugger or image after load -# unsigned long entry_point; The image address to jump to after load -# unsigned long reserved[3]; -# } boot_block_t; -# -# - -use File::Basename; -use Getopt::Std; - -# -# usage() -# -# Description: -# This routine prints out the proper command line usage for this program -# -# Input(s): -# status - Flag determining what usage information will be printed and what -# the exit status of the program will be after the information is -# printed. -# -# Output(s): -# N/A -# -# Returns: -# This subroutine does not return. -# - -sub usage { - my($status); - $status = $_[0]; - - printf("Usage: %s [-hlvV] \n", - $program); - - if ($status != 0) { - printf("Try `%s -h' for more information.\n", $program); - } - - if ($status != 1) { - print(" -h Print out this message and exit.\n"); - print(" -l Linux mode; if present, copy 'image' and 'initrd' sections.\n"); - print(" -v Verbose. Print out lots of ELF information.\n"); - print(" -V Print out version information and exit.\n"); - } - - exit($status); -} - -# -# version() -# -# Description: -# This routine prints out program version information -# -# Input(s): -# N/A -# -# Output(s): -# N/A -# -# Returns: -# This subroutine does not return. -# - -sub version { - print("mkevimg Version 1.1.0\n"); - print("Copyright (c) 1998-1999 TiVo, Inc.\n"); - print("Copyright (c) 1999 Grant Erickson \n"); - - exit (0); -} - -# -# file_check() -# -# Description: -# This routine checks an input file to ensure that it exists, is a -# regular file, and is readable. -# -# Input(s): -# file - Input file to be checked. -# -# Output(s): -# N/A -# -# Returns: -# 0 if the file exists, is a regular file, and is readable, otherwise -1. -# - -sub file_check { - my($file); - $file = $_[0]; - - if (!(-e $file)) { - printf("The file \"%s\" does not exist.\n", $file); - return (-1); - } elsif (!(-f $file)) { - printf("The file \"%s\" is not a regular file.\n", $file); - return (-1); - } elsif (!(-r $file)) { - printf("The file \"%s\" is not readable.\n", $file); - return (-1); - } - - return (0); -} - -# -# decode_options() -# -# Description: -# This routine steps through the command-line arguments, parsing out -# recognzied options. -# -# Input(s): -# N/A -# -# Output(s): -# N/A -# -# Returns: -# N/A -# - -sub decode_options { - - if (!getopts("hlvV")) { - usage(1); - } - - if ($opt_h) { - usage(0); - } - - if ($opt_l) { - $linux = 1; - } - - if ($opt_V) { - version(); - exit (0); - } - - if ($opt_v) { - $verbose = 1; - } - - if (!($ifile = shift(@ARGV))) { - usage(1); - } - - if (!($ofile = shift(@ARGV))) { - usage (1); - } - - if (file_check($ifile)) { - exit(1); - } - -} - -# -# ELF file and section header field numbers -# - -require 'elf.pl'; - -# -# Main program body -# - -{ - $program = basename($0); - - decode_options(); - - open(ELF, "<$ifile") || die "Cannot open input file"; - - $ifilesize = (-s $ifile); - - if ($verbose) { - print("Output file: $ofile\n"); - print("Input file: $ifile, $ifilesize bytes.\n"); - } - - if (read(ELF, $ibuf, $ifilesize) != $ifilesize) { - print("Failed to read input file!\n"); - exit(1); - } - - # - # Parse ELF header - # - - @eh = unpack("a16n2N5n6", $ibuf); - - # - # Make sure this is actually a PowerPC ELF file. - # - - if (substr($eh[$e_ident], 0, 4) ne "\177ELF") { - printf("The file \"%s\" is not an ELF file.\n", $ifile); - exit (1); - } elsif ($eh[$e_machine] != 20) { - printf("The file \"%s\" is not a PowerPC ELF file.\n", $ifile); - exit (1); - } - - if ($verbose) { - print("File header:\n"); - printf(" Identifier: %s\n", $eh[$e_ident]); - printf(" Type: %d\n", $eh[$e_type]); - printf(" Machine: %d\n", $eh[$e_machine]); - printf(" Version: %d\n", $eh[$e_version]); - printf(" Entry point: 0x%08x\n", $eh[$e_entry]); - printf(" Program header offset: 0x%x\n", $eh[$e_phoff]); - printf(" Section header offset: 0x%x\n", $eh[$e_shoff]); - printf(" Flags: 0x%08x\n", $eh[$e_flags]); - printf(" Header size: %d\n", $eh[$e_ehsize]); - printf(" Program entry size: %d\n", $eh[$e_phentsize]); - printf(" Program table entries: %d\n", $eh[$e_phnum]); - printf(" Section header size: %d\n", $eh[$e_shentsize]); - printf(" Section table entries: %d\n", $eh[$e_shnum]); - printf(" String table section: %d\n", $eh[$e_shstrndx]); - } - - # - # Find the section header for the string table. - # - - $strtable_section_offset = $eh[$e_shoff] + - $eh[$e_shstrndx] * $eh[$e_shentsize]; - - if ($verbose) { - printf("String table section header offset: 0x%x\n", - $strtable_section_offset); - } - - # - # Find the start of the string table. - # - - @strh = unpack("N10", substr($ibuf, $strtable_section_offset, - $eh[$e_shentsize])); - - if ($verbose) { - printf("Section name strings start at: 0x%x, %d bytes.\n", - $strh[$sh_offset], $strh[$sh_size]); - } - - $names = substr($ibuf, $strh[$sh_offset], $strh[$sh_size]); - - # Grab each section header and find '.text' and '.bss' sections in - # particular. - - if ($verbose) { - print("Section headers:\n"); - print("Idx Name Size Address File off Algn\n"); - print("--- ------------------------ -------- -------- -------- ----\n"); - } - - $off = $eh[$e_shoff]; - - for($i = 0; $i < $eh[$e_shnum]; $i++, $off += $eh[$e_shentsize]) { - @sh = unpack("N10", substr($ibuf, $off, $eh[$e_shentsize])); - - # Take the first section name from the array returned by split. - - ($name) = split(/\000/, substr($names, $sh[$sh_name])); - - if ($verbose) { - printf("%3d %-24s %8x %08x %08x %4d\n", - $i, $name, $sh[$sh_size], $sh[$sh_addr], - $sh[$sh_offset], $sh[$sh_addralign]); - } - - # Attempt to find the .text and .bss sections - - if ($name =~ /^\.bss$/) { - ($bss_addr, $bss_offset, $bss_size) = - ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]); - - } elsif ($name =~ /^\.text$/) { - ($text_addr, $text_offset, $text_size) = - ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]); - - } elsif ($linux && ($name =~ /^\image$/)) { - $image_found = 1; - - ($image_addr, $image_offset, $image_size) = - ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]); - - } elsif ($linux && ($name =~ /^\initrd$/)) { - $initrd_found = 1; - - ($initrd_addr, $initrd_offset, $initrd_size) = - ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]); - - } - } - - printf("Text section - Address: 0x%08x, Size: 0x%08x\n", - $text_addr, $text_size); - printf("Bss section - Address: 0x%08x, Size: 0x%08x\n", - $bss_addr, $bss_size); - - if ($linux) { - if ($image_found) { - printf("Image section - Address: 0x%08x, Size: 0x%08x\n", - $image_addr, $image_size); - } - - if ($initrd_found) { - printf("Initrd section - Address: 0x%08x, Size: 0x%08x\n", - $initrd_addr, $initrd_size); - } - } - - # - # Open output file - # - - open(BOOT, ">$ofile") || die "Cannot open output file"; - - # - # Compute image size - # - - $output_size = $bss_offset - $text_offset + $bss_size; - - if ($linux && $image_found) { - $output_size += $image_size; - } - - if ($linux && $initrd_found) { - $output_size += $initrd_size; - } - - $num_blocks = $output_size / 512 + 1; - - # - # Write IBM PowerPC evaluation board boot_block_t header - # - - $header = pack("H8N7", "0052504f", $text_addr, $num_blocks, 0, - $text_addr, 0, 0, 0); - - $bytes = length($header); - - if (($resid = syswrite(BOOT, $header, $bytes)) != $bytes) { - die("Could not write boot image header to output file."); - } - - printf("Entry point = 0x%08x\n", $text_addr); - printf("Image size = 0x%08x (%d bytes) (%d blocks).\n", - $output_size, $output_size, $num_blocks); - - # - # Write image starting after ELF and program headers and - # continuing to beginning of bss - # - - $bytes = $bss_offset - $text_offset + $bss_size; - - if (($resid = syswrite(BOOT, $ibuf, $bytes, $text_offset)) != $bytes) { - die("Could not write boot image to output file.\n"); - } - - # - # If configured, write out the image and initrd sections as well - # - - if ($linux) { - if ($image_found) { - $bytes = $image_size; - if (($resid = syswrite(BOOT, $ibuf, $bytes, $image_offset)) != $bytes) { - die("Could not write boot image to output file.\n"); - } - } - - if ($initrd_found) { - $bytes = $initrd_size; - if (($resid = syswrite(BOOT, $ibuf, $bytes, $initrd_offset)) != $bytes) { - die("Could not write boot image to output file.\n"); - } - } - } - - # - # Pad to a multiple of 512 bytes - # - - $pad_size = 512 - (length($header) + $output_size) % 512; - - if ($verbose) { - print("Padding boot image by an additional $pad_size bytes.\n"); - } - - $pad_string = pack(("H8","deadbeef") x 128); - - syswrite(BOOT, $pad_string, $pad_size) or - die "Could not pad boot image in output file.\n"; - - # - # Clean-up and leave - # - - close(BOOT); - - print("\nBoot image file \"$ofile\" built successfully.\n\n"); - - exit(0); -} diff -Nru a/arch/ppc/treeboot/mkirimg b/arch/ppc/treeboot/mkirimg --- a/arch/ppc/treeboot/mkirimg Wed May 16 06:00:25 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,367 +0,0 @@ -#!/usr/bin/perl -# -# Copyright (c) 1998-1999 TiVo, Inc. -# Original ELF parsing code. -# -# Copyright (c) 1999 Grant Erickson -# Original code from 'mkevimg'. -# -# Module name: mkirimg -# -# Description: -# Reads an ELF file and assigns global variables 'imageSect_start', -# 'imageSect_size', 'initrdSect_start', and 'initrdSect_size' from -# the "image" and "initrd" section header information. It then -# rewrites the input ELF file with assigned globals to an output -# file. -# -# An input file, "irSectStart.txt" has the memory address of -# 'irSectStart'. The irSectStart memory address is used to find -# the global variables in the ".data" section of the ELF file. -# The 'irSectStart' and the above global variables are defined -# in "irSect.c". -# -# - -use File::Basename; -use Getopt::Std; - -# -# usage() -# -# Description: -# This routine prints out the proper command line usage for this program -# -# Input(s): -# status - Flag determining what usage information will be printed and what -# the exit status of the program will be after the information is -# printed. -# -# Output(s): -# N/A -# -# Returns: -# This subroutine does not return. -# - -sub usage { - my($status); - $status = $_[0]; - - printf("Usage: %s [-hvV] \n", - $program); - - if ($status != 0) { - printf("Try `%s -h' for more information.\n", $program); - } - - if ($status != 1) { - print(" -h Print out this message and exit.\n"); - print(" -v Verbose. Print out lots of ELF information.\n"); - print(" -V Print out version information and exit.\n"); - } - - exit($status); -} - -# -# version() -# -# Description: -# This routine prints out program version information -# -# Input(s): -# N/A -# -# Output(s): -# N/A -# -# Returns: -# This subroutine does not return. -# - -sub version { - print("mkirimg Version 1.1.0\n"); - print("Copyright (c) 1998-1999 TiVo, Inc.\n"); - print("Copyright (c) 1999 Grant Erickson \n"); - - exit (0); -} - -# -# file_check() -# -# Description: -# This routine checks an input file to ensure that it exists, is a -# regular file, and is readable. -# -# Input(s): -# file - Input file to be checked. -# -# Output(s): -# N/A -# -# Returns: -# 0 if the file exists, is a regular file, and is readable, otherwise -1. -# - -sub file_check { - my($file); - $file = $_[0]; - - if (!(-e $file)) { - printf("The file \"%s\" does not exist.\n", $file); - return (-1); - } elsif (!(-f $file)) { - printf("The file \"%s\" is not a regular file.\n", $file); - return (-1); - } elsif (!(-r $file)) { - printf("The file \"%s\" is not readable.\n", $file); - return (-1); - } - - return (0); -} - -# -# decode_options() -# -# Description: -# This routine steps through the command-line arguments, parsing out -# recognzied options. -# -# Input(s): -# N/A -# -# Output(s): -# N/A -# -# Returns: -# N/A -# - -sub decode_options { - - if (!getopts("hvV")) { - usage(1); - } - - if ($opt_h) { - usage(0); - } - - if ($opt_V) { - version(); - exit (0); - } - - if ($opt_v) { - $verbose = 1; - } - - if (!($ElfFile = shift(@ARGV))) { - usage(1); - } - - if (!($OutputFile = shift(@ARGV))) { - usage (1); - } - - if (!($IrFile = shift(@ARGV))) { - usage (1); - } - - if (file_check($ElfFile)) { - exit(1); - } - - if (file_check($IrFile)) { - exit(1); - } -} - -# -# ELF file and section header field numbers -# - -require 'elf.pl'; - -# -# Main program body -# - -{ - $program = basename($0); - decode_options(); - - open(ELF, "<$ElfFile") || die "Cannot open input file"; - open(OUTPUT, ">$OutputFile") || die "Cannot open output file"; - open(IR, "$IrFile") || die "Cannot open input file"; - - $ElfFilesize = (-s $ElfFile); - - if (read(ELF, $ibuf, $ElfFilesize) != $ElfFilesize) { - print("Failed to read ELF input file!\n"); - exit(1); - } - - if (read(IR, $irbuf, 8) != 8) { - print("Failed to read Ir input file!\n"); - exit(1); - } - - # - # Parse ELF header - # - - @eh = unpack("a16n2N5n6", $ibuf); - - # - # Make sure this is actually a PowerPC ELF file. - # - - if (substr($eh[$e_ident], 0, 4) ne "\177ELF") { - printf("The file \"%s\" is not an ELF file.\n", $ElfFile); - exit (1); - } elsif ($eh[$e_machine] != 20) { - printf("The file \"%s\" is not a PowerPC ELF file.\n", $ElfFile); - exit (1); - } - - # - # Find the section header for the string table. - # - - $strtable_section_offset = $eh[$e_shoff] + - - $eh[$e_shstrndx] * $eh[$e_shentsize]; - - if ($verbose) { - printf("String table section header offset: 0x%x\n", - $strtable_section_offset); - } - - # - # Find the start of the string table. - # - - @strh = unpack("N10", substr($ibuf, $strtable_section_offset, - $eh[$e_shentsize])); - - if ($verbose) { - printf("Section name strings start at: 0x%x, %d bytes.\n", - $strh[$sh_offset], $strh[$sh_size]); - } - - $names = substr($ibuf, $strh[$sh_offset], $strh[$sh_size]); - - # Grab each section header and find '.data', 'image', and - # 'initrd' sections in particular. - - $off = $eh[$e_shoff]; - $imageFound = 0; - $initrdFound = 0; - - for($i = 0; $i < $eh[$e_shnum]; $i++, $off += $eh[$e_shentsize]) { - @sh = unpack("N10", substr($ibuf, $off, $eh[$e_shentsize])); - - # Take the first section name from the array returned by split. - - ($name) = split(/\000/, substr($names, $sh[$sh_name])); - - # Attempt to find the .data, image, and initrd sections - - if ($name =~ /^\image$/) { - ($image_addr, $image_offset, $image_size) = - ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]); - $imageFound = 1; - - } elsif ($name =~ /^\initrd$/) { - ($initrd_addr, $initrd_offset, $initrd_size) = - ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]); - $initrdFound = 1; - - } elsif ($name =~ /^\.data$/) { - ($data_addr, $data_offset, $data_size) = - ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]); - - } elsif ($name =~ /^\.bss$/) { - ($bss_addr, $bss_offset, $bss_size) = - ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]); - - } - } - - if ($verbose) { - printf("Data section - Address: 0x%08x, Size: 0x%08x, File Offset 0x%08x\n", - $data_addr, $data_size, $data_offset); - printf("Bss section - Address: 0x%08x, Size: 0x%08x, File Offset 0x%08x\n", - $bss_addr, $bss_size, $bss_offset); - } - - if ($verbose) { - if ($imageFound) { - printf("Image section - Address: 0x%08x, Size: 0x%08x\n", - $image_addr, $image_size); - } else { - printf("Image section not found in file: $ElfFile\n"); - } - - if ($initrdFound) { - printf("Initrd section - Address: 0x%08x, Size: 0x%08x\n", - $initrd_addr, $initrd_size); - } else { - printf("Initrd section not found in file: $ElfFile\n"); - } - } - - # get file offset of irSectStart - - $irSectStartoffset = hex ($irbuf); - - if ($verbose) { - printf("irSectStartOffset Address: 0x%08x\n", $irSectStartoffset); - } - - # get the offset of global variables - - $initialOffset = ($irSectStartoffset - $data_addr) + $data_offset + 4; - - # write modified values to OUTPUT file - - syswrite(OUTPUT, $ibuf, $initialOffset); - - if ($imageFound) { - $testN = pack ("N2", $bss_addr + $bss_size, $image_size); - syswrite(OUTPUT, $testN, length($testN)); - printf("Updated symbol \"imageSect_start\" to 0x%08x\n", - $bss_addr + $bss_size); - printf("Updated symbol \"imageSect_size\" to 0x%08x\n", $image_size); - } else { - syswrite(OUTPUT, $ibuf, 8, $initialOffset); - } - - if ($initrdFound) { - $testN = pack ("N2", $bss_addr + $bss_size + $image_size, $initrd_size); - syswrite(OUTPUT, $testN, length($testN)); - printf("Updated symbol \"initrdSect_start\" to 0x%08x\n", - $bss_addr + $bss_size + $image_size); - printf("Updated symbol \"initrdSect_size\" to 0x%08x\n", $initrd_size); - } else { - syswrite(OUTPUT, $ibuf,8, $initialOffset + 8); - } - - syswrite(OUTPUT, $ibuf, $ElfFilesize - ($initialOffset + 16), - $initialOffset + 16); - - # - # Clean-up and leave - # - - close (ELF); - close (OUTPUT); - close (IR); - - exit (0); -} - diff -Nru a/arch/ppc/xmon/start.c b/arch/ppc/xmon/start.c --- a/arch/ppc/xmon/start.c Wed May 16 06:00:18 2001 +++ b/arch/ppc/xmon/start.c Wed May 16 06:00:18 2001 @@ -61,27 +61,37 @@ struct device_node *np; unsigned long addr; #ifdef CONFIG_BOOTX_TEXT - extern boot_infos_t *disp_bi; + if (!machine_is_compatible("iMac")) { + extern boot_infos_t *disp_bi; - /* see if there is a keyboard in the device tree - with a parent of type "adb" */ - for (np = find_devices("keyboard"); np; np = np->next) - if (np->parent && np->parent->type - && strcmp(np->parent->type, "adb") == 0) - break; + /* see if there is a keyboard in the device tree + with a parent of type "adb" */ + for (np = find_devices("keyboard"); np; np = np->next) + if (np->parent && np->parent->type + && strcmp(np->parent->type, "adb") == 0) + break; - /* needs to be hacked if xmon_printk is to be used - from within find_via_pmu() */ + /* needs to be hacked if xmon_printk is to be used + from within find_via_pmu() */ #ifdef CONFIG_ADB_PMU - if (np != NULL && disp_bi && find_via_pmu()) - use_screen = 1; + if (np != NULL && disp_bi && find_via_pmu()) + use_screen = 1; #endif #ifdef CONFIG_ADB_CUDA - if (np != NULL && disp_bi && find_via_cuda()) - use_screen = 1; + if (np != NULL && disp_bi && find_via_cuda()) + use_screen = 1; #endif + } + prom_drawstring("xmon uses "); if (use_screen) - prom_drawstring("xmon uses screen and keyboard\n"); + prom_drawstring("screen and keyboard\n"); + else { + if (via_modem) + prom_drawstring("modem on "); + prom_drawstring(xmon_use_sccb? "printer": "modem"); + prom_drawstring(" port\n"); + } + #endif /* CONFIG_BOOTX_TEXT */ #ifdef CHRP_ESCC @@ -100,6 +110,15 @@ base = (volatile unsigned char *) ioremap(addr & PAGE_MASK, PAGE_SIZE); sccc = base + (addr & ~PAGE_MASK); sccd = sccc + 0x10; + } + else if ( _machine & _MACH_gemini ) + { + /* should already be mapped by the kernel boot */ + sccc = (volatile unsigned char *) 0xffeffb0d; + sccd = (volatile unsigned char *) 0xffeffb08; + TXRDY = 0x20; + RXRDY = 1; + console = 1; } else { diff -Nru a/arch/ppc/xmon/start_8xx.c b/arch/ppc/xmon/start_8xx.c --- a/arch/ppc/xmon/start_8xx.c Wed May 16 06:00:20 2001 +++ b/arch/ppc/xmon/start_8xx.c Wed May 16 06:00:20 2001 @@ -15,7 +15,7 @@ #include #include #include -#include "commproc.h" +#include "../8xx_io/commproc.h" extern void xmon_printf(const char *fmt, ...); extern int xmon_8xx_write(char *str, int nb); diff -Nru a/arch/ppc/xmon/xmon.c b/arch/ppc/xmon/xmon.c --- a/arch/ppc/xmon/xmon.c Wed May 16 06:00:16 2001 +++ b/arch/ppc/xmon/xmon.c Wed May 16 06:00:16 2001 @@ -208,10 +208,11 @@ xmon_irq(int irq, void *d, struct pt_regs *regs) { unsigned long flags; - save_flags(flags);cli(); + __save_flags(flags); + __cli(); printf("Keyboard interrupt\n"); xmon(regs); - restore_flags(flags); + __restore_flags(flags); } int @@ -657,7 +658,7 @@ unsigned stack[2]; struct pt_regs regs; extern char ret_from_intercept, ret_from_syscall_1, ret_from_syscall_2; - extern char lost_irq_ret, do_bottom_half_ret, do_signal_ret; + extern char do_bottom_half_ret, do_signal_ret; extern char ret_from_except; printf("backtrace:\n"); @@ -676,7 +677,6 @@ || stack[1] == (unsigned) &ret_from_except || stack[1] == (unsigned) &ret_from_syscall_1 || stack[1] == (unsigned) &ret_from_syscall_2 - || stack[1] == (unsigned) &lost_irq_ret || stack[1] == (unsigned) &do_bottom_half_ret || stack[1] == (unsigned) &do_signal_ret) { if (mread(sp+16, ®s, sizeof(regs)) != sizeof(regs)) diff -Nru a/arch/sparc/kernel/head.S b/arch/sparc/kernel/head.S --- a/arch/sparc/kernel/head.S Wed May 16 06:00:18 2001 +++ b/arch/sparc/kernel/head.S Wed May 16 06:00:18 2001 @@ -1,4 +1,4 @@ -/* $Id: head.S,v 1.103 2000/05/09 17:40:13 davem Exp $ +/* $Id: head.S,v 1.104 2001/04/27 07:02:41 davem Exp $ * head.S: The initial boot code for the Sparc port of Linux. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) diff -Nru a/arch/sparc/kernel/irq.c b/arch/sparc/kernel/irq.c --- a/arch/sparc/kernel/irq.c Wed May 16 06:00:18 2001 +++ b/arch/sparc/kernel/irq.c Wed May 16 06:00:18 2001 @@ -1,4 +1,4 @@ -/* $Id: irq.c,v 1.111 2001/04/14 21:13:46 davem Exp $ +/* $Id: irq.c,v 1.112 2001/04/27 07:02:42 davem Exp $ * arch/sparc/kernel/irq.c: Interrupt request handling routines. On the * Sparc the IRQ's are basically 'cast in stone' * and you are supposed to probe the prom's device diff -Nru a/arch/sparc/kernel/sys_sunos.c b/arch/sparc/kernel/sys_sunos.c --- a/arch/sparc/kernel/sys_sunos.c Wed May 16 06:00:19 2001 +++ b/arch/sparc/kernel/sys_sunos.c Wed May 16 06:00:19 2001 @@ -1,4 +1,4 @@ -/* $Id: sys_sunos.c,v 1.133 2001/03/24 09:36:10 davem Exp $ +/* $Id: sys_sunos.c,v 1.134 2001/04/27 07:02:42 davem Exp $ * sys_sunos.c: SunOS specific syscall compatibility support. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) diff -Nru a/arch/sparc/prom/console.c b/arch/sparc/prom/console.c --- a/arch/sparc/prom/console.c Wed May 16 06:00:17 2001 +++ b/arch/sparc/prom/console.c Wed May 16 06:00:17 2001 @@ -1,4 +1,4 @@ -/* $Id: console.c,v 1.23 2000/08/26 02:38:03 anton Exp $ +/* $Id: console.c,v 1.24 2001/04/27 07:02:42 davem Exp $ * console.c: Routines that deal with sending and receiving IO * to/from the current console device using the PROM. * diff -Nru a/arch/sparc64/defconfig b/arch/sparc64/defconfig --- a/arch/sparc64/defconfig Wed May 16 06:00:18 2001 +++ b/arch/sparc64/defconfig Wed May 16 06:00:18 2001 @@ -311,7 +311,7 @@ CONFIG_SCSI_QLOGICPTI=m CONFIG_SCSI_AIC7XXX=m CONFIG_AIC7XXX_CMDS_PER_DEVICE=253 -CONFIG_AIC7XXX_RESET_DELAY=5000 +CONFIG_AIC7XXX_RESET_DELAY_MS=5000 CONFIG_SCSI_AIC7XXX_OLD=m CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT=y CONFIG_AIC7XXX_OLD_CMDS_PER_DEVICE=8 @@ -573,6 +573,7 @@ CONFIG_USB_STORAGE=m # CONFIG_USB_STORAGE_DEBUG is not set CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_STORAGE_DPCM=y CONFIG_USB_ACM=m CONFIG_USB_PRINTER=m diff -Nru a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c --- a/arch/sparc64/kernel/pci.c Wed May 16 06:00:16 2001 +++ b/arch/sparc64/kernel/pci.c Wed May 16 06:00:16 2001 @@ -1,4 +1,4 @@ -/* $Id: pci.c,v 1.24 2001/03/28 10:56:34 davem Exp $ +/* $Id: pci.c,v 1.25 2001/05/02 00:27:27 davem Exp $ * pci.c: UltraSparc PCI controller support. * * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com) @@ -77,13 +77,13 @@ volatile int pci_poke_faulted; /* Probe for all PCI controllers in the system. */ -extern void sabre_init(int); -extern void psycho_init(int); -extern void schizo_init(int); +extern void sabre_init(int, char *); +extern void psycho_init(int, char *); +extern void schizo_init(int, char *); static struct { char *model_name; - void (*init)(int); + void (*init)(int, char *); } pci_controller_table[] = { { "SUNW,sabre", sabre_init }, { "pci108e,a000", sabre_init }, @@ -104,7 +104,7 @@ if (!strncmp(model_name, pci_controller_table[i].model_name, namelen)) { - pci_controller_table[i].init(node); + pci_controller_table[i].init(node, model_name); return; } } diff -Nru a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c --- a/arch/sparc64/kernel/pci_psycho.c Wed May 16 06:00:25 2001 +++ b/arch/sparc64/kernel/pci_psycho.c Wed May 16 06:00:25 2001 @@ -1,4 +1,4 @@ -/* $Id: pci_psycho.c,v 1.22 2001/04/17 01:19:23 davem Exp $ +/* $Id: pci_psycho.c,v 1.23 2001/05/02 00:27:27 davem Exp $ * pci_psycho.c: PSYCHO/U2P specific PCI controller support. * * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu) @@ -1521,7 +1521,7 @@ #define PSYCHO_CONFIGSPACE 0x001000000UL -void __init psycho_init(int node) +void __init psycho_init(int node, char *model_name) { struct linux_prom64_registers pr_regs[3]; struct pci_controller_info *p; diff -Nru a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c --- a/arch/sparc64/kernel/pci_sabre.c Wed May 16 06:00:20 2001 +++ b/arch/sparc64/kernel/pci_sabre.c Wed May 16 06:00:20 2001 @@ -1,4 +1,4 @@ -/* $Id: pci_sabre.c,v 1.27 2001/04/24 05:14:12 davem Exp $ +/* $Id: pci_sabre.c,v 1.29 2001/05/02 00:32:56 davem Exp $ * pci_sabre.c: Sabre specific PCI controller support. * * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu) @@ -215,7 +215,7 @@ ((unsigned long)(DEVFN) << 8) | \ ((unsigned long)(REG))) -static int apb_present; +static int hummingbird_p; static void *sabre_pci_config_mkaddr(struct pci_pbm_info *pbm, unsigned char bus, @@ -231,7 +231,7 @@ static int sabre_out_of_range(unsigned char devfn) { - if (!apb_present) + if (hummingbird_p) return 0; return (((PCI_SLOT(devfn) == 0) && (PCI_FUNC(devfn) > 0)) || @@ -243,7 +243,7 @@ unsigned char bus, unsigned char devfn) { - if (!apb_present) + if (hummingbird_p) return 0; return ((pbm->parent == 0) || @@ -1461,12 +1461,10 @@ prom_printf("Cannot register Hummingbird's MEM space.\n"); prom_halt(); } - } else { - apb_present = 1; } } -void __init sabre_init(int pnode) +void __init sabre_init(int pnode, char *model_name) { struct linux_prom64_registers pr_regs[2]; struct pci_controller_info *p; @@ -1477,6 +1475,18 @@ u32 vdma[2]; u32 upa_portid, dma_mask; int bus; + + hummingbird_p = 0; + if (!strcmp(model_name, "pci108e,a001")) + hummingbird_p = 1; + else if (!strcmp(model_name, "SUNW,sabre")) { + char compat[64]; + + if (prom_getproperty(pnode, "compatible", + compat, sizeof(compat)) > 0 && + !strcmp(compat, "pci108e,a001")) + hummingbird_p = 1; + } p = kmalloc(sizeof(*p), GFP_ATOMIC); if (!p) { diff -Nru a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c --- a/arch/sparc64/kernel/pci_schizo.c Wed May 16 06:00:17 2001 +++ b/arch/sparc64/kernel/pci_schizo.c Wed May 16 06:00:17 2001 @@ -1,4 +1,4 @@ -/* $Id: pci_schizo.c,v 1.14 2001/04/17 01:19:23 davem Exp $ +/* $Id: pci_schizo.c,v 1.15 2001/05/02 00:27:27 davem Exp $ * pci_schizo.c: SCHIZO specific PCI controller support. * * Copyright (C) 2001 David S. Miller (davem@redhat.com) @@ -1709,7 +1709,7 @@ schizo_write(pbm_b_base + 0x2000UL, tmp); } -void __init schizo_init(int node) +void __init schizo_init(int node, char *model_name) { struct linux_prom64_registers pr_regs[3]; struct pci_controller_info *p; diff -Nru a/arch/sparc64/kernel/sys_sunos32.c b/arch/sparc64/kernel/sys_sunos32.c --- a/arch/sparc64/kernel/sys_sunos32.c Wed May 16 06:00:19 2001 +++ b/arch/sparc64/kernel/sys_sunos32.c Wed May 16 06:00:19 2001 @@ -1,4 +1,4 @@ -/* $Id: sys_sunos32.c,v 1.59 2001/03/24 09:36:11 davem Exp $ +/* $Id: sys_sunos32.c,v 1.60 2001/04/27 07:02:42 davem Exp $ * sys_sunos32.c: SunOS binary compatability layer on sparc64. * * Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu) diff -Nru a/drivers/Makefile b/drivers/Makefile --- a/drivers/Makefile Wed May 16 06:00:24 2001 +++ b/drivers/Makefile Wed May 16 06:00:24 2001 @@ -23,7 +23,7 @@ subdir-$(CONFIG_TC) += tc subdir-$(CONFIG_VT) += video subdir-$(CONFIG_MAC) += macintosh -subdir-$(CONFIG_ALL_PPC) += macintosh +subdir-$(CONFIG_PPC) += macintosh subdir-$(CONFIG_USB) += usb subdir-$(CONFIG_INPUT) += input subdir-$(CONFIG_PHONE) += telephony diff -Nru a/drivers/block/swim3.c b/drivers/block/swim3.c --- a/drivers/block/swim3.c Wed May 16 06:00:18 2001 +++ b/drivers/block/swim3.c Wed May 16 06:00:18 2001 @@ -33,6 +33,7 @@ #define MAJOR_NR FLOPPY_MAJOR #include +#include static int floppy_blocksizes[2] = {512,512}; static int floppy_sizes[2] = {2880,2880}; @@ -248,10 +249,7 @@ int swim3_init(void); #ifndef CONFIG_PMAC_PBOOK -static inline int check_media_bay(struct device_node *which_bay, int what) -{ - return 1; -} +#define check_media_bay(which, what) 1 #endif static void swim3_select(struct floppy_state *fs, int sel) @@ -1014,10 +1012,14 @@ revalidate: floppy_revalidate, }; +static devfs_handle_t floppy_devfs_handle; + int swim3_init(void) { struct device_node *swim; + floppy_devfs_handle = devfs_mk_dir(NULL, "floppy", NULL); + swim = find_devices("floppy"); while (swim && (floppy_count < MAX_FLOPPIES)) { @@ -1034,7 +1036,7 @@ if (floppy_count > 0) { - if (register_blkdev(MAJOR_NR, "fd", &floppy_fops)) { + if (devfs_register_blkdev(MAJOR_NR, "fd", &floppy_fops)) { printk(KERN_ERR "Unable to get major %d for floppy\n", MAJOR_NR); return -EBUSY; @@ -1051,7 +1053,9 @@ { struct device_node *mediabay; struct floppy_state *fs = &floppy_states[floppy_count]; - + char floppy_name[16]; + devfs_handle_t floppy_handle; + if (swim->n_addrs < 2) { printk(KERN_INFO "swim3: expecting 2 addrs (n_addrs:%d, n_intrs:%d)\n", @@ -1108,6 +1112,12 @@ printk(KERN_INFO "fd%d: SWIM3 floppy controller %s\n", floppy_count, mediabay ? "in media bay" : ""); + sprintf(floppy_name, "%s%d", floppy_devfs_handle ? "" : "floppy", + floppy_count); + floppy_handle = devfs_register(floppy_devfs_handle, floppy_name, + DEVFS_FL_DEFAULT, MAJOR_NR, floppy_count, + S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP |S_IWGRP, + &floppy_fops, NULL); floppy_count++; diff -Nru a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c --- a/drivers/cdrom/cdrom.c Wed May 16 06:00:21 2001 +++ b/drivers/cdrom/cdrom.c Wed May 16 06:00:21 2001 @@ -2626,7 +2626,8 @@ static void cdrom_sysctl_unregister(void) { - unregister_sysctl_table(cdrom_sysctl_header); + if (cdrom_sysctl_header) + unregister_sysctl_table(cdrom_sysctl_header); } #endif /* CONFIG_SYSCTL */ diff -Nru a/drivers/char/keyboard.c b/drivers/char/keyboard.c --- a/drivers/char/keyboard.c Wed May 16 06:00:17 2001 +++ b/drivers/char/keyboard.c Wed May 16 06:00:17 2001 @@ -322,7 +322,7 @@ compute_shiftstate(); kbd->slockstate = 0; /* play it safe */ #else - keysym = U(plain_map[keycode]); + keysym = U(key_maps[0][keycode]); type = KTYP(keysym); if (type == KT_SHIFT) (*key_handler[type])(keysym & 0xff, up_flag); @@ -750,7 +750,7 @@ k = i*BITS_PER_LONG; for(j=0; j */ #include @@ -61,7 +62,7 @@ #include #include -#define MXSER_VERSION "1.1kern" +#define MXSER_VERSION "1.2" #define MXSERMAJOR 174 #define MXSERCUMAJOR 175 @@ -120,7 +121,7 @@ #define CI104J_ASIC_ID 5 enum { - MXSER_BOARD_C168_ISA = 1, + MXSER_BOARD_C168_ISA = 0, MXSER_BOARD_C104_ISA, MXSER_BOARD_CI104J, MXSER_BOARD_C168_PCI, @@ -434,7 +435,7 @@ "mxser", info); if (retval) { restore_flags(flags); - printk("Board %d: %s", board, mxser_brdname[hwconf->board_type - 1]); + printk("Board %d: %s", board, mxser_brdname[hwconf->board_type]); printk(" Request irq fail,IRQ (%d) may be conflit with another device.\n", info->irq); return (retval); } @@ -455,7 +456,7 @@ unsigned int ioaddress; hwconf->board_type = board_type; - hwconf->ports = mxser_numports[board_type - 1]; + hwconf->ports = mxser_numports[board_type]; ioaddress = pci_resource_start (pdev, 2); for (i = 0; i < hwconf->ports; i++) hwconf->ioaddr[i] = ioaddress + 8 * i; @@ -544,7 +545,7 @@ if (retval != 0) printk("Found MOXA %s board (CAP=0x%x)\n", - mxser_brdname[hwconf.board_type - 1], + mxser_brdname[hwconf.board_type], ioaddr[b]); if (retval <= 0) { @@ -579,7 +580,7 @@ if (retval != 0) printk("Found MOXA %s board (CAP=0x%x)\n", - mxser_brdname[hwconf.board_type - 1], + mxser_brdname[hwconf.board_type], ioaddr[b]); if (retval <= 0) { @@ -612,21 +613,15 @@ n = sizeof(mxser_pcibrds) / sizeof(mxser_pciinfo); index = 0; - b = 0; - while (b < n) { + for (b = 0; b < n; b++) { pdev = pci_find_device(mxser_pcibrds[b].vendor_id, mxser_pcibrds[b].device_id, pdev); - if (!pdev) - { - b++; - continue; - } - if (pci_enable_device(pdev)) + if (!pdev || pci_enable_device(pdev)) continue; hwconf.pdev = pdev; printk("Found MOXA %s board(BusNo=%d,DevNo=%d)\n", - mxser_brdname[mxser_pcibrds[b].board_type - 1], - pdev->bus->number, PCI_SLOT(pdev->devfn >> 3)); + mxser_brdname[mxser_pcibrds[b].board_type], + pdev->bus->number, PCI_SLOT(pdev->devfn)); if (m >= MXSER_BOARDS) { printk("Too many Smartio family boards found (maximum %d),board not configured\n", MXSER_BOARDS); } else { @@ -1352,7 +1347,7 @@ return; if (port == 0) return; - max = mxser_numports[mxsercfg[i].board_type - 1]; + max = mxser_numports[mxsercfg[i].board_type]; while (1) { irqbits = inb(port->vector) & port->vectormask; diff -Nru a/drivers/char/serial.c b/drivers/char/serial.c --- a/drivers/char/serial.c Wed May 16 06:00:18 2001 +++ b/drivers/char/serial.c Wed May 16 06:00:18 2001 @@ -5221,6 +5221,7 @@ #endif serial_driver.major = TTY_MAJOR; serial_driver.minor_start = 64 + SERIAL_DEV_OFFSET; + serial_driver.name_base = SERIAL_DEV_OFFSET; serial_driver.num = NR_PORTS; serial_driver.type = TTY_DRIVER_TYPE_SERIAL; serial_driver.subtype = SERIAL_TYPE_NORMAL; diff -Nru a/drivers/char/tty_io.c b/drivers/char/tty_io.c --- a/drivers/char/tty_io.c Wed May 16 06:00:16 2001 +++ b/drivers/char/tty_io.c Wed May 16 06:00:16 2001 @@ -148,6 +148,7 @@ extern long serial167_console_init(void); extern void console_8xx_init(void); extern int rs_8xx_init(void); +extern void mac_scc_console_init(void); extern void hwc_console_init(void); extern void hwc_tty_init(void); extern void con3215_init(void); @@ -2184,6 +2185,8 @@ #ifdef CONFIG_SERIAL_CONSOLE #if (defined(CONFIG_8xx) || defined(CONFIG_8260)) console_8xx_init(); +#elif defined(CONFIG_MAC_SERIAL) + mac_scc_console_init(); #elif defined(CONFIG_SERIAL) serial_console_init(); #endif /* CONFIG_8xx */ diff -Nru a/drivers/ide/ide-features.c b/drivers/ide/ide-features.c --- a/drivers/ide/ide-features.c Wed May 16 06:00:16 2001 +++ b/drivers/ide/ide-features.c Wed May 16 06:00:16 2001 @@ -287,7 +287,11 @@ #if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI) byte unit = (drive->select.b.unit & 0x01); - outb(inb(hwif->dma_base+2) & ~(1<<(5+unit)), hwif->dma_base+2); + /* Some interfaces would like to use this routine, but don"t have this + * kind of DMA engine. --BenH. + */ + if (hwif->dma_base) + outb(inb(hwif->dma_base+2) & ~(1<<(5+unit)), hwif->dma_base+2); #endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */ /* @@ -356,10 +360,15 @@ drive->id->dma_1word &= ~0x0F00; #if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI) - if (speed > XFER_PIO_4) { - outb(inb(hwif->dma_base+2)|(1<<(5+unit)), hwif->dma_base+2); - } else { - outb(inb(hwif->dma_base+2) & ~(1<<(5+unit)), hwif->dma_base+2); + /* Some interfaces would like to use this routine, but don"t have this + * kind of DMA engine. --BenH. + */ + if (hwif->dma_base) { + if (speed > XFER_PIO_4) { + outb(inb(hwif->dma_base+2)|(1<<(5+unit)), hwif->dma_base+2); + } else { + outb(inb(hwif->dma_base+2) & ~(1<<(5+unit)), hwif->dma_base+2); + } } #endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */ diff -Nru a/drivers/macintosh/mac_hid.c b/drivers/macintosh/mac_hid.c --- a/drivers/macintosh/mac_hid.c Wed May 16 06:00:16 2001 +++ b/drivers/macintosh/mac_hid.c Wed May 16 06:00:16 2001 @@ -15,6 +15,7 @@ #include #include #include +#include #ifdef CONFIG_MAC_ADBKEYCODES #include @@ -401,6 +402,8 @@ return keyboard_sends_linux_keycodes; } +EXPORT_SYMBOL(mac_hid_keyboard_sends_linux_keycodes); + static int __init mac_hid_setup(char *str) { int ints[2]; @@ -448,6 +451,8 @@ return 0; } +EXPORT_SYMBOL(mac_hid_mouse_emulate_buttons); + static void emumousebtn_input_register(void) { emumousebtn.name = "Macintosh mouse button emulation"; @@ -473,9 +478,19 @@ #ifdef CONFIG_MAC_ADBKEYCODES memcpy(pc_key_maps_save, key_maps, sizeof(key_maps)); - if (!keyboard_sends_linux_keycodes) + if (!keyboard_sends_linux_keycodes) { +#ifdef CONFIG_MAGIC_SYSRQ + ppc_md.ppc_kbd_sysrq_xlate = mac_hid_kbd_sysrq_xlate; + SYSRQ_KEY = 0x69; +#endif memcpy(key_maps, mac_key_maps_save, sizeof(key_maps)); + } else { +#ifdef CONFIG_MAGIC_SYSRQ + ppc_md.ppc_kbd_sysrq_xlate = pckbd_sysrq_xlate; + SYSRQ_KEY = 0x54; #endif + } +#endif /* CONFIG_MAC_ADBKEYCODES */ #ifdef CONFIG_MAC_EMUMOUSEBTN emumousebtn_input_register(); diff -Nru a/drivers/macintosh/mac_keyb.c b/drivers/macintosh/mac_keyb.c --- a/drivers/macintosh/mac_keyb.c Wed May 16 06:00:19 2001 +++ b/drivers/macintosh/mac_keyb.c Wed May 16 06:00:19 2001 @@ -305,7 +305,7 @@ return 1; } -int mackbd_unexpected_up(unsigned char keycode) +char mackbd_unexpected_up(unsigned char keycode) { return 0x80; } diff -Nru a/drivers/macintosh/macserial.c b/drivers/macintosh/macserial.c --- a/drivers/macintosh/macserial.c Wed May 16 06:00:23 2001 +++ b/drivers/macintosh/macserial.c Wed May 16 06:00:23 2001 @@ -448,7 +448,7 @@ goto out; info->tx_active = 0; - if (info->x_char) { + if (info->x_char && !info->power_wait) { /* Send next char */ write_zsdata(info->zs_channel, info->x_char); info->x_char = 0; @@ -456,7 +456,8 @@ goto out; } - if ((info->xmit_cnt <= 0) || info->tty->stopped || info->tx_stopped) { + if ((info->xmit_cnt <= 0) || info->tty->stopped || info->tx_stopped + || info->power_wait) { write_zsreg(info->zs_channel, 0, RES_Tx_P); goto out; } @@ -474,6 +475,14 @@ restore_flags(flags); } +static void powerup_done(unsigned long data) +{ + struct mac_serial *info = (struct mac_serial *) data; + + info->power_wait = 0; + transmit_chars(info); +} + static _INLINE_ void status_handle(struct mac_serial *info) { unsigned char status; @@ -730,7 +739,7 @@ } } -static int startup(struct mac_serial * info, int can_sleep) +static int startup(struct mac_serial * info) { int delay; @@ -753,6 +762,18 @@ setup_scc(info); + if (delay) { + unsigned long flags; + + /* delay is in ms */ + save_flags(flags); + cli(); + info->power_wait = 1; + mod_timer(&info->powerup_timer, + jiffies + (delay * HZ + 999) / 1000); + restore_flags(flags); + } + OPNDBG("enabling IRQ on ttyS%d (irq %d)...\n", info->line, info->irq); info->flags |= ZILOG_INITIALIZED; @@ -761,15 +782,6 @@ enable_irq(info->rx_dma_irq); } - if (delay) { - if (can_sleep) { - /* we need to wait a bit before using the port */ - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(delay * HZ / 1000); - } else - mdelay(delay); - } - return 0; } @@ -863,7 +875,7 @@ queue_task(&tty->flip.tqueue, &tq_timer); } -static void poll_rxdma(void *private_) +static void poll_rxdma(unsigned long private_) { struct mac_serial *info = (struct mac_serial *) private_; unsigned long flags; @@ -2325,7 +2337,7 @@ * Start up serial port */ - retval = startup(info, 1); + retval = startup(info); if (retval) return retval; @@ -2426,6 +2438,10 @@ zss->rx_dma_irq = ch->intrs[2].line; spin_lock_init(&zss->rx_dma_lock); } + + init_timer(&zss->powerup_timer); + zss->powerup_timer.function = powerup_done; + zss->powerup_timer.data = (unsigned long) zss; } /* Ask the PROM how many Z8530s we have and initialize their zs_channels */ @@ -3119,7 +3135,7 @@ struct mac_serial *info = &zs_soft[i]; if (info->flags & ZILOG_SLEEPING) { info->flags &= ~ZILOG_SLEEPING; - startup(info, 0); + startup(info); } } break; diff -Nru a/drivers/macintosh/macserial.h b/drivers/macintosh/macserial.h --- a/drivers/macintosh/macserial.h Wed May 16 06:00:25 2001 +++ b/drivers/macintosh/macserial.h Wed May 16 06:00:25 2001 @@ -115,6 +115,7 @@ char is_irda; /* is connected to an IrDA codec */ unsigned char tx_active; /* character is being xmitted */ unsigned char tx_stopped; /* output is suspended */ + unsigned char power_wait; /* waiting for power-up delay to expire */ /* We need to know the current clock divisor * to read the bps rate the chip has currently @@ -186,6 +187,8 @@ void *dma_priv; struct timer_list poll_dma_timer; #define RX_DMA_TIMER (jiffies + 10*HZ/1000) + + struct timer_list powerup_timer; }; diff -Nru a/drivers/net/8139too.c b/drivers/net/8139too.c --- a/drivers/net/8139too.c Wed May 16 06:00:21 2001 +++ b/drivers/net/8139too.c Wed May 16 06:00:21 2001 @@ -149,7 +149,7 @@ #include -#define RTL8139_VERSION "0.9.16" +#define RTL8139_VERSION "0.9.17" #define MODNAME "8139too" #define RTL8139_DRIVER_NAME MODNAME " Fast Ethernet driver " RTL8139_VERSION #define PFX MODNAME ": " @@ -728,7 +728,7 @@ struct rtl8139_private *tp; u8 tmp8; int rc; - unsigned int i, have_pci_pm = 1; + unsigned int i; u32 pio_start, pio_end, pio_flags, pio_len; unsigned long mmio_start, mmio_end, mmio_flags, mmio_len; u32 tmp; @@ -770,10 +770,6 @@ DPRINTK("PIO region size == 0x%02X\n", pio_len); DPRINTK("MMIO region size == 0x%02lX\n", mmio_len); - /* ugly hueristic, but it's a chicken-and-egg problem */ - if (pio_len < RTL8139B_IO_SIZE) - have_pci_pm = 0; - #ifdef USE_IO_OPS /* make sure PCI base addr 0 is PIO */ if (!(pio_flags & IORESOURCE_IO)) { @@ -824,30 +820,7 @@ #endif /* USE_IO_OPS */ /* Bring old chips out of low-power mode. */ - if (have_pci_pm) { - u8 new_tmp8 = tmp8 = RTL_R8 (Config1); - if ((rtl_chip_info[tp->chipset].flags & HasLWake) && - (tmp8 & LWAKE)) - new_tmp8 &= ~LWAKE; - new_tmp8 |= Cfg1_PM_Enable; - if (new_tmp8 != tmp8) { - RTL_W8 (Cfg9346, Cfg9346_Unlock); - RTL_W8 (Config1, tmp8); - RTL_W8 (Cfg9346, Cfg9346_Lock); - } - if (rtl_chip_info[tp->chipset].flags & HasLWake) { - tmp8 = RTL_R8 (Config4); - if (tmp8 & LWPTN) - RTL_W8 (Config4, tmp8 & ~LWPTN); - } - } else { - RTL_W8 (HltClk, 'R'); - tmp8 = RTL_R8 (Config1); - tmp8 &= ~(SLEEP | PWRDN); - RTL_W8 (Config1, tmp8); - } - - rtl8139_chip_reset (ioaddr); + RTL_W8 (HltClk, 'R'); /* check for missing/broken hardware */ if (RTL_R32 (TxConfig) == 0xFFFFFFFF) { @@ -877,6 +850,32 @@ tp->chipset, rtl_chip_info[tp->chipset].name); + if (tp->chipset >= CH_8139B) { + u8 new_tmp8 = tmp8 = RTL_R8 (Config1); + DPRINTK("PCI PM wakeup\n"); + if ((rtl_chip_info[tp->chipset].flags & HasLWake) && + (tmp8 & LWAKE)) + new_tmp8 &= ~LWAKE; + new_tmp8 |= Cfg1_PM_Enable; + if (new_tmp8 != tmp8) { + RTL_W8 (Cfg9346, Cfg9346_Unlock); + RTL_W8 (Config1, tmp8); + RTL_W8 (Cfg9346, Cfg9346_Lock); + } + if (rtl_chip_info[tp->chipset].flags & HasLWake) { + tmp8 = RTL_R8 (Config4); + if (tmp8 & LWPTN) + RTL_W8 (Config4, tmp8 & ~LWPTN); + } + } else { + DPRINTK("Old chip wakeup\n"); + tmp8 = RTL_R8 (Config1); + tmp8 &= ~(SLEEP | PWRDN); + RTL_W8 (Config1, tmp8); + } + + rtl8139_chip_reset (ioaddr); + DPRINTK ("EXIT, returning 0\n"); *dev_out = dev; return 0; @@ -1358,11 +1357,16 @@ else if ((mii_reg5 & 0x0100) == 0x0100 || (mii_reg5 & 0x00C0) == 0x0040) tp->full_duplex = 1; - printk(KERN_INFO"%s: Setting %s%s-duplex based on" + if (mii_reg5) { + printk(KERN_INFO"%s: Setting %s%s-duplex based on" " auto-negotiated partner ability %4.4x.\n", dev->name, mii_reg5 == 0 ? "" : (mii_reg5 & 0x0180) ? "100mbps " : "10mbps ", tp->full_duplex ? "full" : "half", mii_reg5); + } else { + printk(KERN_INFO"%s: media is unconnected, link down, or incompatible connection\n", + dev->name); + } } if (tp->chipset >= CH_8139B) { @@ -1542,11 +1546,18 @@ || (mii_reg5 & 0x01C0) == 0x0040; if (tp->full_duplex != duplex) { tp->full_duplex = duplex; - printk (KERN_INFO - "%s: Setting %s-duplex based on MII #%d link" - " partner ability of %4.4x.\n", dev->name, - tp->full_duplex ? "full" : "half", - tp->phys[0], mii_reg5); + + if (mii_reg5) { + printk (KERN_INFO + "%s: Setting %s-duplex based on MII #%d link" + " partner ability of %4.4x.\n", + dev->name, + tp->full_duplex ? "full" : "half", + tp->phys[0], mii_reg5); + } else { + printk(KERN_INFO"%s: media is unconnected, link down, or incompatible connection\n", + dev->name); + } #if 0 RTL_W8 (Cfg9346, Cfg9346_Unlock); RTL_W8 (Config1, tp->full_duplex ? 0x60 : 0x20); diff -Nru a/drivers/net/Config.in b/drivers/net/Config.in --- a/drivers/net/Config.in Wed May 16 06:00:18 2001 +++ b/drivers/net/Config.in Wed May 16 06:00:18 2001 @@ -35,6 +35,9 @@ fi if [ "$CONFIG_PPC" = "y" ]; then tristate ' MACE (Power Mac ethernet) support' CONFIG_MACE + if [ "$CONFIG_MACE" != "n" ]; then + bool ' Use AAUI port instead of TP by default' CONFIG_MACE_AAUI_PORT + fi tristate ' BMAC (G3 ethernet) support' CONFIG_BMAC tristate ' GMAC (G4/iBook ethernet) support' CONFIG_GMAC tristate ' Symbios 53c885 (Synergy ethernet) support' CONFIG_NCR885E @@ -261,6 +264,9 @@ dep_bool ' Aironet 4500/4800 I365 broken support (EXPERIMENTAL)' CONFIG_AIRONET4500_I365 $CONFIG_EXPERIMENTAL fi dep_tristate ' Aironet 4500/4800 PROC interface ' CONFIG_AIRONET4500_PROC $CONFIG_AIRONET4500 m + +# New directory for Wireless LAN devices - cards above will move there + source drivers/net/wireless/Config.in fi endmenu diff -Nru a/drivers/net/Makefile b/drivers/net/Makefile --- a/drivers/net/Makefile Wed May 16 06:00:21 2001 +++ b/drivers/net/Makefile Wed May 16 06:00:21 2001 @@ -8,7 +8,7 @@ obj-n := obj- := -mod-subdirs := appletalk arcnet fc irda tokenring pcmcia wan +mod-subdirs := appletalk arcnet fc irda tokenring pcmcia wireless wan O_TARGET := net.o @@ -30,6 +30,7 @@ endif subdir-$(CONFIG_NET_PCMCIA) += pcmcia +subdir-$(CONFIG_NET_RADIO) += wireless subdir-$(CONFIG_TULIP) += tulip subdir-$(CONFIG_IRDA) += irda subdir-$(CONFIG_TR) += tokenring diff -Nru a/drivers/net/acenic_firmware.h b/drivers/net/acenic_firmware.h --- a/drivers/net/acenic_firmware.h Wed May 16 06:00:21 2001 +++ b/drivers/net/acenic_firmware.h Wed May 16 06:00:21 2001 @@ -17,7 +17,7 @@ #define tigonFwSbssLen 0x38 #define tigonFwBssAddr 0x00015dd0 #define tigonFwBssLen 0x2080 -#ifndef CONFIG_ACENIC_OMIT_TIGON_I +#ifdef CONFIG_ACENIC_OMIT_TIGON_I #define tigonFwText 0 #define tigonFwData 0 #define tigonFwRodata 0 diff -Nru a/drivers/net/bmac.c b/drivers/net/bmac.c --- a/drivers/net/bmac.c Wed May 16 06:00:19 2001 +++ b/drivers/net/bmac.c Wed May 16 06:00:19 2001 @@ -76,9 +76,6 @@ struct net_device_stats stats; struct timer_list tx_timeout; int timeout_active; - int reset_and_enabled; - int rx_allocated; - int tx_allocated; unsigned short hash_use_count[64]; unsigned short hash_table_mask[4]; struct net_device *next_bmac; @@ -126,6 +123,7 @@ }; static struct net_device *bmac_devs; +static unsigned char *bmac_emergency_rxbuf; #ifdef CONFIG_PMAC_PBOOK static int bmac_sleep_notify(struct pmu_sleep_notifier *self, int when); @@ -151,9 +149,9 @@ static int bmac_transmit_packet(struct sk_buff *skb, struct net_device *dev); static struct net_device_stats *bmac_stats(struct net_device *dev); static void bmac_set_multicast(struct net_device *dev); -static int bmac_reset_and_enable(struct net_device *dev, int enable); +static void bmac_reset_and_enable(struct net_device *dev); static void bmac_start_chip(struct net_device *dev); -static int bmac_init_chip(struct net_device *dev); +static void bmac_init_chip(struct net_device *dev); static void bmac_init_registers(struct net_device *dev); static void bmac_reset_chip(struct net_device *dev); static int bmac_set_address(struct net_device *dev, void *addr); @@ -185,17 +183,6 @@ } static void -dbdma_stop(volatile struct dbdma_regs *dmap) -{ - dbdma_st32((volatile unsigned long *)&dmap->control, - DBDMA_CLEAR(RUN) | DBDMA_SET(FLUSH)); - eieio(); - - while (dbdma_ld32((volatile unsigned long *)&dmap->status) & (ACTIVE|FLUSH)) - eieio(); -} - -static void dbdma_continue(volatile struct dbdma_regs *dmap) { dbdma_st32((volatile unsigned long *)&dmap->control, @@ -467,12 +454,11 @@ } } -static int +static void bmac_init_chip(struct net_device *dev) { bmac_init_phy(dev); bmac_init_registers(dev); - return 1; } #ifdef CONFIG_PMAC_PBOOK @@ -503,7 +489,7 @@ break; case PBOOK_WAKE: /* see if this is enough */ - bmac_reset_and_enable(bmac_devs, 1); + bmac_reset_and_enable(bmac_devs); enable_irq(bmac_devs->irq); enable_irq(bp->tx_dma_intr); enable_irq(bp->rx_dma_intr); @@ -569,9 +555,12 @@ } static void -bmac_construct_rxbuff(unsigned char *addr, volatile struct dbdma_cmd *cp) +bmac_construct_rxbuff(struct sk_buff *skb, volatile struct dbdma_cmd *cp) { - dbdma_setcmd(cp, (INPUT_LAST | INTR_ALWAYS), RX_BUFLEN, virt_to_bus(addr), 0); + unsigned char *addr = skb? skb->data: bmac_emergency_rxbuf; + + dbdma_setcmd(cp, (INPUT_LAST | INTR_ALWAYS), RX_BUFLEN, + virt_to_bus(addr), 0); } /* Bit-reverse one byte of an ethernet hardware address. */ @@ -586,7 +575,7 @@ } -static int +static void bmac_init_tx_ring(struct bmac_data *bp) { volatile struct dbdma_regs *td = bp->tx_dma; @@ -605,9 +594,6 @@ dbdma_reset(td); out_le32(&td->wait_sel, 0x00200020); out_le32(&td->cmdptr, virt_to_bus(bp->tx_cmds)); - - return 1; - } static int @@ -615,22 +601,20 @@ { volatile struct dbdma_regs *rd = bp->rx_dma; int i; + struct sk_buff *skb; /* initialize list of sk_buffs for receiving and set up recv dma */ - if (!bp->rx_allocated) { - for (i = 0; i < N_RX_RING; i++) { - bp->rx_bufs[i] = dev_alloc_skb(RX_BUFLEN+2); - if (bp->rx_bufs[i] == NULL) - return 0; - skb_reserve(bp->rx_bufs[i], 2); + memset((char *)bp->rx_cmds, 0, + (N_RX_RING + 1) * sizeof(struct dbdma_cmd)); + for (i = 0; i < N_RX_RING; i++) { + if ((skb = bp->rx_bufs[i]) == NULL) { + bp->rx_bufs[i] = skb = dev_alloc_skb(RX_BUFLEN+2); + if (skb != NULL) + skb_reserve(skb, 2); } - bp->rx_allocated = 1; + bmac_construct_rxbuff(skb, &bp->rx_cmds[i]); } - memset((char *)bp->rx_cmds, 0, (N_RX_RING+1) * sizeof(struct dbdma_cmd)); - for (i = 0; i < N_RX_RING; i++) - bmac_construct_rxbuff(bp->rx_bufs[i]->data, &bp->rx_cmds[i]); - bp->rx_empty = 0; bp->rx_fill = i; @@ -706,27 +690,36 @@ cp = &bp->rx_cmds[i]; stat = ld_le16(&cp->xfer_status); residual = ld_le16(&cp->res_count); - if ((stat & ACTIVE) == 0) break; + if ((stat & ACTIVE) == 0) + break; nb = RX_BUFLEN - residual - 2; if (nb < (ETHERMINPACKET - ETHERCRC)) { skb = NULL; bp->stats.rx_length_errors++; bp->stats.rx_errors++; - } else skb = bp->rx_bufs[i]; + } else { + skb = bp->rx_bufs[i]; + bp->rx_bufs[i] = NULL; + } if (skb != NULL) { nb -= ETHERCRC; skb_put(skb, nb); skb->dev = dev; skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - bp->rx_bufs[i] = dev_alloc_skb(RX_BUFLEN+2); - skb_reserve(bp->rx_bufs[i], 2); - bmac_construct_rxbuff(bp->rx_bufs[i]->data, &bp->rx_cmds[i]); + dev->last_rx = jiffies; ++bp->stats.rx_packets; bp->stats.rx_bytes += nb; } else { ++bp->stats.rx_dropped; } + dev->last_rx = jiffies; + if ((skb = bp->rx_bufs[i]) == NULL) { + bp->rx_bufs[i] = skb = dev_alloc_skb(RX_BUFLEN+2); + if (skb != NULL) + skb_reserve(bp->rx_bufs[i], 2); + } + bmac_construct_rxbuff(skb, &bp->rx_cmds[i]); st_le16(&cp->res_count, 0); st_le16(&cp->xfer_status, 0); last = i; @@ -772,7 +765,13 @@ if (txintcount < 10) { XXDEBUG(("bmac_txdma_xfer_stat=%#0x\n", stat)); } - if (!(stat & ACTIVE)) break; + if (!(stat & ACTIVE)) { + /* + * status field might not have been filled by DBDMA + */ + if (cp == bus_to_virt(in_le32(&bp->tx_dma->cmdptr))) + break; + } if (bp->tx_bufs[bp->tx_empty]) { ++bp->stats.tx_packets; @@ -1215,7 +1214,7 @@ } } -static int bmac_reset_and_enable(struct net_device *dev, int enable) +static void bmac_reset_and_enable(struct net_device *dev) { struct bmac_data *bp = dev->priv; unsigned long flags; @@ -1223,22 +1222,19 @@ unsigned char *data; save_flags(flags); cli(); - bp->reset_and_enabled = 0; bmac_reset_chip(dev); - if (enable) { - if (!bmac_init_tx_ring(bp) || !bmac_init_rx_ring(bp)) - return 0; - if (!bmac_init_chip(dev)) - return 0; - bmac_start_chip(dev); - bmwrite(dev, INTDISABLE, EnableNormal); - bp->reset_and_enabled = 1; - - /* - * It seems that the bmac can't receive until it's transmitted - * a packet. So we give it a dummy packet to transmit. - */ - skb = dev_alloc_skb(ETHERMINPACKET); + bmac_init_tx_ring(bp); + bmac_init_rx_ring(bp); + bmac_init_chip(dev); + bmac_start_chip(dev); + bmwrite(dev, INTDISABLE, EnableNormal); + + /* + * It seems that the bmac can't receive until it's transmitted + * a packet. So we give it a dummy packet to transmit. + */ + skb = dev_alloc_skb(ETHERMINPACKET); + if (skb != NULL) { data = skb_put(skb, ETHERMINPACKET); memset(data, 0, ETHERMINPACKET); memcpy(data, dev->dev_addr, 6); @@ -1246,13 +1242,14 @@ bmac_transmit_packet(skb, dev); } restore_flags(flags); - return 1; } static int __init bmac_probe(void) { struct device_node *bmac; + MOD_INC_USE_COUNT; + for (bmac = find_devices("bmac"); bmac != 0; bmac = bmac->next) bmac_probe1(bmac, 0); for (bmac = find_compatible_devices("network", "bmac+"); bmac != 0; @@ -1265,7 +1262,10 @@ pmu_register_sleep_notifier(&bmac_sleep_notifier); #endif } - return 0; + + MOD_DEC_USE_COUNT; + + return bmac_devs? 0: -ENODEV; } static void __init bmac_probe1(struct device_node *bmac, int is_bmac_plus) @@ -1290,6 +1290,14 @@ } } + if (bmac_emergency_rxbuf == NULL) { + bmac_emergency_rxbuf = kmalloc(RX_BUFLEN, GFP_KERNEL); + if (bmac_emergency_rxbuf == NULL) { + printk(KERN_ERR "BMAC: can't allocate emergency RX buffer\n"); + return; + } + } + dev = init_etherdev(NULL, PRIV_BYTES); if (!dev) { printk(KERN_ERR "init_etherdev failed, out of memory for BMAC %s\n", @@ -1390,9 +1398,7 @@ { /* XXDEBUG(("bmac: enter open\n")); */ /* reset the chip */ - if (!bmac_reset_and_enable(dev, 1)) - return -ENOMEM; - + bmac_reset_and_enable(dev); dev->flags |= IFF_RUNNING; return 0; } @@ -1428,7 +1434,6 @@ bp->rx_bufs[i] = NULL; } } - bp->rx_allocated = 0; XXDEBUG(("bmac: free tx bufs\n")); for (i = 0; itx_bufs[i] != NULL) { @@ -1436,7 +1441,6 @@ bp->tx_bufs[i] = NULL; } } - bp->reset_and_enabled = 0; XXDEBUG(("bmac: all bufs freed\n")); return 0; @@ -1607,6 +1611,11 @@ { struct bmac_data *bp; struct net_device *dev; + + if (bmac_emergency_rxbuf != NULL) { + kfree(bmac_emergency_rxbuf); + bmac_emergency_rxbuf = NULL; + } if (bmac_devs == 0) return; diff -Nru a/drivers/net/dmfe.c b/drivers/net/dmfe.c --- a/drivers/net/dmfe.c Wed May 16 06:00:22 2001 +++ b/drivers/net/dmfe.c Wed May 16 06:00:22 2001 @@ -1306,7 +1306,7 @@ rxptr = db->rx_insert_ptr; while (db->rx_avail_cnt < RX_DESC_CNT) { - if ((skb = alloc_skb(RX_ALLOC_SIZE, GFP_ATOMIC)) == NULL) + if ((skb = dev_alloc_skb(RX_ALLOC_SIZE)) == NULL) break; rxptr->rx_skb_ptr = (u32) skb; rxptr->rdes2 = virt_to_bus(skb->tail); diff -Nru a/drivers/net/eql.c b/drivers/net/eql.c --- a/drivers/net/eql.c Wed May 16 06:00:25 2001 +++ b/drivers/net/eql.c Wed May 16 06:00:25 2001 @@ -422,6 +422,8 @@ slave_t *s = eql_new_slave (); equalizer_t *eql = (equalizer_t *) master_dev->priv; + if (!s) + return -ENOMEM; s->dev = slave_dev; s->priority = srq.priority; s->priority_bps = srq.priority; diff -Nru a/drivers/net/gmac.c b/drivers/net/gmac.c --- a/drivers/net/gmac.c Wed May 16 06:00:21 2001 +++ b/drivers/net/gmac.c Wed May 16 06:00:21 2001 @@ -9,7 +9,7 @@ * Changes: * Arnaldo Carvalho de Melo - 08/06/2000 * - check init_etherdev return in gmac_probe1 - * BenH - 03/09/2000 + * BenH - 03/09/2000 * - Add support for new PHYs * - Add some PowerBook sleep code * @@ -47,10 +47,11 @@ #define DEBUG_PHY /* Driver version 1.3, kernel 2.4.x */ -#define GMAC_VERSION "v1.3k4" +#define GMAC_VERSION "v1.4k4" -static unsigned char dummy_buf[RX_BUF_ALLOC_SIZE + RX_OFFSET + GMAC_BUFFER_ALIGN]; -static struct net_device *gmacs = NULL; +#define DUMMY_BUF_LEN RX_BUF_ALLOC_SIZE + RX_OFFSET + GMAC_BUFFER_ALIGN +static unsigned char *dummy_buf; +static struct net_device *gmacs; /* Prototypes */ static int mii_read(struct gmac *gm, int phy, int r); @@ -62,6 +63,7 @@ static void mii_setup_phy(struct gmac *gm); static int mii_do_reset_phy(struct gmac *gm, int phy_addr); static void mii_init_BCM5400(struct gmac *gm); +static void mii_init_BCM5401(struct gmac *gm); static void gmac_set_power(struct gmac *gm, int power_up); static int gmac_powerup_and_reset(struct net_device *dev); @@ -211,10 +213,12 @@ int link_100 = 0; int gigabit = 0; #ifdef DEBUG_PHY - printk("Link state change, phy_status: 0x%04x\n", phy_status); + printk("%s: Link state change, phy_status: 0x%04x\n", + gm->dev->name, phy_status); #endif gm->phy_status = phy_status; + /* Should we enable that in generic mode ? */ lpar_ability = mii_read(gm, gm->phy_addr, MII_ANLPA); if (lpar_ability & MII_ANLPA_PAUS) GM_BIS(GM_MAC_CTRL_CONFIG, GM_MAC_CTRL_CONF_SND_PAUSE_EN); @@ -249,6 +253,9 @@ #endif full_duplex = ((stat2 & MII_LXT971_STATUS2_FULLDUPLEX) != 0); link_100 = ((stat2 & MII_LXT971_STATUS2_SPEED) != 0); + } else { + full_duplex = (lpar_ability & MII_ANLPA_FDAM) != 0; + link_100 = (lpar_ability & MII_ANLPA_100M) != 0; } #ifdef DEBUG_PHY printk(" full_duplex: %d, speed: %s\n", full_duplex, @@ -274,6 +281,144 @@ } } +/* Power management: stop PHY chip for suspend mode + */ +static void +gmac_suspend(struct gmac* gm) +{ + int data, timeout; + unsigned long flags; + + gm->sleeping = 1; + netif_stop_queue(gm->dev); + + + spin_lock_irqsave(&gm->lock, flags); + if (gm->opened) { + disable_irq(gm->dev->irq); + /* Stop polling PHY */ + mii_poll_stop(gm); + } + /* Mask out all chips interrupts */ + GM_OUT(GM_IRQ_MASK, 0xffffffff); + spin_unlock_irqrestore(&gm->lock, flags); + + if (gm->opened) { + int i; + /* Empty Tx ring of any remaining gremlins */ + gmac_tx_cleanup(gm->dev, 1); + + /* Empty Rx ring of any remaining gremlins */ + for (i = 0; i < NRX; ++i) { + if (gm->rx_buff[i] != 0) { + dev_kfree_skb_irq(gm->rx_buff[i]); + gm->rx_buff[i] = 0; + } + } + } + + /* Clear interrupts on 5201 */ + if (gm->phy_type == PHY_B5201) + mii_write(gm, gm->phy_addr, MII_BCM5201_INTERRUPT, 0); + + /* Drive MDIO high */ + GM_OUT(GM_MIF_CFG, 0); + + /* Unchanged, don't ask me why */ + data = mii_read(gm, gm->phy_addr, MII_ANLPA); + mii_write(gm, gm->phy_addr, MII_ANLPA, data); + + /* Put MDIO in sane state */ + GM_OUT(GM_MIF_CFG, GM_MIF_CFGBB); + GM_OUT(GM_MIF_BB_CLOCK, 0); + GM_OUT(GM_MIF_BB_DATA, 0); + GM_OUT(GM_MIF_BB_OUT_ENABLE, 0); + + /* Stop everything */ + GM_OUT(GM_MAC_RX_CONFIG, 0); + GM_OUT(GM_MAC_TX_CONFIG, 0); + GM_OUT(GM_MAC_XIF_CONFIG, 0); + GM_OUT(GM_TX_CONF, 0); + GM_OUT(GM_RX_CONF, 0); + + /* Set reset state */ + GM_OUT(GM_RESET, GM_RESET_TX | GM_RESET_RX); + for (timeout = 100; timeout > 0; --timeout) { + mdelay(10); + if ((GM_IN(GM_RESET) & (GM_RESET_TX | GM_RESET_RX)) == 0) + break; + } + GM_OUT(GM_MAC_TX_RESET, GM_MAC_TX_RESET_NOW); + GM_OUT(GM_MAC_RX_RESET, GM_MAC_RX_RESET_NOW); + + /* Superisolate PHY */ + if (gm->phy_type == PHY_B5201) + mii_write(gm, gm->phy_addr, MII_BCM5201_MULTIPHY, + MII_BCM5201_MULTIPHY_SUPERISOLATE); + + /* Unclock chip */ + gmac_set_power(gm, 0); +} + +static void +gmac_resume(struct gmac *gm) +{ + int data; + + if (gmac_powerup_and_reset(gm->dev)) { + printk(KERN_ERR "%s: Couldn't revive gmac ethernet !\n", gm->dev->name); + return; + } + + gm->sleeping = 0; + + if (gm->opened) { + /* Create fresh rings */ + gmac_init_rings(gm, 1); + /* re-initialize the MAC */ + gmac_mac_init(gm, gm->dev->dev_addr); + /* re-initialize the multicast tables & promisc mode if any */ + gmac_set_multicast(gm->dev); + } + + /* Early enable Tx and Rx so that we are clocked */ + GM_BIS(GM_TX_CONF, GM_TX_CONF_DMA_EN); + mdelay(20); + GM_BIS(GM_RX_CONF, GM_RX_CONF_DMA_EN); + mdelay(20); + GM_BIS(GM_MAC_TX_CONFIG, GM_MAC_TX_CONF_ENABLE); + mdelay(20); + GM_BIS(GM_MAC_RX_CONFIG, GM_MAC_RX_CONF_ENABLE); + mdelay(20); + if (gm->phy_type == PHY_B5201) { + data = mii_read(gm, gm->phy_addr, MII_BCM5201_MULTIPHY); + mii_write(gm, gm->phy_addr, MII_BCM5201_MULTIPHY, + data & ~MII_BCM5201_MULTIPHY_SUPERISOLATE); + } + mdelay(1); + + if (gm->opened) { + /* restart polling PHY */ + mii_interrupt(gm); + /* restart DMA operations */ + gmac_start_dma(gm); + netif_start_queue(gm->dev); + enable_irq(gm->dev->irq); + } else { + /* Driver not opened, just leave things off. Note that + * we could be smart and superisolate the PHY when the + * driver is closed, but I won't do that unless I have + * a better understanding of some electrical issues with + * this PHY chip --BenH + */ + GM_OUT(GM_MAC_RX_CONFIG, 0); + GM_OUT(GM_MAC_TX_CONFIG, 0); + GM_OUT(GM_MAC_XIF_CONFIG, 0); + GM_OUT(GM_TX_CONF, 0); + GM_OUT(GM_RX_CONF, 0); + } +} + static int mii_do_reset_phy(struct gmac *gm, int phy_addr) { @@ -326,6 +471,40 @@ mii_write(gm, gm->phy_addr, MII_BCM5400_AUXCONTROL, data); } +static void +mii_init_BCM5401(struct gmac *gm) +{ + int data; + int rev; + + rev = mii_read(gm, gm->phy_addr, MII_ID1) & 0x000f; + if (rev == 0 || rev == 3) { + /* A bit of black magic from Apple */ + mii_write(gm, gm->phy_addr, 0x18, 0x0c20); + mii_write(gm, gm->phy_addr, 0x17, 0x0012); + mii_write(gm, gm->phy_addr, 0x15, 0x1804); + mii_write(gm, gm->phy_addr, 0x17, 0x0013); + mii_write(gm, gm->phy_addr, 0x15, 0x1204); + mii_write(gm, gm->phy_addr, 0x17, 0x8006); + mii_write(gm, gm->phy_addr, 0x15, 0x0132); + mii_write(gm, gm->phy_addr, 0x17, 0x8006); + mii_write(gm, gm->phy_addr, 0x15, 0x0232); + mii_write(gm, gm->phy_addr, 0x17, 0x201f); + mii_write(gm, gm->phy_addr, 0x15, 0x0a20); + } + + data = mii_read(gm, gm->phy_addr, MII_BCM5400_GB_CONTROL); + data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP; + mii_write(gm, gm->phy_addr, MII_BCM5400_GB_CONTROL, data); + + mdelay(10); + mii_do_reset_phy(gm, 0x1f); + + data = mii_read(gm, 0x1f, MII_BCM5201_MULTIPHY); + data |= MII_BCM5201_MULTIPHY_SERIALMODE; + mii_write(gm, 0x1f, MII_BCM5201_MULTIPHY, data); +} + static int mii_lookup_and_reset(struct gmac *gm) { @@ -335,10 +514,7 @@ gm->phy_type = PHY_UNKNOWN; /* Hard reset the PHY */ - feature_set_gmac_phy_reset(gm->of_node, KL_GPIO_ETH_PHY_RESET_ASSERT); - mdelay(10); - feature_set_gmac_phy_reset(gm->of_node, KL_GPIO_ETH_PHY_RESET_RELEASE); - mdelay(10); + feature_gmac_phy_reset(gm->of_node); /* Find the PHY */ for(i=0; i<=31; i++) { @@ -367,14 +543,22 @@ printk(KERN_ERR "%s Found Broadcom BCM5400 PHY (Gigabit)\n", gm->dev->name); mii_init_BCM5400(gm); + } else if ((gm->phy_id & MII_BCM5401_MASK) == MII_BCM5401_ID) { + gm->phy_type = PHY_B5401; + printk(KERN_ERR "%s Found Broadcom BCM5401 PHY (Gigabit)\n", + gm->dev->name); + mii_init_BCM5401(gm); } else if ((gm->phy_id & MII_BCM5201_MASK) == MII_BCM5201_ID) { gm->phy_type = PHY_B5201; printk(KERN_INFO "%s Found Broadcom BCM5201 PHY\n", gm->dev->name); + } else if ((gm->phy_id & MII_BCM5221_MASK) == MII_BCM5221_ID) { + gm->phy_type = PHY_B5201; /* Same as 5201 for now */ + printk(KERN_INFO "%s Found Broadcom BCM5221 PHY\n", gm->dev->name); } else if ((gm->phy_id & MII_LXT971_MASK) == MII_LXT971_ID) { gm->phy_type = PHY_LXT971; printk(KERN_INFO "%s Found LevelOne LX971 PHY\n", gm->dev->name); } else { - printk(KERN_ERR "%s: Warning ! Unknown PHY ID 0x%08x !\n", + printk(KERN_ERR "%s: Warning ! Unknown PHY ID 0x%08x, using generic mode...\n", gm->dev->name, gm->phy_id); } @@ -448,8 +632,6 @@ PCI_CACHE_LINE_SIZE, 8); } } else { - /* FIXME: Add PHY power down */ - gm->phy_type = 0; feature_set_gmac_power(gm->of_node, 0); } } @@ -472,11 +654,14 @@ if ((GM_IN(GM_RESET) & (GM_RESET_TX | GM_RESET_RX)) == 0) { /* Mask out all chips interrupts */ GM_OUT(GM_IRQ_MASK, 0xffffffff); + GM_OUT(GM_MAC_TX_RESET, GM_MAC_TX_RESET_NOW); + GM_OUT(GM_MAC_RX_RESET, GM_MAC_RX_RESET_NOW); return 0; } } printk(KERN_ERR "%s reset failed!\n", dev->name); gmac_set_power(gm, 0); + gm->phy_type = 0; return -1; } @@ -747,7 +932,9 @@ int multicast_hash = 0; int multicast_all = 0; int promisc = 0; - + + if (gm->sleeping) + return; /* Lock out others. */ netif_stop_queue(dev); @@ -881,6 +1068,7 @@ /* Shut down chip */ gmac_set_power(gm, 0); + gm->phy_type = 0; /* Empty rings of any remaining gremlins */ for (i = 0; i < NRX; ++i) { @@ -904,7 +1092,6 @@ gmac_sleep_notify(struct pmu_sleep_notifier *self, int when) { struct gmac *gm; - int i; /* XXX should handle more than one */ if (gmacs == NULL) @@ -920,38 +1107,10 @@ case PBOOK_SLEEP_REJECT: break; case PBOOK_SLEEP_NOW: - disable_irq(gm->dev->irq); - netif_stop_queue(gm->dev); - gmac_stop_dma(gm); - mii_poll_stop(gm); - gmac_set_power(gm, 0); - for (i = 0; i < NRX; ++i) { - if (gm->rx_buff[i] != 0) { - dev_kfree_skb(gm->rx_buff[i]); - gm->rx_buff[i] = 0; - } - } - for (i = 0; i < NTX; ++i) { - if (gm->tx_buff[i] != 0) { - dev_kfree_skb(gm->tx_buff[i]); - gm->tx_buff[i] = 0; - } - } + gmac_suspend(gm); break; case PBOOK_WAKE: - /* see if this is enough */ - gmac_powerup_and_reset(gm->dev); - gm->full_duplex = 0; - gm->phy_status = 0; - mii_lookup_and_reset(gm); - mii_setup_phy(gm); - gmac_init_rings(gm, 0); - gmac_mac_init(gm, gm->dev->dev_addr); - gmac_set_multicast(gm->dev); - mii_interrupt(gm); - gmac_start_dma(gm); - netif_start_queue(gm->dev); - enable_irq(gm->dev->irq); + gmac_resume(gm); break; } return PBOOK_SLEEP_OK; @@ -967,7 +1126,10 @@ struct gmac *gm = (struct gmac *) dev->priv; int i, timeout; unsigned long flags; - + + if (gm->sleeping) + return; + printk (KERN_ERR "%s: transmit timed out, resetting\n", dev->name); spin_lock_irqsave(&gm->lock, flags); @@ -990,6 +1152,8 @@ if ((GM_IN(GM_RESET) & (GM_RESET_TX | GM_RESET_RX)) == 0) { /* Mask out all chips interrupts */ GM_OUT(GM_IRQ_MASK, 0xffffffff); + GM_OUT(GM_MAC_TX_RESET, GM_MAC_TX_RESET_NOW); + GM_OUT(GM_MAC_RX_RESET, GM_MAC_RX_RESET_NOW); break; } } @@ -1022,6 +1186,9 @@ unsigned long flags; int i; + if (gm->sleeping) + return 1; + spin_lock_irqsave(&gm->lock, flags); i = gm->next_tx; @@ -1274,7 +1441,7 @@ struct gmac *gm = (struct gmac *) dev->priv; struct net_device_stats *stats = &gm->stats; - if (gm && gm->opened) { + if (gm && gm->opened && !gm->sleeping) { stats->rx_crc_errors += GM_IN(GM_MAC_RX_CRC_ERR_CTR); GM_OUT(GM_MAC_RX_CRC_ERR_CTR, 0); @@ -1315,10 +1482,14 @@ gmac = gmac->next) gmac_probe1(gmac); +#ifdef CONFIG_PMAC_PBOOK + if (gmacs) + pmu_register_sleep_notifier(&gmac_sleep_notifier); +#endif MOD_DEC_USE_COUNT; - return 0; + return gmacs? 0: -ENODEV; } static void @@ -1343,6 +1514,14 @@ return; } + if (dummy_buf == NULL) { + dummy_buf = kmalloc(DUMMY_BUF_LEN, GFP_KERNEL); + if (dummy_buf == NULL) { + printk(KERN_ERR "GMAC: failed to allocated dummy buffer\n"); + return; + } + } + tx_descpage = get_free_page(GFP_KERNEL); if (tx_descpage == 0) { printk(KERN_ERR "GMAC: can't get a page for tx descriptors\n"); @@ -1351,17 +1530,13 @@ rx_descpage = get_free_page(GFP_KERNEL); if (rx_descpage == 0) { printk(KERN_ERR "GMAC: can't get a page for rx descriptors\n"); - free_page(tx_descpage); - return; + goto out_txdesc; } dev = init_etherdev(NULL, sizeof(struct gmac)); - if (!dev) { printk(KERN_ERR "GMAC: init_etherdev failed, out of memory\n"); - free_page(tx_descpage); - free_page(rx_descpage); - return; + goto out_rxdesc; } SET_MODULE_OWNER(dev); @@ -1369,6 +1544,10 @@ dev->base_addr = gmac->addrs[0].address; gm->regs = (volatile unsigned int *) ioremap(gmac->addrs[0].address, 0x10000); + if (!gm->regs) { + printk(KERN_ERR "GMAC: unable to map I/O registers\n"); + goto out_unreg; + } dev->irq = gmac->intrs[0].line; gm->dev = dev; gm->of_node = gmac; @@ -1394,6 +1573,7 @@ gm->phy_addr = 0; gm->opened = 0; + gm->sleeping = 0; dev->open = gmac_open; dev->stop = gmac_close; @@ -1404,13 +1584,18 @@ dev->watchdog_timeo = 5*HZ; ether_setup(dev); - + gm->next_gmac = gmacs; gmacs = dev; + return; -#ifdef CONFIG_PMAC_PBOOK - pmu_register_sleep_notifier(&gmac_sleep_notifier); -#endif +out_unreg: + unregister_netdev(dev); + kfree(dev); +out_rxdesc: + free_page(rx_descpage); +out_txdesc: + free_page(tx_descpage); } MODULE_AUTHOR("Paul Mackerras/Ben Herrenschmidt"); @@ -1421,16 +1606,25 @@ struct gmac *gm; struct net_device *dev; +#ifdef CONFIG_PMAC_PBOOK + if (gmacs) + pmu_unregister_sleep_notifier(&gmac_sleep_notifier); +#endif + while ((dev = gmacs) != NULL) { gm = (struct gmac *) dev->priv; unregister_netdev(dev); + iounmap((void *) gm->regs); free_page(gm->tx_desc_page); free_page(gm->rx_desc_page); gmacs = gm->next_gmac; kfree(dev); } + if (dummy_buf != NULL) { + kfree(dummy_buf); + dummy_buf = NULL; + } } module_init(gmac_probe); module_exit(gmac_cleanup_module); - diff -Nru a/drivers/net/gmac.h b/drivers/net/gmac.h --- a/drivers/net/gmac.h Wed May 16 06:00:23 2001 +++ b/drivers/net/gmac.h Wed May 16 06:00:23 2001 @@ -722,6 +722,13 @@ #define MII_ANLPA_CSMA 0x0001 /* CSMA-CD Capable */ #define MII_ANLPA_PAUS 0x0400 +/* Generic PHYs + * + * These GENERIC values assumes that the PHY devices follow 802.3u and + * allow parallel detection to set the link partner ability register. + * Detection of 100Base-TX [H/F Duplex] and 100Base-T4 is supported. + */ + /* * Model-specific PHY registers * @@ -731,6 +738,7 @@ /* Supported PHYs (phy_type field ) */ #define PHY_B5400 0x5400 +#define PHY_B5401 0x5401 #define PHY_B5201 0x5201 #define PHY_LXT971 0x0971 #define PHY_UNKNOWN 0 @@ -741,11 +749,21 @@ #define MII_BCM5201_REV 0x01 #define MII_BCM5201_ID ((MII_BCM5201_OUI << 10) | (MII_BCM5201_MODEL << 4)) #define MII_BCM5201_MASK 0xfffffff0 +#define MII_BCM5221_OUI 0x001018 +#define MII_BCM5221_MODEL 0x1e +#define MII_BCM5221_REV 0x00 +#define MII_BCM5221_ID ((MII_BCM5221_OUI << 10) | (MII_BCM5221_MODEL << 4)) +#define MII_BCM5221_MASK 0xfffffff0 #define MII_BCM5400_OUI 0x000818 #define MII_BCM5400_MODEL 0x04 #define MII_BCM5400_REV 0x01 #define MII_BCM5400_ID ((MII_BCM5400_OUI << 10) | (MII_BCM5400_MODEL << 4)) #define MII_BCM5400_MASK 0xfffffff0 +#define MII_BCM5401_OUI 0x000818 +#define MII_BCM5401_MODEL 0x05 +#define MII_BCM5401_REV 0x01 +#define MII_BCM5401_ID ((MII_BCM5401_OUI << 10) | (MII_BCM5401_MODEL << 4)) +#define MII_BCM5401_MASK 0xfffffff0 #define MII_LXT971_OUI 0x0004de #define MII_LXT971_MODEL 0x0e #define MII_LXT971_REV 0x00 @@ -791,7 +809,6 @@ #define MII_LXT971_STATUS2_AUTONEG_COMPLETE 0x0080 - /* * DMA descriptors */ @@ -877,6 +894,7 @@ u8 pci_devfn; spinlock_t lock; int opened; + int sleeping; struct net_device *next_gmac; }; diff -Nru a/drivers/net/mace.c b/drivers/net/mace.c --- a/drivers/net/mace.c Wed May 16 06:00:23 2001 +++ b/drivers/net/mace.c Wed May 16 06:00:23 2001 @@ -21,6 +21,9 @@ #include "mace.h" static struct net_device *mace_devs; +static int port_aaui = -1; + +MODULE_PARM(port_aaui, "i"); #define N_RX_RING 8 #define N_TX_RING 6 @@ -53,6 +56,7 @@ struct net_device_stats stats; struct timer_list tx_timeout; int timeout_active; + int port_aaui; struct net_device *next_mace; }; @@ -178,6 +182,21 @@ init_timer(&mp->tx_timeout); mp->timeout_active = 0; + if (port_aaui >= 0) + mp->port_aaui = port_aaui; + else { + /* Apple Network Server uses the AAUI port */ + if (machine_is_compatible("AAPL,ShinerESB")) + mp->port_aaui = 1; + else { +#ifdef CONFIG_MACE_AAUI_PORT + mp->port_aaui = 1; +#else + mp->port_aaui = 0; +#endif + } + } + dev->open = mace_open; dev->stop = mace_close; dev->hard_start_xmit = mace_xmit_start; @@ -261,7 +280,10 @@ /* done changing address */ out_8(&mb->iac, 0); - out_8(&mb->plscc, PORTSEL_GPSI + ENPLSIO); + if (mp->port_aaui) + out_8(&mb->plscc, PORTSEL_AUI + ENPLSIO); + else + out_8(&mb->plscc, PORTSEL_GPSI + ENPLSIO); } static void __mace_set_address(struct net_device *dev, void *addr) diff -Nru a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c --- a/drivers/net/ne2k-pci.c Wed May 16 06:00:19 2001 +++ b/drivers/net/ne2k-pci.c Wed May 16 06:00:19 2001 @@ -62,6 +62,8 @@ #if defined(__powerpc__) #define inl_le(addr) le32_to_cpu(inl(addr)) #define inw_le(addr) le16_to_cpu(inw(addr)) +#undef insl +#undef outsl #define insl insl_ns #define outsl outsl_ns #endif diff -Nru a/drivers/net/pcmcia/Config.in b/drivers/net/pcmcia/Config.in --- a/drivers/net/pcmcia/Config.in Wed May 16 06:00:25 2001 +++ b/drivers/net/pcmcia/Config.in Wed May 16 06:00:25 2001 @@ -26,7 +26,6 @@ bool ' Pcmcia Wireless LAN' CONFIG_NET_PCMCIA_RADIO if [ "$CONFIG_NET_PCMCIA_RADIO" = "y" ]; then dep_tristate ' Aviator/Raytheon 2.4MHz wireless support' CONFIG_PCMCIA_RAYCS $CONFIG_PCMCIA - dep_tristate ' Hermes support (Orinoco/WavelanIEEE/PrismII/Symbol 802.11b cards)' CONFIG_PCMCIA_HERMES $CONFIG_PCMCIA dep_tristate ' Xircom Netwave AirSurfer wireless support' CONFIG_PCMCIA_NETWAVE $CONFIG_PCMCIA dep_tristate ' AT&T/Lucent Wavelan wireless support' CONFIG_PCMCIA_WAVELAN $CONFIG_PCMCIA dep_tristate ' Aironet 4500/4800 PCMCIA support' CONFIG_AIRONET4500_CS $CONFIG_AIRONET4500 $CONFIG_PCMCIA diff -Nru a/drivers/net/pcmcia/Makefile b/drivers/net/pcmcia/Makefile --- a/drivers/net/pcmcia/Makefile Wed May 16 06:00:25 2001 +++ b/drivers/net/pcmcia/Makefile Wed May 16 06:00:25 2001 @@ -12,7 +12,7 @@ obj- := # Things that need to export symbols -export-objs := ray_cs.o hermes.o +export-objs := ray_cs.o # 16-bit client drivers obj-$(CONFIG_PCMCIA_3C589) += 3c589_cs.o @@ -25,7 +25,6 @@ obj-$(CONFIG_ARCNET_COM20020_CS)+= com20020_cs.o # 16-bit wireless client drivers -obj-$(CONFIG_PCMCIA_HERMES) += orinoco_cs.o hermes.o obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o obj-$(CONFIG_PCMCIA_NETWAVE) += netwave_cs.o obj-$(CONFIG_PCMCIA_WAVELAN) += wavelan_cs.o diff -Nru a/drivers/net/pcmcia/hermes.c b/drivers/net/pcmcia/hermes.c --- a/drivers/net/pcmcia/hermes.c Wed May 16 06:00:18 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,502 +0,0 @@ -/* hermes.c - * - * Driver core for the "Hermes" wireless MAC controller, as used in - * the Lucent Orinoco and Cabletron RoamAbout cards. It should also - * work on the hfa3841 and hfa3842 MAC controller chips used in the - * Prism I & II chipsets. - * - * This is not a complete driver, just low-level access routines for - * the MAC controller itself. - * - * Based on the prism2 driver from Absolute Value Systems' linux-wlan - * project, the Linux wvlan_cs driver, Lucent's HCF-Light - * (wvlan_hcf.c) library, and the NetBSD wireless driver. - * - * Copyright (C) 2000, David Gibson, Linuxcare Australia - * - * This file distributed under the GPL, version 2. - */ - -static const char *version = "hermes.c: 12 Dec 2000 David Gibson "; - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "hermes.h" - -#define CMD_BUSY_TIMEOUT (100) /* In iterations of ~1us */ -#define CMD_INIT_TIMEOUT (50000) /* in iterations of ~10us */ -#define CMD_COMPL_TIMEOUT (10000) /* in iterations of ~10us */ -#define ALLOC_COMPL_TIMEOUT (1000) /* in iterations of ~10us */ -#define BAP_BUSY_TIMEOUT (500) /* In iterations of ~1us */ -#define BAP_ERROR_RETRY (10) /* How many times to retry a BAP seek when there is an error */ - -#define MAX(a, b) ( (a) > (b) ? (a) : (b) ) -#define MIN(a, b) ( (a) < (b) ? (a) : (b) ) - -/* - * Debugging helpers - */ - -#undef HERMES_DEBUG -#ifdef HERMES_DEBUG - -#include - -#define DMSG(stuff...) do {printk(KERN_DEBUG "hermes @ 0x%x: " , hw->iobase); \ - printk(#stuff);} while (0) - -#define DEBUG(lvl, stuff...) if ( (lvl) <= HERMES_DEBUG) DMSG(#stuff) - -#else /* ! HERMES_DEBUG */ - -#define DEBUG(lvl, stuff...) do { } while (0) - -#endif /* ! HERMES_DEBUG */ - -/* - * Prototypes - */ - -static int hermes_issue_cmd(hermes_t *hw, uint16_t cmd, uint16_t param0); - -/* - * Internal inline functions - */ - -/* - * Internal functions - */ - -/* Issue a command to the chip. Waiting for it to complete is the caller's - problem. - - Returns -EBUSY if the command register is busy, 0 on success. - - Callable from any context. -*/ -static int hermes_issue_cmd(hermes_t *hw, uint16_t cmd, uint16_t param0) -{ - uint16_t reg; -/* unsigned long k = CMD_BUSY_TIMEOUT; */ - - /* First check that the command register is not busy */ - reg = hermes_read_regn(hw, CMD); - if (reg & HERMES_CMD_BUSY) { - return -EBUSY; - } - - hermes_write_regn(hw, PARAM2, 0); - hermes_write_regn(hw, PARAM1, 0); - hermes_write_regn(hw, PARAM0, param0); - hermes_write_regn(hw, CMD, cmd); - - return 0; -} - -/* - * Function definitions - */ - -void hermes_struct_init(hermes_t *hw, ushort io) -{ - hw->iobase = io; - hw->inten = 0x0; -} - -int hermes_reset(hermes_t *hw) -{ - uint16_t status, reg; - int err = 0; - int k; - - /* We don't want to be interrupted while resetting the chipset */ - hw->inten = 0x0; - hermes_write_regn(hw, INTEN, 0); - hermes_write_regn(hw, EVACK, 0xffff); - - /* Because we hope we can reset the card even if it gets into - a stupid state, we actually wait to see if the command - register will unbusy itself */ - k = CMD_BUSY_TIMEOUT; - reg = hermes_read_regn(hw, CMD); - while (k && (reg & HERMES_CMD_BUSY)) { - if (reg == 0xffff) /* Special case - the card has probably been removed, - so don't wait for the timeout */ - return -ENODEV; - - k--; - udelay(1); - reg = hermes_read_regn(hw, CMD); - } - - /* No need to explicitly handle the timeout - hermes_issue_cmd() will - probably return -EBUSY */ - - /* We don't use hermes_docmd_wait here, because the reset wipes - the magic constant in SWSUPPORT0 away, and it gets confused */ - err = hermes_issue_cmd(hw, HERMES_CMD_INIT, 0); - if (err) - return err; - - reg = hermes_read_regn(hw, EVSTAT); - k = CMD_INIT_TIMEOUT; - while ( (! (reg & HERMES_EV_CMD)) && k) { - k--; - udelay(10); - reg = hermes_read_regn(hw, EVSTAT); - } - - DEBUG(0, "Reset completed in %d iterations\n", CMD_INIT_TIMEOUT - k); - - hermes_write_regn(hw, SWSUPPORT0, HERMES_MAGIC); - - if (! hermes_present(hw)) { - DEBUG(0, "hermes @ 0x%x: Card removed during reset.\n", - hw->iobase); - err = -ENODEV; - goto out; - } - - if (! (reg & HERMES_EV_CMD)) { - printk(KERN_ERR "hermes @ 0x%x: Timeout waiting for card to reset (reg=0x%04x)!\n", - hw->iobase, reg); - err = -ETIMEDOUT; - goto out; - } - - status = hermes_read_regn(hw, STATUS); - - hermes_write_regn(hw, EVACK, HERMES_EV_CMD); - - err = status & HERMES_STATUS_RESULT; - - out: - return err; -} - -/* Issue a command to the chip, and (busy!) wait for it to - * complete. - * - * Returns: < 0 on internal error, 0 on success, > 0 on error returned by the firmware - * - * Callable from any context, but locking is your problem. */ -int hermes_docmd_wait(hermes_t *hw, uint16_t cmd, uint16_t parm0, hermes_response_t *resp) -{ - int err; - int k; - uint16_t reg; - - err = hermes_issue_cmd(hw, cmd, parm0); - if (err) { - if (! hermes_present(hw)) { - printk(KERN_WARNING "hermes @ 0x%x: Card removed while issuing command.\n", - hw->iobase); - err = -ENODEV; - } else - printk(KERN_ERR "hermes @ 0x%x: CMD register busy in hermes_issue_command().\n", - hw->iobase); - goto out; - } - - reg = hermes_read_regn(hw, EVSTAT); - k = CMD_COMPL_TIMEOUT; - while ( (! (reg & HERMES_EV_CMD)) && k) { - k--; - udelay(10); - reg = hermes_read_regn(hw, EVSTAT); - } - - if (! hermes_present(hw)) { - printk(KERN_WARNING "hermes @ 0x%x: Card removed while waiting for command completion.\n", - hw->iobase); - err = -ENODEV; - goto out; - } - - if (! (reg & HERMES_EV_CMD)) { - printk(KERN_ERR "hermes @ 0x%x: Timeout waiting for command completion.\n", - hw->iobase); - err = -ETIMEDOUT; - goto out; - } - - resp->status = hermes_read_regn(hw, STATUS); - resp->resp0 = hermes_read_regn(hw, RESP0); - resp->resp1 = hermes_read_regn(hw, RESP1); - resp->resp2 = hermes_read_regn(hw, RESP2); - - hermes_write_regn(hw, EVACK, HERMES_EV_CMD); - - err = resp->status & HERMES_STATUS_RESULT; - - out: - return err; -} - -int hermes_allocate(hermes_t *hw, uint16_t size, uint16_t *fid) -{ - int err = 0; - hermes_response_t resp; - int k; - uint16_t reg; - - if ( (size < HERMES_ALLOC_LEN_MIN) || (size > HERMES_ALLOC_LEN_MAX) ) - return -EINVAL; - - err = hermes_docmd_wait(hw, HERMES_CMD_ALLOC, size, &resp); - if (err) { - printk(KERN_WARNING "hermes @ 0x%x: Frame allocation command failed (0x%X).\n", - hw->iobase, err); - return err; - } - - reg = hermes_read_regn(hw, EVSTAT); - k = ALLOC_COMPL_TIMEOUT; - while ( (! (reg & HERMES_EV_ALLOC)) && k) { - k--; - udelay(10); - reg = hermes_read_regn(hw, EVSTAT); - } - - if (! hermes_present(hw)) { - printk(KERN_WARNING "hermes @ 0x%x: Card removed waiting for frame allocation.\n", - hw->iobase); - return -ENODEV; - } - - if (! (reg & HERMES_EV_ALLOC)) { - printk(KERN_ERR "hermes @ 0x%x: Timeout waiting for frame allocation\n", - hw->iobase); - return -ETIMEDOUT; - } - - *fid = hermes_read_regn(hw, ALLOCFID); - hermes_write_regn(hw, EVACK, HERMES_EV_ALLOC); - - return 0; -} - -/* Set up a BAP to read a particular chunk of data from card's internal buffer. - * - * Returns: < 0 on internal failure (errno), 0 on success, >0 on error - * from firmware - * - * Callable from any context */ -static int hermes_bap_seek(hermes_t *hw, int bap, uint16_t id, uint16_t offset) -{ - int sreg = bap ? HERMES_SELECT1 : HERMES_SELECT0; - int oreg = bap ? HERMES_OFFSET1 : HERMES_OFFSET0; - int k; - int l = BAP_ERROR_RETRY; - uint16_t reg; - - /* Paranoia.. */ - if ( (offset > HERMES_BAP_OFFSET_MAX) || (offset % 2) ) - return -EINVAL; - - k = BAP_BUSY_TIMEOUT; - reg = hermes_read_reg(hw, oreg); - - if (reg & HERMES_OFFSET_BUSY) - return -EBUSY; - - /* Now we actually set up the transfer */ - retry: - hermes_write_reg(hw, sreg, id); - hermes_write_reg(hw, oreg, offset); - - /* Wait for the BAP to be ready */ - k = BAP_BUSY_TIMEOUT; - reg = hermes_read_reg(hw, oreg); - while ( (reg & (HERMES_OFFSET_BUSY | HERMES_OFFSET_ERR)) && k) { - k--; - udelay(1); - reg = hermes_read_reg(hw, oreg); - } - - if (reg & HERMES_OFFSET_BUSY) - return -ETIMEDOUT; - - /* For some reason, seeking the BAP seems to randomly fail somewhere - (firmware bug?). We retry a few times before giving up. */ - if (reg & HERMES_OFFSET_ERR) { - if (l--) { - udelay(1); - goto retry; - } else - return -EIO; - } - - return 0; -} - -/* Read a block of data from the chip's buffer, via the - * BAP. Synchronization/serialization is the caller's problem. len - * must be even. - * - * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware - */ -int hermes_bap_pread(hermes_t *hw, int bap, void *buf, uint16_t len, - uint16_t id, uint16_t offset) -{ - int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; - int err = 0; - - if (len % 2) - return -EINVAL; - - err = hermes_bap_seek(hw, bap, id, offset); - if (err) - goto out; - - /* Actually do the transfer */ - hermes_read_data(hw, dreg, buf, len/2); - - out: - return err; -} - -/* Write a block of data to the chip's buffer, via the - * BAP. Synchronization/serialization is the caller's problem. len - * must be even. - * - * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware - */ -int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, uint16_t len, - uint16_t id, uint16_t offset) -{ - int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; - int err = 0; - - if (len % 2) - return -EINVAL; - - err = hermes_bap_seek(hw, bap, id, offset); - if (err) - goto out; - - /* Actually do the transfer */ - hermes_write_data(hw, dreg, buf, len/2); - - out: - return err; -} - -/* Read a Length-Type-Value record from the card. - * - * If length is NULL, we ignore the length read from the card, and - * read the entire buffer regardless. This is useful because some of - * the configuration records appear to have incorrect lengths in - * practice. - * - * Callable from user or bh context. */ -int hermes_read_ltv(hermes_t *hw, int bap, uint16_t rid, int buflen, - uint16_t *length, void *buf) -{ - int err = 0; - int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; - uint16_t rlength, rtype; - hermes_response_t resp; - int count; - - if (buflen % 2) - return -EINVAL; - - err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS, rid, &resp); - if (err) - goto out; - - err = hermes_bap_seek(hw, bap, rid, 0); - if (err) - goto out; - - rlength = hermes_read_reg(hw, dreg); - rtype = hermes_read_reg(hw, dreg); - - if (length) - *length = rlength; - - if (rtype != rid) - printk(KERN_WARNING "hermes_read_ltv(): rid (0x%04x) does " - "not match type (0x%04x)\n", rid, rtype); - if (HERMES_RECLEN_TO_BYTES(rlength) > buflen) - printk(KERN_WARNING "hermes @ 0x%x: Truncating LTV record from %d to %d bytes. " - "(rid=0x%04x, len=0x%04x)\n", hw->iobase, - HERMES_RECLEN_TO_BYTES(rlength), buflen, rid, rlength); - - /* For now we always read the whole buffer, the - lengths in the records seem to be wrong, frequently */ - count = buflen / 2; - -#if 0 - if (length) - count = (MIN(buflen, rlength) + 1) / 2; - else { - count = buflen / 2; - if (rlength != buflen) - printk(KERN_WARNING "hermes_read_ltv(): Incorrect \ -record length %d instead of %d on RID 0x%04x\n", rlength, buflen, rid); - } -#endif - hermes_read_data(hw, dreg, buf, count); - - out: - return err; -} - -int hermes_write_ltv(hermes_t *hw, int bap, uint16_t rid, - uint16_t length, const void *value) -{ - int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; - int err = 0; - hermes_response_t resp; - int count; - - DEBUG(3, "write_ltv(): bap=%d rid=0x%04x length=%d (value=0x%04x)\n", - bap, rid, length, * ((uint16_t *)value)); - - err = hermes_bap_seek(hw, bap, rid, 0); - if (err) - goto out; - - hermes_write_reg(hw, dreg, length); - hermes_write_reg(hw, dreg, rid); - - count = length - 1; - - hermes_write_data(hw, dreg, value, count); - - err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS | HERMES_CMD_WRITE, - rid, &resp); - - out: - return err; -} - -EXPORT_SYMBOL(hermes_struct_init); -EXPORT_SYMBOL(hermes_reset); -EXPORT_SYMBOL(hermes_docmd_wait); -EXPORT_SYMBOL(hermes_allocate); - -EXPORT_SYMBOL(hermes_bap_pread); -EXPORT_SYMBOL(hermes_bap_pwrite); -EXPORT_SYMBOL(hermes_read_ltv); -EXPORT_SYMBOL(hermes_write_ltv); - -static int __init init_hermes(void) -{ - printk(KERN_INFO "%s\n", version); - - return 0; -} - -module_init(init_hermes); diff -Nru a/drivers/net/pcmcia/hermes.h b/drivers/net/pcmcia/hermes.h --- a/drivers/net/pcmcia/hermes.h Wed May 16 06:00:23 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,402 +0,0 @@ -/* hermes.h - * - * Driver core for the "Hermes" wireless MAC controller, as used in - * the Lucent Orinoco and Cabletron RoamAbout cards. It should also - * work on the hfa3841 and hfa3842 MAC controller chips used in the - * Prism I & II chipsets. - * - * This is not a complete driver, just low-level access routines for - * the MAC controller itself. - * - * Based on the prism2 driver from Absolute Value Systems' linux-wlan - * project, the Linux wvlan_cs driver, Lucent's HCF-Light - * (wvlan_hcf.c) library, and the NetBSD wireless driver. - * - * Copyright (C) 2000, David Gibson, Linuxcare Australia - * - * Portions taken from hfa384x.h, Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. - * - * This file distributed under the GPL, version 2. - */ - -#ifndef _HERMES_H -#define _HERMES_H - -/* Notes on locking: - * - * As a module of low level hardware access routines, there is no - * locking. Users of this module should ensure that they serialize - * access to the hermes_t structure, and to the hardware -*/ - -#include -#include - -/* - * Limits and constants - */ -#define HERMES_ALLOC_LEN_MIN (4) -#define HERMES_ALLOC_LEN_MAX (2400) -#define HERMES_LTV_LEN_MAX (34) -#define HERMES_BAP_DATALEN_MAX (4096) -#define HERMES_BAP_OFFSET_MAX (4096) -#define HERMES_PORTID_MAX (7) -#define HERMES_NUMPORTS_MAX (HERMES_PORTID_MAX+1) -#define HERMES_PDR_LEN_MAX (260) /* in bytes, from EK */ -#define HERMES_PDA_RECS_MAX (200) /* a guess */ -#define HERMES_PDA_LEN_MAX (1024) /* in bytes, from EK */ -#define HERMES_SCANRESULT_MAX (35) -#define HERMES_CHINFORESULT_MAX (8) -#define HERMES_FRAME_LEN_MAX (2304) -#define HERMES_MAX_MULTICAST (16) -#define HERMES_MAGIC (0x7d1f) - -/* - * Hermes register offsets - */ -#define HERMES_CMD (0x00) -#define HERMES_PARAM0 (0x02) -#define HERMES_PARAM1 (0x04) -#define HERMES_PARAM2 (0x06) -#define HERMES_STATUS (0x08) -#define HERMES_RESP0 (0x0A) -#define HERMES_RESP1 (0x0C) -#define HERMES_RESP2 (0x0E) -#define HERMES_INFOFID (0x10) -#define HERMES_RXFID (0x20) -#define HERMES_ALLOCFID (0x22) -#define HERMES_TXCOMPLFID (0x24) -#define HERMES_SELECT0 (0x18) -#define HERMES_OFFSET0 (0x1C) -#define HERMES_DATA0 (0x36) -#define HERMES_SELECT1 (0x1A) -#define HERMES_OFFSET1 (0x1E) -#define HERMES_DATA1 (0x38) -#define HERMES_EVSTAT (0x30) -#define HERMES_INTEN (0x32) -#define HERMES_EVACK (0x34) -#define HERMES_CONTROL (0x14) -#define HERMES_SWSUPPORT0 (0x28) -#define HERMES_SWSUPPORT1 (0x2A) -#define HERMES_SWSUPPORT2 (0x2C) -#define HERMES_AUXPAGE (0x3A) -#define HERMES_AUXOFFSET (0x3C) -#define HERMES_AUXDATA (0x3E) - -/* - * CMD register bitmasks - */ -#define HERMES_CMD_BUSY (0x8000) -#define HERMES_CMD_AINFO (0x7f00) -#define HERMES_CMD_MACPORT (0x0700) -#define HERMES_CMD_RECL (0x0100) -#define HERMES_CMD_WRITE (0x0100) -#define HERMES_CMD_PROGMODE (0x0300) -#define HERMES_CMD_CMDCODE (0x003f) - -/* - * STATUS register bitmasks - */ -#define HERMES_STATUS_RESULT (0x7f00) -#define HERMES_STATUS_CMDCODE (0x003f) - -/* - * OFFSET refister bitmasks - */ -#define HERMES_OFFSET_BUSY (0x8000) -#define HERMES_OFFSET_ERR (0x4000) -#define HERMES_OFFSET_DATAOFF (0x0ffe) - -/* - * Event register bitmasks (INTEN, EVSTAT, EVACK) - */ -#define HERMES_EV_TICK (0x8000) -#define HERMES_EV_WTERR (0x4000) -#define HERMES_EV_INFDROP (0x2000) -#define HERMES_EV_INFO (0x0080) -#define HERMES_EV_DTIM (0x0020) -#define HERMES_EV_CMD (0x0010) -#define HERMES_EV_ALLOC (0x0008) -#define HERMES_EV_TXEXC (0x0004) -#define HERMES_EV_TX (0x0002) -#define HERMES_EV_RX (0x0001) - -/* - * Command codes - */ -/*--- Controller Commands --------------------------*/ -#define HERMES_CMD_INIT (0x0000) -#define HERMES_CMD_ENABLE (0x0001) -#define HERMES_CMD_DISABLE (0x0002) -#define HERMES_CMD_DIAG (0x0003) - -/*--- Buffer Mgmt Commands --------------------------*/ -#define HERMES_CMD_ALLOC (0x000A) -#define HERMES_CMD_TX (0x000B) -#define HERMES_CMD_CLRPRST (0x0012) - -/*--- Regulate Commands --------------------------*/ -#define HERMES_CMD_NOTIFY (0x0010) -#define HERMES_CMD_INQ (0x0011) - -/*--- Configure Commands --------------------------*/ -#define HERMES_CMD_ACCESS (0x0021) -#define HERMES_CMD_DOWNLD (0x0022) - -/*--- Debugging Commands -----------------------------*/ -#define HERMES_CMD_MONITOR (0x0038) -#define HERMES_MONITOR_ENABLE (0x000b) -#define HERMES_MONITOR_DISABLE (0x000f) - -/* - * Configuration RIDs - */ - -#define HERMES_RID_CNF_PORTTYPE (0xfc00) -#define HERMES_RID_CNF_MACADDR (0xfc01) -#define HERMES_RID_CNF_DESIRED_SSID (0xfc02) -#define HERMES_RID_CNF_CHANNEL (0xfc03) -#define HERMES_RID_CNF_OWN_SSID (0xfc04) -#define HERMES_RID_CNF_SYSTEM_SCALE (0xfc06) -#define HERMES_RID_CNF_MAX_DATA_LEN (0xfc07) -#define HERMES_RID_CNF_PM_ENABLE (0xfc09) -#define HERMES_RID_CNF_PM_MCAST_RX (0xfc0b) -#define HERMES_RID_CNF_PM_PERIOD (0xfc0c) -#define HERMES_RID_CNF_PM_HOLDOVER (0xfc0d) -#define HERMES_RID_CNF_NICKNAME (0xfc0e) -#define HERMES_RID_CNF_WEP_ON (0xfc20) -#define HERMES_RID_CNF_MWO_ROBUST (0xfc25) -#define HERMES_RID_CNF_PRISM2_WEP_ON (0xfc28) -#define HERMES_RID_CNF_MULTICAST_LIST (0xfc80) -#define HERMES_RID_CNF_CREATEIBSS (0xfc81) -#define HERMES_RID_CNF_FRAG_THRESH (0xfc82) -#define HERMES_RID_CNF_RTS_THRESH (0xfc83) -#define HERMES_RID_CNF_TX_RATE_CTRL (0xfc84) -#define HERMES_RID_CNF_PROMISCUOUS (0xfc85) -#define HERMES_RID_CNF_KEYS (0xfcb0) -#define HERMES_RID_CNF_TX_KEY (0xfcb1) -#define HERMES_RID_CNF_TICKTIME (0xfce0) - -#define HERMES_RID_CNF_PRISM2_TX_KEY (0xfc23) -#define HERMES_RID_CNF_PRISM2_KEY0 (0xfc24) -#define HERMES_RID_CNF_PRISM2_KEY1 (0xfc25) -#define HERMES_RID_CNF_PRISM2_KEY2 (0xfc26) -#define HERMES_RID_CNF_PRISM2_KEY3 (0xfc27) -#define HERMES_RID_CNF_SYMBOL_MANDATORY_BSSID (0xfc21) -#define HERMES_RID_CNF_SYMBOL_AUTH_TYPE (0xfc2A) -#define HERMES_RID_CNF_SYMBOL_BASIC_RATES (0xfc8A) -#define HERMES_RID_CNF_SYMBOL_PREAMBLE (0xfc8C) - -/* - * Information RIDs - */ -#define HERMES_RID_CHANNEL_LIST (0xfd10) -#define HERMES_RID_STAIDENTITY (0xfd20) -#define HERMES_RID_CURRENT_SSID (0xfd41) -#define HERMES_RID_CURRENT_BSSID (0xfd42) -#define HERMES_RID_COMMSQUALITY (0xfd43) -#define HERMES_RID_CURRENT_TX_RATE (0xfd44) -#define HERMES_RID_SHORT_RETRY_LIMIT (0xfd48) -#define HERMES_RID_LONG_RETRY_LIMIT (0xfd49) -#define HERMES_RID_MAX_TX_LIFETIME (0xfd4A) -#define HERMES_RID_WEP_AVAIL (0xfd4f) -#define HERMES_RID_CURRENT_CHANNEL (0xfdc1) -#define HERMES_RID_DATARATES (0xfdc6) -#define HERMES_RID_SYMBOL_PRIMARY_VER (0xfd03) -#define HERMES_RID_SYMBOL_SECONDARY_VER (0xfd21) -#define HERMES_RID_SYMBOL_KEY_LENGTH (0xfc2B) - -/* - * Frame structures and constants - */ - -typedef struct hermes_frame_desc { - /* Hermes - i.e. little-endian byte-order */ - uint16_t status; /* 0x0 */ - uint16_t res1, res2; /* 0x2, 0x4 */ - uint16_t q_info; /* 0x6 */ - uint16_t res3, res4; /* 0x8, 0xA */ - uint16_t tx_ctl; /* 0xC */ -} __attribute__ ((packed)) hermes_frame_desc_t; - -#define HERMES_RXSTAT_ERR (0x0003) -#define HERMES_RXSTAT_MACPORT (0x0700) -#define HERMES_RXSTAT_MSGTYPE (0xE000) - -#define HERMES_RXSTAT_BADCRC (0x0001) -#define HERMES_RXSTAT_UNDECRYPTABLE (0x0002) - -/* RFC-1042 encoded frame */ -#define HERMES_RXSTAT_1042 (0x2000) -/* Bridge-tunnel encoded frame */ -#define HERMES_RXSTAT_TUNNEL (0x4000) -/* Wavelan-II Management Protocol frame */ -#define HERMES_RXSTAT_WMP (0x6000) - -#ifdef __KERNEL__ - -/* Basic control structure */ -typedef struct hermes { - uint iobase; - - uint16_t inten; /* Which interrupts should be enabled? */ -} hermes_t; - -typedef struct hermes_response { - uint16_t status, resp0, resp1, resp2; -} hermes_response_t; - -/* Firmware information structure */ -typedef struct hermes_identity { - uint16_t id, vendor, major, minor; -} __attribute__ ((packed)) hermes_identity_t; - -/* "ID" structure - used for ESSID and station nickname */ -typedef struct hermes_id { - uint16_t len; - uint16_t val[16]; -} __attribute__ ((packed)) hermes_id_t; - -typedef struct hermes_commsqual { - uint16_t qual, signal, noise; -} __attribute__ ((packed)) hermes_commsqual_t; - -typedef struct hermes_multicast { - uint8_t addr[HERMES_MAX_MULTICAST][ETH_ALEN]; -} __attribute__ ((packed)) hermes_multicast_t; - -/* Register access convenience macros */ -#define hermes_read_reg(hw, off) (inw((hw)->iobase + (off))) -#define hermes_write_reg(hw, off, val) (outw_p((val), (hw)->iobase + (off))) - -#define hermes_read_regn(hw, name) (hermes_read_reg((hw), HERMES_##name)) -#define hermes_write_regn(hw, name, val) (hermes_write_reg((hw), HERMES_##name, (val))) - -/* Note that for the next two, the count is in 16-bit words, not bytes */ -#define hermes_read_data(hw, off, buf, count) (insw((hw)->iobase + (off), (buf), (count))) -#define hermes_write_data(hw, off, buf, count) (outsw((hw)->iobase + (off), (buf), (count))) - -/* Function prototypes */ -void hermes_struct_init(hermes_t *hw, ushort io); -int hermes_reset(hermes_t *hw); -int hermes_docmd_wait(hermes_t *hw, uint16_t cmd, uint16_t parm0, hermes_response_t *resp); -int hermes_allocate(hermes_t *hw, uint16_t size, uint16_t *fid); - - -int hermes_bap_pread(hermes_t *hw, int bap, void *buf, uint16_t len, - uint16_t id, uint16_t offset); -int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, uint16_t len, - uint16_t id, uint16_t offset); -int hermes_read_ltv(hermes_t *hw, int bap, uint16_t rid, int buflen, - uint16_t *length, void *buf); -int hermes_write_ltv(hermes_t *hw, int bap, uint16_t rid, - uint16_t length, const void *value); - -/* Inline functions */ - -static inline int hermes_present(hermes_t *hw) -{ - return hermes_read_regn(hw, SWSUPPORT0) == HERMES_MAGIC; -} - -static inline void hermes_enable_interrupt(hermes_t *hw, uint16_t events) -{ - hw->inten |= events; - hermes_write_regn(hw, INTEN, hw->inten); -} - -static inline void hermes_set_irqmask(hermes_t *hw, uint16_t events) -{ - hw->inten = events; - hermes_write_regn(hw, INTEN, events); -} - -static inline int hermes_enable_port(hermes_t *hw, int port) -{ - hermes_response_t resp; - - return hermes_docmd_wait(hw, HERMES_CMD_ENABLE | (port << 8), - 0, &resp); -} - -static inline int hermes_disable_port(hermes_t *hw, int port) -{ - hermes_response_t resp; - - return hermes_docmd_wait(hw, HERMES_CMD_ENABLE | (port << 8), - 0, &resp); -} - -#define HERMES_BYTES_TO_RECLEN(n) ( ((n) % 2) ? (((n)+1)/2)+1 : ((n)/2)+1 ) -#define HERMES_RECLEN_TO_BYTES(n) ( ((n)-1) * 2 ) - -#define HERMES_READ_RECORD(hw, bap, rid, buf) \ - (hermes_read_ltv((hw),(bap),(rid), sizeof(*buf), NULL, (buf))) -#define HERMES_WRITE_RECORD(hw, bap, rid, buf) \ - (hermes_write_ltv((hw),(bap),(rid),HERMES_BYTES_TO_RECLEN(sizeof(*buf)),(buf))) - -static inline int hermes_read_wordrec(hermes_t *hw, int bap, uint16_t rid, uint16_t *word) -{ - uint16_t rec; - int err; - - err = HERMES_READ_RECORD(hw, bap, rid, &rec); - *word = le16_to_cpu(rec); - return err; -} - -static inline int hermes_write_wordrec(hermes_t *hw, int bap, uint16_t rid, uint16_t word) -{ - uint16_t rec = cpu_to_le16(word); - return HERMES_WRITE_RECORD(hw, bap, rid, &rec); -} - -static inline int hermes_read_staidentity(hermes_t *hw, int bap, hermes_identity_t *buf) -{ - int err; - - err = HERMES_READ_RECORD(hw, bap, HERMES_RID_STAIDENTITY, buf); - if (err) - return err; - - le16_to_cpus(&buf->id); - le16_to_cpus(&buf->vendor); - le16_to_cpus(&buf->major); - le16_to_cpus(&buf->minor); - - return 0; -} - -static inline int hermes_read_commsqual(hermes_t *hw, int bap, hermes_commsqual_t *buf) -{ - int err; - - err = HERMES_READ_RECORD(hw, bap, HERMES_RID_COMMSQUALITY, buf); - if (err) - return err; - - le16_to_cpus(&buf->qual); - le16_to_cpus(&buf->signal); - le16_to_cpus(&buf->noise); - - return 0; -} - -#else /* ! __KERNEL__ */ - -/* These are provided for the benefit of userspace drivers and testing programs - which use ioperm() or iopl() */ - -#define hermes_read_reg(base, off) (inw((base) + (off))) -#define hermes_write_reg(base, off, val) (outw((val), (base) + (off))) - -#define hermes_read_regn(base, name) (hermes_read_reg((base), HERMES_##name)) -#define hermes_write_regn(base, name, val) (hermes_write_reg((base), HERMES_##name, (val))) - -/* Note that for the next two, the count is in 16-bit words, not bytes */ -#define hermes_read_data(base, off, buf, count) (insw((base) + (off), (buf), (count))) -#define hermes_write_data(base, off, buf, count) (outsw((base) + (off), (buf), (count))) - -#endif /* ! __KERNEL__ */ - -#endif /* _HERMES_H */ diff -Nru a/drivers/net/pcmcia/orinoco_cs.c b/drivers/net/pcmcia/orinoco_cs.c --- a/drivers/net/pcmcia/orinoco_cs.c Wed May 16 06:00:18 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,4327 +0,0 @@ -/* orinoco_cs.c 0.04 - (formerly known as dldwd_cs.c) - * - * A driver for "Hermes" chipset based PCMCIA wireless adaptors, such - * as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/ - * EnteraSys RoamAbout 802.11, ELSA Airlancer, Melco Buffalo and others). - * It should also be usable on various Prism II based cards such as the - * Linksys, D-Link and Farallon Skyline. It should also work on Symbol - * cards such as the 3Com AirConnect and Ericsson WLAN. - * - * Copyright (C) 2000 David Gibson, Linuxcare Australia - * With some help from : - * Copyright (C) 2001 Jean Tourrilhes, HP Labs - * - * Based on dummy_cs.c 1.27 2000/06/12 21:27:25 - * - * Portions based on wvlan_cs.c 1.0.6, Copyright Andreas Neuhaus - * http://www.fasta.fh-dortmund.de/users/andy/wvlan/ - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License - * at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and - * limitations under the License. - * - * The initial developer of the original code is David A. Hinds - * . Portions created by David - * A. Hinds are Copyright (C) 1999 David A. Hinds. All Rights - * Reserved. - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU Public License version 2 (the "GPL"), in which - * case the provisions of the GPL are applicable instead of the above. - * If you wish to allow the use of your version of this file only - * under the terms of the GPL and not to allow others to use your - * version of this file under the MPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the MPL or the GPL. - */ - -/* Notes on locking: - * - * The basic principle of operation is that everything except the - * interrupt handler is serialized through a single spinlock in the - * dldwd_priv_t structure, using dldwd_lock() and - * dldwd_unlock() (which in turn use spin_lock_bh() and spin_unlock_bh()). - * - * The kernel's IRQ handling stuff ensures that the interrupt handler - * does not re-enter itself. The interrupt handler is written such - * that everything it does is safe without a lock: chiefly this means - * that the Rx path uses one of the Hermes chipset's BAPs while - * everything else uses the other. - * - * For the moment access to the device statistics from the interrupt - * handler is unsafe - we just put up with any resulting errors in the - * statisics. FIXME: This should probably be changed to store the - * stats in atomic types. - * - * EXCEPT that we don't want the irq handler running when we actually - * reset or shut down the card, because strange things might happen - * (probably the worst would be one packet of garbage, but you can't - * be too careful). For this we use __dldwd_stop_irqs() which will set - * a flag to disable the interrupt handler, and wait for any - * outstanding instances of the handler to complete. THIS WILL LOSE - * INTERRUPTS! so it shouldn't be used except for resets, when we - * don't care about that.*/ - -/* - * Tentative changelog... - * - * v0.01 -> v0.02 - 21/3/2001 - Jean II - * o Allow to use regular ethX device name instead of dldwdX - * o Warning on IBSS with ESSID=any for firmware 6.06 - * o Put proper range.throughput values (optimistic) - * o IWSPY support (IOCTL and stat gather in Rx path) - * o Allow setting frequency in Ad-Hoc mode - * o Disable WEP setting if !has_wep to work on old firmware - * o Fix txpower range - * o Start adding support for Samsung/Compaq firmware - * - * v0.02 -> v0.03 - 23/3/2001 - Jean II - * o Start adding Symbol support - need to check all that - * o Fix Prism2/Symbol WEP to accept 128 bits keys - * o Add Symbol WEP (add authentication type) - * o Add Prism2/Symbol rate - * o Add PM timeout (holdover duration) - * o Enable "iwconfig eth0 key off" and friends (toggle flags) - * o Enable "iwconfig eth0 power unicast/all" (toggle flags) - * o Try with an intel card. It report firmware 1.01, behave like - * an antiquated firmware, however on windows it says 2.00. Yuck ! - * o Workaround firmware bug in allocate buffer (Intel 1.01) - * o Finish external renaming to orinoco... - * o Testing with various Wavelan firmwares - * - * v0.03 -> v0.04 - 30/3/2001 - Jean II - * o Update to Wireless 11 -> add retry limit/lifetime support - * o Tested with a D-Link DWL 650 card, fill in firmware support - * o Warning on Vcc mismatch (D-Link 3.3v card in Lucent 5v only slot) - * o Fixed the Prims2 WEP bugs that I introduced in v0.03 :-( - * It work on D-Link *only* after a tcpdump. Weird... - * And still doesn't work on Intel card. Grrrr... - * o Update the mode after a setport3 - * o Add preamble setting for Symbol cards (not yet enabled) - * o Don't complain as much about Symbol cards... - * - * v0.04 -> v0.04b - 22/4/2001 - David Gibson - * o Removed the 'eth' parameter - always use ethXX as the - * interface name instead of dldwdXX. The other was racy - * anyway. - * o Clean up RID definitions in hermes.h, other cleanups - * - * v0.04b -> v0.04c - 24/4/2001 - Jean II - * o Tim Hurley reported a D-Link card - * with vendor 02 and firmware 0.08. Added in the capabilities... - * o Tested Lucent firmware 7.28, everything works... - * - * TODO - Jean II - * o inline functions (lot's of candidate, need to reorder code) - * o Separate Pcmcia specific code to help Airport/Mini PCI driver - * o Test PrismII/Symbol cards & firmware versions - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "hermes.h" - -#ifdef PCMCIA_DEBUG -static int pc_debug = PCMCIA_DEBUG; -static char *version = "orinoco_cs.c 0.04 (David Gibson )"; -MODULE_PARM(pc_debug, "i"); -#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) -#define DEBUGMORE(n, args...) do { if (pc_debug>(n)) printk(args); } while (0) -#else -#define DEBUG(n, args...) do { } while (0) -#define DEBUGMORE(n, args...) do { } while (0) -#endif - -#define TRACE_ENTER(devname) DEBUG(2, "%s: -> " __FUNCTION__ "()\n", devname); -#define TRACE_EXIT(devname) DEBUG(2, "%s: <- " __FUNCTION__ "()\n", devname); - -#define MAX(a, b) ( (a) > (b) ? (a) : (b) ) -#define MIN(a, b) ( (a) < (b) ? (a) : (b) ) - -#define RUP_EVEN(a) ( (a) % 2 ? (a) + 1 : (a) ) - - -#if (! defined (WIRELESS_EXT)) || (WIRELESS_EXT < 10) -#error "orinoco_cs requires Wireless extensions v10 or later." -#endif /* (! defined (WIRELESS_EXT)) || (WIRELESS_EXT < 10) */ -#define WIRELESS_SPY // enable iwspy support - -/*====================================================================*/ - -/* Parameters that can be set with 'insmod' */ - -/* The old way: bit map of interrupts to choose from */ -/* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4, and 3 */ -static uint irq_mask = 0xdeb8; -/* Newer, simpler way of listing specific interrupts */ -static int irq_list[4] = { -1 }; -/* Do a Pcmcia soft reset (may help some cards) */ -static int reset_cor = 0; - -MODULE_PARM(irq_mask, "i"); -MODULE_PARM(irq_list, "1-4i"); -MODULE_PARM(reset_cor, "i"); - -/*====================================================================*/ - -#define DLDWD_MIN_MTU 256 -#define DLDWD_MAX_MTU (HERMES_FRAME_LEN_MAX - ENCAPS_OVERHEAD) - -#define LTV_BUF_SIZE 128 -#define USER_BAP 0 -#define IRQ_BAP 1 -#define DLDWD_MACPORT 0 -#define IRQ_LOOP_MAX 10 -#define TX_NICBUF_SIZE 2048 -#define TX_NICBUF_SIZE_BUG 1585 /* Bug in Intel firmware */ -#define MAX_KEYS 4 -#define MAX_KEY_SIZE 14 -#define LARGE_KEY_SIZE 13 -#define SMALL_KEY_SIZE 5 -#define MAX_FRAME_SIZE 2304 - -const long channel_frequency[] = { - 2412, 2417, 2422, 2427, 2432, 2437, 2442, - 2447, 2452, 2457, 2462, 2467, 2472, 2484 -}; - -#define NUM_CHANNELS ( sizeof(channel_frequency) / sizeof(channel_frequency[0]) ) - -/* This tables gives the actual meanings of the bitrate IDs returned by the firmware. - It gives the rate in halfMb/s, negative indicates auto mode */ -const int rate_list[] = { 0, 2, 4, -22, 11, 22, -4, -11, 0, 0, 0, 0}; - -#define NUM_RATES (sizeof(rate_list) / sizeof(rate_list[0])) -typedef struct dldwd_key { - uint16_t len; - char data[MAX_KEY_SIZE]; -} __attribute__ ((packed)) dldwd_key_t; - -typedef dldwd_key_t dldwd_keys_t[MAX_KEYS]; - -typedef struct dldwd_priv { - dev_link_t link; - dev_node_t node; - int instance; - - spinlock_t lock; - long state; -#define DLDWD_STATE_INIRQ 0 -#define DLDWD_STATE_DOIRQ 1 - - /* Net device stuff */ - struct net_device ndev; - struct net_device_stats stats; - struct iw_statistics wstats; - - - /* Hardware control variables */ - hermes_t hw; - uint16_t txfid; - - /* Capabilities of the hardware/firmware */ - hermes_identity_t firmware_info; - int firmware_type; -#define FIRMWARE_TYPE_LUCENT 1 -#define FIRMWARE_TYPE_PRISM2 2 -#define FIRMWARE_TYPE_SYMBOL 3 - int has_ibss, has_port3, prefer_port3, has_ibss_any; - int has_wep, has_big_wep; - int has_mwo; - int has_pm; - int has_retry; - int has_preamble; - int broken_reset, broken_allocate; - uint16_t channel_mask; - - /* Current configuration */ - uint32_t iw_mode; - int port_type, allow_ibss; - uint16_t wep_on, wep_restrict, tx_key; - dldwd_keys_t keys; - char nick[IW_ESSID_MAX_SIZE+1]; - char desired_essid[IW_ESSID_MAX_SIZE+1]; - uint16_t frag_thresh, mwo_robust; - uint16_t channel; - uint16_t ap_density, rts_thresh; - uint16_t tx_rate_ctrl; - uint16_t pm_on, pm_mcast, pm_period, pm_timeout; - uint16_t retry_short, retry_long, retry_time; - uint16_t preamble; - - int promiscuous, allmulti, mc_count; - -#ifdef WIRELESS_SPY - int spy_number; - u_char spy_address[IW_MAX_SPY][ETH_ALEN]; - struct iw_quality spy_stat[IW_MAX_SPY]; -#endif - - /* /proc based debugging stuff */ - struct proc_dir_entry *dir_dev; - struct proc_dir_entry *dir_regs; - struct proc_dir_entry *dir_recs; -} dldwd_priv_t; - -struct p80211_hdr { - uint16_t frame_ctl; - uint16_t duration_id; - uint8_t addr1[ETH_ALEN]; - uint8_t addr2[ETH_ALEN]; - uint8_t addr3[ETH_ALEN]; - uint16_t seq_ctl; - uint8_t addr4[ETH_ALEN]; - uint16_t data_len; -} __attribute__ ((packed)); - -/* Frame control field constants */ -#define DLDWD_FCTL_VERS 0x0002 -#define DLDWD_FCTL_FTYPE 0x000c -#define DLDWD_FCTL_STYPE 0x00f0 -#define DLDWD_FCTL_TODS 0x0100 -#define DLDWD_FCTL_FROMDS 0x0200 -#define DLDWD_FCTL_MOREFRAGS 0x0400 -#define DLDWD_FCTL_RETRY 0x0800 -#define DLDWD_FCTL_PM 0x1000 -#define DLDWD_FCTL_MOREDATA 0x2000 -#define DLDWD_FCTL_WEP 0x4000 -#define DLDWD_FCTL_ORDER 0x8000 - -#define DLDWD_FTYPE_MGMT 0x0000 -#define DLDWD_FTYPE_CTL 0x0004 -#define DLDWD_FTYPE_DATA 0x0008 - -struct p8022_hdr { - uint8_t dsap; - uint8_t ssap; - uint8_t ctrl; - uint8_t oui[3]; -} __attribute__ ((packed)); - -struct dldwd_frame_hdr { - hermes_frame_desc_t desc; - struct p80211_hdr p80211; - struct ethhdr p8023; - struct p8022_hdr p8022; - uint16_t ethertype; -} __attribute__ ((packed)); - -#define P8023_OFFSET (sizeof(hermes_frame_desc_t) + \ - sizeof(struct p80211_hdr)) -#define ENCAPS_OVERHEAD (sizeof(struct p8022_hdr) + 2) - -/* - * Function prototypes - */ - -/* PCMCIA gumpf */ - -static void dldwd_config(dev_link_t * link); -static void dldwd_release(u_long arg); -static int dldwd_event(event_t event, int priority, - event_callback_args_t * args); - -static dev_link_t *dldwd_attach(void); -static void dldwd_detach(dev_link_t *); - -/* Hardware control routines */ - -static int __dldwd_hw_reset(dldwd_priv_t *priv); -static void dldwd_shutdown(dldwd_priv_t *dev); -static int dldwd_reset(dldwd_priv_t *dev); -static int __dldwd_hw_setup_wep(dldwd_priv_t *priv); -static int dldwd_hw_get_bssid(dldwd_priv_t *priv, char buf[ETH_ALEN]); -static int dldwd_hw_get_essid(dldwd_priv_t *priv, int *active, char buf[IW_ESSID_MAX_SIZE+1]); -static long dldwd_hw_get_freq(dldwd_priv_t *priv); -static int dldwd_hw_get_bitratelist(dldwd_priv_t *priv, int *numrates, - int32_t *rates, int max); - -/* Interrupt handling routines */ -void dldwd_interrupt(int irq, void * dev_id, struct pt_regs *regs); -static void __dldwd_ev_tick(dldwd_priv_t *priv, hermes_t *hw); -static void __dldwd_ev_wterr(dldwd_priv_t *priv, hermes_t *hw); -static void __dldwd_ev_infdrop(dldwd_priv_t *priv, hermes_t *hw); -static void __dldwd_ev_info(dldwd_priv_t *priv, hermes_t *hw); -static void __dldwd_ev_rx(dldwd_priv_t *priv, hermes_t *hw); -static void __dldwd_ev_txexc(dldwd_priv_t *priv, hermes_t *hw); -static void __dldwd_ev_tx(dldwd_priv_t *priv, hermes_t *hw); -static void __dldwd_ev_alloc(dldwd_priv_t *priv, hermes_t *hw); - -/* struct net_device methods */ -static int dldwd_init(struct net_device *dev); -static int dldwd_open(struct net_device *dev); -static int dldwd_stop(struct net_device *dev); - -static int dldwd_xmit(struct sk_buff *skb, struct net_device *dev); -static void dldwd_tx_timeout(struct net_device *dev); - -static struct net_device_stats *dldwd_get_stats(struct net_device *dev); -static struct iw_statistics *dldwd_get_wireless_stats(struct net_device *dev); -static void dldwd_stat_gather(struct net_device *dev, - struct sk_buff *skb, - struct dldwd_frame_hdr *hdr); - -static int dldwd_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq); -static int dldwd_ioctl_setiwencode(struct net_device *dev, struct iw_point *erq); -static int dldwd_ioctl_getiwencode(struct net_device *dev, struct iw_point *erq); -static int dldwd_ioctl_setessid(struct net_device *dev, struct iw_point *erq); -static int dldwd_ioctl_getessid(struct net_device *dev, struct iw_point *erq); -static int dldwd_ioctl_setnick(struct net_device *dev, struct iw_point *nrq); -static int dldwd_ioctl_getnick(struct net_device *dev, struct iw_point *nrq); -static int dldwd_ioctl_setfreq(struct net_device *dev, struct iw_freq *frq); -static int dldwd_ioctl_getsens(struct net_device *dev, struct iw_param *srq); -static int dldwd_ioctl_setsens(struct net_device *dev, struct iw_param *srq); -static int dldwd_ioctl_setrts(struct net_device *dev, struct iw_param *rrq); -static int dldwd_ioctl_setfrag(struct net_device *dev, struct iw_param *frq); -static int dldwd_ioctl_getfrag(struct net_device *dev, struct iw_param *frq); -static int dldwd_ioctl_setrate(struct net_device *dev, struct iw_param *frq); -static int dldwd_ioctl_getrate(struct net_device *dev, struct iw_param *frq); -static int dldwd_ioctl_setpower(struct net_device *dev, struct iw_param *prq); -static int dldwd_ioctl_getpower(struct net_device *dev, struct iw_param *prq); -static int dldwd_ioctl_setport3(struct net_device *dev, struct iwreq *wrq); -static int dldwd_ioctl_getport3(struct net_device *dev, struct iwreq *wrq); -static int dldwd_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); - -static int dldwd_change_mtu(struct net_device *dev, int new_mtu); -static void __dldwd_set_multicast_list(struct net_device *dev); - -/* /proc debugging stuff */ -static int dldwd_proc_init(void); -static void dldwd_proc_cleanup(void); -static int dldwd_proc_dev_init(dldwd_priv_t *dev); -static void dldwd_proc_dev_cleanup(dldwd_priv_t *dev); - -/* - * Inline functions - */ -static inline void -dldwd_lock(dldwd_priv_t *priv) -{ - spin_lock_bh(&priv->lock); -} - -static inline void -dldwd_unlock(dldwd_priv_t *priv) -{ - spin_unlock_bh(&priv->lock); -} - -static inline int -dldwd_irqs_allowed(dldwd_priv_t *priv) -{ - return test_bit(DLDWD_STATE_DOIRQ, &priv->state); -} - -static inline void -__dldwd_stop_irqs(dldwd_priv_t *priv) -{ - hermes_t *hw = &priv->hw; - - hermes_set_irqmask(hw, 0); - clear_bit(DLDWD_STATE_DOIRQ, &priv->state); - while (test_bit(DLDWD_STATE_INIRQ, &priv->state)) - ; -} - -static inline void -__dldwd_start_irqs(dldwd_priv_t *priv, uint16_t irqmask) -{ - hermes_t *hw = &priv->hw; - - TRACE_ENTER(priv->ndev.name); - - __cli(); - set_bit(DLDWD_STATE_DOIRQ, &priv->state); - hermes_set_irqmask(hw, irqmask); - __sti(); - - TRACE_EXIT(priv->ndev.name); -} - -static inline void -set_port_type(dldwd_priv_t *priv) -{ - switch (priv->iw_mode) { - case IW_MODE_INFRA: - priv->port_type = 1; - priv->allow_ibss = 0; - break; - case IW_MODE_ADHOC: - if (priv->prefer_port3) { - priv->port_type = 3; - priv->allow_ibss = 0; - } else { - priv->port_type = 1; - priv->allow_ibss = 1; - } - break; - default: - printk(KERN_ERR "%s: Invalid priv->iw_mode in set_port_type()\n", - priv->ndev.name); - } -} - -static inline void -dldwd_set_multicast_list(struct net_device *dev) -{ - dldwd_priv_t *priv = dev->priv; - - dldwd_lock(priv); - __dldwd_set_multicast_list(dev); - dldwd_unlock(priv); -} - -/* - * Hardware control routines - */ - -static int -__dldwd_hw_reset(dldwd_priv_t *priv) -{ - hermes_t *hw = &priv->hw; - int err; - - if (! priv->broken_reset) - return hermes_reset(hw); - else { - hw->inten = 0; - hermes_write_regn(hw, INTEN, 0); - err = hermes_disable_port(hw, 0); - hermes_write_regn(hw, EVACK, 0xffff); - return err; - } -} - -static void -dldwd_shutdown(dldwd_priv_t *priv) -{ -/* hermes_t *hw = &priv->hw; */ - int err = 0; - - TRACE_ENTER(priv->ndev.name); - - dldwd_lock(priv); - __dldwd_stop_irqs(priv); - - err = __dldwd_hw_reset(priv); - if (err && err != -ENODEV) /* If the card is gone, we don't care about shutting it down */ - printk(KERN_ERR "%s: Error %d shutting down Hermes chipset\n", priv->ndev.name, err); - - dldwd_unlock(priv); - - TRACE_EXIT(priv->ndev.name); -} - -static int -dldwd_reset(dldwd_priv_t *priv) -{ - struct net_device *dev = &priv->ndev; - hermes_t *hw = &priv->hw; - int err = 0; - hermes_id_t idbuf; - int frame_size; - - TRACE_ENTER(priv->ndev.name); - - dldwd_lock(priv); - - __dldwd_stop_irqs(priv); - - err = __dldwd_hw_reset(priv); - if (err) - goto out; - - frame_size = TX_NICBUF_SIZE; - /* This stupid bug is present in Intel firmware 1.10, and - * may be fixed in later firmwares - Jean II */ - if(priv->broken_allocate) - frame_size = TX_NICBUF_SIZE_BUG; - err = hermes_allocate(hw, frame_size, &priv->txfid); - if (err) - goto out; - - /* Now set up all the parameters on the card */ - - /* Set up the link mode */ - - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PORTTYPE, priv->port_type); - if (err) - goto out; - if (priv->has_ibss) { - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_CREATEIBSS, - priv->allow_ibss); - if (err) - goto out; - if((strlen(priv->desired_essid) == 0) && (priv->allow_ibss) - && (!priv->has_ibss_any)) { - printk(KERN_WARNING "%s: This firmware requires an \ -ESSID in IBSS-Ad-Hoc mode.\n", dev->name); - /* With wvlan_cs, in this case, we would crash. - * hopefully, this driver will behave better... - * Jean II */ - } - } - - /* Set up encryption */ - if (priv->has_wep) { - err = __dldwd_hw_setup_wep(priv); - if (err) - goto out; - } - - /* Set the desired ESSID */ - idbuf.len = cpu_to_le16(strlen(priv->desired_essid)); - memcpy(&idbuf.val, priv->desired_essid, sizeof(idbuf.val)); - err = hermes_write_ltv(hw, USER_BAP, (priv->port_type == 3) ? - HERMES_RID_CNF_OWN_SSID : HERMES_RID_CNF_DESIRED_SSID, - HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2), - &idbuf); - if (err) - goto out; - - /* Set the station name */ - idbuf.len = cpu_to_le16(strlen(priv->nick)); - memcpy(&idbuf.val, priv->nick, sizeof(idbuf.val)); - err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNF_NICKNAME, - HERMES_BYTES_TO_RECLEN(strlen(priv->nick)+2), - &idbuf); - if (err) - goto out; - - /* Set the channel/frequency */ - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_CHANNEL, priv->channel); - if (err) - goto out; - - /* Set AP density */ - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYSTEM_SCALE, priv->ap_density); - if (err) - goto out; - - /* Set RTS threshold */ - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_RTS_THRESH, priv->rts_thresh); - if (err) - goto out; - - /* Set fragmentation threshold or MWO robustness */ - if (priv->has_mwo) - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNF_MWO_ROBUST, priv->mwo_robust); - else - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNF_FRAG_THRESH, priv->frag_thresh); - if (err) - goto out; - - /* Set bitrate */ - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_TX_RATE_CTRL, - priv->tx_rate_ctrl); - if (err) - goto out; - - /* Set power management */ - if (priv->has_pm) { - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_ENABLE, - priv->pm_on); - if (err) - goto out; - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_MCAST_RX, - priv->pm_mcast); - if (err) - goto out; - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_PERIOD, - priv->pm_period); - if (err) - goto out; - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_HOLDOVER, - priv->pm_timeout); - if (err) - goto out; - } - - /* Set retry settings - will fail on lot's of firmwares */ - if (priv->has_retry) { - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_SHORT_RETRY_LIMIT, - priv->retry_short); - if (err) { - printk(KERN_WARNING "%s: Can't set retry limit!\n", dev->name); - goto out; - } - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_LONG_RETRY_LIMIT, - priv->retry_long); - if (err) - goto out; - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_MAX_TX_LIFETIME, - priv->retry_time); - if (err) - goto out; - } - - /* Set preamble - only for Symbol so far... */ - if (priv->has_preamble) { - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYMBOL_PREAMBLE, - priv->preamble); - if (err) { - printk(KERN_WARNING "%s: Can't set preamble!\n", dev->name); - goto out; - } - } - - /* Set promiscuity / multicast*/ - priv->promiscuous = 0; - priv->allmulti = 0; - priv->mc_count = 0; - __dldwd_set_multicast_list(dev); - - err = hermes_enable_port(hw, DLDWD_MACPORT); - if (err) - goto out; - - __dldwd_start_irqs(priv, HERMES_EV_RX | HERMES_EV_ALLOC | - HERMES_EV_TX | HERMES_EV_TXEXC | - HERMES_EV_WTERR | HERMES_EV_INFO | - HERMES_EV_INFDROP); - - out: - dldwd_unlock(priv); - - TRACE_EXIT(priv->ndev.name); - - return err; -} - -static int __dldwd_hw_setup_wep(dldwd_priv_t *priv) -{ - hermes_t *hw = &priv->hw; - int err = 0; - int extra_wep_flag = 0; - - switch (priv->firmware_type) { - case FIRMWARE_TYPE_LUCENT: /* Lucent style WEP */ - if (priv->wep_on) { - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_TX_KEY, priv->tx_key); - if (err) - return err; - - err = HERMES_WRITE_RECORD(hw, USER_BAP, HERMES_RID_CNF_KEYS, &priv->keys); - if (err) - return err; - } - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_WEP_ON, priv->wep_on); - if (err) - return err; - break; - - case FIRMWARE_TYPE_PRISM2: /* Prism II style WEP */ - case FIRMWARE_TYPE_SYMBOL: /* Symbol style WEP */ - if (priv->wep_on) { - char keybuf[LARGE_KEY_SIZE+1]; - int keylen; - int i; - - /* Write all 4 keys */ - for(i = 0; i < MAX_KEYS; i++) { - keylen = priv->keys[i].len; - keybuf[keylen] = '\0'; - memcpy(keybuf, priv->keys[i].data, keylen); - err = hermes_write_ltv(hw, USER_BAP, - HERMES_RID_CNF_PRISM2_KEY0 + i, - HERMES_BYTES_TO_RECLEN(keylen + 1), - &keybuf); - if (err) - return err; - } - - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PRISM2_TX_KEY, - priv->tx_key); - if (err) - return err; - - /* Authentication is where Prism2 and Symbol - * firmware differ... */ - if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL) { - /* Symbol cards : set the authentication : - * 0 -> no encryption, 1 -> open, - * 2 -> shared key, 3 -> shared key 128bit */ - if(priv->wep_restrict) { - if(priv->keys[priv->tx_key].len > - SMALL_KEY_SIZE) - extra_wep_flag = 3; - else - extra_wep_flag = 2; - } else - extra_wep_flag = 1; - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYMBOL_AUTH_TYPE, priv->wep_restrict); - if (err) - return err; - } else { - /* Prism2 card : we need to modify master - * WEP setting */ - if(priv->wep_restrict) - extra_wep_flag = 2; - else - extra_wep_flag = 0; - } - } - - /* Master WEP setting : on/off */ - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PRISM2_WEP_ON, (priv->wep_on | extra_wep_flag)); - if (err) - return err; - break; - - default: - if (priv->wep_on) { - printk(KERN_ERR "%s: WEP enabled, although not supported!\n", - priv->ndev.name); - return -EINVAL; - } - } - - return 0; -} - -static int dldwd_hw_get_bssid(dldwd_priv_t *priv, char buf[ETH_ALEN]) -{ - hermes_t *hw = &priv->hw; - int err = 0; - - dldwd_lock(priv); - - err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_BSSID, - ETH_ALEN, NULL, buf); - - dldwd_unlock(priv); - - return err; -} - -static int dldwd_hw_get_essid(dldwd_priv_t *priv, int *active, - char buf[IW_ESSID_MAX_SIZE+1]) -{ - hermes_t *hw = &priv->hw; - int err = 0; - hermes_id_t essidbuf; - char *p = (char *)(&essidbuf.val); - int len; - - TRACE_ENTER(priv->ndev.name); - - dldwd_lock(priv); - - if (strlen(priv->desired_essid) > 0) { - /* We read the desired SSID from the hardware rather - than from priv->desired_essid, just in case the - firmware is allowed to change it on us. I'm not - sure about this */ - /* My guess is that the OWN_SSID should always be whatever - * we set to the card, whereas CURRENT_SSID is the one that - * may change... - Jean II */ - uint16_t rid; - - *active = 1; - - rid = (priv->port_type == 3) ? HERMES_RID_CNF_OWN_SSID : - HERMES_RID_CNF_DESIRED_SSID; - - err = hermes_read_ltv(hw, USER_BAP, rid, sizeof(essidbuf), - NULL, &essidbuf); - if (err) - goto fail_unlock; - } else { - *active = 0; - - err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_SSID, - sizeof(essidbuf), NULL, &essidbuf); - if (err) - goto fail_unlock; - } - - len = le16_to_cpu(essidbuf.len); - - memset(buf, 0, sizeof(buf)); - memcpy(buf, p, len); - buf[len] = '\0'; - - fail_unlock: - dldwd_unlock(priv); - - TRACE_EXIT(priv->ndev.name); - - return err; -} - -static long dldwd_hw_get_freq(dldwd_priv_t *priv) -{ - - hermes_t *hw = &priv->hw; - int err = 0; - uint16_t channel; - long freq = 0; - - dldwd_lock(priv); - - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENT_CHANNEL, &channel); - if (err) - goto out; - - if ( (channel < 1) || (channel > NUM_CHANNELS) ) { - struct net_device *dev = &priv->ndev; - - printk(KERN_WARNING "%s: Channel out of range (%d)!\n", dev->name, channel); - err = -EBUSY; - goto out; - - } - freq = channel_frequency[channel-1] * 100000; - - out: - dldwd_unlock(priv); - - if (err > 0) - err = -EBUSY; - return err ? err : freq; -} - -static int dldwd_hw_get_bitratelist(dldwd_priv_t *priv, int *numrates, - int32_t *rates, int max) -{ - hermes_t *hw = &priv->hw; - hermes_id_t list; - unsigned char *p = (unsigned char *)&list.val; - int err = 0; - int num; - int i; - - dldwd_lock(priv); - err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_DATARATES, sizeof(list), - NULL, &list); - dldwd_unlock(priv); - - if (err) - return err; - - num = le16_to_cpu(list.len); - *numrates = num; - num = MIN(num, max); - - for (i = 0; i < num; i++) { - rates[i] = (p[i] & 0x7f) * 500000; /* convert to bps */ - } - - return 0; -} - -#ifndef PCMCIA_DEBUG -static inline void show_rx_frame(struct dldwd_frame_hdr *frame) {} -#else -static void show_rx_frame(struct dldwd_frame_hdr *frame) -{ - printk(KERN_DEBUG "RX descriptor:\n"); - printk(KERN_DEBUG " status = 0x%04x\n", frame->desc.status); - printk(KERN_DEBUG " res1 = 0x%04x\n", frame->desc.res1); - printk(KERN_DEBUG " res2 = 0x%04x\n", frame->desc.res2); - printk(KERN_DEBUG " q_info = 0x%04x\n", frame->desc.q_info); - printk(KERN_DEBUG " res3 = 0x%04x\n", frame->desc.res3); - printk(KERN_DEBUG " res4 = 0x%04x\n", frame->desc.res4); - printk(KERN_DEBUG " tx_ctl = 0x%04x\n", frame->desc.tx_ctl); - - printk(KERN_DEBUG "IEEE 802.11 header:\n"); - printk(KERN_DEBUG " frame_ctl = 0x%04x\n", - frame->p80211.frame_ctl); - printk(KERN_DEBUG " duration_id = 0x%04x\n", - frame->p80211.duration_id); - printk(KERN_DEBUG " addr1 = %02x:%02x:%02x:%02x:%02x:%02x\n", - frame->p80211.addr1[0], frame->p80211.addr1[1], - frame->p80211.addr1[2], frame->p80211.addr1[3], - frame->p80211.addr1[4], frame->p80211.addr1[5]); - printk(KERN_DEBUG " addr2 = %02x:%02x:%02x:%02x:%02x:%02x\n", - frame->p80211.addr2[0], frame->p80211.addr2[1], - frame->p80211.addr2[2], frame->p80211.addr2[3], - frame->p80211.addr2[4], frame->p80211.addr2[5]); - printk(KERN_DEBUG " addr3 = %02x:%02x:%02x:%02x:%02x:%02x\n", - frame->p80211.addr3[0], frame->p80211.addr3[1], - frame->p80211.addr3[2], frame->p80211.addr3[3], - frame->p80211.addr3[4], frame->p80211.addr3[5]); - printk(KERN_DEBUG " seq_ctl = 0x%04x\n", - frame->p80211.seq_ctl); - printk(KERN_DEBUG " addr4 = %02x:%02x:%02x:%02x:%02x:%02x\n", - frame->p80211.addr4[0], frame->p80211.addr4[1], - frame->p80211.addr4[2], frame->p80211.addr4[3], - frame->p80211.addr4[4], frame->p80211.addr4[5]); - printk(KERN_DEBUG " data_len = 0x%04x\n", - frame->p80211.data_len); - - printk(KERN_DEBUG "IEEE 802.3 header:\n"); - printk(KERN_DEBUG " dest = %02x:%02x:%02x:%02x:%02x:%02x\n", - frame->p8023.h_dest[0], frame->p8023.h_dest[1], - frame->p8023.h_dest[2], frame->p8023.h_dest[3], - frame->p8023.h_dest[4], frame->p8023.h_dest[5]); - printk(KERN_DEBUG " src = %02x:%02x:%02x:%02x:%02x:%02x\n", - frame->p8023.h_source[0], frame->p8023.h_source[1], - frame->p8023.h_source[2], frame->p8023.h_source[3], - frame->p8023.h_source[4], frame->p8023.h_source[5]); - printk(KERN_DEBUG " len = 0x%04x\n", frame->p8023.h_proto); - - printk(KERN_DEBUG "IEEE 802.2 LLC/SNAP header:\n"); - printk(KERN_DEBUG " DSAP = 0x%02x\n", frame->p8022.dsap); - printk(KERN_DEBUG " SSAP = 0x%02x\n", frame->p8022.ssap); - printk(KERN_DEBUG " ctrl = 0x%02x\n", frame->p8022.ctrl); - printk(KERN_DEBUG " OUI = %02x:%02x:%02x\n", - frame->p8022.oui[0], frame->p8022.oui[1], frame->p8022.oui[2]); - printk(KERN_DEBUG " ethertype = 0x%04x\n", frame->ethertype); -} -#endif - -/* - * Interrupt handler - */ -void dldwd_interrupt(int irq, void * dev_id, struct pt_regs *regs) -{ - dldwd_priv_t *priv = (dldwd_priv_t *) dev_id; - hermes_t *hw = &priv->hw; - struct net_device *dev = &priv->ndev; - int count = IRQ_LOOP_MAX; - uint16_t evstat, events; - static int old_time = 0, timecount = 0; /* Eugh, revolting hack for now */ - - if (test_and_set_bit(DLDWD_STATE_INIRQ, &priv->state)) - BUG(); - - if (! dldwd_irqs_allowed(priv)) { - clear_bit(DLDWD_STATE_INIRQ, &priv->state); - return; - } - - DEBUG(3, "%s: dldwd_interrupt() irq %d\n", priv->ndev.name, irq); - - while (1) { - if (jiffies != old_time) - timecount = 0; - if ( (++timecount > 50) || (! count--) ) { - printk(KERN_CRIT "%s: IRQ handler is looping too \ -much! Shutting down.\n", - dev->name); - /* Perform an emergency shutdown */ - clear_bit(DLDWD_STATE_DOIRQ, &priv->state); - hermes_set_irqmask(hw, 0); - break; - } - - evstat = hermes_read_regn(hw, EVSTAT); - DEBUG(3, "__dldwd_interrupt(): count=%d EVSTAT=0x%04x inten=0x%04x\n", - count, evstat, hw->inten); - - events = evstat & hw->inten; - - if (! events) { - if (netif_queue_stopped(dev)) { - /* There seems to be a firmware bug which - sometimes causes the card to give an - interrupt with no event set, when there - sould be a Tx completed event. */ - DEBUG(3, "%s: Interrupt with no event (ALLOCFID=0x%04x)\n", - dev->name, (int)hermes_read_regn(hw, ALLOCFID)); - events = HERMES_EV_TX | HERMES_EV_ALLOC; - } else /* Nothing's happening, we're done */ - break; - } - - /* Check the card hasn't been removed */ - if (! hermes_present(hw)) { - DEBUG(0, "dldwd_interrupt(): card removed\n"); - break; - } - - if (events & HERMES_EV_TICK) - __dldwd_ev_tick(priv, hw); - if (events & HERMES_EV_WTERR) - __dldwd_ev_wterr(priv, hw); - if (events & HERMES_EV_INFDROP) - __dldwd_ev_infdrop(priv, hw); - if (events & HERMES_EV_INFO) - __dldwd_ev_info(priv, hw); - if (events & HERMES_EV_RX) - __dldwd_ev_rx(priv, hw); - if (events & HERMES_EV_TXEXC) - __dldwd_ev_txexc(priv, hw); - if (events & HERMES_EV_TX) - __dldwd_ev_tx(priv, hw); - if (events & HERMES_EV_ALLOC) - __dldwd_ev_alloc(priv, hw); - - hermes_write_regn(hw, EVACK, events); - } - - clear_bit(DLDWD_STATE_INIRQ, &priv->state); -} - -static void __dldwd_ev_tick(dldwd_priv_t *priv, hermes_t *hw) -{ - printk(KERN_DEBUG "%s: TICK\n", priv->ndev.name); -} - -static void __dldwd_ev_wterr(dldwd_priv_t *priv, hermes_t *hw) -{ - /* This seems to happen a fair bit under load, but ignoring it - seems to work fine...*/ - DEBUG(1, "%s: MAC controller error (WTERR). Ignoring.\n", - priv->ndev.name); -} - -static void __dldwd_ev_infdrop(dldwd_priv_t *priv, hermes_t *hw) -{ - printk(KERN_WARNING "%s: Information frame lost.\n", priv->ndev.name); -} - -static void __dldwd_ev_info(dldwd_priv_t *priv, hermes_t *hw) -{ - DEBUG(3, "%s: Information frame received.\n", priv->ndev.name); - /* We don't actually do anything about it - we assume the MAC - controller can deal with it */ -} - -static void __dldwd_ev_rx(dldwd_priv_t *priv, hermes_t *hw) -{ - struct net_device *dev = &priv->ndev; - struct net_device_stats *stats = &priv->stats; - struct iw_statistics *wstats = &priv->wstats; - struct sk_buff *skb = NULL; - uint16_t rxfid, status; - int length, data_len, data_off; - char *p; - struct dldwd_frame_hdr hdr; - struct ethhdr *eh; - int err; - - rxfid = hermes_read_regn(hw, RXFID); - DEBUG(3, "__dldwd_ev_rx(): RXFID=0x%04x\n", rxfid); - - /* We read in the entire frame header here. This isn't really - necessary, since we ignore most of it, but it's - conceptually simpler. We can tune this later if - necessary. */ - err = hermes_bap_pread(hw, IRQ_BAP, &hdr, sizeof(hdr), rxfid, 0); - if (err) { - printk(KERN_ERR "%s: error %d reading frame header. " - "Frame dropped.\n", dev->name, err); - stats->rx_errors++; - goto drop; - } - - status = le16_to_cpu(hdr.desc.status); - - if (status & HERMES_RXSTAT_ERR) { - if ((status & HERMES_RXSTAT_ERR) == HERMES_RXSTAT_BADCRC) { - stats->rx_crc_errors++; - printk(KERN_WARNING "%s: Bad CRC on Rx. Frame dropped.\n", - dev->name); - show_rx_frame(&hdr); - } else if ((status & HERMES_RXSTAT_ERR) - == HERMES_RXSTAT_UNDECRYPTABLE) { - wstats->discard.code++; - printk(KERN_WARNING "%s: Undecryptable frame on Rx. Frame dropped.\n", - dev->name); - } else { - wstats->discard.misc++; - printk("%s: Unknown Rx error (0x%x). Frame dropped.\n", - dev->name, status & HERMES_RXSTAT_ERR); - } - stats->rx_errors++; - goto drop; - } - - length = le16_to_cpu(hdr.p80211.data_len); - /* Yes, you heard right, that's le16. 802.2 and 802.3 are - big-endian, but 802.11 is little-endian believe it or - not. */ - /* Correct. 802.3 is big-endian byte order and little endian bit - * order, whereas 802.11 is little endian for both byte and bit - * order. That's specified in the 802.11 spec. - Jean II */ - - /* Sanity check */ - if (length > MAX_FRAME_SIZE) { - printk(KERN_WARNING "%s: Oversized frame received (%d bytes)\n", - dev->name, length); - stats->rx_length_errors++; - stats->rx_errors++; - goto drop; - } - - /* We need space for the packet data itself, plus an ethernet - header, plus 2 bytes so we can align the IP header on a - 32bit boundary, plus 1 byte so we can read in odd length - packets from the card, which has an IO granularity of 16 - bits */ - skb = dev_alloc_skb(length+ETH_HLEN+2+1); - if (!skb) { - printk(KERN_WARNING "%s: Can't allocate skb for Rx\n", - dev->name); - stats->rx_dropped++; - goto drop; - } - - skb_reserve(skb, 2); /* This way the IP header is aligned */ - - /* Handle decapsulation */ - switch (status & HERMES_RXSTAT_MSGTYPE) { - /* These both indicate a SNAP within 802.2 LLC within - 802.3 within 802.11 frame which we'll need to - de-encapsulate. IEEE and ISO OSI have a lot to - answer for. */ - case HERMES_RXSTAT_1042: - case HERMES_RXSTAT_TUNNEL: - data_len = length - ENCAPS_OVERHEAD; - data_off = sizeof(hdr); - - eh = (struct ethhdr *)skb_put(skb, ETH_HLEN); - - memcpy(eh, &hdr.p8023, sizeof(hdr.p8023)); - eh->h_proto = hdr.ethertype; - - break; - - /* Otherwise, we just throw the whole thing in, and hope - the protocol layer can deal with it as 802.3 */ - default: - data_len = length; - data_off = P8023_OFFSET; - break; - } - - p = skb_put(skb, data_len); - if (hermes_bap_pread(hw, IRQ_BAP, p, RUP_EVEN(data_len), - rxfid, data_off) != 0) { - printk(KERN_WARNING "%s: Error reading packet data\n", - dev->name); - stats->rx_errors++; - goto drop; - } - - dev->last_rx = jiffies; - skb->dev = dev; - skb->protocol = eth_type_trans(skb, dev); - skb->ip_summed = CHECKSUM_NONE; - - /* Process the wireless stats if needed */ - dldwd_stat_gather(dev, skb, &hdr); - - /* Pass the packet to the networking stack */ - netif_rx(skb); - stats->rx_packets++; - stats->rx_bytes += length; - - return; - - drop: - if (skb) - dev_kfree_skb_irq(skb); - return; -} - -static void __dldwd_ev_txexc(dldwd_priv_t *priv, hermes_t *hw) -{ - struct net_device *dev = &priv->ndev; - struct net_device_stats *stats = &priv->stats; - - printk(KERN_WARNING "%s: Tx error!\n", dev->name); - - netif_wake_queue(dev); - stats->tx_errors++; -} - -static void __dldwd_ev_tx(dldwd_priv_t *priv, hermes_t *hw) -{ - struct net_device *dev = &priv->ndev; - struct net_device_stats *stats = &priv->stats; - - DEBUG(3, "%s: Transmit completed\n", dev->name); - - stats->tx_packets++; - netif_wake_queue(dev); -} - -static void __dldwd_ev_alloc(dldwd_priv_t *priv, hermes_t *hw) -{ - uint16_t allocfid; - - allocfid = hermes_read_regn(hw, ALLOCFID); - DEBUG(3, "%s: Allocation complete FID=0x%04x\n", priv->ndev.name, allocfid); - - /* For some reason we don't seem to get transmit completed events properly */ - if (allocfid == priv->txfid) - __dldwd_ev_tx(priv, hw); - -/* hermes_write_regn(hw, ALLOCFID, 0); */ -} - -/* - * struct net_device methods - */ - -static int dldwd_init(struct net_device *dev) -{ - dldwd_priv_t *priv = dev->priv; - hermes_t *hw = &priv->hw; - int err = 0; - hermes_id_t nickbuf; - uint16_t reclen; - int len; - char *vendor_str; - uint32_t firmver; - - TRACE_ENTER("dldwd"); - - dldwd_lock(priv); - - err = hermes_reset(hw); - if (err != 0) { - printk(KERN_ERR "%s: failed to reset hardware\n", dev->name); - goto out; - } - - /* Get the firmware version */ - err = hermes_read_staidentity(hw, USER_BAP, &priv->firmware_info); - if (err) { - printk(KERN_WARNING "%s: Error %d reading firmware info. Wildly guessing capabilities...\n", - dev->name, err); - memset(&priv->firmware_info, 0, sizeof(priv->firmware_info)); - } - - firmver = ((uint32_t)priv->firmware_info.major << 16) | priv->firmware_info.minor; - DEBUG(2, "%s: firmver = 0x%X\n", dev->name, firmver); - - /* Determine capabilities from the firmware version */ - - switch (priv->firmware_info.vendor) { - case 0x1: - /* Lucent Wavelan IEEE, Lucent Orinoco, Cabletron RoamAbout, - * ELSA, Melco, HP, IBM, Dell 1150 cards */ - vendor_str = "Lucent"; - /* Lucent MAC : 00:60:1D:* & 00:02:2D:* */ - - priv->firmware_type = FIRMWARE_TYPE_LUCENT; - priv->broken_reset = 0; - priv->broken_allocate = 0; - priv->has_port3 = 1; /* Still works in 7.28 */ - priv->has_ibss = (firmver >= 0x60006); - priv->has_ibss_any = (firmver >= 0x60010); - priv->has_wep = (firmver >= 0x40020); - priv->has_big_wep = 1; /* FIXME: this is wrong - how do we tell - Gold cards from the others? */ - priv->has_mwo = (firmver >= 0x60000); - priv->has_pm = (firmver >= 0x40020); - priv->has_retry = 0; - priv->has_preamble = 0; - /* Tested with Lucent firmware : - * 1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II - * Tested CableTron firmware : 4.32 => Anton */ - break; - case 0x2: - vendor_str = "Generic Prism II"; - /* Some D-Link cards report vendor 0x02... */ - - priv->firmware_type = FIRMWARE_TYPE_PRISM2; - priv->broken_reset = 0; - priv->broken_allocate = 0; - priv->has_port3 = 1; - priv->has_ibss = (firmver >= 0x00007); /* FIXME */ - priv->has_wep = (firmver >= 0x00007); /* FIXME */ - priv->has_big_wep = 0; - priv->has_mwo = 0; - priv->has_pm = (firmver >= 0x00007); /* FIXME */ - priv->has_retry = 0; - priv->has_preamble = 0; - - /* Tim Hurley -> D-Link card, vendor 02, firmware 0.08 */ - - /* Special case for Symbol cards */ - if(firmver == 0x10001) { - /* Symbol , 3Com AirConnect, Intel, Ericsson WLAN */ - vendor_str = "Symbol"; - /* Intel MAC : 00:02:B3:* */ - /* 3Com MAC : 00:50:DA:* */ - - /* FIXME : probably need to use SYMBOL_***ARY_VER - * to get proper firmware version */ - priv->firmware_type = FIRMWARE_TYPE_SYMBOL; - priv->broken_reset = 0; - priv->broken_allocate = 1; - priv->has_port3 = 1; - priv->has_ibss = 1; /* FIXME */ - priv->has_wep = 1; /* FIXME */ - priv->has_big_wep = 1; /* RID_SYMBOL_KEY_LENGTH */ - priv->has_mwo = 0; - priv->has_pm = 1; /* FIXME */ - priv->has_retry = 0; - priv->has_preamble = 0; /* FIXME */ - /* Tested with Intel firmware : v15 => Jean II */ - } - break; - case 0x3: - vendor_str = "Samsung"; - /* To check - Should cover Samsung & Compaq */ - - priv->firmware_type = FIRMWARE_TYPE_PRISM2; - priv->broken_reset = 0; - priv->broken_allocate = 0; - priv->has_port3 = 1; - priv->has_ibss = 0; /* FIXME: available in later firmwares */ - priv->has_wep = (firmver >= 0x20000); /* FIXME */ - priv->has_big_wep = 0; /* FIXME */ - priv->has_mwo = 0; - priv->has_pm = (firmver >= 0x20000); /* FIXME */ - priv->has_retry = 0; - priv->has_preamble = 0; - break; - case 0x6: - /* D-Link DWL 650, ... */ - vendor_str = "LinkSys/D-Link"; - /* D-Link MAC : 00:40:05:* */ - - priv->firmware_type = FIRMWARE_TYPE_PRISM2; - priv->broken_reset = 0; - priv->broken_allocate = 0; - priv->has_port3 = 1; - priv->has_ibss = (firmver >= 0x00007); /* FIXME */ - priv->has_wep = (firmver >= 0x00007); /* FIXME */ - priv->has_big_wep = 0; - priv->has_mwo = 0; - priv->has_pm = (firmver >= 0x00007); /* FIXME */ - priv->has_retry = 0; - priv->has_preamble = 0; - /* Tested with D-Link firmware 0.07 => Jean II */ - /* Note : with 0.07, IBSS to a Lucent card seem flaky */ - break; - default: - vendor_str = "UNKNOWN"; - - priv->firmware_type = 0; - priv->broken_reset = 0; - priv->broken_allocate = 0; - priv->has_port3 = 0; - priv->has_ibss = 0; - priv->has_wep = 0; - priv->has_big_wep = 0; - priv->has_mwo = 0; - priv->has_pm = 0; - priv->has_retry = 0; - priv->has_preamble = 0; - } - - printk(KERN_INFO "%s: Firmware ID %02X vendor 0x%x (%s) version %d.%02d\n", - dev->name, priv->firmware_info.id, priv->firmware_info.vendor, - vendor_str, priv->firmware_info.major, priv->firmware_info.minor); - - if (priv->has_port3) - printk(KERN_INFO "%s: Ad-hoc demo mode supported.\n", dev->name); - if (priv->has_ibss) - printk(KERN_INFO "%s: IEEE standard IBSS ad-hoc mode supported.\n", - dev->name); - if (priv->has_wep) { - printk(KERN_INFO "%s: WEP supported, ", dev->name); - if (priv->has_big_wep) - printk("\"128\"-bit key.\n"); - else - printk("40-bit key.\n"); - } - - /* Get the MAC address */ - err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNF_MACADDR, - ETH_ALEN, NULL, dev->dev_addr); - if (err) { - printk(KERN_WARNING "%s: failed to read MAC address!\n", - dev->name); - goto out; - } - - printk(KERN_INFO "%s: MAC address %02X:%02X:%02X:%02X:%02X:%02X\n", - dev->name, dev->dev_addr[0], dev->dev_addr[1], - dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4], - dev->dev_addr[5]); - - /* Get the station name */ - err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNF_NICKNAME, - sizeof(nickbuf), &reclen, &nickbuf); - if (err) { - printk(KERN_ERR "%s: failed to read station name!n", - dev->name); - goto out; - } - if ( nickbuf.len ) - len = MIN(IW_ESSID_MAX_SIZE, le16_to_cpu(nickbuf.len)); - else - len = MIN(IW_ESSID_MAX_SIZE, 2 * reclen); - memcpy(priv->nick, &nickbuf.val, len); - priv->nick[len] = '\0'; - - printk(KERN_INFO "%s: Station name \"%s\"\n", dev->name, priv->nick); - - /* Get allowed channels */ - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CHANNEL_LIST, &priv->channel_mask); - if (err) { - printk(KERN_ERR "%s: failed to read channel list!\n", - dev->name); - goto out; - } - - /* Get initial AP density */ - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYSTEM_SCALE, &priv->ap_density); - if (err) { - printk(KERN_ERR "%s: failed to read AP density!\n", dev->name); - goto out; - } - - /* Get initial RTS threshold */ - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_RTS_THRESH, &priv->rts_thresh); - if (err) { - printk(KERN_ERR "%s: failed to read RTS threshold!\n", dev->name); - goto out; - } - - /* Get initial fragmentation settings */ - if (priv->has_mwo) - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_MWO_ROBUST, - &priv->mwo_robust); - else - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_FRAG_THRESH, - &priv->frag_thresh); - if (err) { - printk(KERN_ERR "%s: failed to read fragmentation settings!\n", dev->name); - goto out; - } - - /* Set initial bitrate control*/ - priv->tx_rate_ctrl = 3; - - /* Power management setup */ - if (priv->has_pm) { - priv->pm_on = 0; - priv->pm_mcast = 1; - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_PERIOD, - &priv->pm_period); - if (err) { - printk(KERN_ERR "%s: failed to read power management period!\n", - dev->name); - goto out; - } - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_HOLDOVER, - &priv->pm_timeout); - if (err) { - printk(KERN_ERR "%s: failed to read power management timeout!\n", - dev->name); - goto out; - } - } - - /* Retry setup */ - if (priv->has_retry) { - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_SHORT_RETRY_LIMIT, &priv->retry_short); - if (err) - goto out; - - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_LONG_RETRY_LIMIT, &priv->retry_long); - if (err) - goto out; - - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_MAX_TX_LIFETIME, &priv->retry_time); - if (err) - goto out; - } - - /* Preamble setup */ - if (priv->has_preamble) { - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYMBOL_PREAMBLE, &priv->preamble); - if (err) - goto out; - } - - /* Set up the default configuration */ - priv->iw_mode = IW_MODE_INFRA; - /* By default use IEEE/IBSS ad-hoc mode if we have it */ - priv->prefer_port3 = priv->has_port3 && (! priv->has_ibss); - set_port_type(priv); - - priv->promiscuous = 0; - priv->allmulti = 0; - priv->wep_on = 0; - priv->tx_key = 0; - - printk(KERN_INFO "%s: ready\n", dev->name); - - out: - dldwd_unlock(priv); - - TRACE_EXIT("dldwd"); - - return err; -} - -static int dldwd_open(struct net_device *dev) -{ - dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; - dev_link_t *link = &priv->link; - int err = 0; - - TRACE_ENTER(dev->name); - - link->open++; - MOD_INC_USE_COUNT; - netif_device_attach(dev); - - err = dldwd_reset(priv); - if (err) - dldwd_stop(dev); - else - netif_start_queue(dev); - - TRACE_EXIT(dev->name); - - return err; -} - -static int dldwd_stop(struct net_device *dev) -{ - dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; - dev_link_t *link = &priv->link; - - TRACE_ENTER(dev->name); - - netif_stop_queue(dev); - - dldwd_shutdown(priv); - - link->open--; - - if (link->state & DEV_STALE_CONFIG) - mod_timer(&link->release, jiffies + HZ/20); - - MOD_DEC_USE_COUNT; - - TRACE_EXIT(dev->name); - - return 0; -} - -static struct net_device_stats *dldwd_get_stats(struct net_device *dev) -{ - dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; - - return &priv->stats; -} - -static struct iw_statistics *dldwd_get_wireless_stats(struct net_device *dev) -{ - dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; - hermes_t *hw = &priv->hw; - struct iw_statistics *wstats = &priv->wstats; - int err = 0; - hermes_commsqual_t cq; - - dldwd_lock(priv); - - if (priv->port_type == 3) { - memset(&wstats->qual, 0, sizeof(wstats->qual)); -#ifdef WIRELESS_SPY - /* If a spy address is defined, we report stats of the - * first spy address - Jean II */ - if (priv->spy_number > 0) { - wstats->qual.qual = priv->spy_stat[0].qual; - wstats->qual.level = priv->spy_stat[0].level; - wstats->qual.noise = priv->spy_stat[0].noise; - wstats->qual.updated = priv->spy_stat[0].updated; - } -#endif /* WIRELESS_SPY */ - } else { - err = hermes_read_commsqual(hw, USER_BAP, &cq); - - DEBUG(3, "%s: Global stats = %X-%X-%X\n", dev->name, - cq.qual, cq.signal, cq.noise); - - /* Why are we using MIN/MAX ? We don't really care - * if the value goes above max, because we export the - * raw dBm values anyway. The normalisation should be done - * in user space - Jean II */ - wstats->qual.qual = MAX(MIN(cq.qual, 0x8b-0x2f), 0); - wstats->qual.level = MAX(MIN(cq.signal, 0x8a), 0x2f) - 0x95; - wstats->qual.noise = MAX(MIN(cq.noise, 0x8a), 0x2f) - 0x95; - wstats->qual.updated = 7; - } - - dldwd_unlock(priv); - - if (err) - return NULL; - - return wstats; -} - -#ifdef WIRELESS_SPY -static inline void dldwd_spy_gather(struct net_device *dev, - u_char *mac, - hermes_commsqual_t *cq) -{ - dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; - int i; - - /* Gather wireless spy statistics: for each packet, compare the - * source address with out list, and if match, get the stats... */ - for (i = 0; i < priv->spy_number; i++) - if (!memcmp(mac, priv->spy_address[i], ETH_ALEN)) { - priv->spy_stat[i].qual = MAX(MIN(cq->qual, 0x8b-0x2f), 0); - priv->spy_stat[i].level = MAX(MIN(cq->signal, 0x8a), 0x2f) - 0x95; - priv->spy_stat[i].noise = MAX(MIN(cq->noise, 0x8a), 0x2f) - 0x95; - priv->spy_stat[i].updated = 7; - } -} -#endif /* WIRELESS_SPY */ - -static void dldwd_stat_gather(struct net_device *dev, - struct sk_buff *skb, - struct dldwd_frame_hdr *hdr) -{ - dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; - hermes_commsqual_t cq; - - /* Using spy support with lots of Rx packets, like in an - * infrastructure (AP), will really slow down everything, because - * the MAC address must be compared to each entry of the spy list. - * If the user really asks for it (set some address in the - * spy list), we do it, but he will pay the price. - * Note that to get here, you need both WIRELESS_SPY - * compiled in AND some addresses in the list !!! - */ -#ifdef WIRELESS_EXT - /* Note : gcc will optimise the whole section away if - * WIRELESS_SPY is not defined... - Jean II */ - if ( -#ifdef WIRELESS_SPY - (priv->spy_number > 0) || -#endif - 0 ) - { - u_char *stats = (u_char *) &(hdr->desc.q_info); - /* This code may look strange. Everywhere we are using 16 bit - * ints except here. I've verified that these are are the - * correct values. Please check on PPC - Jean II */ - cq.signal = stats[1]; /* High order byte */ - cq.noise = stats[0]; /* Low order byte */ - cq.qual = stats[0] - stats[1]; /* Better than nothing */ - - DEBUG(3, "%s: Packet stats = %X-%X-%X\n", dev->name, - cq.qual, cq.signal, cq.noise); - -#ifdef WIRELESS_SPY - dldwd_spy_gather(dev, skb->mac.raw + ETH_ALEN, &cq); -#endif - } -#endif /* WIRELESS_EXT */ -} - -struct p8022_hdr encaps_hdr = { - 0xaa, 0xaa, 0x03, {0x00, 0x00, 0xf8} -}; - -static int dldwd_xmit(struct sk_buff *skb, struct net_device *dev) -{ - dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; - struct net_device_stats *stats = &priv->stats; - hermes_t *hw = &priv->hw; - int err = 0; - uint16_t txfid = priv->txfid; - char *p; - struct ethhdr *eh; - int len, data_len, data_off; - struct dldwd_frame_hdr hdr; - hermes_response_t resp; - - if (! netif_running(dev)) { - printk(KERN_ERR "%s: Tx on stopped device!\n", - dev->name); - return 1; - - } - - if (netif_queue_stopped(dev)) { - printk(KERN_ERR "%s: Tx while transmitter busy!\n", - dev->name); - return 1; - } - - dldwd_lock(priv); - - /* Length of the packet body */ - len = MAX(skb->len - ETH_HLEN, ETH_ZLEN); - - eh = (struct ethhdr *)skb->data; - - /* Build the IEEE 802.11 header */ - memset(&hdr, 0, sizeof(hdr)); - memcpy(hdr.p80211.addr1, eh->h_dest, ETH_ALEN); - memcpy(hdr.p80211.addr2, eh->h_source, ETH_ALEN); - hdr.p80211.frame_ctl = DLDWD_FTYPE_DATA; - - /* Encapsulate Ethernet-II frames */ - if (ntohs(eh->h_proto) > 1500) { /* Ethernet-II frame */ - data_len = len; - data_off = sizeof(hdr); - p = skb->data + ETH_HLEN; - - /* 802.11 header */ - hdr.p80211.data_len = cpu_to_le16(data_len + ENCAPS_OVERHEAD); - - /* 802.3 header */ - memcpy(hdr.p8023.h_dest, eh->h_dest, ETH_ALEN); - memcpy(hdr.p8023.h_source, eh->h_source, ETH_ALEN); - hdr.p8023.h_proto = htons(data_len + ENCAPS_OVERHEAD); - - /* 802.2 header */ - memcpy(&hdr.p8022, &encaps_hdr, sizeof(encaps_hdr)); - - hdr.ethertype = eh->h_proto; - err = hermes_bap_pwrite(hw, USER_BAP, &hdr, sizeof(hdr), - txfid, 0); - if (err) { - printk(KERN_ERR - "%s: Error %d writing packet header to BAP\n", - dev->name, err); - stats->tx_errors++; - goto fail; - } - } else { /* IEEE 802.3 frame */ - data_len = len + ETH_HLEN; - data_off = P8023_OFFSET; - p = skb->data; - - /* 802.11 header */ - hdr.p80211.data_len = cpu_to_le16(len); - err = hermes_bap_pwrite(hw, USER_BAP, &hdr, P8023_OFFSET, - txfid, 0); - if (err) { - printk(KERN_ERR - "%s: Error %d writing packet header to BAP\n", - dev->name, err); - stats->tx_errors++; - goto fail; - } - } - - /* Round up for odd length packets */ - err = hermes_bap_pwrite(hw, USER_BAP, p, RUP_EVEN(data_len), txfid, data_off); - if (err) { - printk(KERN_ERR "%s: Error %d writing packet data to BAP\n", - dev->name, err); - stats->tx_errors++; - goto fail; - } - - - /* Finally, we actually initiate the send */ - err = hermes_docmd_wait(hw, HERMES_CMD_TX | HERMES_CMD_RECL, txfid, &resp); - if (err) { - printk(KERN_ERR "%s: Error %d transmitting packet\n", dev->name, err); - stats->tx_errors++; - goto fail; - } - - dev->trans_start = jiffies; - stats->tx_bytes += data_off + data_len; - - netif_stop_queue(dev); - - dldwd_unlock(priv); - - dev_kfree_skb(skb); - - return 0; - fail: - - dldwd_unlock(priv); - return err; -} - -static void dldwd_tx_timeout(struct net_device *dev) -{ - dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; - struct net_device_stats *stats = &priv->stats; - int err = 0; - - printk(KERN_WARNING "%s: Tx timeout! Resetting card.\n", dev->name); - - stats->tx_errors++; - - err = dldwd_reset(priv); - if (err) - printk(KERN_ERR "%s: Error %d resetting card on Tx timeout!\n", - dev->name, err); - else { - dev->trans_start = jiffies; - netif_wake_queue(dev); - } -} - -static int dldwd_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq) -{ - dldwd_priv_t *priv = dev->priv; - int err = 0; - int ptype; - struct iw_range range; - int numrates; - int i, k; - - TRACE_ENTER(dev->name); - - err = verify_area(VERIFY_WRITE, rrq->pointer, sizeof(range)); - if (err) - return err; - - rrq->length = sizeof(range); - - dldwd_lock(priv); - ptype = priv->port_type; - dldwd_unlock(priv); - - memset(&range, 0, sizeof(range)); - - /* Much of this shamelessly taken from wvlan_cs.c. No idea - * what it all means -dgibson */ -#if WIRELESS_EXT > 10 - range.we_version_compiled = WIRELESS_EXT; - range.we_version_source = 11; -#endif /* WIRELESS_EXT > 10 */ - - range.min_nwid = range.max_nwid = 0; /* We don't use nwids */ - - /* Set available channels/frequencies */ - range.num_channels = NUM_CHANNELS; - k = 0; - for (i = 0; i < NUM_CHANNELS; i++) { - if (priv->channel_mask & (1 << i)) { - range.freq[k].i = i + 1; - range.freq[k].m = channel_frequency[i] * 100000; - range.freq[k].e = 1; - k++; - } - - if (k >= IW_MAX_FREQUENCIES) - break; - } - range.num_frequency = k; - - range.sensitivity = 3; - - if ((ptype == 3) && (priv->spy_number == 0)){ - /* Quality stats meaningless in ad-hoc mode */ - range.max_qual.qual = 0; - range.max_qual.level = 0; - range.max_qual.noise = 0; - } else { - range.max_qual.qual = 0x8b - 0x2f; - range.max_qual.level = 0x2f - 0x95 - 1; - range.max_qual.noise = 0x2f - 0x95 - 1; - } - - err = dldwd_hw_get_bitratelist(priv, &numrates, - range.bitrate, IW_MAX_BITRATES); - if (err) - return err; - range.num_bitrates = numrates; - - /* Set an indication of the max TCP throughput in bit/s that we can - * expect using this interface. May be use for QoS stuff... - * Jean II */ - if(numrates > 2) - range.throughput = 5 * 1000 * 1000; /* ~5 Mb/s */ - else - range.throughput = 1.5 * 1000 * 1000; /* ~1.5 Mb/s */ - - range.min_rts = 0; - range.max_rts = 2347; - range.min_frag = 256; - range.max_frag = 2346; - - dldwd_lock(priv); - if (priv->has_wep) { - range.max_encoding_tokens = MAX_KEYS; - - range.encoding_size[0] = SMALL_KEY_SIZE; - range.num_encoding_sizes = 1; - - if (priv->has_big_wep) { - range.encoding_size[1] = LARGE_KEY_SIZE; - range.num_encoding_sizes = 2; - } - } else { - range.num_encoding_sizes = 0; - range.max_encoding_tokens = 0; - } - dldwd_unlock(priv); - - range.min_pmp = 0; - range.max_pmp = 65535000; - range.min_pmt = 0; - range.max_pmt = 65535 * 1000; /* ??? */ - range.pmp_flags = IW_POWER_PERIOD; - range.pmt_flags = IW_POWER_TIMEOUT; - range.pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_UNICAST_R; - - range.num_txpower = 1; - range.txpower[0] = 15; /* 15dBm */ - range.txpower_capa = IW_TXPOW_DBM; - -#if WIRELESS_EXT > 10 - range.retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME; - range.retry_flags = IW_RETRY_LIMIT; - range.r_time_flags = IW_RETRY_LIFETIME; - range.min_retry = 0; - range.max_retry = 65535; /* ??? */ - range.min_r_time = 0; - range.max_r_time = 65535 * 1000; /* ??? */ -#endif /* WIRELESS_EXT > 10 */ - - if (copy_to_user(rrq->pointer, &range, sizeof(range))) - return -EFAULT; - - TRACE_EXIT(dev->name); - - return 0; -} - -static int dldwd_ioctl_setiwencode(struct net_device *dev, struct iw_point *erq) -{ - dldwd_priv_t *priv = dev->priv; - int index = (erq->flags & IW_ENCODE_INDEX) - 1; - int setindex = priv->tx_key; - int enable = priv->wep_on; - int restricted = priv->wep_restrict; - uint16_t xlen = 0; - int err = 0; - char keybuf[MAX_KEY_SIZE]; - - if (erq->pointer) { - /* We actually have a key to set */ - - if (copy_from_user(keybuf, erq->pointer, erq->length)) - return -EFAULT; - } - - dldwd_lock(priv); - - if (erq->pointer) { - if (erq->length > MAX_KEY_SIZE) { - err = -E2BIG; - goto out; - } - - if ( (erq->length > LARGE_KEY_SIZE) - || ( ! priv->has_big_wep && (erq->length > SMALL_KEY_SIZE)) ) { - err = -EINVAL; - goto out; - } - - if ((index < 0) || (index >= MAX_KEYS)) - index = priv->tx_key; - - if (erq->length > SMALL_KEY_SIZE) { - xlen = LARGE_KEY_SIZE; - } else if (erq->length > 0) { - xlen = SMALL_KEY_SIZE; - } else - xlen = 0; - - /* Switch on WEP if off */ - if ((!enable) && (xlen > 0)) { - setindex = index; - enable = 1; - } - } else { - /* Important note : if the user do "iwconfig eth0 enc off", - * we will arrive there with an index of -1. This is valid - * but need to be taken care off... Jean II */ - if ((index < 0) || (index >= MAX_KEYS)) { - if((index != -1) || (erq->flags == 0)) { - err = -EINVAL; - goto out; - } - } else { - /* Set the index : Check that the key is valid */ - if(priv->keys[index].len == 0) { - err = -EINVAL; - goto out; - } - setindex = index; - } - } - - if (erq->flags & IW_ENCODE_DISABLED) - enable = 0; - /* Only for Prism2 & Symbol cards (so far) - Jean II */ - if (erq->flags & IW_ENCODE_OPEN) - restricted = 0; - if (erq->flags & IW_ENCODE_RESTRICTED) - restricted = 1; - - if (erq->pointer) { - priv->keys[index].len = cpu_to_le16(xlen); - memset(priv->keys[index].data, 0, sizeof(priv->keys[index].data)); - memcpy(priv->keys[index].data, keybuf, erq->length); - } - priv->tx_key = setindex; - priv->wep_on = enable; - priv->wep_restrict = restricted; - - out: - dldwd_unlock(priv); - - return 0; -} - -static int dldwd_ioctl_getiwencode(struct net_device *dev, struct iw_point *erq) -{ - dldwd_priv_t *priv = dev->priv; - int index = (erq->flags & IW_ENCODE_INDEX) - 1; - uint16_t xlen = 0; - char keybuf[MAX_KEY_SIZE]; - - - dldwd_lock(priv); - - if ((index < 0) || (index >= MAX_KEYS)) - index = priv->tx_key; - - erq->flags = 0; - if (! priv->wep_on) - erq->flags |= IW_ENCODE_DISABLED; - erq->flags |= index + 1; - - /* Only for symbol cards - Jean II */ - if (priv->firmware_type != FIRMWARE_TYPE_LUCENT) { - if(priv->wep_restrict) - erq->flags |= IW_ENCODE_RESTRICTED; - else - erq->flags |= IW_ENCODE_OPEN; - } - - xlen = le16_to_cpu(priv->keys[index].len); - - erq->length = xlen; - - if (erq->pointer) { - memcpy(keybuf, priv->keys[index].data, MAX_KEY_SIZE); - } - - dldwd_unlock(priv); - - if (erq->pointer) { - if (copy_to_user(erq->pointer, keybuf, xlen)) - return -EFAULT; - } - - return 0; -} - -static int dldwd_ioctl_setessid(struct net_device *dev, struct iw_point *erq) -{ - dldwd_priv_t *priv = dev->priv; - char essidbuf[IW_ESSID_MAX_SIZE+1]; - - /* Note : ESSID is ignored in Ad-Hoc demo mode, but we can set it - * anyway... - Jean II */ - - memset(&essidbuf, 0, sizeof(essidbuf)); - - if (erq->flags) { - if (erq->length > IW_ESSID_MAX_SIZE) - return -E2BIG; - - if (copy_from_user(&essidbuf, erq->pointer, erq->length)) - return -EFAULT; - - essidbuf[erq->length] = '\0'; - } - - dldwd_lock(priv); - - memcpy(priv->desired_essid, essidbuf, IW_ESSID_MAX_SIZE+1); - - dldwd_unlock(priv); - - return 0; -} - -static int dldwd_ioctl_getessid(struct net_device *dev, struct iw_point *erq) -{ - dldwd_priv_t *priv = dev->priv; - char essidbuf[IW_ESSID_MAX_SIZE+1]; - int active; - int err = 0; - - TRACE_ENTER(dev->name); - - err = dldwd_hw_get_essid(priv, &active, essidbuf); - if (err) - return err; - - erq->flags = 1; - erq->length = strlen(essidbuf) + 1; - if (erq->pointer) - if ( copy_to_user(erq->pointer, essidbuf, erq->length) ) - return -EFAULT; - - TRACE_EXIT(dev->name); - - return 0; -} - -static int dldwd_ioctl_setnick(struct net_device *dev, struct iw_point *nrq) -{ - dldwd_priv_t *priv = dev->priv; - char nickbuf[IW_ESSID_MAX_SIZE+1]; - - if (nrq->length > IW_ESSID_MAX_SIZE) - return -E2BIG; - - memset(nickbuf, 0, sizeof(nickbuf)); - - if (copy_from_user(nickbuf, nrq->pointer, nrq->length)) - return -EFAULT; - - nickbuf[nrq->length] = '\0'; - - dldwd_lock(priv); - - memcpy(priv->nick, nickbuf, sizeof(priv->nick)); - - dldwd_unlock(priv); - - return 0; -} - -static int dldwd_ioctl_getnick(struct net_device *dev, struct iw_point *nrq) -{ - dldwd_priv_t *priv = dev->priv; - char nickbuf[IW_ESSID_MAX_SIZE+1]; - - dldwd_lock(priv); - memcpy(nickbuf, priv->nick, IW_ESSID_MAX_SIZE+1); - dldwd_unlock(priv); - - nrq->length = strlen(nickbuf)+1; - - if (copy_to_user(nrq->pointer, nickbuf, sizeof(nickbuf))) - return -EFAULT; - - return 0; -} - -static int dldwd_ioctl_setfreq(struct net_device *dev, struct iw_freq *frq) -{ - dldwd_priv_t *priv = dev->priv; - int chan = -1; - - /* We can only use this in Ad-Hoc demo mode to set the operating - * frequency, or in IBSS mode to set the frequency where the IBSS - * will be created - Jean II */ - if (priv->iw_mode != IW_MODE_ADHOC) - return -EOPNOTSUPP; - - if ( (frq->e == 0) && (frq->m <= 1000) ) { - /* Setting by channel number */ - chan = frq->m; - } else { - /* Setting by frequency - search the table */ - int mult = 1; - int i; - - for (i = 0; i < (6 - frq->e); i++) - mult *= 10; - - for (i = 0; i < NUM_CHANNELS; i++) - if (frq->m == (channel_frequency[i] * mult)) - chan = i+1; - } - - if ( (chan < 1) || (chan > NUM_CHANNELS) || - ! (priv->channel_mask & (1 << (chan-1)) ) ) - return -EINVAL; - - dldwd_lock(priv); - priv->channel = chan; - dldwd_unlock(priv); - - return 0; -} - -static int dldwd_ioctl_getsens(struct net_device *dev, struct iw_param *srq) -{ - dldwd_priv_t *priv = dev->priv; - hermes_t *hw = &priv->hw; - uint16_t val; - int err; - - dldwd_lock(priv); - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYSTEM_SCALE, &val); - dldwd_unlock(priv); - - if (err) - return err; - - srq->value = val; - srq->fixed = 0; /* auto */ - - return 0; -} - -static int dldwd_ioctl_setsens(struct net_device *dev, struct iw_param *srq) -{ - dldwd_priv_t *priv = dev->priv; - int val = srq->value; - - if ((val < 1) || (val > 3)) - return -EINVAL; - - dldwd_lock(priv); - priv->ap_density = val; - dldwd_unlock(priv); - - return 0; -} - -static int dldwd_ioctl_setrts(struct net_device *dev, struct iw_param *rrq) -{ - dldwd_priv_t *priv = dev->priv; - int val = rrq->value; - - if (rrq->disabled) - val = 2347; - - if ( (val < 0) || (val > 2347) ) - return -EINVAL; - - dldwd_lock(priv); - priv->rts_thresh = val; - dldwd_unlock(priv); - - return 0; -} - -static int dldwd_ioctl_setfrag(struct net_device *dev, struct iw_param *frq) -{ - dldwd_priv_t *priv = dev->priv; - int err = 0; - - dldwd_lock(priv); - - if (priv->has_mwo) { - if (frq->disabled) - priv->mwo_robust = 0; - else { - if (frq->fixed) - printk(KERN_WARNING "%s: Fixed fragmentation not \ -supported on this firmware. Using MWO robust instead.\n", dev->name); - priv->mwo_robust = 1; - } - } else { - if (frq->disabled) - priv->frag_thresh = 2346; - else { - if ( (frq->value < 256) || (frq->value > 2346) ) - err = -EINVAL; - else - priv->frag_thresh = frq->value & ~0x1; /* must be even */ - } - } - - dldwd_unlock(priv); - - return err; -} - -static int dldwd_ioctl_getfrag(struct net_device *dev, struct iw_param *frq) -{ - dldwd_priv_t *priv = dev->priv; - hermes_t *hw = &priv->hw; - int err = 0; - uint16_t val; - - dldwd_lock(priv); - - if (priv->has_mwo) { - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_MWO_ROBUST, &val); - if (err) - val = 0; - - frq->value = val ? 2347 : 0; - frq->disabled = ! val; - frq->fixed = 0; - } else { - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_FRAG_THRESH, &val); - if (err) - val = 0; - - frq->value = val; - frq->disabled = (val >= 2346); - frq->fixed = 1; - } - - dldwd_unlock(priv); - - return err; -} - -static int dldwd_ioctl_setrate(struct net_device *dev, struct iw_param *rrq) -{ - dldwd_priv_t *priv = dev->priv; - int err = 0; - int rate_ctrl = -1; - int fixed, upto; - int brate; - int i; - - dldwd_lock(priv); - - /* Normalise value */ - brate = rrq->value / 500000; - - switch (priv->firmware_type) { - case FIRMWARE_TYPE_LUCENT: /* Lucent style rate */ - if (! rrq->fixed) { - if (brate > 0) - brate = -brate; - else - brate = -22; - } - - for (i = 0; i < NUM_RATES; i++) - if (rate_list[i] == brate) { - rate_ctrl = i; - break; - } - - if ( (rate_ctrl < 1) || (rate_ctrl >= NUM_RATES) ) - err = -EINVAL; - else - priv->tx_rate_ctrl = rate_ctrl; - break; - case FIRMWARE_TYPE_PRISM2: /* Prism II style rate */ - case FIRMWARE_TYPE_SYMBOL: /* Symbol style rate */ - switch(brate) { - case 0: - fixed = 0x0; - upto = 0x15; - break; - case 2: - fixed = 0x1; - upto = 0x1; - break; - case 4: - fixed = 0x2; - upto = 0x3; - break; - case 11: - fixed = 0x4; - upto = 0x7; - break; - case 22: - fixed = 0x8; - upto = 0x15; - break; - default: - fixed = 0x0; - upto = 0x0; - } - if (rrq->fixed) - rate_ctrl = fixed; - else - rate_ctrl = upto; - if (rate_ctrl == 0) - err = -EINVAL; - else - priv->tx_rate_ctrl = rate_ctrl; - break; - } - - dldwd_unlock(priv); - - return err; -} - -static int dldwd_ioctl_getrate(struct net_device *dev, struct iw_param *rrq) -{ - dldwd_priv_t *priv = dev->priv; - hermes_t *hw = &priv->hw; - int err = 0; - uint16_t val; - int brate = 0; - - dldwd_lock(priv); - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_TX_RATE_CTRL, &val); - if (err) - goto out; - - switch (priv->firmware_type) { - case FIRMWARE_TYPE_LUCENT: /* Lucent style rate */ - brate = rate_list[val]; - - if (brate < 0) { - rrq->fixed = 0; - - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENT_TX_RATE, &val); - if (err) - goto out; - - if (val == 6) - brate = 11; - else - brate = 2*val; - } else - rrq->fixed = 1; - break; - case FIRMWARE_TYPE_PRISM2: /* Prism II style rate */ - case FIRMWARE_TYPE_SYMBOL: /* Symbol style rate */ - /* Check if auto or fixed (crude approximation) */ - if((val & 0x1) && (val > 1)) { - rrq->fixed = 0; - - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENT_TX_RATE, &val); - if (err) - goto out; - } else - rrq->fixed = 1; - - if(val >= 8) - brate = 22; - else if(val >= 4) - brate = 11; - else if(val >= 2) - brate = 4; - else - brate = 2; - break; - } - - rrq->value = brate * 500000; - rrq->disabled = 0; - - out: - dldwd_unlock(priv); - - return err; -} - -static int dldwd_ioctl_setpower(struct net_device *dev, struct iw_param *prq) -{ - dldwd_priv_t *priv = dev->priv; - int err = 0; - - - dldwd_lock(priv); - - if (prq->disabled) { - priv->pm_on = 0; - } else { - switch (prq->flags & IW_POWER_MODE) { - case IW_POWER_UNICAST_R: - priv->pm_mcast = 0; - priv->pm_on = 1; - break; - case IW_POWER_ALL_R: - priv->pm_mcast = 1; - priv->pm_on = 1; - break; - case IW_POWER_ON: - /* No flags : but we may have a value - Jean II */ - break; - default: - err = -EINVAL; - } - if (err) - goto out; - - if (prq->flags & IW_POWER_TIMEOUT) { - priv->pm_on = 1; - priv->pm_timeout = prq->value / 1000; - } - if (prq->flags & IW_POWER_PERIOD) { - priv->pm_on = 1; - priv->pm_period = prq->value / 1000; - } - /* It's valid to not have a value if we are just toggling - * the flags... Jean II */ - if(!priv->pm_on) { - err = -EINVAL; - goto out; - } - } - - out: - dldwd_unlock(priv); - - return err; -} - -static int dldwd_ioctl_getpower(struct net_device *dev, struct iw_param *prq) -{ - dldwd_priv_t *priv = dev->priv; - hermes_t *hw = &priv->hw; - int err = 0; - uint16_t enable, period, timeout, mcast; - - dldwd_lock(priv); - - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_ENABLE, &enable); - if (err) - goto out; - - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_PERIOD, &period); - if (err) - goto out; - - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_HOLDOVER, &timeout); - if (err) - goto out; - - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_MCAST_RX, &mcast); - if (err) - goto out; - - prq->disabled = !enable; - /* Note : by default, display the period */ - if ((prq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) { - prq->flags = IW_POWER_TIMEOUT; - prq->value = timeout * 1000; - } else { - prq->flags = IW_POWER_PERIOD; - prq->value = period * 1000; - } - if (mcast) - prq->flags |= IW_POWER_ALL_R; - else - prq->flags |= IW_POWER_UNICAST_R; - - out: - dldwd_unlock(priv); - - return err; -} - -#if WIRELESS_EXT > 10 -static int dldwd_ioctl_setretry(struct net_device *dev, struct iw_param *rrq) -{ - dldwd_priv_t *priv = dev->priv; - int err = 0; - - - dldwd_lock(priv); - - if ((rrq->disabled) || (!priv->has_retry)){ - err = -EOPNOTSUPP; - goto out; - } else { - if (rrq->flags & IW_RETRY_LIMIT) { - if (rrq->flags & IW_RETRY_MAX) - priv->retry_long = rrq->value; - else if (rrq->flags & IW_RETRY_MIN) - priv->retry_short = rrq->value; - else { - /* No modifier : set both */ - priv->retry_long = rrq->value; - priv->retry_short = rrq->value; - } - } - if (rrq->flags & IW_RETRY_LIFETIME) { - priv->retry_time = rrq->value / 1000; - } - if ((rrq->flags & IW_RETRY_TYPE) == 0) { - err = -EINVAL; - goto out; - } - } - - out: - dldwd_unlock(priv); - - return err; -} - -static int dldwd_ioctl_getretry(struct net_device *dev, struct iw_param *rrq) -{ - dldwd_priv_t *priv = dev->priv; - hermes_t *hw = &priv->hw; - int err = 0; - uint16_t short_limit, long_limit, lifetime; - - dldwd_lock(priv); - - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_SHORT_RETRY_LIMIT, &short_limit); - if (err) - goto out; - - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_LONG_RETRY_LIMIT, &long_limit); - if (err) - goto out; - - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_MAX_TX_LIFETIME, &lifetime); - if (err) - goto out; - - rrq->disabled = 0; /* Can't be disabled */ - - /* Note : by default, display the retry number */ - if ((rrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) { - rrq->flags = IW_RETRY_LIFETIME; - rrq->value = lifetime * 1000; /* ??? */ - } else { - /* By default, display the min number */ - if ((rrq->flags & IW_RETRY_MAX)) { - rrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX; - rrq->value = long_limit; - } else { - rrq->flags = IW_RETRY_LIMIT; - rrq->value = short_limit; - if(short_limit != long_limit) - rrq->flags |= IW_RETRY_MIN; - } - } - - out: - dldwd_unlock(priv); - - return err; -} -#endif /* WIRELESS_EXT > 10 */ - -static int dldwd_ioctl_setport3(struct net_device *dev, struct iwreq *wrq) -{ - dldwd_priv_t *priv = dev->priv; - int val = *( (int *) wrq->u.name ); - int err = 0; - - dldwd_lock(priv); - switch (val) { - case 0: /* Try to do IEEE ad-hoc mode */ - if (! priv->has_ibss) { - err = -EINVAL; - break; - } - priv->prefer_port3 = 0; - - break; - - case 1: /* Try to do Lucent proprietary ad-hoc mode */ - if (! priv->has_port3) { - err = -EINVAL; - break; - } - priv->prefer_port3 = 1; - break; - - default: - err = -EINVAL; - } - - if (! err) - /* Actually update the mode we are using */ - set_port_type(priv); - - dldwd_unlock(priv); - - return err; -} - -static int dldwd_ioctl_getport3(struct net_device *dev, struct iwreq *wrq) -{ - dldwd_priv_t *priv = dev->priv; - int *val = (int *)wrq->u.name; - - dldwd_lock(priv); - *val = priv->prefer_port3; - dldwd_unlock(priv); - - return 0; -} - -/* Spy is used for link quality/strength measurements in Ad-Hoc mode - * Jean II */ -static int dldwd_ioctl_setspy(struct net_device *dev, struct iw_point *srq) -{ - dldwd_priv_t *priv = dev->priv; - struct sockaddr address[IW_MAX_SPY]; - int number = srq->length; - int i; - int err = 0; - - /* Check the number of addresses */ - if (number > IW_MAX_SPY) - return -E2BIG; - - /* Get the data in the driver */ - if (srq->pointer) { - if (copy_from_user(address, srq->pointer, - sizeof(struct sockaddr) * number)) - return -EFAULT; - } - - /* Make sure nobody mess with the structure while we do */ - dldwd_lock(priv); - - /* dldwd_lock() doesn't disable interrupts, so make sure the - * interrupt rx path don't get confused while we copy */ - priv->spy_number = 0; - - if (number > 0) { - /* Extract the addresses */ - for (i = 0; i < number; i++) - memcpy(priv->spy_address[i], address[i].sa_data, - ETH_ALEN); - /* Reset stats */ - memset(priv->spy_stat, 0, - sizeof(struct iw_quality) * IW_MAX_SPY); - /* Set number of addresses */ - priv->spy_number = number; - } - - /* Time to show what we have done... */ - DEBUG(0, "%s: New spy list:\n", dev->name); - for (i = 0; i < number; i++) { - DEBUG(0, "%s: %d - %02x:%02x:%02x:%02x:%02x:%02x\n", - dev->name, i+1, - priv->spy_address[i][0], priv->spy_address[i][1], - priv->spy_address[i][2], priv->spy_address[i][3], - priv->spy_address[i][4], priv->spy_address[i][5]); - } - - /* Now, let the others play */ - dldwd_unlock(priv); - - return err; -} - -static int dldwd_ioctl_getspy(struct net_device *dev, struct iw_point *srq) -{ - dldwd_priv_t *priv = dev->priv; - struct sockaddr address[IW_MAX_SPY]; - struct iw_quality spy_stat[IW_MAX_SPY]; - int number; - int i; - - dldwd_lock(priv); - - number = priv->spy_number; - if ((number > 0) && (srq->pointer)) { - /* Create address struct */ - for (i = 0; i < number; i++) { - memcpy(address[i].sa_data, priv->spy_address[i], - ETH_ALEN); - address[i].sa_family = AF_UNIX; - } - /* Copy stats */ - /* In theory, we should disable irqs while copying the stats - * because the rx path migh update it in the middle... - * Bah, who care ? - Jean II */ - memcpy(&spy_stat, priv->spy_stat, - sizeof(struct iw_quality) * IW_MAX_SPY); - for (i=0; i < number; i++) - priv->spy_stat[i].updated = 0; - } - - dldwd_unlock(priv); - - /* Push stuff to user space */ - srq->length = number; - if(copy_to_user(srq->pointer, address, - sizeof(struct sockaddr) * number)) - return -EFAULT; - if(copy_to_user(srq->pointer + (sizeof(struct sockaddr)*number), - &spy_stat, sizeof(struct iw_quality) * number)) - return -EFAULT; - - return 0; -} - -static int dldwd_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -{ - dldwd_priv_t *priv = dev->priv; - struct iwreq *wrq = (struct iwreq *)rq; - int err = 0; - int changed = 0; - - TRACE_ENTER(dev->name); - - switch (cmd) { - case SIOCGIWNAME: - DEBUG(1, "%s: SIOCGIWNAME\n", dev->name); - strcpy(wrq->u.name, "IEEE 802.11-DS"); - break; - - case SIOCGIWAP: - DEBUG(1, "%s: SIOCGIWAP\n", dev->name); - wrq->u.ap_addr.sa_family = ARPHRD_ETHER; - err = dldwd_hw_get_bssid(priv, wrq->u.ap_addr.sa_data); - break; - - case SIOCGIWRANGE: - DEBUG(1, "%s: SIOCGIWRANGE\n", dev->name); - err = dldwd_ioctl_getiwrange(dev, &wrq->u.data); - break; - - case SIOCSIWMODE: - DEBUG(1, "%s: SIOCSIWMODE\n", dev->name); - dldwd_lock(priv); - switch (wrq->u.mode) { - case IW_MODE_ADHOC: - if (! (priv->has_ibss || priv->has_port3) ) - err = -EINVAL; - else { - priv->iw_mode = IW_MODE_ADHOC; - changed = 1; - } - break; - - case IW_MODE_INFRA: - priv->iw_mode = IW_MODE_INFRA; - changed = 1; - break; - - default: - err = -EINVAL; - break; - } - set_port_type(priv); - dldwd_unlock(priv); - break; - - case SIOCGIWMODE: - DEBUG(1, "%s: SIOCGIWMODE\n", dev->name); - dldwd_lock(priv); - wrq->u.mode = priv->iw_mode; - dldwd_unlock(priv); - break; - - case SIOCSIWENCODE: - DEBUG(1, "%s: SIOCSIWENCODE\n", dev->name); - if (! priv->has_wep) { - err = -EOPNOTSUPP; - break; - } - - err = dldwd_ioctl_setiwencode(dev, &wrq->u.encoding); - if (! err) - changed = 1; - break; - - case SIOCGIWENCODE: - DEBUG(1, "%s: SIOCGIWENCODE\n", dev->name); - if (! priv->has_wep) { - err = -EOPNOTSUPP; - break; - } - - if (! capable(CAP_NET_ADMIN)) { - err = -EPERM; - break; - } - - err = dldwd_ioctl_getiwencode(dev, &wrq->u.encoding); - break; - - case SIOCSIWESSID: - DEBUG(1, "%s: SIOCSIWESSID\n", dev->name); - err = dldwd_ioctl_setessid(dev, &wrq->u.essid); - if (! err) - changed = 1; - break; - - case SIOCGIWESSID: - DEBUG(1, "%s: SIOCGIWESSID\n", dev->name); - err = dldwd_ioctl_getessid(dev, &wrq->u.essid); - break; - - case SIOCSIWNICKN: - DEBUG(1, "%s: SIOCSIWNICKN\n", dev->name); - err = dldwd_ioctl_setnick(dev, &wrq->u.data); - if (! err) - changed = 1; - break; - - case SIOCGIWNICKN: - DEBUG(1, "%s: SIOCGIWNICKN\n", dev->name); - err = dldwd_ioctl_getnick(dev, &wrq->u.data); - break; - - case SIOCGIWFREQ: - DEBUG(1, "%s: SIOCGIWFREQ\n", dev->name); - wrq->u.freq.m = dldwd_hw_get_freq(priv); - wrq->u.freq.e = 1; - break; - - case SIOCSIWFREQ: - DEBUG(1, "%s: SIOCSIWFREQ\n", dev->name); - err = dldwd_ioctl_setfreq(dev, &wrq->u.freq); - if (! err) - changed = 1; - break; - - case SIOCGIWSENS: - DEBUG(1, "%s: SIOCGIWSENS\n", dev->name); - err = dldwd_ioctl_getsens(dev, &wrq->u.sens); - break; - - case SIOCSIWSENS: - DEBUG(1, "%s: SIOCSIWSENS\n", dev->name); - err = dldwd_ioctl_setsens(dev, &wrq->u.sens); - if (! err) - changed = 1; - break; - - case SIOCGIWRTS: - DEBUG(1, "%s: SIOCGIWRTS\n", dev->name); - wrq->u.rts.value = priv->rts_thresh; - wrq->u.rts.disabled = (wrq->u.rts.value == 2347); - wrq->u.rts.fixed = 1; - break; - - case SIOCSIWRTS: - DEBUG(1, "%s: SIOCSIWRTS\n", dev->name); - err = dldwd_ioctl_setrts(dev, &wrq->u.rts); - if (! err) - changed = 1; - break; - - case SIOCSIWFRAG: - DEBUG(1, "%s: SIOCSIWFRAG\n", dev->name); - err = dldwd_ioctl_setfrag(dev, &wrq->u.frag); - if (! err) - changed = 1; - break; - - case SIOCGIWFRAG: - DEBUG(1, "%s: SIOCGIWFRAG\n", dev->name); - err = dldwd_ioctl_getfrag(dev, &wrq->u.frag); - break; - - case SIOCSIWRATE: - DEBUG(1, "%s: SIOCSIWRATE\n", dev->name); - err = dldwd_ioctl_setrate(dev, &wrq->u.bitrate); - if (! err) - changed = 1; - break; - - case SIOCGIWRATE: - DEBUG(1, "%s: SIOCGIWRATE\n", dev->name); - err = dldwd_ioctl_getrate(dev, &wrq->u.bitrate); - break; - - case SIOCSIWPOWER: - DEBUG(1, "%s: SIOCSIWPOWER\n", dev->name); - err = dldwd_ioctl_setpower(dev, &wrq->u.power); - if (! err) - changed = 1; - break; - - case SIOCGIWPOWER: - DEBUG(1, "%s: SIOCGIWPOWER\n", dev->name); - err = dldwd_ioctl_getpower(dev, &wrq->u.power); - break; - - case SIOCGIWTXPOW: - DEBUG(1, "%s: SIOCGIWTXPOW\n", dev->name); - /* The card only supports one tx power, so this is easy */ - wrq->u.txpower.value = 15; /* dBm */ - wrq->u.txpower.fixed = 1; - wrq->u.txpower.disabled = 0; - wrq->u.txpower.flags = IW_TXPOW_DBM; - break; - -#if WIRELESS_EXT > 10 - case SIOCSIWRETRY: - DEBUG(1, "%s: SIOCSIWRETRY\n", dev->name); - err = dldwd_ioctl_setretry(dev, &wrq->u.retry); - if (! err) - changed = 1; - break; - - case SIOCGIWRETRY: - DEBUG(1, "%s: SIOCGIWRETRY\n", dev->name); - err = dldwd_ioctl_getretry(dev, &wrq->u.retry); - break; -#endif /* WIRELESS_EXT > 10 */ - - case SIOCSIWSPY: - DEBUG(1, "%s: SIOCSIWSPY\n", dev->name); - - err = dldwd_ioctl_setspy(dev, &wrq->u.data); - break; - - case SIOCGIWSPY: - DEBUG(1, "%s: SIOCGIWSPY\n", dev->name); - - err = dldwd_ioctl_getspy(dev, &wrq->u.data); - break; - - case SIOCGIWPRIV: - DEBUG(1, "%s: SIOCGIWPRIV\n", dev->name); - if (wrq->u.data.pointer) { - struct iw_priv_args privtab[] = { - { SIOCDEVPRIVATE + 0x0, 0, 0, "force_reset" }, - { SIOCDEVPRIVATE + 0x2, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - 0, "set_port3" }, - { SIOCDEVPRIVATE + 0x3, 0, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - "get_port3" }, - { SIOCDEVPRIVATE + 0x4, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - 0, "set_preamble" }, - { SIOCDEVPRIVATE + 0x5, 0, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - "get_preamble" } - }; - - err = verify_area(VERIFY_WRITE, wrq->u.data.pointer, sizeof(privtab)); - if (err) - break; - - wrq->u.data.length = sizeof(privtab) / sizeof(privtab[0]); - if (copy_to_user(wrq->u.data.pointer, privtab, sizeof(privtab))) - err = -EFAULT; - } - break; - - case SIOCDEVPRIVATE + 0x0: /* force_reset */ - DEBUG(1, "%s: SIOCDEVPRIVATE + 0x0 (force_reset)\n", - dev->name); - if (! capable(CAP_NET_ADMIN)) { - err = -EPERM; - break; - } - - printk(KERN_DEBUG "%s: Forcing reset!\n", dev->name); - dldwd_reset(priv); - break; - - case SIOCDEVPRIVATE + 0x2: /* set_port3 */ - DEBUG(1, "%s: SIOCDEVPRIVATE + 0x2 (set_port3)\n", - dev->name); - if (! capable(CAP_NET_ADMIN)) { - err = -EPERM; - break; - } - - err = dldwd_ioctl_setport3(dev, wrq); - if (! err) - changed = 1; - break; - - case SIOCDEVPRIVATE + 0x3: /* get_port3 */ - DEBUG(1, "%s: SIOCDEVPRIVATE + 0x3 (get_port3)\n", - dev->name); - err = dldwd_ioctl_getport3(dev, wrq); - break; - - case SIOCDEVPRIVATE + 0x4: /* set_preamble */ - DEBUG(1, "%s: SIOCDEVPRIVATE + 0x4 (set_preamble)\n", - dev->name); - if (! capable(CAP_NET_ADMIN)) { - err = -EPERM; - break; - } - - /* 802.11b has recently defined some short preamble. - * Basically, the Phy header has been reduced in size. - * This increase performance, especially at high rates - * (the preamble is transmitted at 1Mb/s), unfortunately - * this give compatibility troubles... - Jean II */ - if(priv->has_preamble) { - int val = *( (int *) wrq->u.name ); - - dldwd_lock(priv); - if(val) - priv->preamble = 1; - else - priv->preamble = 0; - dldwd_unlock(priv); - changed = 1; - } else - err = -EOPNOTSUPP; - break; - - case SIOCDEVPRIVATE + 0x5: /* get_preamble */ - DEBUG(1, "%s: SIOCDEVPRIVATE + 0x5 (get_preamble)\n", - dev->name); - if(priv->has_preamble) { - int *val = (int *)wrq->u.name; - - dldwd_lock(priv); - *val = priv->preamble; - dldwd_unlock(priv); - } else - err = -EOPNOTSUPP; - break; - - default: - err = -EOPNOTSUPP; - } - - if (! err && changed && netif_running(dev)) { - err = dldwd_reset(priv); - if (err) - dldwd_stop(dev); - } - - TRACE_EXIT(dev->name); - - return err; -} - -static int dldwd_change_mtu(struct net_device *dev, int new_mtu) -{ - TRACE_ENTER(dev->name); - - if ( (new_mtu < DLDWD_MIN_MTU) || (new_mtu > DLDWD_MAX_MTU) ) - return -EINVAL; - - dev->mtu = new_mtu; - - TRACE_EXIT(dev->name); - - return 0; -} - -static void __dldwd_set_multicast_list(struct net_device *dev) -{ - dldwd_priv_t *priv = dev->priv; - hermes_t *hw = &priv->hw; - int err = 0; - int promisc, allmulti, mc_count; - - TRACE_ENTER(dev->name); - - DEBUG(3, "dev->flags=0x%x, priv->promiscuous=%d, dev->mc_count=%d priv->mc_count=%d\n", - dev->flags, priv->promiscuous, dev->mc_count, priv->mc_count); - - /* The Hermes doesn't seem to have an allmulti mode, so we go - * into promiscuous mode and let the upper levels deal. */ - if ( (dev->flags & IFF_PROMISC) ) { - promisc = 1; - allmulti = 0; - mc_count = 0; - } else if ( (dev->flags & IFF_ALLMULTI) || - (dev->mc_count > HERMES_MAX_MULTICAST) ) { - promisc = 0; - allmulti = 1; - mc_count = HERMES_MAX_MULTICAST; - } else { - promisc = 0; - allmulti = 0; - mc_count = dev->mc_count; - } - - DEBUG(3, "promisc=%d mc_count=%d\n", - promisc, mc_count); - - if (promisc != priv->promiscuous) { /* Don't touch the hardware if we don't have to */ - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PROMISCUOUS, - promisc); - if (err) { - printk(KERN_ERR "%s: Error %d setting promiscuity to %d.\n", - dev->name, err, promisc); - } else - priv->promiscuous = promisc; - } - - if (allmulti) { - /* FIXME: This method of doing allmulticast reception - comes from the NetBSD driver. Haven't actually - tested whether it works or not. */ - hermes_multicast_t mclist; - - memset(&mclist, 0, sizeof(mclist)); - err = HERMES_WRITE_RECORD(hw, USER_BAP, HERMES_RID_CNF_MULTICAST_LIST, &mclist); - if (err) - printk(KERN_ERR "%s: Error %d setting multicast list.\n", - dev->name, err); - else - priv->allmulti = 1; - - } else if (mc_count || (! mc_count && priv->mc_count) ) { - struct dev_mc_list *p = dev->mc_list; - hermes_multicast_t mclist; - int i; - - for (i = 0; i < mc_count; i++) { - /* First some paranoid checks */ - if (! p) { - printk(KERN_ERR "%s: Multicast list shorter than mc_count.\n", - dev->name); - break; - } - if (p->dmi_addrlen != ETH_ALEN) { - - printk(KERN_ERR "%s: Bad address size (%d) in multicast list.\n", - dev->name, p->dmi_addrlen); - break; - } - - memcpy(mclist.addr[i], p->dmi_addr, ETH_ALEN); - p = p->next; - } - - /* More paranoia */ - if (p) - printk(KERN_ERR "%s: Multicast list longer than mc_count.\n", - dev->name); - - priv->mc_count = i; - - DEBUG(3, "priv->mc_count = %d\n", priv->mc_count); - - err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNF_MULTICAST_LIST, - HERMES_BYTES_TO_RECLEN(priv->mc_count * ETH_ALEN), - &mclist); - if (err) - printk(KERN_ERR "%s: Error %d setting multicast list.\n", - dev->name, err); - else - priv->allmulti = 0; - } - - /* Since we can set the promiscuous flag when it wasn't asked - for, make sure the net_device knows about it. */ - if (priv->promiscuous) - dev->flags |= IFF_PROMISC; - else - dev->flags &= ~IFF_PROMISC; - - if (priv->allmulti) - dev->flags |= IFF_ALLMULTI; - else - dev->flags &= ~IFF_ALLMULTI; - - TRACE_EXIT(dev->name); -} - -/* - * procfs stuff - */ - -static struct proc_dir_entry *dir_base = NULL; - -/* - * This function updates the total amount of data printed so far. It then - * determines if the amount of data printed into a buffer has reached the - * offset requested. If it hasn't, then the buffer is shifted over so that - * the next bit of data can be printed over the old bit. If the total - * amount printed so far exceeds the total amount requested, then this - * function returns 1, otherwise 0. - */ -static int - -shift_buffer(char *buffer, int requested_offset, int requested_len, - int *total, int *slop, char **buf) -{ - int printed; - - printed = *buf - buffer; - if (*total + printed <= requested_offset) { - *total += printed; - *buf = buffer; - } - else { - if (*total < requested_offset) { - *slop = requested_offset - *total; - } - *total = requested_offset + printed - *slop; - } - if (*total > requested_offset + requested_len) { - return 1; - } - else { - return 0; - } -} - -/* - * This function calculates the actual start of the requested data - * in the buffer. It also calculates actual length of data returned, - * which could be less that the amount of data requested. - */ -#define PROC_BUFFER_SIZE 4096 -#define PROC_SAFE_SIZE 3072 - -static int -calc_start_len(char *buffer, char **start, int requested_offset, - int requested_len, int total, char *buf) -{ - int return_len, buffer_len; - - buffer_len = buf - buffer; - if (buffer_len >= PROC_BUFFER_SIZE - 1) { - printk(KERN_ERR "calc_start_len: exceeded /proc buffer size\n"); - } - - /* - * There may be bytes before and after the - * chunk that was actually requested. - */ - return_len = total - requested_offset; - if (return_len < 0) { - return_len = 0; - } - *start = buf - return_len; - if (return_len > requested_len) { - return_len = requested_len; - } - return return_len; -} - -static int -dldwd_proc_get_hermes_regs(char *page, char **start, off_t requested_offset, - int requested_len, int *eof, void *data) -{ - dldwd_priv_t *dev = (dldwd_priv_t *)data; - hermes_t *hw = &dev->hw; - char *buf; - int total = 0, slop = 0; - - buf = page; - -#define DHERMESREG(name) buf += sprintf(buf, "%-16s: %04x\n", #name, hermes_read_regn(hw, name)) - - DHERMESREG(CMD); - DHERMESREG(PARAM0); - DHERMESREG(PARAM1); - DHERMESREG(PARAM2); - DHERMESREG(STATUS); - DHERMESREG(RESP0); - DHERMESREG(RESP1); - DHERMESREG(RESP2); - DHERMESREG(INFOFID); - DHERMESREG(RXFID); - DHERMESREG(ALLOCFID); - DHERMESREG(TXCOMPLFID); - DHERMESREG(SELECT0); - DHERMESREG(OFFSET0); - DHERMESREG(SELECT1); - DHERMESREG(OFFSET1); - DHERMESREG(EVSTAT); - DHERMESREG(INTEN); - DHERMESREG(EVACK); - DHERMESREG(CONTROL); - DHERMESREG(SWSUPPORT0); - DHERMESREG(SWSUPPORT1); - DHERMESREG(SWSUPPORT2); - DHERMESREG(AUXPAGE); - DHERMESREG(AUXOFFSET); - DHERMESREG(AUXDATA); -#undef DHERMESREG - - shift_buffer(page, requested_offset, requested_len, &total, - &slop, &buf); - return calc_start_len(page, start, requested_offset, requested_len, - total, buf); -} - -struct { - uint16_t rid; - char *name; - int minlen, maxlen; - int displaytype; -#define DISPLAY_WORDS 0 -#define DISPLAY_BYTES 1 -#define DISPLAY_STRING 2 -} record_table[] = { -#define RTCNFENTRY(name, type) { HERMES_RID_CNF_##name, #name, 0, LTV_BUF_SIZE, type } - RTCNFENTRY(PORTTYPE, DISPLAY_WORDS), - RTCNFENTRY(MACADDR, DISPLAY_BYTES), - RTCNFENTRY(DESIRED_SSID, DISPLAY_STRING), - RTCNFENTRY(CHANNEL, DISPLAY_WORDS), - RTCNFENTRY(OWN_SSID, DISPLAY_STRING), - RTCNFENTRY(SYSTEM_SCALE, DISPLAY_WORDS), - RTCNFENTRY(MAX_DATA_LEN, DISPLAY_WORDS), - RTCNFENTRY(PM_ENABLE, DISPLAY_WORDS), - RTCNFENTRY(PM_MCAST_RX, DISPLAY_WORDS), - RTCNFENTRY(PM_PERIOD, DISPLAY_WORDS), - RTCNFENTRY(NICKNAME, DISPLAY_STRING), - RTCNFENTRY(WEP_ON, DISPLAY_WORDS), - RTCNFENTRY(MWO_ROBUST, DISPLAY_WORDS), - RTCNFENTRY(MULTICAST_LIST, DISPLAY_BYTES), - RTCNFENTRY(CREATEIBSS, DISPLAY_WORDS), - RTCNFENTRY(FRAG_THRESH, DISPLAY_WORDS), - RTCNFENTRY(RTS_THRESH, DISPLAY_WORDS), - RTCNFENTRY(TX_RATE_CTRL, DISPLAY_WORDS), - RTCNFENTRY(PROMISCUOUS, DISPLAY_WORDS), - RTCNFENTRY(KEYS, DISPLAY_BYTES), - RTCNFENTRY(TX_KEY, DISPLAY_WORDS), - RTCNFENTRY(TICKTIME, DISPLAY_WORDS), - RTCNFENTRY(PRISM2_TX_KEY, DISPLAY_WORDS), - RTCNFENTRY(PRISM2_KEY0, DISPLAY_BYTES), - RTCNFENTRY(PRISM2_KEY1, DISPLAY_BYTES), - RTCNFENTRY(PRISM2_KEY2, DISPLAY_BYTES), - RTCNFENTRY(PRISM2_KEY3, DISPLAY_BYTES), - RTCNFENTRY(PRISM2_WEP_ON, DISPLAY_WORDS), -#undef RTCNFENTRY -#define RTINFENTRY(name,type) { HERMES_RID_##name, #name, 0, LTV_BUF_SIZE, type } - RTINFENTRY(CHANNEL_LIST, DISPLAY_WORDS), - RTINFENTRY(STAIDENTITY, DISPLAY_WORDS), - RTINFENTRY(CURRENT_SSID, DISPLAY_STRING), - RTINFENTRY(CURRENT_BSSID, DISPLAY_BYTES), - RTINFENTRY(COMMSQUALITY, DISPLAY_WORDS), - RTINFENTRY(CURRENT_TX_RATE, DISPLAY_WORDS), - RTINFENTRY(WEP_AVAIL, DISPLAY_WORDS), - RTINFENTRY(CURRENT_CHANNEL, DISPLAY_WORDS), - RTINFENTRY(DATARATES, DISPLAY_BYTES), -#undef RTINFENTRY -}; -#define NUM_RIDS ( sizeof(record_table) / sizeof(record_table[0]) ) - -static int -dldwd_proc_get_hermes_recs(char *page, char **start, off_t requested_offset, - int requested_len, int *eof, void *data) -{ - dldwd_priv_t *dev = (dldwd_priv_t *)data; - hermes_t *hw = &dev->hw; - char *buf; - int total = 0, slop = 0; - int i; - uint16_t length; - int err; - - buf = page; - - /* print out all the config RIDs */ - for (i = 0; i < NUM_RIDS; i++) { - uint16_t rid = record_table[i].rid; - int minlen = record_table[i].minlen; - int maxlen = record_table[i].maxlen; - int len; - uint8_t *val8; - uint16_t *val16; - int j; - - val8 = kmalloc(maxlen + 2, GFP_KERNEL); - if (! val8) - return -ENOMEM; - - err = hermes_read_ltv(hw, USER_BAP, rid, maxlen, - &length, val8); - if (err) { - DEBUG(0, "Error %d reading RID 0x%04x\n", err, rid); - continue; - } - val16 = (uint16_t *)val8; - - buf += sprintf(buf, "%-15s (0x%04x): length=%d (%d bytes)\tvalue=", record_table[i].name, - rid, length, (length-1)*2); - len = MIN( MAX(minlen, (length-1)*2), maxlen); - - switch (record_table[i].displaytype) { - case DISPLAY_WORDS: - for (j = 0; j < len / 2; j++) { - buf += sprintf(buf, "%04X-", le16_to_cpu(val16[j])); - } - buf--; - break; - - case DISPLAY_BYTES: - default: - for (j = 0; j < len; j++) { - buf += sprintf(buf, "%02X:", val8[j]); - } - buf--; - break; - - case DISPLAY_STRING: - len = MIN(len, le16_to_cpu(val16[0])+2); - val8[len] = '\0'; - buf += sprintf(buf, "\"%s\"", (char *)&val16[1]); - break; - } - - buf += sprintf(buf, "\n"); - - kfree(val8); - - if (shift_buffer(page, requested_offset, requested_len, - &total, &slop, &buf)) - break; - - if ( (buf - page) > PROC_SAFE_SIZE ) - break; - } - - return calc_start_len(page, start, requested_offset, requested_len, - total, buf); -} - -/* initialise the /proc subsystem for the hermes driver, creating the - * separate entries */ -static int -dldwd_proc_init(void) -{ - int err = 0; - - TRACE_ENTER("dldwd"); - - /* create the directory for it to sit in */ - dir_base = create_proc_entry("hermes", S_IFDIR, &proc_root); - if (dir_base == NULL) { - printk(KERN_ERR "Unable to initialise /proc/hermes.\n"); - dldwd_proc_cleanup(); - err = -ENOMEM; - } - - TRACE_EXIT("dldwd"); - - return err; -} - -static int -dldwd_proc_dev_init(dldwd_priv_t *dev) -{ - dev->dir_dev = NULL; - /* create the directory for it to sit in */ - dev->dir_dev = create_proc_entry(dev->node.dev_name, S_IFDIR | S_IRUGO | S_IXUGO, - dir_base); - if (dev->dir_dev == NULL) { - printk(KERN_ERR "Unable to initialise /proc/hermes/%s.\n", dev->node.dev_name); - goto fail; - } - - dev->dir_regs = NULL; - dev->dir_regs = create_proc_read_entry("regs", S_IFREG | S_IRUGO, - dev->dir_dev, dldwd_proc_get_hermes_regs, dev); - if (dev->dir_regs == NULL) { - printk(KERN_ERR "Unable to initialise /proc/hermes/%s/regs.\n", dev->node.dev_name); - goto fail; - } - - dev->dir_recs = NULL; - dev->dir_recs = create_proc_read_entry("recs", S_IFREG | S_IRUGO, - dev->dir_dev, dldwd_proc_get_hermes_recs, dev); - if (dev->dir_recs == NULL) { - printk(KERN_ERR "Unable to initialise /proc/hermes/%s/recs.\n", dev->node.dev_name); - goto fail; - } - - return 0; - fail: - dldwd_proc_dev_cleanup(dev); - return -ENOMEM; -} - -static void -dldwd_proc_dev_cleanup(dldwd_priv_t *priv) -{ - if (priv->dir_regs) { - remove_proc_entry("regs", priv->dir_dev); - priv->dir_regs = NULL; - } - if (priv->dir_recs) { - remove_proc_entry("recs", priv->dir_dev); - priv->dir_recs = NULL; - } - if (priv->dir_dev) { - remove_proc_entry(priv->node.dev_name, dir_base); - priv->dir_dev = NULL; - } -} - -static void -dldwd_proc_cleanup(void) -{ - TRACE_ENTER("dldwd"); - - if (dir_base) { - remove_proc_entry("hermes", &proc_root); - dir_base = NULL; - } - - TRACE_EXIT("dldwd"); -} - -/*====================================================================*/ - -/* - * From here on in, it's all PCMCIA junk, taken almost directly from - * dummy_cs.c - */ - -/* - The dev_info variable is the "key" that is used to match up this - device driver with appropriate cards, through the card configuration - database. -*/ - -static dev_info_t dev_info = "orinoco_cs"; - -/* - A linked list of "instances" of the dummy device. Each actual - PCMCIA card corresponds to one device instance, and is described - by one dev_link_t structure (defined in ds.h). - - You may not want to use a linked list for this -- for example, the - memory card driver uses an array of dev_link_t pointers, where minor - device numbers are used to derive the corresponding array index. -*/ - -static dev_link_t *dev_list = NULL; -static int num_instances = 0; - -/*====================================================================*/ - -static void cs_error(client_handle_t handle, int func, int ret) -{ - error_info_t err = { func, ret }; - CardServices(ReportError, handle, &err); -} - -/*====================================================================== - dldwd_attach() creates an "instance" of the driver, allocating - local data structures for one device. The device is registered - with Card Services. - - The dev_link structure is initialized, but we don't actually - configure the card at this point -- we wait until we receive a - card insertion event. - ======================================================================*/ - -static dev_link_t *dldwd_attach(void) -{ - dldwd_priv_t *priv; - dev_link_t *link; - struct net_device *ndev; - client_reg_t client_reg; - int ret, i; - - TRACE_ENTER("dldwd"); - - /* Allocate space for private device-specific data */ - priv = kmalloc(sizeof(*priv), GFP_KERNEL); - if (! priv) { - link = NULL; - goto out; - } - - memset(priv, 0, sizeof(*priv)); - priv->instance = num_instances++; /* FIXME: Racy? */ - spin_lock_init(&priv->lock); - - link = &priv->link; - ndev = &priv->ndev; - link->priv = ndev->priv = priv; - - /* Initialize the dev_link_t structure */ - link->release.function = &dldwd_release; - link->release.data = (u_long) link; - - /* Interrupt setup */ - link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; - link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID; - if (irq_list[0] == -1) - link->irq.IRQInfo2 = irq_mask; - else - for (i = 0; i < 4; i++) - link->irq.IRQInfo2 |= 1 << irq_list[i]; - link->irq.Handler = NULL; - - /* - General socket configuration defaults can go here. In this - client, we assume very little, and rely on the CIS for almost - everything. In most clients, many details (i.e., number, sizes, - and attributes of IO windows) are fixed by the nature of the - device, and can be hard-wired here. - */ - link->conf.Attributes = 0; - link->conf.IntType = INT_MEMORY_AND_IO; - - /* Set up the net_device */ - ether_setup(ndev); - ndev->init = dldwd_init; - ndev->open = dldwd_open; - ndev->stop = dldwd_stop; - ndev->hard_start_xmit = dldwd_xmit; - ndev->tx_timeout = dldwd_tx_timeout; - ndev->watchdog_timeo = 4*HZ; /* 4 second timeout */ - - ndev->get_stats = dldwd_get_stats; - ndev->get_wireless_stats = dldwd_get_wireless_stats; - - ndev->do_ioctl = dldwd_ioctl; - - ndev->change_mtu = dldwd_change_mtu; - ndev->set_multicast_list = dldwd_set_multicast_list; - - netif_stop_queue(ndev); - - /* Register with Card Services */ - link->next = dev_list; - dev_list = link; - client_reg.dev_info = &dev_info; - client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &dldwd_event; - client_reg.Version = 0x0210; - client_reg.event_callback_args.client_data = link; - ret = CardServices(RegisterClient, &link->handle, &client_reg); - if (ret != CS_SUCCESS) { - cs_error(link->handle, RegisterClient, ret); - dldwd_detach(link); - link = NULL; - goto out; - } - - out: - TRACE_EXIT("dldwd"); - return link; -} /* dldwd_attach */ - -/*====================================================================== - This deletes a driver "instance". The device is de-registered - with Card Services. If it has been released, all local data - structures are freed. Otherwise, the structures will be freed - when the device is released. - ======================================================================*/ - -static void dldwd_detach(dev_link_t * link) -{ - dev_link_t **linkp; - dldwd_priv_t *priv = link->priv; - - TRACE_ENTER("dldwd"); - - /* Locate device structure */ - for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) - if (*linkp == link) - break; - if (*linkp == NULL) - goto out; - - /* - If the device is currently configured and active, we won't - actually delete it yet. Instead, it is marked so that when - the release() function is called, that will trigger a proper - detach(). - */ - if (link->state & DEV_CONFIG) { -#ifdef PCMCIA_DEBUG - printk(KERN_DEBUG "orinoco_cs: detach postponed, '%s' " - "still locked\n", link->dev->dev_name); -#endif - link->state |= DEV_STALE_LINK; - goto out; - } - - /* Break the link with Card Services */ - if (link->handle) - CardServices(DeregisterClient, link->handle); - - /* Unlink device structure, and free it */ - *linkp = link->next; - DEBUG(0, "orinoco_cs: detach: link=%p link->dev=%p\n", link, link->dev); - if (link->dev) { - DEBUG(0, "orinoco_cs: About to unregister net device %p\n", - &priv->ndev); - unregister_netdev(&priv->ndev); - } - kfree(priv); - - num_instances--; /* FIXME: Racy? */ - - out: - TRACE_EXIT("dldwd"); -} /* dldwd_detach */ - -/* - * Do a soft reset of the Pcmcia card using the Configuration Option Register - * Can't do any harm, and actually may do some good on some cards... - */ -static int dldwd_cor_reset(dev_link_t *link) -{ - conf_reg_t reg; - u_long default_cor; - - /* Save original COR value */ - reg.Function = 0; - reg.Action = CS_READ; - reg.Offset = CISREG_COR; - reg.Value = 0; - CardServices(AccessConfigurationRegister, link->handle, ®); - default_cor = reg.Value; - - DEBUG(2, "dldwd : dldwd_cor_reset() : cor=0x%lX\n", default_cor); - - /* Soft-Reset card */ - reg.Action = CS_WRITE; - reg.Offset = CISREG_COR; - reg.Value = (default_cor | COR_SOFT_RESET); - CardServices(AccessConfigurationRegister, link->handle, ®); - - /* Wait until the card has acknowledged our reset */ - mdelay(1); - - /* Restore original COR configuration index */ - reg.Value = (default_cor & COR_CONFIG_MASK); - CardServices(AccessConfigurationRegister, link->handle, ®); - - /* Wait until the card has finished restarting */ - mdelay(1); - - return(0); -} - -/*====================================================================== - dldwd_config() is scheduled to run after a CARD_INSERTION event - is received, to configure the PCMCIA socket, and to make the - device available to the system. - ======================================================================*/ - -#define CS_CHECK(fn, args...) \ -while ((last_ret=CardServices(last_fn=(fn),args))!=0) goto cs_failed - -#define CFG_CHECK(fn, args...) \ -if (CardServices(fn, args) != 0) goto next_entry - -static void dldwd_config(dev_link_t * link) -{ - client_handle_t handle = link->handle; - dldwd_priv_t *priv = link->priv; - hermes_t *hw = &priv->hw; - struct net_device *ndev = &priv->ndev; - tuple_t tuple; - cisparse_t parse; - int last_fn, last_ret; - u_char buf[64]; - config_info_t conf; - cistpl_cftable_entry_t dflt = { 0 }; - cisinfo_t info; - - TRACE_ENTER("dldwd"); - - CS_CHECK(ValidateCIS, handle, &info); - - /* - This reads the card's CONFIG tuple to find its configuration - registers. - */ - tuple.DesiredTuple = CISTPL_CONFIG; - tuple.Attributes = 0; - tuple.TupleData = buf; - tuple.TupleDataMax = sizeof(buf); - tuple.TupleOffset = 0; - CS_CHECK(GetFirstTuple, handle, &tuple); - CS_CHECK(GetTupleData, handle, &tuple); - CS_CHECK(ParseTuple, handle, &tuple, &parse); - link->conf.ConfigBase = parse.config.base; - link->conf.Present = parse.config.rmask[0]; - - /* Configure card */ - link->state |= DEV_CONFIG; - - /* Look up the current Vcc */ - CS_CHECK(GetConfigurationInfo, handle, &conf); - link->conf.Vcc = conf.Vcc; - - DEBUG(0, "dldwd_config: ConfigBase = 0x%x link->conf.Vcc = %d\n", - link->conf.ConfigBase, link->conf.Vcc); - - /* - In this loop, we scan the CIS for configuration table entries, - each of which describes a valid card configuration, including - voltage, IO window, memory window, and interrupt settings. - - We make no assumptions about the card to be configured: we use - just the information available in the CIS. In an ideal world, - this would work for any PCMCIA card, but it requires a complete - and accurate CIS. In practice, a driver usually "knows" most of - these things without consulting the CIS, and most client drivers - will only use the CIS to fill in implementation-defined details. - */ - tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - CS_CHECK(GetFirstTuple, handle, &tuple); - while (1) { - cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); - CFG_CHECK(GetTupleData, handle, &tuple); - CFG_CHECK(ParseTuple, handle, &tuple, &parse); - - DEBUG(0, "dldwd_config: index = 0x%x, flags = 0x%x\n", - cfg->index, cfg->flags); - - if (cfg->flags & CISTPL_CFTABLE_DEFAULT) - dflt = *cfg; - if (cfg->index == 0) - goto next_entry; - link->conf.ConfigIndex = cfg->index; - - /* Does this card need audio output? */ - if (cfg->flags & CISTPL_CFTABLE_AUDIO) { - link->conf.Attributes |= CONF_ENABLE_SPKR; - link->conf.Status = CCSR_AUDIO_ENA; - } - - /* Use power settings for Vcc and Vpp if present */ - /* Note that the CIS values need to be rescaled */ - if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { - if (conf.Vcc != - cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) { - DEBUG(2, "dldwd_config: Vcc mismatch (conf.Vcc = %d, CIS = %d)\n", conf.Vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000); - goto next_entry; - } - } else if (dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) { - if (conf.Vcc != - dflt.vcc.param[CISTPL_POWER_VNOM] / 10000) { - DEBUG(2, "dldwd_config: Vcc mismatch (conf.Vcc = %d, CIS = %d)\n", conf.Vcc, dflt.vcc.param[CISTPL_POWER_VNOM] / 10000); - goto next_entry; - } - } - - if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) - link->conf.Vpp1 = link->conf.Vpp2 = - cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; - else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM)) - link->conf.Vpp1 = link->conf.Vpp2 = - dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000; - - DEBUG(0, "dldwd_config: We seem to have configured Vcc and Vpp\n"); - - /* Do we need to allocate an interrupt? */ - if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) - link->conf.Attributes |= CONF_ENABLE_IRQ; - - /* IO window settings */ - link->io.NumPorts1 = link->io.NumPorts2 = 0; - if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { - cistpl_io_t *io = - (cfg->io.nwin) ? &cfg->io : &dflt.io; - link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; - if (!(io->flags & CISTPL_IO_8BIT)) - link->io.Attributes1 = - IO_DATA_PATH_WIDTH_16; - if (!(io->flags & CISTPL_IO_16BIT)) - link->io.Attributes1 = - IO_DATA_PATH_WIDTH_8; - link->io.IOAddrLines = - io->flags & CISTPL_IO_LINES_MASK; - link->io.BasePort1 = io->win[0].base; - link->io.NumPorts1 = io->win[0].len; - if (io->nwin > 1) { - link->io.Attributes2 = - link->io.Attributes1; - link->io.BasePort2 = io->win[1].base; - link->io.NumPorts2 = io->win[1].len; - } - - /* This reserves IO space but doesn't actually enable it */ - CFG_CHECK(RequestIO, link->handle, &link->io); - } - - - /* If we got this far, we're cool! */ - - break; - - next_entry: - if (link->io.NumPorts1) - CardServices(ReleaseIO, link->handle, &link->io); - CS_CHECK(GetNextTuple, handle, &tuple); - } - - /* - Allocate an interrupt line. Note that this does not assign a - handler to the interrupt, unless the 'Handler' member of the - irq structure is initialized. - */ - if (link->conf.Attributes & CONF_ENABLE_IRQ) { - int i; - - link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; - link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID; - if (irq_list[0] == -1) - link->irq.IRQInfo2 = irq_mask; - else - for (i=0; i<4; i++) - link->irq.IRQInfo2 |= 1 << irq_list[i]; - - link->irq.Handler = dldwd_interrupt; - link->irq.Instance = priv; - - CS_CHECK(RequestIRQ, link->handle, &link->irq); - } - - /* We initialize the hermes structure before completing PCMCIA - configuration just in case the interrupt handler gets - called. */ - hermes_struct_init(hw, link->io.BasePort1); - - /* - This actually configures the PCMCIA socket -- setting up - the I/O windows and the interrupt mapping, and putting the - card and host interface into "Memory and IO" mode. - */ - CS_CHECK(RequestConfiguration, link->handle, &link->conf); - - ndev->base_addr = link->io.BasePort1; - ndev->irq = link->irq.AssignedIRQ; - - /* Do a Pcmcia soft reset of the card (optional) */ - if(reset_cor) - dldwd_cor_reset(link); - - /* register_netdev will give us an ethX name */ - ndev->name[0] = '\0'; - /* Tell the stack we exist */ - if (register_netdev(ndev) != 0) { - printk(KERN_ERR "orinoco_cs: register_netdev() failed\n"); - goto failed; - } - strcpy(priv->node.dev_name, ndev->name); - - /* Finally, report what we've done */ - printk(KERN_INFO "%s: index 0x%02x: Vcc %d.%d", - priv->node.dev_name, link->conf.ConfigIndex, - link->conf.Vcc / 10, link->conf.Vcc % 10); - if (link->conf.Vpp1) - printk(", Vpp %d.%d", link->conf.Vpp1 / 10, - link->conf.Vpp1 % 10); - if (link->conf.Attributes & CONF_ENABLE_IRQ) - printk(", irq %d", link->irq.AssignedIRQ); - if (link->io.NumPorts1) - printk(", io 0x%04x-0x%04x", link->io.BasePort1, - link->io.BasePort1 + link->io.NumPorts1 - 1); - if (link->io.NumPorts2) - printk(" & 0x%04x-0x%04x", link->io.BasePort2, - link->io.BasePort2 + link->io.NumPorts2 - 1); - printk("\n"); - - /* And give us the proc nodes for debugging */ - if (dldwd_proc_dev_init(priv) != 0) { - printk(KERN_ERR "orinoco_cs: Failed to create /proc node for %s\n", - priv->node.dev_name); - goto failed; - } - - /* - At this point, the dev_node_t structure(s) need to be - initialized and arranged in a linked list at link->dev. - */ - priv->node.major = priv->node.minor = 0; - link->dev = &priv->node; - link->state &= ~DEV_CONFIG_PENDING; - - TRACE_EXIT("dldwd"); - - return; - - cs_failed: - cs_error(link->handle, last_fn, last_ret); - failed: - dldwd_release((u_long) link); - - TRACE_EXIT("dldwd"); -} /* dldwd_config */ - -/*====================================================================== - After a card is removed, dldwd_release() will unregister the - device, and release the PCMCIA configuration. If the device is - still open, this will be postponed until it is closed. - ======================================================================*/ - -static void dldwd_release(u_long arg) -{ - dev_link_t *link = (dev_link_t *) arg; - dldwd_priv_t *priv = link->priv; - - TRACE_ENTER(link->dev->dev_name); - - /* - If the device is currently in use, we won't release until it - is actually closed, because until then, we can't be sure that - no one will try to access the device or its data structures. - */ - if (link->open) { - DEBUG(0, "orinoco_cs: release postponed, '%s' still open\n", - link->dev->dev_name); - link->state |= DEV_STALE_CONFIG; - return; - } - - /* - In a normal driver, additional code may be needed to release - other kernel data structures associated with this device. - */ - - dldwd_proc_dev_cleanup(priv); - - /* Don't bother checking to see if these succeed or not */ - CardServices(ReleaseConfiguration, link->handle); - if (link->io.NumPorts1) - CardServices(ReleaseIO, link->handle, &link->io); - if (link->irq.AssignedIRQ) - CardServices(ReleaseIRQ, link->handle, &link->irq); - link->state &= ~DEV_CONFIG; - - TRACE_EXIT(link->dev->dev_name); -} /* dldwd_release */ - -/*====================================================================== - The card status event handler. Mostly, this schedules other - stuff to run after an event is received. - - When a CARD_REMOVAL event is received, we immediately set a - private flag to block future accesses to this device. All the - functions that actually access the device should check this flag - to make sure the card is still present. - ======================================================================*/ - -static int dldwd_event(event_t event, int priority, - event_callback_args_t * args) -{ - dev_link_t *link = args->client_data; - dldwd_priv_t *priv = (dldwd_priv_t *)link->priv; - struct net_device *dev = &priv->ndev; - - TRACE_ENTER("dldwd"); - - switch (event) { - case CS_EVENT_CARD_REMOVAL: - dldwd_shutdown(priv); - link->state &= ~DEV_PRESENT; - if (link->state & DEV_CONFIG) { - netif_stop_queue(dev); - netif_device_detach(dev); - mod_timer(&link->release, jiffies + HZ / 20); - } - break; - case CS_EVENT_CARD_INSERTION: - link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; - dldwd_config(link); - break; - case CS_EVENT_PM_SUSPEND: - - link->state |= DEV_SUSPEND; - /* Fall through... */ - case CS_EVENT_RESET_PHYSICAL: - dldwd_shutdown(priv); - /* Mark the device as stopped, to block IO until later */ - - if (link->state & DEV_CONFIG) { - if (link->open) { - netif_stop_queue(dev); - netif_device_detach(dev); - } - CardServices(ReleaseConfiguration, link->handle); - } - break; - case CS_EVENT_PM_RESUME: - link->state &= ~DEV_SUSPEND; - /* Fall through... */ - case CS_EVENT_CARD_RESET: - if (link->state & DEV_CONFIG) { - CardServices(RequestConfiguration, link->handle, - &link->conf); - - if (link->open) { - if (dldwd_reset(priv) == 0) { - netif_device_attach(dev); - netif_start_queue(dev); - } else { - printk(KERN_ERR "%s: Error resetting device on PCMCIA event\n", - dev->name); - dldwd_stop(dev); - } - } - } - /* - In a normal driver, additional code may go here to restore - the device state and restart IO. - */ - break; - } - - TRACE_EXIT("dldwd"); - - return 0; -} /* dldwd_event */ - -static int __init init_dldwd_cs(void) -{ - servinfo_t serv; - int err; - - TRACE_ENTER("dldwd"); - - printk(KERN_INFO "dldwd: David's Less Dodgy WaveLAN/IEEE Driver\n"); - - DEBUG(0, "%s\n", version); - CardServices(GetCardServicesInfo, &serv); - if (serv.Revision != CS_RELEASE_CODE) { - printk(KERN_NOTICE "orinoco_cs: Card Services release " - "does not match!\n"); - return -1; - } - register_pccard_driver(&dev_info, &dldwd_attach, &dldwd_detach); - - - err = dldwd_proc_init(); - - TRACE_EXIT("dldwd"); - return err; -} - -static void __exit exit_dldwd_cs(void) -{ - TRACE_ENTER("dldwd"); - - dldwd_proc_cleanup(); - - unregister_pccard_driver(&dev_info); - - if (dev_list) - DEBUG(0, "orinoco_cs: Removing leftover devices.\n"); - while (dev_list != NULL) { - del_timer(&dev_list->release); - if (dev_list->state & DEV_CONFIG) - dldwd_release((u_long) dev_list); - dldwd_detach(dev_list); - } - - TRACE_EXIT("dldwd"); -} - -module_init(init_dldwd_cs); -module_exit(exit_dldwd_cs); diff -Nru a/drivers/net/wireless/Config.in b/drivers/net/wireless/Config.in --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/Config.in Wed May 16 06:00:33 2001 @@ -0,0 +1,22 @@ +# +# Wireless LAN device configuration +# + +###tristate ' Hermes chipset support' CONFIG_NET_ORINOCO +###dep_tristate ' PCMCIA Hermes support (Orinoco/WavelanIEEE/PrismII/Symbol 802.11b cards)' CONFIG_PCMCIA_HERMES $CONFIG_NET_ORINOCO $CONFIG_PCMCIA + +if [ "$CONFIG_ALL_PPC" = "y" ]; then + tristate ' Apple Airport support (built-in)' CONFIG_APPLE_AIRPORT +fi + +# If Pcmcia is compiled in, offer Pcmcia cards... +if [ "$CONFIG_HOTPLUG" = "y" -a "$CONFIG_PCMCIA" != "n" ]; then + comment 'Wireless Pcmcia cards support' + + dep_tristate ' Hermes support (Orinoco/WavelanIEEE/PrismII/Symbol 802.11b cards)' CONFIG_PCMCIA_HERMES $CONFIG_PCMCIA + +# If one of the Pcmcia cards above is enabled, activate Pcmcia network support + if [ "$CONFIG_PCMCIA_HERMES" = "y" ]; then + define_bool CONFIG_PCMCIA_NETCARD y + fi +fi diff -Nru a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/Makefile Wed May 16 06:00:25 2001 @@ -0,0 +1,27 @@ +# +# drivers/net/wireless/Makefile +# +# Makefile for the Linux Wireless network device drivers. +# + +O_TARGET := orinoco_drvs.o + +obj-y := +obj-m := +obj-n := +obj- := + +# Things that need to export symbols +export-objs := orinoco.o hermes.o + +# ISA Bus cards + +# PCI bus cards + +# Other cards +obj-$(CONFIG_APPLE_AIRPORT) += airport.o orinoco.o hermes.o + +# 16-bit Pcmcia wireless client drivers +obj-$(CONFIG_PCMCIA_HERMES) += orinoco_cs.o orinoco.o hermes.o + +include $(TOPDIR)/Rules.make diff -Nru a/drivers/net/wireless/README b/drivers/net/wireless/README --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/README Wed May 16 06:00:34 2001 @@ -0,0 +1,25 @@ + README + ------ + + This directory is mostly for Wireless LAN drivers, in their +various incarnations (ISA, PCI, Pcmcia...). + This separate directory is needed because a lot of driver work +on different bus (typically PCI + Pcmcia) and share 95% of the +code. This allow the code and the config options to be in one single +place instead of scattered all over the driver tree, which is never +100% satisfactory. + + Note : if you want more info on the topic of Wireless LANs, +you are kindly invited to have a look at the Wireless Howto : + http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/ + Some Wireless LAN drivers, like orinoco_cs, require the use of +Wireless Tools to be configured : + http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html + + Special notes for distribution maintainers : + 1) wvlan_cs will be discontinued soon in favor of orinoco_cs + 2) Please add Wireless Tools support in your scripts + + Have fun... + + Jean diff -Nru a/drivers/net/wireless/airport.c b/drivers/net/wireless/airport.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/airport.c Wed May 16 06:00:33 2001 @@ -0,0 +1,270 @@ +/* airport.c 0.05 + * + * A driver for "Hermes" chipset based Apple Airport wireless + * card. + * + * Copyright notice & release notes in file orinoco.c + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "hermes.h" +#include "orinoco.h" + +typedef struct dldwd_card { + struct device_node* node; + int irq_requested; + int ndev_registered; + /* Common structure (fully included), see orinoco.h */ + struct dldwd_priv priv; +} dldwd_card_t; + +static char *version = "airport.c 0.05 (Benjamin Herrenschmidt )"; + +/* + * Function prototypes + */ + +static dldwd_priv_t* airport_attach(struct device_node *of_node); +static void airport_detach(dldwd_priv_t* priv); +static int airport_init(struct net_device *dev); +static int airport_open(struct net_device *dev); +static int airport_stop(struct net_device *dev); + +/* + A linked list of "instances" of the dummy device. Each actual + PCMCIA card corresponds to one device instance, and is described + by one dev_link_t structure (defined in ds.h). + + You may not want to use a linked list for this -- for example, the + memory card driver uses an array of dev_link_t pointers, where minor + device numbers are used to derive the corresponding array index. +*/ + +static dldwd_priv_t *airport_dev; + +static int airport_init(struct net_device *dev) +{ + dldwd_priv_t *priv = dev->priv; + dldwd_card_t* card = (dldwd_card_t *)priv->card; + int rc; + + TRACE_ENTER(priv->ndev.name); + + MOD_INC_USE_COUNT; + + feature_set_airport_power(card->node, 1); + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(HZ); + + rc = dldwd_init(dev); + if (rc) { + feature_set_airport_power(card->node, 0); + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(HZ); + } + priv->hw_ready = 1; + + MOD_DEC_USE_COUNT; + + return rc; +} + +static int +airport_open(struct net_device *dev) +{ + dldwd_priv_t *priv = dev->priv; + int rc; + + TRACE_ENTER(priv->ndev.name); + + netif_device_attach(dev); + rc = dldwd_reset(priv); + if (rc) + airport_stop(dev); + else + netif_start_queue(dev); + + TRACE_EXIT(priv->ndev.name); + + return rc; +} + +static int +airport_stop(struct net_device *dev) +{ + dldwd_priv_t *priv = dev->priv; + + TRACE_ENTER(priv->ndev.name); + + netif_stop_queue(dev); + + dldwd_shutdown(priv); + + TRACE_EXIT(priv->ndev.name); + + return 0; +} + +static dldwd_priv_t* +airport_attach(struct device_node* of_node) +{ + dldwd_priv_t *priv; + struct net_device *ndev; + dldwd_card_t* card; + hermes_t *hw; + + TRACE_ENTER("dldwd"); + + if (of_node->n_addrs < 1 || of_node->n_intrs < 1) { + printk(KERN_ERR "airport: wrong interrupt/addresses in OF tree\n"); + return NULL; + } + + /* Allocate space for private device-specific data */ + card = kmalloc(sizeof(*card), GFP_KERNEL); + if (!card) { + printk(KERN_ERR "airport: can't allocate device datas\n"); + return NULL; + } + memset(card, 0, sizeof(*card)); + + priv = &(card->priv); + priv->card = card; + ndev = &priv->ndev; + hw = &priv->hw; + card->node = of_node; + + /* Setup the common part */ + if (dldwd_setup(priv) < 0) { + kfree(card); + return NULL; + } + + /* Overrides */ + ndev->init = airport_init; + ndev->open = airport_open; + ndev->stop = airport_stop; + + /* Setup interrupts & base address */ + ndev->irq = of_node->intrs[0].line; + ndev->base_addr = (unsigned long)ioremap(of_node->addrs[0].address, 0x1000) - _IO_BASE; + + hermes_struct_init(hw, ndev->base_addr); + + if (request_irq(ndev->irq, dldwd_interrupt, 0, "Airport", (void *)priv)) { + printk(KERN_ERR "airport: Couldn't get IRQ %d\n", ndev->irq); + goto failed; + } + card->irq_requested = 1; + + /* register_netdev will give us an ethX name */ + ndev->name[0] = '\0'; + /* Tell the stack we exist */ + if (register_netdev(ndev) != 0) { + printk(KERN_ERR "airport: register_netdev() failed\n"); + goto failed; + } + printk(KERN_INFO "airport: card registered for interface %s\n", ndev->name); + card->ndev_registered = 1; + + SET_MODULE_OWNER(ndev); + + /* And give us the proc nodes for debugging */ + if (dldwd_proc_dev_init(priv) != 0) + printk(KERN_ERR "airport: Failed to create /proc node for %s\n", + ndev->name); + + return priv; + +failed: + airport_detach(priv); + return NULL; +} /* airport_attach */ + +/*====================================================================== + This deletes a driver "instance". + ======================================================================*/ + +static void +airport_detach(dldwd_priv_t *priv) +{ + dldwd_card_t* card = (dldwd_card_t *)priv->card; + + priv->hw_ready = 0; + + /* Unregister proc entry */ + dldwd_proc_dev_cleanup(priv); + + if (card->ndev_registered) + unregister_netdev(&priv->ndev); + card->ndev_registered = 0; + + if (card->irq_requested) + free_irq(priv->ndev.irq, priv); + card->irq_requested = 0; + +// FIXME +// if (ndev->base_addr) +// iounmap(ndev->base_addr + _IO_BASE); +// ndev->base_addr = 0; + + feature_set_airport_power(card->node, 0); + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(HZ); + + kfree(card); +} /* airport_detach */ + +static int __init +init_airport(void) +{ + struct device_node* airport_node; + + printk(KERN_INFO "%s\n", version); + + MOD_INC_USE_COUNT; + + /* Lookup card in device tree */ + airport_node = find_devices("radio"); + if (airport_node && !strcmp(airport_node->parent->name, "mac-io")) + airport_dev = airport_attach(airport_node); + + MOD_DEC_USE_COUNT; + + return airport_dev ? 0 : -ENODEV; +} + +static void __exit +exit_airport(void) +{ + if (airport_dev) + airport_detach(airport_dev); + airport_dev = NULL; +} + +MODULE_DESCRIPTION("Apple Airport driver"); + +module_init(init_airport); +module_exit(exit_airport); diff -Nru a/drivers/net/wireless/hermes.c b/drivers/net/wireless/hermes.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/hermes.c Wed May 16 06:00:18 2001 @@ -0,0 +1,502 @@ +/* hermes.c + * + * Driver core for the "Hermes" wireless MAC controller, as used in + * the Lucent Orinoco and Cabletron RoamAbout cards. It should also + * work on the hfa3841 and hfa3842 MAC controller chips used in the + * Prism I & II chipsets. + * + * This is not a complete driver, just low-level access routines for + * the MAC controller itself. + * + * Based on the prism2 driver from Absolute Value Systems' linux-wlan + * project, the Linux wvlan_cs driver, Lucent's HCF-Light + * (wvlan_hcf.c) library, and the NetBSD wireless driver. + * + * Copyright (C) 2000, David Gibson, Linuxcare Australia + * + * This file distributed under the GPL, version 2. + */ + +static const char *version = "hermes.c: 12 Dec 2000 David Gibson "; + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hermes.h" + +#define CMD_BUSY_TIMEOUT (100) /* In iterations of ~1us */ +#define CMD_INIT_TIMEOUT (50000) /* in iterations of ~10us */ +#define CMD_COMPL_TIMEOUT (10000) /* in iterations of ~10us */ +#define ALLOC_COMPL_TIMEOUT (1000) /* in iterations of ~10us */ +#define BAP_BUSY_TIMEOUT (500) /* In iterations of ~1us */ +#define BAP_ERROR_RETRY (10) /* How many times to retry a BAP seek when there is an error */ + +#define MAX(a, b) ( (a) > (b) ? (a) : (b) ) +#define MIN(a, b) ( (a) < (b) ? (a) : (b) ) + +/* + * Debugging helpers + */ + +#undef HERMES_DEBUG +#ifdef HERMES_DEBUG + +#include + +#define DMSG(stuff...) do {printk(KERN_DEBUG "hermes @ 0x%x: " , hw->iobase); \ + printk(#stuff);} while (0) + +#define DEBUG(lvl, stuff...) if ( (lvl) <= HERMES_DEBUG) DMSG(#stuff) + +#else /* ! HERMES_DEBUG */ + +#define DEBUG(lvl, stuff...) do { } while (0) + +#endif /* ! HERMES_DEBUG */ + +/* + * Prototypes + */ + +static int hermes_issue_cmd(hermes_t *hw, uint16_t cmd, uint16_t param0); + +/* + * Internal inline functions + */ + +/* + * Internal functions + */ + +/* Issue a command to the chip. Waiting for it to complete is the caller's + problem. + + Returns -EBUSY if the command register is busy, 0 on success. + + Callable from any context. +*/ +static int hermes_issue_cmd(hermes_t *hw, uint16_t cmd, uint16_t param0) +{ + uint16_t reg; +/* unsigned long k = CMD_BUSY_TIMEOUT; */ + + /* First check that the command register is not busy */ + reg = hermes_read_regn(hw, CMD); + if (reg & HERMES_CMD_BUSY) { + return -EBUSY; + } + + hermes_write_regn(hw, PARAM2, 0); + hermes_write_regn(hw, PARAM1, 0); + hermes_write_regn(hw, PARAM0, param0); + hermes_write_regn(hw, CMD, cmd); + + return 0; +} + +/* + * Function definitions + */ + +void hermes_struct_init(hermes_t *hw, uint io) +{ + hw->iobase = io; + hw->inten = 0x0; +} + +int hermes_reset(hermes_t *hw) +{ + uint16_t status, reg; + int err = 0; + int k; + + /* We don't want to be interrupted while resetting the chipset */ + hw->inten = 0x0; + hermes_write_regn(hw, INTEN, 0); + hermes_write_regn(hw, EVACK, 0xffff); + + /* Because we hope we can reset the card even if it gets into + a stupid state, we actually wait to see if the command + register will unbusy itself */ + k = CMD_BUSY_TIMEOUT; + reg = hermes_read_regn(hw, CMD); + while (k && (reg & HERMES_CMD_BUSY)) { + if (reg == 0xffff) /* Special case - the card has probably been removed, + so don't wait for the timeout */ + return -ENODEV; + + k--; + udelay(1); + reg = hermes_read_regn(hw, CMD); + } + + /* No need to explicitly handle the timeout - hermes_issue_cmd() will + probably return -EBUSY */ + + /* We don't use hermes_docmd_wait here, because the reset wipes + the magic constant in SWSUPPORT0 away, and it gets confused */ + err = hermes_issue_cmd(hw, HERMES_CMD_INIT, 0); + if (err) + return err; + + reg = hermes_read_regn(hw, EVSTAT); + k = CMD_INIT_TIMEOUT; + while ( (! (reg & HERMES_EV_CMD)) && k) { + k--; + udelay(10); + reg = hermes_read_regn(hw, EVSTAT); + } + + DEBUG(0, "Reset completed in %d iterations\n", CMD_INIT_TIMEOUT - k); + + hermes_write_regn(hw, SWSUPPORT0, HERMES_MAGIC); + + if (! hermes_present(hw)) { + DEBUG(0, "hermes @ 0x%x: Card removed during reset.\n", + hw->iobase); + err = -ENODEV; + goto out; + } + + if (! (reg & HERMES_EV_CMD)) { + printk(KERN_ERR "hermes @ 0x%x: Timeout waiting for card to reset (reg=0x%04x)!\n", + hw->iobase, reg); + err = -ETIMEDOUT; + goto out; + } + + status = hermes_read_regn(hw, STATUS); + + hermes_write_regn(hw, EVACK, HERMES_EV_CMD); + + err = status & HERMES_STATUS_RESULT; + + out: + return err; +} + +/* Issue a command to the chip, and (busy!) wait for it to + * complete. + * + * Returns: < 0 on internal error, 0 on success, > 0 on error returned by the firmware + * + * Callable from any context, but locking is your problem. */ +int hermes_docmd_wait(hermes_t *hw, uint16_t cmd, uint16_t parm0, hermes_response_t *resp) +{ + int err; + int k; + uint16_t reg; + + err = hermes_issue_cmd(hw, cmd, parm0); + if (err) { + if (! hermes_present(hw)) { + printk(KERN_WARNING "hermes @ 0x%x: Card removed while issuing command.\n", + hw->iobase); + err = -ENODEV; + } else + printk(KERN_ERR "hermes @ 0x%x: CMD register busy in hermes_issue_command().\n", + hw->iobase); + goto out; + } + + reg = hermes_read_regn(hw, EVSTAT); + k = CMD_COMPL_TIMEOUT; + while ( (! (reg & HERMES_EV_CMD)) && k) { + k--; + udelay(10); + reg = hermes_read_regn(hw, EVSTAT); + } + + if (! hermes_present(hw)) { + printk(KERN_WARNING "hermes @ 0x%x: Card removed while waiting for command completion.\n", + hw->iobase); + err = -ENODEV; + goto out; + } + + if (! (reg & HERMES_EV_CMD)) { + printk(KERN_ERR "hermes @ 0x%x: Timeout waiting for command completion.\n", + hw->iobase); + err = -ETIMEDOUT; + goto out; + } + + resp->status = hermes_read_regn(hw, STATUS); + resp->resp0 = hermes_read_regn(hw, RESP0); + resp->resp1 = hermes_read_regn(hw, RESP1); + resp->resp2 = hermes_read_regn(hw, RESP2); + + hermes_write_regn(hw, EVACK, HERMES_EV_CMD); + + err = resp->status & HERMES_STATUS_RESULT; + + out: + return err; +} + +int hermes_allocate(hermes_t *hw, uint16_t size, uint16_t *fid) +{ + int err = 0; + hermes_response_t resp; + int k; + uint16_t reg; + + if ( (size < HERMES_ALLOC_LEN_MIN) || (size > HERMES_ALLOC_LEN_MAX) ) + return -EINVAL; + + err = hermes_docmd_wait(hw, HERMES_CMD_ALLOC, size, &resp); + if (err) { + printk(KERN_WARNING "hermes @ 0x%x: Frame allocation command failed (0x%X).\n", + hw->iobase, err); + return err; + } + + reg = hermes_read_regn(hw, EVSTAT); + k = ALLOC_COMPL_TIMEOUT; + while ( (! (reg & HERMES_EV_ALLOC)) && k) { + k--; + udelay(10); + reg = hermes_read_regn(hw, EVSTAT); + } + + if (! hermes_present(hw)) { + printk(KERN_WARNING "hermes @ 0x%x: Card removed waiting for frame allocation.\n", + hw->iobase); + return -ENODEV; + } + + if (! (reg & HERMES_EV_ALLOC)) { + printk(KERN_ERR "hermes @ 0x%x: Timeout waiting for frame allocation\n", + hw->iobase); + return -ETIMEDOUT; + } + + *fid = hermes_read_regn(hw, ALLOCFID); + hermes_write_regn(hw, EVACK, HERMES_EV_ALLOC); + + return 0; +} + +/* Set up a BAP to read a particular chunk of data from card's internal buffer. + * + * Returns: < 0 on internal failure (errno), 0 on success, >0 on error + * from firmware + * + * Callable from any context */ +static int hermes_bap_seek(hermes_t *hw, int bap, uint16_t id, uint16_t offset) +{ + int sreg = bap ? HERMES_SELECT1 : HERMES_SELECT0; + int oreg = bap ? HERMES_OFFSET1 : HERMES_OFFSET0; + int k; + int l = BAP_ERROR_RETRY; + uint16_t reg; + + /* Paranoia.. */ + if ( (offset > HERMES_BAP_OFFSET_MAX) || (offset % 2) ) + return -EINVAL; + + k = BAP_BUSY_TIMEOUT; + reg = hermes_read_reg(hw, oreg); + + if (reg & HERMES_OFFSET_BUSY) + return -EBUSY; + + /* Now we actually set up the transfer */ + retry: + hermes_write_reg(hw, sreg, id); + hermes_write_reg(hw, oreg, offset); + + /* Wait for the BAP to be ready */ + k = BAP_BUSY_TIMEOUT; + reg = hermes_read_reg(hw, oreg); + while ( (reg & (HERMES_OFFSET_BUSY | HERMES_OFFSET_ERR)) && k) { + k--; + udelay(1); + reg = hermes_read_reg(hw, oreg); + } + + if (reg & HERMES_OFFSET_BUSY) + return -ETIMEDOUT; + + /* For some reason, seeking the BAP seems to randomly fail somewhere + (firmware bug?). We retry a few times before giving up. */ + if (reg & HERMES_OFFSET_ERR) { + if (l--) { + udelay(1); + goto retry; + } else + return -EIO; + } + + return 0; +} + +/* Read a block of data from the chip's buffer, via the + * BAP. Synchronization/serialization is the caller's problem. len + * must be even. + * + * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware + */ +int hermes_bap_pread(hermes_t *hw, int bap, void *buf, uint16_t len, + uint16_t id, uint16_t offset) +{ + int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; + int err = 0; + + if (len % 2) + return -EINVAL; + + err = hermes_bap_seek(hw, bap, id, offset); + if (err) + goto out; + + /* Actually do the transfer */ + hermes_read_data(hw, dreg, buf, len/2); + + out: + return err; +} + +/* Write a block of data to the chip's buffer, via the + * BAP. Synchronization/serialization is the caller's problem. len + * must be even. + * + * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware + */ +int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, uint16_t len, + uint16_t id, uint16_t offset) +{ + int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; + int err = 0; + + if (len % 2) + return -EINVAL; + + err = hermes_bap_seek(hw, bap, id, offset); + if (err) + goto out; + + /* Actually do the transfer */ + hermes_write_data(hw, dreg, buf, len/2); + + out: + return err; +} + +/* Read a Length-Type-Value record from the card. + * + * If length is NULL, we ignore the length read from the card, and + * read the entire buffer regardless. This is useful because some of + * the configuration records appear to have incorrect lengths in + * practice. + * + * Callable from user or bh context. */ +int hermes_read_ltv(hermes_t *hw, int bap, uint16_t rid, int buflen, + uint16_t *length, void *buf) +{ + int err = 0; + int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; + uint16_t rlength, rtype; + hermes_response_t resp; + int count; + + if (buflen % 2) + return -EINVAL; + + err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS, rid, &resp); + if (err) + goto out; + + err = hermes_bap_seek(hw, bap, rid, 0); + if (err) + goto out; + + rlength = hermes_read_reg(hw, dreg); + rtype = hermes_read_reg(hw, dreg); + + if (length) + *length = rlength; + + if (rtype != rid) + printk(KERN_WARNING "hermes_read_ltv(): rid (0x%04x) does " + "not match type (0x%04x)\n", rid, rtype); + if (HERMES_RECLEN_TO_BYTES(rlength) > buflen) + printk(KERN_WARNING "hermes @ 0x%x: Truncating LTV record from %d to %d bytes. " + "(rid=0x%04x, len=0x%04x)\n", hw->iobase, + HERMES_RECLEN_TO_BYTES(rlength), buflen, rid, rlength); + + /* For now we always read the whole buffer, the + lengths in the records seem to be wrong, frequently */ + count = buflen / 2; + +#if 0 + if (length) + count = (MIN(buflen, rlength) + 1) / 2; + else { + count = buflen / 2; + if (rlength != buflen) + printk(KERN_WARNING "hermes_read_ltv(): Incorrect \ +record length %d instead of %d on RID 0x%04x\n", rlength, buflen, rid); + } +#endif + hermes_read_data(hw, dreg, buf, count); + + out: + return err; +} + +int hermes_write_ltv(hermes_t *hw, int bap, uint16_t rid, + uint16_t length, const void *value) +{ + int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; + int err = 0; + hermes_response_t resp; + int count; + + DEBUG(3, "write_ltv(): bap=%d rid=0x%04x length=%d (value=0x%04x)\n", + bap, rid, length, * ((uint16_t *)value)); + + err = hermes_bap_seek(hw, bap, rid, 0); + if (err) + goto out; + + hermes_write_reg(hw, dreg, length); + hermes_write_reg(hw, dreg, rid); + + count = length - 1; + + hermes_write_data(hw, dreg, value, count); + + err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS | HERMES_CMD_WRITE, + rid, &resp); + + out: + return err; +} + +EXPORT_SYMBOL(hermes_struct_init); +EXPORT_SYMBOL(hermes_reset); +EXPORT_SYMBOL(hermes_docmd_wait); +EXPORT_SYMBOL(hermes_allocate); + +EXPORT_SYMBOL(hermes_bap_pread); +EXPORT_SYMBOL(hermes_bap_pwrite); +EXPORT_SYMBOL(hermes_read_ltv); +EXPORT_SYMBOL(hermes_write_ltv); + +static int __init init_hermes(void) +{ + printk(KERN_INFO "%s\n", version); + + return 0; +} + +module_init(init_hermes); diff -Nru a/drivers/net/wireless/hermes.h b/drivers/net/wireless/hermes.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/hermes.h Wed May 16 06:00:23 2001 @@ -0,0 +1,402 @@ +/* hermes.h + * + * Driver core for the "Hermes" wireless MAC controller, as used in + * the Lucent Orinoco and Cabletron RoamAbout cards. It should also + * work on the hfa3841 and hfa3842 MAC controller chips used in the + * Prism I & II chipsets. + * + * This is not a complete driver, just low-level access routines for + * the MAC controller itself. + * + * Based on the prism2 driver from Absolute Value Systems' linux-wlan + * project, the Linux wvlan_cs driver, Lucent's HCF-Light + * (wvlan_hcf.c) library, and the NetBSD wireless driver. + * + * Copyright (C) 2000, David Gibson, Linuxcare Australia + * + * Portions taken from hfa384x.h, Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. + * + * This file distributed under the GPL, version 2. + */ + +#ifndef _HERMES_H +#define _HERMES_H + +/* Notes on locking: + * + * As a module of low level hardware access routines, there is no + * locking. Users of this module should ensure that they serialize + * access to the hermes_t structure, and to the hardware +*/ + +#include +#include + +/* + * Limits and constants + */ +#define HERMES_ALLOC_LEN_MIN (4) +#define HERMES_ALLOC_LEN_MAX (2400) +#define HERMES_LTV_LEN_MAX (34) +#define HERMES_BAP_DATALEN_MAX (4096) +#define HERMES_BAP_OFFSET_MAX (4096) +#define HERMES_PORTID_MAX (7) +#define HERMES_NUMPORTS_MAX (HERMES_PORTID_MAX+1) +#define HERMES_PDR_LEN_MAX (260) /* in bytes, from EK */ +#define HERMES_PDA_RECS_MAX (200) /* a guess */ +#define HERMES_PDA_LEN_MAX (1024) /* in bytes, from EK */ +#define HERMES_SCANRESULT_MAX (35) +#define HERMES_CHINFORESULT_MAX (8) +#define HERMES_FRAME_LEN_MAX (2304) +#define HERMES_MAX_MULTICAST (16) +#define HERMES_MAGIC (0x7d1f) + +/* + * Hermes register offsets + */ +#define HERMES_CMD (0x00) +#define HERMES_PARAM0 (0x02) +#define HERMES_PARAM1 (0x04) +#define HERMES_PARAM2 (0x06) +#define HERMES_STATUS (0x08) +#define HERMES_RESP0 (0x0A) +#define HERMES_RESP1 (0x0C) +#define HERMES_RESP2 (0x0E) +#define HERMES_INFOFID (0x10) +#define HERMES_RXFID (0x20) +#define HERMES_ALLOCFID (0x22) +#define HERMES_TXCOMPLFID (0x24) +#define HERMES_SELECT0 (0x18) +#define HERMES_OFFSET0 (0x1C) +#define HERMES_DATA0 (0x36) +#define HERMES_SELECT1 (0x1A) +#define HERMES_OFFSET1 (0x1E) +#define HERMES_DATA1 (0x38) +#define HERMES_EVSTAT (0x30) +#define HERMES_INTEN (0x32) +#define HERMES_EVACK (0x34) +#define HERMES_CONTROL (0x14) +#define HERMES_SWSUPPORT0 (0x28) +#define HERMES_SWSUPPORT1 (0x2A) +#define HERMES_SWSUPPORT2 (0x2C) +#define HERMES_AUXPAGE (0x3A) +#define HERMES_AUXOFFSET (0x3C) +#define HERMES_AUXDATA (0x3E) + +/* + * CMD register bitmasks + */ +#define HERMES_CMD_BUSY (0x8000) +#define HERMES_CMD_AINFO (0x7f00) +#define HERMES_CMD_MACPORT (0x0700) +#define HERMES_CMD_RECL (0x0100) +#define HERMES_CMD_WRITE (0x0100) +#define HERMES_CMD_PROGMODE (0x0300) +#define HERMES_CMD_CMDCODE (0x003f) + +/* + * STATUS register bitmasks + */ +#define HERMES_STATUS_RESULT (0x7f00) +#define HERMES_STATUS_CMDCODE (0x003f) + +/* + * OFFSET refister bitmasks + */ +#define HERMES_OFFSET_BUSY (0x8000) +#define HERMES_OFFSET_ERR (0x4000) +#define HERMES_OFFSET_DATAOFF (0x0ffe) + +/* + * Event register bitmasks (INTEN, EVSTAT, EVACK) + */ +#define HERMES_EV_TICK (0x8000) +#define HERMES_EV_WTERR (0x4000) +#define HERMES_EV_INFDROP (0x2000) +#define HERMES_EV_INFO (0x0080) +#define HERMES_EV_DTIM (0x0020) +#define HERMES_EV_CMD (0x0010) +#define HERMES_EV_ALLOC (0x0008) +#define HERMES_EV_TXEXC (0x0004) +#define HERMES_EV_TX (0x0002) +#define HERMES_EV_RX (0x0001) + +/* + * Command codes + */ +/*--- Controller Commands --------------------------*/ +#define HERMES_CMD_INIT (0x0000) +#define HERMES_CMD_ENABLE (0x0001) +#define HERMES_CMD_DISABLE (0x0002) +#define HERMES_CMD_DIAG (0x0003) + +/*--- Buffer Mgmt Commands --------------------------*/ +#define HERMES_CMD_ALLOC (0x000A) +#define HERMES_CMD_TX (0x000B) +#define HERMES_CMD_CLRPRST (0x0012) + +/*--- Regulate Commands --------------------------*/ +#define HERMES_CMD_NOTIFY (0x0010) +#define HERMES_CMD_INQ (0x0011) + +/*--- Configure Commands --------------------------*/ +#define HERMES_CMD_ACCESS (0x0021) +#define HERMES_CMD_DOWNLD (0x0022) + +/*--- Debugging Commands -----------------------------*/ +#define HERMES_CMD_MONITOR (0x0038) +#define HERMES_MONITOR_ENABLE (0x000b) +#define HERMES_MONITOR_DISABLE (0x000f) + +/* + * Configuration RIDs + */ + +#define HERMES_RID_CNF_PORTTYPE (0xfc00) +#define HERMES_RID_CNF_MACADDR (0xfc01) +#define HERMES_RID_CNF_DESIRED_SSID (0xfc02) +#define HERMES_RID_CNF_CHANNEL (0xfc03) +#define HERMES_RID_CNF_OWN_SSID (0xfc04) +#define HERMES_RID_CNF_SYSTEM_SCALE (0xfc06) +#define HERMES_RID_CNF_MAX_DATA_LEN (0xfc07) +#define HERMES_RID_CNF_PM_ENABLE (0xfc09) +#define HERMES_RID_CNF_PM_MCAST_RX (0xfc0b) +#define HERMES_RID_CNF_PM_PERIOD (0xfc0c) +#define HERMES_RID_CNF_PM_HOLDOVER (0xfc0d) +#define HERMES_RID_CNF_NICKNAME (0xfc0e) +#define HERMES_RID_CNF_WEP_ON (0xfc20) +#define HERMES_RID_CNF_MWO_ROBUST (0xfc25) +#define HERMES_RID_CNF_PRISM2_WEP_ON (0xfc28) +#define HERMES_RID_CNF_MULTICAST_LIST (0xfc80) +#define HERMES_RID_CNF_CREATEIBSS (0xfc81) +#define HERMES_RID_CNF_FRAG_THRESH (0xfc82) +#define HERMES_RID_CNF_RTS_THRESH (0xfc83) +#define HERMES_RID_CNF_TX_RATE_CTRL (0xfc84) +#define HERMES_RID_CNF_PROMISCUOUS (0xfc85) +#define HERMES_RID_CNF_KEYS (0xfcb0) +#define HERMES_RID_CNF_TX_KEY (0xfcb1) +#define HERMES_RID_CNF_TICKTIME (0xfce0) + +#define HERMES_RID_CNF_PRISM2_TX_KEY (0xfc23) +#define HERMES_RID_CNF_PRISM2_KEY0 (0xfc24) +#define HERMES_RID_CNF_PRISM2_KEY1 (0xfc25) +#define HERMES_RID_CNF_PRISM2_KEY2 (0xfc26) +#define HERMES_RID_CNF_PRISM2_KEY3 (0xfc27) +#define HERMES_RID_CNF_SYMBOL_MANDATORY_BSSID (0xfc21) +#define HERMES_RID_CNF_SYMBOL_AUTH_TYPE (0xfc2A) +#define HERMES_RID_CNF_SYMBOL_BASIC_RATES (0xfc8A) +#define HERMES_RID_CNF_SYMBOL_PREAMBLE (0xfc8C) + +/* + * Information RIDs + */ +#define HERMES_RID_CHANNEL_LIST (0xfd10) +#define HERMES_RID_STAIDENTITY (0xfd20) +#define HERMES_RID_CURRENT_SSID (0xfd41) +#define HERMES_RID_CURRENT_BSSID (0xfd42) +#define HERMES_RID_COMMSQUALITY (0xfd43) +#define HERMES_RID_CURRENT_TX_RATE (0xfd44) +#define HERMES_RID_SHORT_RETRY_LIMIT (0xfd48) +#define HERMES_RID_LONG_RETRY_LIMIT (0xfd49) +#define HERMES_RID_MAX_TX_LIFETIME (0xfd4A) +#define HERMES_RID_WEP_AVAIL (0xfd4f) +#define HERMES_RID_CURRENT_CHANNEL (0xfdc1) +#define HERMES_RID_DATARATES (0xfdc6) +#define HERMES_RID_SYMBOL_PRIMARY_VER (0xfd03) +#define HERMES_RID_SYMBOL_SECONDARY_VER (0xfd21) +#define HERMES_RID_SYMBOL_KEY_LENGTH (0xfc2B) + +/* + * Frame structures and constants + */ + +typedef struct hermes_frame_desc { + /* Hermes - i.e. little-endian byte-order */ + uint16_t status; /* 0x0 */ + uint16_t res1, res2; /* 0x2, 0x4 */ + uint16_t q_info; /* 0x6 */ + uint16_t res3, res4; /* 0x8, 0xA */ + uint16_t tx_ctl; /* 0xC */ +} __attribute__ ((packed)) hermes_frame_desc_t; + +#define HERMES_RXSTAT_ERR (0x0003) +#define HERMES_RXSTAT_MACPORT (0x0700) +#define HERMES_RXSTAT_MSGTYPE (0xE000) + +#define HERMES_RXSTAT_BADCRC (0x0001) +#define HERMES_RXSTAT_UNDECRYPTABLE (0x0002) + +/* RFC-1042 encoded frame */ +#define HERMES_RXSTAT_1042 (0x2000) +/* Bridge-tunnel encoded frame */ +#define HERMES_RXSTAT_TUNNEL (0x4000) +/* Wavelan-II Management Protocol frame */ +#define HERMES_RXSTAT_WMP (0x6000) + +#ifdef __KERNEL__ + +/* Basic control structure */ +typedef struct hermes { + uint iobase; + + uint16_t inten; /* Which interrupts should be enabled? */ +} hermes_t; + +typedef struct hermes_response { + uint16_t status, resp0, resp1, resp2; +} hermes_response_t; + +/* Firmware information structure */ +typedef struct hermes_identity { + uint16_t id, vendor, major, minor; +} __attribute__ ((packed)) hermes_identity_t; + +/* "ID" structure - used for ESSID and station nickname */ +typedef struct hermes_id { + uint16_t len; + uint16_t val[16]; +} __attribute__ ((packed)) hermes_id_t; + +typedef struct hermes_commsqual { + uint16_t qual, signal, noise; +} __attribute__ ((packed)) hermes_commsqual_t; + +typedef struct hermes_multicast { + uint8_t addr[HERMES_MAX_MULTICAST][ETH_ALEN]; +} __attribute__ ((packed)) hermes_multicast_t; + +/* Register access convenience macros */ +#define hermes_read_reg(hw, off) (inw((hw)->iobase + (off))) +#define hermes_write_reg(hw, off, val) (outw_p((val), (hw)->iobase + (off))) + +#define hermes_read_regn(hw, name) (hermes_read_reg((hw), HERMES_##name)) +#define hermes_write_regn(hw, name, val) (hermes_write_reg((hw), HERMES_##name, (val))) + +/* Note that for the next two, the count is in 16-bit words, not bytes */ +#define hermes_read_data(hw, off, buf, count) (insw((hw)->iobase + (off), (buf), (count))) +#define hermes_write_data(hw, off, buf, count) (outsw((hw)->iobase + (off), (buf), (count))) + +/* Function prototypes */ +void hermes_struct_init(hermes_t *hw, uint io); +int hermes_reset(hermes_t *hw); +int hermes_docmd_wait(hermes_t *hw, uint16_t cmd, uint16_t parm0, hermes_response_t *resp); +int hermes_allocate(hermes_t *hw, uint16_t size, uint16_t *fid); + + +int hermes_bap_pread(hermes_t *hw, int bap, void *buf, uint16_t len, + uint16_t id, uint16_t offset); +int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, uint16_t len, + uint16_t id, uint16_t offset); +int hermes_read_ltv(hermes_t *hw, int bap, uint16_t rid, int buflen, + uint16_t *length, void *buf); +int hermes_write_ltv(hermes_t *hw, int bap, uint16_t rid, + uint16_t length, const void *value); + +/* Inline functions */ + +static inline int hermes_present(hermes_t *hw) +{ + return hermes_read_regn(hw, SWSUPPORT0) == HERMES_MAGIC; +} + +static inline void hermes_enable_interrupt(hermes_t *hw, uint16_t events) +{ + hw->inten |= events; + hermes_write_regn(hw, INTEN, hw->inten); +} + +static inline void hermes_set_irqmask(hermes_t *hw, uint16_t events) +{ + hw->inten = events; + hermes_write_regn(hw, INTEN, events); +} + +static inline int hermes_enable_port(hermes_t *hw, int port) +{ + hermes_response_t resp; + + return hermes_docmd_wait(hw, HERMES_CMD_ENABLE | (port << 8), + 0, &resp); +} + +static inline int hermes_disable_port(hermes_t *hw, int port) +{ + hermes_response_t resp; + + return hermes_docmd_wait(hw, HERMES_CMD_ENABLE | (port << 8), + 0, &resp); +} + +#define HERMES_BYTES_TO_RECLEN(n) ( ((n) % 2) ? (((n)+1)/2)+1 : ((n)/2)+1 ) +#define HERMES_RECLEN_TO_BYTES(n) ( ((n)-1) * 2 ) + +#define HERMES_READ_RECORD(hw, bap, rid, buf) \ + (hermes_read_ltv((hw),(bap),(rid), sizeof(*buf), NULL, (buf))) +#define HERMES_WRITE_RECORD(hw, bap, rid, buf) \ + (hermes_write_ltv((hw),(bap),(rid),HERMES_BYTES_TO_RECLEN(sizeof(*buf)),(buf))) + +static inline int hermes_read_wordrec(hermes_t *hw, int bap, uint16_t rid, uint16_t *word) +{ + uint16_t rec; + int err; + + err = HERMES_READ_RECORD(hw, bap, rid, &rec); + *word = le16_to_cpu(rec); + return err; +} + +static inline int hermes_write_wordrec(hermes_t *hw, int bap, uint16_t rid, uint16_t word) +{ + uint16_t rec = cpu_to_le16(word); + return HERMES_WRITE_RECORD(hw, bap, rid, &rec); +} + +static inline int hermes_read_staidentity(hermes_t *hw, int bap, hermes_identity_t *buf) +{ + int err; + + err = HERMES_READ_RECORD(hw, bap, HERMES_RID_STAIDENTITY, buf); + if (err) + return err; + + le16_to_cpus(&buf->id); + le16_to_cpus(&buf->vendor); + le16_to_cpus(&buf->major); + le16_to_cpus(&buf->minor); + + return 0; +} + +static inline int hermes_read_commsqual(hermes_t *hw, int bap, hermes_commsqual_t *buf) +{ + int err; + + err = HERMES_READ_RECORD(hw, bap, HERMES_RID_COMMSQUALITY, buf); + if (err) + return err; + + le16_to_cpus(&buf->qual); + le16_to_cpus(&buf->signal); + le16_to_cpus(&buf->noise); + + return 0; +} + +#else /* ! __KERNEL__ */ + +/* These are provided for the benefit of userspace drivers and testing programs + which use ioperm() or iopl() */ + +#define hermes_read_reg(base, off) (inw((base) + (off))) +#define hermes_write_reg(base, off, val) (outw((val), (base) + (off))) + +#define hermes_read_regn(base, name) (hermes_read_reg((base), HERMES_##name)) +#define hermes_write_regn(base, name, val) (hermes_write_reg((base), HERMES_##name, (val))) + +/* Note that for the next two, the count is in 16-bit words, not bytes */ +#define hermes_read_data(base, off, buf, count) (insw((base) + (off), (buf), (count))) +#define hermes_write_data(base, off, buf, count) (outsw((base) + (off), (buf), (count))) + +#endif /* ! __KERNEL__ */ + +#endif /* _HERMES_H */ diff -Nru a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/orinoco.c Wed May 16 06:00:34 2001 @@ -0,0 +1,3551 @@ +/* orinoco.c 0.05 - (formerly known as dldwd_cs.c and orinoco_cs.c) + * + * A driver for "Hermes" chipset based PCMCIA wireless adaptors, such + * as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/ + * EnteraSys RoamAbout 802.11, ELSA Airlancer, Melco Buffalo and others). + * It should also be usable on various Prism II based cards such as the + * Linksys, D-Link and Farallon Skyline. It should also work on Symbol + * cards such as the 3Com AirConnect and Ericsson WLAN. + * + * Copyright (C) 2000 David Gibson, Linuxcare Australia + * With some help from : + * Copyright (C) 2001 Jean Tourrilhes, HP Labs + * Copyright (C) 2001 Benjamin Herrenschmidt + * + * Based on dummy_cs.c 1.27 2000/06/12 21:27:25 + * + * Portions based on wvlan_cs.c 1.0.6, Copyright Andreas Neuhaus + * http://www.fasta.fh-dortmund.de/users/andy/wvlan/ + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David + * A. Hinds are Copyright (C) 1999 David A. Hinds. All Rights + * Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License version 2 (the "GPL"), in which + * case the provisions of the GPL are applicable instead of the above. + * If you wish to allow the use of your version of this file only + * under the terms of the GPL and not to allow others to use your + * version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. + */ + +/* Notes on locking: + * + * The basic principle of operation is that everything except the + * interrupt handler is serialized through a single spinlock in the + * dldwd_priv_t structure, using dldwd_lock() and + * dldwd_unlock() (which in turn use spin_lock_bh() and spin_unlock_bh()). + * + * The kernel's IRQ handling stuff ensures that the interrupt handler + * does not re-enter itself. The interrupt handler is written such + * that everything it does is safe without a lock: chiefly this means + * that the Rx path uses one of the Hermes chipset's BAPs while + * everything else uses the other. + * + * For the moment access to the device statistics from the interrupt + * handler is unsafe - we just put up with any resulting errors in the + * statisics. FIXME: This should probably be changed to store the + * stats in atomic types. + * + * EXCEPT that we don't want the irq handler running when we actually + * reset or shut down the card, because strange things might happen + * (probably the worst would be one packet of garbage, but you can't + * be too careful). For this we use __dldwd_stop_irqs() which will set + * a flag to disable the interrupt handler, and wait for any + * outstanding instances of the handler to complete. THIS WILL LOSE + * INTERRUPTS! so it shouldn't be used except for resets, when we + * don't care about that.*/ + +/* + * Tentative changelog... + * + * v0.01 -> v0.02 - 21/3/2001 - Jean II + * o Allow to use regular ethX device name instead of dldwdX + * o Warning on IBSS with ESSID=any for firmware 6.06 + * o Put proper range.throughput values (optimistic) + * o IWSPY support (IOCTL and stat gather in Rx path) + * o Allow setting frequency in Ad-Hoc mode + * o Disable WEP setting if !has_wep to work on old firmware + * o Fix txpower range + * o Start adding support for Samsung/Compaq firmware + * + * v0.02 -> v0.03 - 23/3/2001 - Jean II + * o Start adding Symbol support - need to check all that + * o Fix Prism2/Symbol WEP to accept 128 bits keys + * o Add Symbol WEP (add authentication type) + * o Add Prism2/Symbol rate + * o Add PM timeout (holdover duration) + * o Enable "iwconfig eth0 key off" and friends (toggle flags) + * o Enable "iwconfig eth0 power unicast/all" (toggle flags) + * o Try with an intel card. It report firmware 1.01, behave like + * an antiquated firmware, however on windows it says 2.00. Yuck ! + * o Workaround firmware bug in allocate buffer (Intel 1.01) + * o Finish external renaming to orinoco... + * o Testing with various Wavelan firmwares + * + * v0.03 -> v0.04 - 30/3/2001 - Jean II + * o Update to Wireless 11 -> add retry limit/lifetime support + * o Tested with a D-Link DWL 650 card, fill in firmware support + * o Warning on Vcc mismatch (D-Link 3.3v card in Lucent 5v only slot) + * o Fixed the Prims2 WEP bugs that I introduced in v0.03 :-( + * It work on D-Link *only* after a tcpdump. Weird... + * And still doesn't work on Intel card. Grrrr... + * o Update the mode after a setport3 + * o Add preamble setting for Symbol cards (not yet enabled) + * o Don't complain as much about Symbol cards... + * + * v0.04 -> v0.04b - 22/4/2001 - David Gibson + * o Removed the 'eth' parameter - always use ethXX as the + * interface name instead of dldwdXX. The other was racy + * anyway. + * o Clean up RID definitions in hermes.h, other cleanups + * + * v0.04b -> v0.04c - 24/4/2001 - Jean II + * o Tim Hurley reported a D-Link card + * with vendor 02 and firmware 0.08. Added in the capabilities... + * o Tested Lucent firmware 7.28, everything works... + * + * v0.04c -> v0.05 - 3/5/2001 - Benjamin Herrenschmidt + * o Spin-off Pcmcia code. This file is renamed orinoco.c, + * and orinoco_cs.c now contains only the Pcmcia specific stuff + * o Add Airport driver support on top of orinoco.c (see airport.c) + * + * v0.05 -> v0.05a - 4/5/2001 - Jean II + * o Revert to old Pcmcia code to fix breakage of Ben's changes... + * + * v0.05a -> v0.05b - 4/5/2001 - Jean II + * o add module parameter 'ignore_cis_vcc' for D-Link @ 5V + * o D-Link firmware doesn't support multicast. We just print a few + * error messages, but otherwise everything works... + * o For David : set/getport3 works fine, just upgrade iwpriv... + * + * v0.05b -> v0.05c - 5/5/2001 - Benjamin Herrenschmidt + * o Adapt airport.c to latest changes in orinoco.c + * o Remove deferred power enabling code + * + * v0.05c -> v0.05d - 5/5/2001 - Jean II + * o Workaround to SNAP decapsulate frame from LinkSys AP + * original patch from : Dong Liu + * (note : the memcmp bug was mine - fixed) + * o Remove set_retry stuff, no firmware support it (bloat--). + * + * TODO - Jean II + * o inline functions (lot's of candidate, need to reorder code) + * o Test PrismII/Symbol cards & firmware versions + * o Mini-PCI support + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "hermes.h" +#include "orinoco.h" + +static char *version = "orinoco.c 0.05d (David Gibson and others)"; + +/* Level of debugging. Used in the macros in orinoco.h */ +#ifdef ORINOCO_DEBUG +int dldwd_debug = ORINOCO_DEBUG; +MODULE_PARM(dldwd_debug, "i"); +#endif + +const long channel_frequency[] = { + 2412, 2417, 2422, 2427, 2432, 2437, 2442, + 2447, 2452, 2457, 2462, 2467, 2472, 2484 +}; + +#define NUM_CHANNELS ( sizeof(channel_frequency) / sizeof(channel_frequency[0]) ) + +/* This tables gives the actual meanings of the bitrate IDs returned by the firmware. + It gives the rate in halfMb/s, negative indicates auto mode */ +const int rate_list[] = { 0, 2, 4, -22, 11, 22, -4, -11, 0, 0, 0, 0}; + +#define NUM_RATES (sizeof(rate_list) / sizeof(rate_list[0])) + +struct p80211_hdr { + uint16_t frame_ctl; + uint16_t duration_id; + uint8_t addr1[ETH_ALEN]; + uint8_t addr2[ETH_ALEN]; + uint8_t addr3[ETH_ALEN]; + uint16_t seq_ctl; + uint8_t addr4[ETH_ALEN]; + uint16_t data_len; +} __attribute__ ((packed)); + +/* Frame control field constants */ +#define DLDWD_FCTL_VERS 0x0002 +#define DLDWD_FCTL_FTYPE 0x000c +#define DLDWD_FCTL_STYPE 0x00f0 +#define DLDWD_FCTL_TODS 0x0100 +#define DLDWD_FCTL_FROMDS 0x0200 +#define DLDWD_FCTL_MOREFRAGS 0x0400 +#define DLDWD_FCTL_RETRY 0x0800 +#define DLDWD_FCTL_PM 0x1000 +#define DLDWD_FCTL_MOREDATA 0x2000 +#define DLDWD_FCTL_WEP 0x4000 +#define DLDWD_FCTL_ORDER 0x8000 + +#define DLDWD_FTYPE_MGMT 0x0000 +#define DLDWD_FTYPE_CTL 0x0004 +#define DLDWD_FTYPE_DATA 0x0008 + +struct p8022_hdr { + uint8_t dsap; + uint8_t ssap; + uint8_t ctrl; + uint8_t oui[3]; +} __attribute__ ((packed)); + +struct dldwd_frame_hdr { + hermes_frame_desc_t desc; + struct p80211_hdr p80211; + struct ethhdr p8023; + struct p8022_hdr p8022; + uint16_t ethertype; +} __attribute__ ((packed)); + +#define P8023_OFFSET (sizeof(hermes_frame_desc_t) + \ + sizeof(struct p80211_hdr)) +#define ENCAPS_OVERHEAD (sizeof(struct p8022_hdr) + 2) + +/* 802.2 LLL header SNAP used for SNAP encapsulation over 802.11 */ +struct p8022_hdr encaps_hdr = { + 0xaa, 0xaa, 0x03, {0x00, 0x00, 0xf8} +}; + +/* + * Function prototypes + */ + +static void dldwd_stat_gather(struct net_device *dev, + struct sk_buff *skb, + struct dldwd_frame_hdr *hdr); + +static struct net_device_stats *dldwd_get_stats(struct net_device *dev); +static struct iw_statistics *dldwd_get_wireless_stats(struct net_device *dev); + +/* Hardware control routines */ + +static int __dldwd_hw_reset(dldwd_priv_t *priv); +static int __dldwd_hw_setup_wep(dldwd_priv_t *priv); +static int dldwd_hw_get_bssid(dldwd_priv_t *priv, char buf[ETH_ALEN]); +static int dldwd_hw_get_essid(dldwd_priv_t *priv, int *active, char buf[IW_ESSID_MAX_SIZE+1]); +static long dldwd_hw_get_freq(dldwd_priv_t *priv); +static int dldwd_hw_get_bitratelist(dldwd_priv_t *priv, int *numrates, + int32_t *rates, int max); + +/* Interrupt handling routines */ +static void __dldwd_ev_tick(dldwd_priv_t *priv, hermes_t *hw); +static void __dldwd_ev_wterr(dldwd_priv_t *priv, hermes_t *hw); +static void __dldwd_ev_infdrop(dldwd_priv_t *priv, hermes_t *hw); +static void __dldwd_ev_info(dldwd_priv_t *priv, hermes_t *hw); +static void __dldwd_ev_rx(dldwd_priv_t *priv, hermes_t *hw); +static void __dldwd_ev_txexc(dldwd_priv_t *priv, hermes_t *hw); +static void __dldwd_ev_tx(dldwd_priv_t *priv, hermes_t *hw); +static void __dldwd_ev_alloc(dldwd_priv_t *priv, hermes_t *hw); + +static int dldwd_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq); +static int dldwd_ioctl_setiwencode(struct net_device *dev, struct iw_point *erq); +static int dldwd_ioctl_getiwencode(struct net_device *dev, struct iw_point *erq); +static int dldwd_ioctl_setessid(struct net_device *dev, struct iw_point *erq); +static int dldwd_ioctl_getessid(struct net_device *dev, struct iw_point *erq); +static int dldwd_ioctl_setnick(struct net_device *dev, struct iw_point *nrq); +static int dldwd_ioctl_getnick(struct net_device *dev, struct iw_point *nrq); +static int dldwd_ioctl_setfreq(struct net_device *dev, struct iw_freq *frq); +static int dldwd_ioctl_getsens(struct net_device *dev, struct iw_param *srq); +static int dldwd_ioctl_setsens(struct net_device *dev, struct iw_param *srq); +static int dldwd_ioctl_setrts(struct net_device *dev, struct iw_param *rrq); +static int dldwd_ioctl_setfrag(struct net_device *dev, struct iw_param *frq); +static int dldwd_ioctl_getfrag(struct net_device *dev, struct iw_param *frq); +static int dldwd_ioctl_setrate(struct net_device *dev, struct iw_param *frq); +static int dldwd_ioctl_getrate(struct net_device *dev, struct iw_param *frq); +static int dldwd_ioctl_setpower(struct net_device *dev, struct iw_param *prq); +static int dldwd_ioctl_getpower(struct net_device *dev, struct iw_param *prq); +static int dldwd_ioctl_setport3(struct net_device *dev, struct iwreq *wrq); +static int dldwd_ioctl_getport3(struct net_device *dev, struct iwreq *wrq); +static void __dldwd_set_multicast_list(struct net_device *dev); + +/* /proc debugging stuff */ +static int dldwd_proc_init(void); +static void dldwd_proc_cleanup(void); + +/* + * Inline functions + */ +static inline void +dldwd_lock(dldwd_priv_t *priv) +{ + spin_lock_bh(&priv->lock); +} + +static inline void +dldwd_unlock(dldwd_priv_t *priv) +{ + spin_unlock_bh(&priv->lock); +} + +static inline int +dldwd_irqs_allowed(dldwd_priv_t *priv) +{ + return test_bit(DLDWD_STATE_DOIRQ, &priv->state); +} + +static inline void +__dldwd_stop_irqs(dldwd_priv_t *priv) +{ + hermes_t *hw = &priv->hw; + + hermes_set_irqmask(hw, 0); + clear_bit(DLDWD_STATE_DOIRQ, &priv->state); + while (test_bit(DLDWD_STATE_INIRQ, &priv->state)) + ; +} + +static inline void +__dldwd_start_irqs(dldwd_priv_t *priv, uint16_t irqmask) +{ + hermes_t *hw = &priv->hw; + + TRACE_ENTER(priv->ndev.name); + + __cli(); + set_bit(DLDWD_STATE_DOIRQ, &priv->state); + hermes_set_irqmask(hw, irqmask); + __sti(); + + TRACE_EXIT(priv->ndev.name); +} + +static inline void +set_port_type(dldwd_priv_t *priv) +{ + switch (priv->iw_mode) { + case IW_MODE_INFRA: + priv->port_type = 1; + priv->allow_ibss = 0; + break; + case IW_MODE_ADHOC: + if (priv->prefer_port3) { + priv->port_type = 3; + priv->allow_ibss = 0; + } else { + priv->port_type = 1; + priv->allow_ibss = 1; + } + break; + default: + printk(KERN_ERR "%s: Invalid priv->iw_mode in set_port_type()\n", + priv->ndev.name); + } +} + +extern void +dldwd_set_multicast_list(struct net_device *dev) +{ + dldwd_priv_t *priv = dev->priv; + + dldwd_lock(priv); + __dldwd_set_multicast_list(dev); + dldwd_unlock(priv); +} + +/* + * Hardware control routines + */ + +static int +__dldwd_hw_reset(dldwd_priv_t *priv) +{ + hermes_t *hw = &priv->hw; + int err; + + if (! priv->broken_reset) + return hermes_reset(hw); + else { + hw->inten = 0; + hermes_write_regn(hw, INTEN, 0); + err = hermes_disable_port(hw, 0); + hermes_write_regn(hw, EVACK, 0xffff); + return err; + } +} + +void +dldwd_shutdown(dldwd_priv_t *priv) +{ +/* hermes_t *hw = &priv->hw; */ + int err = 0; + + TRACE_ENTER(priv->ndev.name); + + dldwd_lock(priv); + __dldwd_stop_irqs(priv); + + err = __dldwd_hw_reset(priv); + if (err && err != -ENODEV) /* If the card is gone, we don't care about shutting it down */ + printk(KERN_ERR "%s: Error %d shutting down Hermes chipset\n", priv->ndev.name, err); + + dldwd_unlock(priv); + + TRACE_EXIT(priv->ndev.name); +} + +int +dldwd_reset(dldwd_priv_t *priv) +{ + struct net_device *dev = &priv->ndev; + hermes_t *hw = &priv->hw; + int err = 0; + hermes_id_t idbuf; + int frame_size; + + TRACE_ENTER(priv->ndev.name); + + dldwd_lock(priv); + + __dldwd_stop_irqs(priv); + + err = __dldwd_hw_reset(priv); + if (err) + goto out; + + frame_size = TX_NICBUF_SIZE; + /* This stupid bug is present in Intel firmware 1.10, and + * may be fixed in later firmwares - Jean II */ + if(priv->broken_allocate) + frame_size = TX_NICBUF_SIZE_BUG; + err = hermes_allocate(hw, frame_size, &priv->txfid); + if (err) + goto out; + + /* Now set up all the parameters on the card */ + + /* Set up the link mode */ + + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PORTTYPE, priv->port_type); + if (err) + goto out; + if (priv->has_ibss) { + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_CREATEIBSS, + priv->allow_ibss); + if (err) + goto out; + if((strlen(priv->desired_essid) == 0) && (priv->allow_ibss) + && (!priv->has_ibss_any)) { + printk(KERN_WARNING "%s: This firmware requires an \ +ESSID in IBSS-Ad-Hoc mode.\n", dev->name); + /* With wvlan_cs, in this case, we would crash. + * hopefully, this driver will behave better... + * Jean II */ + } + } + + /* Set up encryption */ + if (priv->has_wep) { + err = __dldwd_hw_setup_wep(priv); + if (err) + goto out; + } + + /* Set the desired ESSID */ + idbuf.len = cpu_to_le16(strlen(priv->desired_essid)); + memcpy(&idbuf.val, priv->desired_essid, sizeof(idbuf.val)); + err = hermes_write_ltv(hw, USER_BAP, (priv->port_type == 3) ? + HERMES_RID_CNF_OWN_SSID : HERMES_RID_CNF_DESIRED_SSID, + HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2), + &idbuf); + if (err) + goto out; + + /* Set the station name */ + idbuf.len = cpu_to_le16(strlen(priv->nick)); + memcpy(&idbuf.val, priv->nick, sizeof(idbuf.val)); + err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNF_NICKNAME, + HERMES_BYTES_TO_RECLEN(strlen(priv->nick)+2), + &idbuf); + if (err) + goto out; + + /* Set the channel/frequency */ + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_CHANNEL, priv->channel); + if (err) + goto out; + + /* Set AP density */ + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYSTEM_SCALE, priv->ap_density); + if (err) + goto out; + + /* Set RTS threshold */ + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_RTS_THRESH, priv->rts_thresh); + if (err) + goto out; + + /* Set fragmentation threshold or MWO robustness */ + if (priv->has_mwo) + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNF_MWO_ROBUST, priv->mwo_robust); + else + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNF_FRAG_THRESH, priv->frag_thresh); + if (err) + goto out; + + /* Set bitrate */ + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_TX_RATE_CTRL, + priv->tx_rate_ctrl); + if (err) + goto out; + + /* Set power management */ + if (priv->has_pm) { + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_ENABLE, + priv->pm_on); + if (err) + goto out; + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_MCAST_RX, + priv->pm_mcast); + if (err) + goto out; + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_PERIOD, + priv->pm_period); + if (err) + goto out; + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_HOLDOVER, + priv->pm_timeout); + if (err) + goto out; + } + + /* Set preamble - only for Symbol so far... */ + if (priv->has_preamble) { + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYMBOL_PREAMBLE, + priv->preamble); + if (err) { + printk(KERN_WARNING "%s: Can't set preamble!\n", dev->name); + goto out; + } + } + + /* Set promiscuity / multicast*/ + priv->promiscuous = 0; + priv->allmulti = 0; + priv->mc_count = 0; + __dldwd_set_multicast_list(dev); + + err = hermes_enable_port(hw, DLDWD_MACPORT); + if (err) + goto out; + + __dldwd_start_irqs(priv, HERMES_EV_RX | HERMES_EV_ALLOC | + HERMES_EV_TX | HERMES_EV_TXEXC | + HERMES_EV_WTERR | HERMES_EV_INFO | + HERMES_EV_INFDROP); + + out: + dldwd_unlock(priv); + + TRACE_EXIT(priv->ndev.name); + + return err; +} + +static int __dldwd_hw_setup_wep(dldwd_priv_t *priv) +{ + hermes_t *hw = &priv->hw; + int err = 0; + int extra_wep_flag = 0; + + switch (priv->firmware_type) { + case FIRMWARE_TYPE_LUCENT: /* Lucent style WEP */ + if (priv->wep_on) { + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_TX_KEY, priv->tx_key); + if (err) + return err; + + err = HERMES_WRITE_RECORD(hw, USER_BAP, HERMES_RID_CNF_KEYS, &priv->keys); + if (err) + return err; + } + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_WEP_ON, priv->wep_on); + if (err) + return err; + break; + + case FIRMWARE_TYPE_PRISM2: /* Prism II style WEP */ + case FIRMWARE_TYPE_SYMBOL: /* Symbol style WEP */ + if (priv->wep_on) { + char keybuf[LARGE_KEY_SIZE+1]; + int keylen; + int i; + + /* Write all 4 keys */ + for(i = 0; i < MAX_KEYS; i++) { + keylen = priv->keys[i].len; + keybuf[keylen] = '\0'; + memcpy(keybuf, priv->keys[i].data, keylen); + err = hermes_write_ltv(hw, USER_BAP, + HERMES_RID_CNF_PRISM2_KEY0 + i, + HERMES_BYTES_TO_RECLEN(keylen + 1), + &keybuf); + if (err) + return err; + } + + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PRISM2_TX_KEY, + priv->tx_key); + if (err) + return err; + + /* Authentication is where Prism2 and Symbol + * firmware differ... */ + if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL) { + /* Symbol cards : set the authentication : + * 0 -> no encryption, 1 -> open, + * 2 -> shared key, 3 -> shared key 128bit */ + if(priv->wep_restrict) { + if(priv->keys[priv->tx_key].len > + SMALL_KEY_SIZE) + extra_wep_flag = 3; + else + extra_wep_flag = 2; + } else + extra_wep_flag = 1; + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYMBOL_AUTH_TYPE, priv->wep_restrict); + if (err) + return err; + } else { + /* Prism2 card : we need to modify master + * WEP setting */ + if(priv->wep_restrict) + extra_wep_flag = 2; + else + extra_wep_flag = 0; + } + } + + /* Master WEP setting : on/off */ + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PRISM2_WEP_ON, (priv->wep_on | extra_wep_flag)); + if (err) + return err; + break; + + default: + if (priv->wep_on) { + printk(KERN_ERR "%s: WEP enabled, although not supported!\n", + priv->ndev.name); + return -EINVAL; + } + } + + return 0; +} + +static int dldwd_hw_get_bssid(dldwd_priv_t *priv, char buf[ETH_ALEN]) +{ + hermes_t *hw = &priv->hw; + int err = 0; + + dldwd_lock(priv); + + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_BSSID, + ETH_ALEN, NULL, buf); + + dldwd_unlock(priv); + + return err; +} + +static int dldwd_hw_get_essid(dldwd_priv_t *priv, int *active, + char buf[IW_ESSID_MAX_SIZE+1]) +{ + hermes_t *hw = &priv->hw; + int err = 0; + hermes_id_t essidbuf; + char *p = (char *)(&essidbuf.val); + int len; + + TRACE_ENTER(priv->ndev.name); + + dldwd_lock(priv); + + if (strlen(priv->desired_essid) > 0) { + /* We read the desired SSID from the hardware rather + than from priv->desired_essid, just in case the + firmware is allowed to change it on us. I'm not + sure about this */ + /* My guess is that the OWN_SSID should always be whatever + * we set to the card, whereas CURRENT_SSID is the one that + * may change... - Jean II */ + uint16_t rid; + + *active = 1; + + rid = (priv->port_type == 3) ? HERMES_RID_CNF_OWN_SSID : + HERMES_RID_CNF_DESIRED_SSID; + + err = hermes_read_ltv(hw, USER_BAP, rid, sizeof(essidbuf), + NULL, &essidbuf); + if (err) + goto fail_unlock; + } else { + *active = 0; + + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_SSID, + sizeof(essidbuf), NULL, &essidbuf); + if (err) + goto fail_unlock; + } + + len = le16_to_cpu(essidbuf.len); + + memset(buf, 0, sizeof(buf)); + memcpy(buf, p, len); + buf[len] = '\0'; + + fail_unlock: + dldwd_unlock(priv); + + TRACE_EXIT(priv->ndev.name); + + return err; +} + +static long dldwd_hw_get_freq(dldwd_priv_t *priv) +{ + + hermes_t *hw = &priv->hw; + int err = 0; + uint16_t channel; + long freq = 0; + + dldwd_lock(priv); + + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENT_CHANNEL, &channel); + if (err) + goto out; + + if ( (channel < 1) || (channel > NUM_CHANNELS) ) { + struct net_device *dev = &priv->ndev; + + printk(KERN_WARNING "%s: Channel out of range (%d)!\n", dev->name, channel); + err = -EBUSY; + goto out; + + } + freq = channel_frequency[channel-1] * 100000; + + out: + dldwd_unlock(priv); + + if (err > 0) + err = -EBUSY; + return err ? err : freq; +} + +static int dldwd_hw_get_bitratelist(dldwd_priv_t *priv, int *numrates, + int32_t *rates, int max) +{ + hermes_t *hw = &priv->hw; + hermes_id_t list; + unsigned char *p = (unsigned char *)&list.val; + int err = 0; + int num; + int i; + + dldwd_lock(priv); + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_DATARATES, sizeof(list), + NULL, &list); + dldwd_unlock(priv); + + if (err) + return err; + + num = le16_to_cpu(list.len); + *numrates = num; + num = MIN(num, max); + + for (i = 0; i < num; i++) { + rates[i] = (p[i] & 0x7f) * 500000; /* convert to bps */ + } + + return 0; +} + +#ifndef PCMCIA_DEBUG +static inline void show_rx_frame(struct dldwd_frame_hdr *frame) {} +#else +static void show_rx_frame(struct dldwd_frame_hdr *frame) +{ + printk(KERN_DEBUG "RX descriptor:\n"); + printk(KERN_DEBUG " status = 0x%04x\n", frame->desc.status); + printk(KERN_DEBUG " res1 = 0x%04x\n", frame->desc.res1); + printk(KERN_DEBUG " res2 = 0x%04x\n", frame->desc.res2); + printk(KERN_DEBUG " q_info = 0x%04x\n", frame->desc.q_info); + printk(KERN_DEBUG " res3 = 0x%04x\n", frame->desc.res3); + printk(KERN_DEBUG " res4 = 0x%04x\n", frame->desc.res4); + printk(KERN_DEBUG " tx_ctl = 0x%04x\n", frame->desc.tx_ctl); + + printk(KERN_DEBUG "IEEE 802.11 header:\n"); + printk(KERN_DEBUG " frame_ctl = 0x%04x\n", + frame->p80211.frame_ctl); + printk(KERN_DEBUG " duration_id = 0x%04x\n", + frame->p80211.duration_id); + printk(KERN_DEBUG " addr1 = %02x:%02x:%02x:%02x:%02x:%02x\n", + frame->p80211.addr1[0], frame->p80211.addr1[1], + frame->p80211.addr1[2], frame->p80211.addr1[3], + frame->p80211.addr1[4], frame->p80211.addr1[5]); + printk(KERN_DEBUG " addr2 = %02x:%02x:%02x:%02x:%02x:%02x\n", + frame->p80211.addr2[0], frame->p80211.addr2[1], + frame->p80211.addr2[2], frame->p80211.addr2[3], + frame->p80211.addr2[4], frame->p80211.addr2[5]); + printk(KERN_DEBUG " addr3 = %02x:%02x:%02x:%02x:%02x:%02x\n", + frame->p80211.addr3[0], frame->p80211.addr3[1], + frame->p80211.addr3[2], frame->p80211.addr3[3], + frame->p80211.addr3[4], frame->p80211.addr3[5]); + printk(KERN_DEBUG " seq_ctl = 0x%04x\n", + frame->p80211.seq_ctl); + printk(KERN_DEBUG " addr4 = %02x:%02x:%02x:%02x:%02x:%02x\n", + frame->p80211.addr4[0], frame->p80211.addr4[1], + frame->p80211.addr4[2], frame->p80211.addr4[3], + frame->p80211.addr4[4], frame->p80211.addr4[5]); + printk(KERN_DEBUG " data_len = 0x%04x\n", + frame->p80211.data_len); + + printk(KERN_DEBUG "IEEE 802.3 header:\n"); + printk(KERN_DEBUG " dest = %02x:%02x:%02x:%02x:%02x:%02x\n", + frame->p8023.h_dest[0], frame->p8023.h_dest[1], + frame->p8023.h_dest[2], frame->p8023.h_dest[3], + frame->p8023.h_dest[4], frame->p8023.h_dest[5]); + printk(KERN_DEBUG " src = %02x:%02x:%02x:%02x:%02x:%02x\n", + frame->p8023.h_source[0], frame->p8023.h_source[1], + frame->p8023.h_source[2], frame->p8023.h_source[3], + frame->p8023.h_source[4], frame->p8023.h_source[5]); + printk(KERN_DEBUG " len = 0x%04x\n", frame->p8023.h_proto); + + printk(KERN_DEBUG "IEEE 802.2 LLC/SNAP header:\n"); + printk(KERN_DEBUG " DSAP = 0x%02x\n", frame->p8022.dsap); + printk(KERN_DEBUG " SSAP = 0x%02x\n", frame->p8022.ssap); + printk(KERN_DEBUG " ctrl = 0x%02x\n", frame->p8022.ctrl); + printk(KERN_DEBUG " OUI = %02x:%02x:%02x\n", + frame->p8022.oui[0], frame->p8022.oui[1], frame->p8022.oui[2]); + printk(KERN_DEBUG " ethertype = 0x%04x\n", frame->ethertype); +} +#endif + +/* + * Interrupt handler + */ +void dldwd_interrupt(int irq, void * dev_id, struct pt_regs *regs) +{ + dldwd_priv_t *priv = (dldwd_priv_t *) dev_id; + hermes_t *hw = &priv->hw; + struct net_device *dev = &priv->ndev; + int count = IRQ_LOOP_MAX; + uint16_t evstat, events; + static int old_time = 0, timecount = 0; /* Eugh, revolting hack for now */ + + if (test_and_set_bit(DLDWD_STATE_INIRQ, &priv->state)) + BUG(); + + if (! dldwd_irqs_allowed(priv)) { + clear_bit(DLDWD_STATE_INIRQ, &priv->state); + return; + } + + DEBUG(3, "%s: dldwd_interrupt()\n", priv->ndev.name); + + while (1) { + if (jiffies != old_time) + timecount = 0; + if ( (++timecount > 50) || (! count--) ) { + printk(KERN_CRIT "%s: IRQ handler is looping too \ +much! Shutting down.\n", + dev->name); + /* Perform an emergency shutdown */ + clear_bit(DLDWD_STATE_DOIRQ, &priv->state); + hermes_set_irqmask(hw, 0); + break; + } + + evstat = hermes_read_regn(hw, EVSTAT); + DEBUG(3, "__dldwd_interrupt(): count=%d EVSTAT=0x%04x inten=0x%04x\n", + count, evstat, hw->inten); + + events = evstat & hw->inten; + + if (! events) { + if (netif_queue_stopped(dev)) { + /* There seems to be a firmware bug which + sometimes causes the card to give an + interrupt with no event set, when there + sould be a Tx completed event. */ + DEBUG(3, "%s: Interrupt with no event (ALLOCFID=0x%04x)\n", + dev->name, (int)hermes_read_regn(hw, ALLOCFID)); + events = HERMES_EV_TX | HERMES_EV_ALLOC; + } else /* Nothing's happening, we're done */ + break; + } + + /* Check the card hasn't been removed */ + if (! hermes_present(hw)) { + DEBUG(0, "dldwd_interrupt(): card removed\n"); + break; + } + + if (events & HERMES_EV_TICK) + __dldwd_ev_tick(priv, hw); + if (events & HERMES_EV_WTERR) + __dldwd_ev_wterr(priv, hw); + if (events & HERMES_EV_INFDROP) + __dldwd_ev_infdrop(priv, hw); + if (events & HERMES_EV_INFO) + __dldwd_ev_info(priv, hw); + if (events & HERMES_EV_RX) + __dldwd_ev_rx(priv, hw); + if (events & HERMES_EV_TXEXC) + __dldwd_ev_txexc(priv, hw); + if (events & HERMES_EV_TX) + __dldwd_ev_tx(priv, hw); + if (events & HERMES_EV_ALLOC) + __dldwd_ev_alloc(priv, hw); + + hermes_write_regn(hw, EVACK, events); + } + + clear_bit(DLDWD_STATE_INIRQ, &priv->state); +} + +static void __dldwd_ev_tick(dldwd_priv_t *priv, hermes_t *hw) +{ + printk(KERN_DEBUG "%s: TICK\n", priv->ndev.name); +} + +static void __dldwd_ev_wterr(dldwd_priv_t *priv, hermes_t *hw) +{ + /* This seems to happen a fair bit under load, but ignoring it + seems to work fine...*/ + DEBUG(1, "%s: MAC controller error (WTERR). Ignoring.\n", + priv->ndev.name); +} + +static void __dldwd_ev_infdrop(dldwd_priv_t *priv, hermes_t *hw) +{ + printk(KERN_WARNING "%s: Information frame lost.\n", priv->ndev.name); +} + +static void __dldwd_ev_info(dldwd_priv_t *priv, hermes_t *hw) +{ + DEBUG(3, "%s: Information frame received.\n", priv->ndev.name); + /* We don't actually do anything about it - we assume the MAC + controller can deal with it */ +} + +static void __dldwd_ev_rx(dldwd_priv_t *priv, hermes_t *hw) +{ + struct net_device *dev = &priv->ndev; + struct net_device_stats *stats = &priv->stats; + struct iw_statistics *wstats = &priv->wstats; + struct sk_buff *skb = NULL; + uint16_t rxfid, status; + int length, data_len, data_off; + char *p; + struct dldwd_frame_hdr hdr; + struct ethhdr *eh; + int err; + + rxfid = hermes_read_regn(hw, RXFID); + DEBUG(3, "__dldwd_ev_rx(): RXFID=0x%04x\n", rxfid); + + /* We read in the entire frame header here. This isn't really + necessary, since we ignore most of it, but it's + conceptually simpler. We can tune this later if + necessary. */ + err = hermes_bap_pread(hw, IRQ_BAP, &hdr, sizeof(hdr), rxfid, 0); + if (err) { + printk(KERN_ERR "%s: error %d reading frame header. " + "Frame dropped.\n", dev->name, err); + stats->rx_errors++; + goto drop; + } + + status = le16_to_cpu(hdr.desc.status); + + if (status & HERMES_RXSTAT_ERR) { + if ((status & HERMES_RXSTAT_ERR) == HERMES_RXSTAT_BADCRC) { + stats->rx_crc_errors++; + printk(KERN_WARNING "%s: Bad CRC on Rx. Frame dropped.\n", + dev->name); + show_rx_frame(&hdr); + } else if ((status & HERMES_RXSTAT_ERR) + == HERMES_RXSTAT_UNDECRYPTABLE) { + wstats->discard.code++; + printk(KERN_WARNING "%s: Undecryptable frame on Rx. Frame dropped.\n", + dev->name); + } else { + wstats->discard.misc++; + printk("%s: Unknown Rx error (0x%x). Frame dropped.\n", + dev->name, status & HERMES_RXSTAT_ERR); + } + stats->rx_errors++; + goto drop; + } + + length = le16_to_cpu(hdr.p80211.data_len); + /* Yes, you heard right, that's le16. 802.2 and 802.3 are + big-endian, but 802.11 is little-endian believe it or + not. */ + /* Correct. 802.3 is big-endian byte order and little endian bit + * order, whereas 802.11 is little endian for both byte and bit + * order. That's specified in the 802.11 spec. - Jean II */ + + /* Sanity check */ + if (length > MAX_FRAME_SIZE) { + printk(KERN_WARNING "%s: Oversized frame received (%d bytes)\n", + dev->name, length); + stats->rx_length_errors++; + stats->rx_errors++; + goto drop; + } + + /* We need space for the packet data itself, plus an ethernet + header, plus 2 bytes so we can align the IP header on a + 32bit boundary, plus 1 byte so we can read in odd length + packets from the card, which has an IO granularity of 16 + bits */ + skb = dev_alloc_skb(length+ETH_HLEN+2+1); + if (!skb) { + printk(KERN_WARNING "%s: Can't allocate skb for Rx\n", + dev->name); + stats->rx_dropped++; + goto drop; + } + + skb_reserve(skb, 2); /* This way the IP header is aligned */ + + /* Handle decapsulation + * In most cases, the firmware tell us about SNAP frames. + * For some reason, the SNAP frames sent by LinkSys APs + * are not properly recognised by most firmwares. + * So, check ourselves (note : only 3 bytes out of 6). + */ + if(((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_1042) || + ((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_TUNNEL) || + (!memcmp(&hdr.p8022, &encaps_hdr, 3))) { + /* These indicate a SNAP within 802.2 LLC within + 802.11 frame which we'll need to de-encapsulate to + the original EthernetII frame. + IEEE and ISO OSI have a lot to answer for. */ + + /* Remove SNAP header, reconstruct EthernetII frame */ + data_len = length - ENCAPS_OVERHEAD; + data_off = sizeof(hdr); + + eh = (struct ethhdr *)skb_put(skb, ETH_HLEN); + + memcpy(eh, &hdr.p8023, sizeof(hdr.p8023)); + eh->h_proto = hdr.ethertype; + } else { + /* All other cases indicate a genuine 802.3 frame. + * No decapsulation needed */ + + /* Otherwise, we just throw the whole thing in, + * and hope the protocol layer can deal with it + * as 802.3 */ + data_len = length; + data_off = P8023_OFFSET; + } + + p = skb_put(skb, data_len); + if (hermes_bap_pread(hw, IRQ_BAP, p, RUP_EVEN(data_len), + rxfid, data_off) != 0) { + printk(KERN_WARNING "%s: Error reading packet data\n", + dev->name); + stats->rx_errors++; + goto drop; + } + + dev->last_rx = jiffies; + skb->dev = dev; + skb->protocol = eth_type_trans(skb, dev); + skb->ip_summed = CHECKSUM_NONE; + + /* Process the wireless stats if needed */ + dldwd_stat_gather(dev, skb, &hdr); + + /* Pass the packet to the networking stack */ + netif_rx(skb); + stats->rx_packets++; + stats->rx_bytes += length; + + return; + + drop: + if (skb) + dev_kfree_skb_irq(skb); + return; +} + +static void __dldwd_ev_txexc(dldwd_priv_t *priv, hermes_t *hw) +{ + struct net_device *dev = &priv->ndev; + struct net_device_stats *stats = &priv->stats; + + printk(KERN_WARNING "%s: Tx error!\n", dev->name); + + netif_wake_queue(dev); + stats->tx_errors++; +} + +static void __dldwd_ev_tx(dldwd_priv_t *priv, hermes_t *hw) +{ + struct net_device *dev = &priv->ndev; + struct net_device_stats *stats = &priv->stats; + + DEBUG(3, "%s: Transmit completed\n", dev->name); + + stats->tx_packets++; + netif_wake_queue(dev); +} + +static void __dldwd_ev_alloc(dldwd_priv_t *priv, hermes_t *hw) +{ + uint16_t allocfid; + + allocfid = hermes_read_regn(hw, ALLOCFID); + DEBUG(3, "%s: Allocation complete FID=0x%04x\n", priv->ndev.name, allocfid); + + /* For some reason we don't seem to get transmit completed events properly */ + if (allocfid == priv->txfid) + __dldwd_ev_tx(priv, hw); + +/* hermes_write_regn(hw, ALLOCFID, 0); */ +} + +/* + * struct net_device methods + */ + +int +dldwd_init(struct net_device *dev) +{ + dldwd_priv_t *priv = dev->priv; + hermes_t *hw = &priv->hw; + int err = 0; + hermes_id_t nickbuf; + uint16_t reclen; + int len; + char *vendor_str; + uint32_t firmver; + + TRACE_ENTER("dldwd"); + + dldwd_lock(priv); + + err = hermes_reset(hw); + if (err != 0) { + printk(KERN_ERR "%s: failed to reset hardware\n", dev->name); + goto out; + } + + /* Get the firmware version */ + err = hermes_read_staidentity(hw, USER_BAP, &priv->firmware_info); + if (err) { + printk(KERN_WARNING "%s: Error %d reading firmware info. Wildly guessing capabilities...\n", + dev->name, err); + memset(&priv->firmware_info, 0, sizeof(priv->firmware_info)); + } + + firmver = ((uint32_t)priv->firmware_info.major << 16) | priv->firmware_info.minor; + DEBUG(2, "%s: firmver = 0x%X\n", dev->name, firmver); + + /* Determine capabilities from the firmware version */ + + switch (priv->firmware_info.vendor) { + case 0x1: + /* Lucent Wavelan IEEE, Lucent Orinoco, Cabletron RoamAbout, + * ELSA, Melco, HP, IBM, Dell 1150 cards */ + vendor_str = "Lucent"; + /* Lucent MAC : 00:60:1D:* & 00:02:2D:* */ + + priv->firmware_type = FIRMWARE_TYPE_LUCENT; + priv->broken_reset = 0; + priv->broken_allocate = 0; + priv->has_port3 = 1; /* Still works in 7.28 */ + priv->has_ibss = (firmver >= 0x60006); + priv->has_ibss_any = (firmver >= 0x60010); + priv->has_wep = (firmver >= 0x40020); + priv->has_big_wep = 1; /* FIXME: this is wrong - how do we tell + Gold cards from the others? */ + priv->has_mwo = (firmver >= 0x60000); + priv->has_pm = (firmver >= 0x40020); + priv->has_preamble = 0; + /* Tested with Lucent firmware : + * 1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II + * Tested CableTron firmware : 4.32 => Anton */ + break; + case 0x2: + vendor_str = "Generic Prism II"; + /* Some D-Link cards report vendor 0x02... */ + + priv->firmware_type = FIRMWARE_TYPE_PRISM2; + priv->broken_reset = 0; + priv->broken_allocate = 0; + priv->has_port3 = 1; + priv->has_ibss = (firmver >= 0x00007); /* FIXME */ + priv->has_wep = (firmver >= 0x00007); /* FIXME */ + priv->has_big_wep = 0; + priv->has_mwo = 0; + priv->has_pm = (firmver >= 0x00007); /* FIXME */ + priv->has_preamble = 0; + + /* Tim Hurley -> D-Link card, vendor 02, firmware 0.08 */ + + /* Special case for Symbol cards */ + if(firmver == 0x10001) { + /* Symbol , 3Com AirConnect, Intel, Ericsson WLAN */ + vendor_str = "Symbol"; + /* Intel MAC : 00:02:B3:* */ + /* 3Com MAC : 00:50:DA:* */ + + /* FIXME : probably need to use SYMBOL_***ARY_VER + * to get proper firmware version */ + priv->firmware_type = FIRMWARE_TYPE_SYMBOL; + priv->broken_reset = 0; + priv->broken_allocate = 1; + priv->has_port3 = 1; + priv->has_ibss = 1; /* FIXME */ + priv->has_wep = 1; /* FIXME */ + priv->has_big_wep = 1; /* RID_SYMBOL_KEY_LENGTH */ + priv->has_mwo = 0; + priv->has_pm = 1; /* FIXME */ + priv->has_preamble = 0; /* FIXME */ + /* Tested with Intel firmware : v15 => Jean II */ + } + break; + case 0x3: + vendor_str = "Samsung"; + /* To check - Should cover Samsung & Compaq */ + + priv->firmware_type = FIRMWARE_TYPE_PRISM2; + priv->broken_reset = 0; + priv->broken_allocate = 0; + priv->has_port3 = 1; + priv->has_ibss = 0; /* FIXME: available in later firmwares */ + priv->has_wep = (firmver >= 0x20000); /* FIXME */ + priv->has_big_wep = 0; /* FIXME */ + priv->has_mwo = 0; + priv->has_pm = (firmver >= 0x20000); /* FIXME */ + priv->has_preamble = 0; + break; + case 0x6: + /* D-Link DWL 650, ... */ + vendor_str = "LinkSys/D-Link"; + /* D-Link MAC : 00:40:05:* */ + + priv->firmware_type = FIRMWARE_TYPE_PRISM2; + priv->broken_reset = 0; + priv->broken_allocate = 0; + priv->has_port3 = 1; + priv->has_ibss = (firmver >= 0x00007); /* FIXME */ + priv->has_wep = (firmver >= 0x00007); /* FIXME */ + priv->has_big_wep = 0; + priv->has_mwo = 0; + priv->has_pm = (firmver >= 0x00007); /* FIXME */ + priv->has_preamble = 0; + /* Tested with D-Link firmware 0.07 => Jean II */ + /* Note : with 0.07, IBSS to a Lucent card seem flaky */ + break; + default: + vendor_str = "UNKNOWN"; + + priv->firmware_type = 0; + priv->broken_reset = 0; + priv->broken_allocate = 0; + priv->has_port3 = 0; + priv->has_ibss = 0; + priv->has_wep = 0; + priv->has_big_wep = 0; + priv->has_mwo = 0; + priv->has_pm = 0; + priv->has_preamble = 0; + } + + printk(KERN_INFO "%s: Firmware ID %02X vendor 0x%x (%s) version %d.%02d\n", + dev->name, priv->firmware_info.id, priv->firmware_info.vendor, + vendor_str, priv->firmware_info.major, priv->firmware_info.minor); + + if (priv->has_port3) + printk(KERN_INFO "%s: Ad-hoc demo mode supported.\n", dev->name); + if (priv->has_ibss) + printk(KERN_INFO "%s: IEEE standard IBSS ad-hoc mode supported.\n", + dev->name); + if (priv->has_wep) { + printk(KERN_INFO "%s: WEP supported, ", dev->name); + if (priv->has_big_wep) + printk("\"128\"-bit key.\n"); + else + printk("40-bit key.\n"); + } + + /* Get the MAC address */ + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNF_MACADDR, + ETH_ALEN, NULL, dev->dev_addr); + if (err) { + printk(KERN_WARNING "%s: failed to read MAC address!\n", + dev->name); + goto out; + } + + printk(KERN_INFO "%s: MAC address %02X:%02X:%02X:%02X:%02X:%02X\n", + dev->name, dev->dev_addr[0], dev->dev_addr[1], + dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4], + dev->dev_addr[5]); + + /* Get the station name */ + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNF_NICKNAME, + sizeof(nickbuf), &reclen, &nickbuf); + if (err) { + printk(KERN_ERR "%s: failed to read station name!n", + dev->name); + goto out; + } + if ( nickbuf.len ) + len = MIN(IW_ESSID_MAX_SIZE, le16_to_cpu(nickbuf.len)); + else + len = MIN(IW_ESSID_MAX_SIZE, 2 * reclen); + memcpy(priv->nick, &nickbuf.val, len); + priv->nick[len] = '\0'; + + printk(KERN_INFO "%s: Station name \"%s\"\n", dev->name, priv->nick); + + /* Get allowed channels */ + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CHANNEL_LIST, &priv->channel_mask); + if (err) { + printk(KERN_ERR "%s: failed to read channel list!\n", + dev->name); + goto out; + } + + /* Get initial AP density */ + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYSTEM_SCALE, &priv->ap_density); + if (err) { + printk(KERN_ERR "%s: failed to read AP density!\n", dev->name); + goto out; + } + + /* Get initial RTS threshold */ + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_RTS_THRESH, &priv->rts_thresh); + if (err) { + printk(KERN_ERR "%s: failed to read RTS threshold!\n", dev->name); + goto out; + } + + /* Get initial fragmentation settings */ + if (priv->has_mwo) + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_MWO_ROBUST, + &priv->mwo_robust); + else + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_FRAG_THRESH, + &priv->frag_thresh); + if (err) { + printk(KERN_ERR "%s: failed to read fragmentation settings!\n", dev->name); + goto out; + } + + /* Set initial bitrate control*/ + priv->tx_rate_ctrl = 3; + + /* Power management setup */ + if (priv->has_pm) { + priv->pm_on = 0; + priv->pm_mcast = 1; + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_PERIOD, + &priv->pm_period); + if (err) { + printk(KERN_ERR "%s: failed to read power management period!\n", + dev->name); + goto out; + } + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_HOLDOVER, + &priv->pm_timeout); + if (err) { + printk(KERN_ERR "%s: failed to read power management timeout!\n", + dev->name); + goto out; + } + } + + /* Preamble setup */ + if (priv->has_preamble) { + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYMBOL_PREAMBLE, &priv->preamble); + if (err) + goto out; + } + + /* Set up the default configuration */ + priv->iw_mode = IW_MODE_INFRA; + /* By default use IEEE/IBSS ad-hoc mode if we have it */ + priv->prefer_port3 = priv->has_port3 && (! priv->has_ibss); + set_port_type(priv); + + priv->promiscuous = 0; + priv->allmulti = 0; + priv->wep_on = 0; + priv->tx_key = 0; + + printk(KERN_INFO "%s: ready\n", dev->name); + + out: + dldwd_unlock(priv); + + TRACE_EXIT("dldwd"); + + return err; +} + +struct net_device_stats * +dldwd_get_stats(struct net_device *dev) +{ + dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; + + return &priv->stats; +} + +struct iw_statistics * +dldwd_get_wireless_stats(struct net_device *dev) +{ + dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; + hermes_t *hw = &priv->hw; + struct iw_statistics *wstats = &priv->wstats; + int err = 0; + hermes_commsqual_t cq; + + if (!priv->hw_ready) + return NULL; + + dldwd_lock(priv); + + if (priv->port_type == 3) { + memset(&wstats->qual, 0, sizeof(wstats->qual)); +#ifdef WIRELESS_SPY + /* If a spy address is defined, we report stats of the + * first spy address - Jean II */ + if (priv->spy_number > 0) { + wstats->qual.qual = priv->spy_stat[0].qual; + wstats->qual.level = priv->spy_stat[0].level; + wstats->qual.noise = priv->spy_stat[0].noise; + wstats->qual.updated = priv->spy_stat[0].updated; + } +#endif /* WIRELESS_SPY */ + } else { + err = hermes_read_commsqual(hw, USER_BAP, &cq); + + DEBUG(3, "%s: Global stats = %X-%X-%X\n", dev->name, + cq.qual, cq.signal, cq.noise); + + /* Why are we using MIN/MAX ? We don't really care + * if the value goes above max, because we export the + * raw dBm values anyway. The normalisation should be done + * in user space - Jean II */ + wstats->qual.qual = MAX(MIN(cq.qual, 0x8b-0x2f), 0); + wstats->qual.level = MAX(MIN(cq.signal, 0x8a), 0x2f) - 0x95; + wstats->qual.noise = MAX(MIN(cq.noise, 0x8a), 0x2f) - 0x95; + wstats->qual.updated = 7; + } + + dldwd_unlock(priv); + + if (err) + return NULL; + + return wstats; +} + +#ifdef WIRELESS_SPY +static inline void dldwd_spy_gather(struct net_device *dev, + u_char *mac, + hermes_commsqual_t *cq) +{ + dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; + int i; + + /* Gather wireless spy statistics: for each packet, compare the + * source address with out list, and if match, get the stats... */ + for (i = 0; i < priv->spy_number; i++) + if (!memcmp(mac, priv->spy_address[i], ETH_ALEN)) { + priv->spy_stat[i].qual = MAX(MIN(cq->qual, 0x8b-0x2f), 0); + priv->spy_stat[i].level = MAX(MIN(cq->signal, 0x8a), 0x2f) - 0x95; + priv->spy_stat[i].noise = MAX(MIN(cq->noise, 0x8a), 0x2f) - 0x95; + priv->spy_stat[i].updated = 7; + } +} +#endif /* WIRELESS_SPY */ + +void +dldwd_stat_gather( struct net_device *dev, + struct sk_buff *skb, + struct dldwd_frame_hdr *hdr) +{ + dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; + hermes_commsqual_t cq; + + /* Using spy support with lots of Rx packets, like in an + * infrastructure (AP), will really slow down everything, because + * the MAC address must be compared to each entry of the spy list. + * If the user really asks for it (set some address in the + * spy list), we do it, but he will pay the price. + * Note that to get here, you need both WIRELESS_SPY + * compiled in AND some addresses in the list !!! + */ +#ifdef WIRELESS_EXT + /* Note : gcc will optimise the whole section away if + * WIRELESS_SPY is not defined... - Jean II */ + if ( +#ifdef WIRELESS_SPY + (priv->spy_number > 0) || +#endif + 0 ) + { + u_char *stats = (u_char *) &(hdr->desc.q_info); + /* This code may look strange. Everywhere we are using 16 bit + * ints except here. I've verified that these are are the + * correct values. Please check on PPC - Jean II */ + cq.signal = stats[1]; /* High order byte */ + cq.noise = stats[0]; /* Low order byte */ + cq.qual = stats[0] - stats[1]; /* Better than nothing */ + + DEBUG(3, "%s: Packet stats = %X-%X-%X\n", dev->name, + cq.qual, cq.signal, cq.noise); + +#ifdef WIRELESS_SPY + dldwd_spy_gather(dev, skb->mac.raw + ETH_ALEN, &cq); +#endif + } +#endif /* WIRELESS_EXT */ +} + +int +dldwd_xmit(struct sk_buff *skb, struct net_device *dev) +{ + dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; + struct net_device_stats *stats = &priv->stats; + hermes_t *hw = &priv->hw; + int err = 0; + uint16_t txfid = priv->txfid; + char *p; + struct ethhdr *eh; + int len, data_len, data_off; + struct dldwd_frame_hdr hdr; + hermes_response_t resp; + + if (! netif_running(dev)) { + printk(KERN_ERR "%s: Tx on stopped device!\n", + dev->name); + return 1; + + } + + if (netif_queue_stopped(dev)) { + printk(KERN_ERR "%s: Tx while transmitter busy!\n", + dev->name); + return 1; + } + + dldwd_lock(priv); + + /* Length of the packet body */ + len = MAX(skb->len - ETH_HLEN, ETH_ZLEN); + + eh = (struct ethhdr *)skb->data; + + /* Build the IEEE 802.11 header */ + memset(&hdr, 0, sizeof(hdr)); + memcpy(hdr.p80211.addr1, eh->h_dest, ETH_ALEN); + memcpy(hdr.p80211.addr2, eh->h_source, ETH_ALEN); + hdr.p80211.frame_ctl = DLDWD_FTYPE_DATA; + + /* Encapsulate Ethernet-II frames */ + if (ntohs(eh->h_proto) > 1500) { /* Ethernet-II frame */ + data_len = len; + data_off = sizeof(hdr); + p = skb->data + ETH_HLEN; + + /* 802.11 header */ + hdr.p80211.data_len = cpu_to_le16(data_len + ENCAPS_OVERHEAD); + + /* 802.3 header */ + memcpy(hdr.p8023.h_dest, eh->h_dest, ETH_ALEN); + memcpy(hdr.p8023.h_source, eh->h_source, ETH_ALEN); + hdr.p8023.h_proto = htons(data_len + ENCAPS_OVERHEAD); + + /* 802.2 header */ + memcpy(&hdr.p8022, &encaps_hdr, sizeof(encaps_hdr)); + + hdr.ethertype = eh->h_proto; + err = hermes_bap_pwrite(hw, USER_BAP, &hdr, sizeof(hdr), + txfid, 0); + if (err) { + printk(KERN_ERR + "%s: Error %d writing packet header to BAP\n", + dev->name, err); + stats->tx_errors++; + goto fail; + } + } else { /* IEEE 802.3 frame */ + data_len = len + ETH_HLEN; + data_off = P8023_OFFSET; + p = skb->data; + + /* 802.11 header */ + hdr.p80211.data_len = cpu_to_le16(len); + err = hermes_bap_pwrite(hw, USER_BAP, &hdr, P8023_OFFSET, + txfid, 0); + if (err) { + printk(KERN_ERR + "%s: Error %d writing packet header to BAP\n", + dev->name, err); + stats->tx_errors++; + goto fail; + } + } + + /* Round up for odd length packets */ + err = hermes_bap_pwrite(hw, USER_BAP, p, RUP_EVEN(data_len), txfid, data_off); + if (err) { + printk(KERN_ERR "%s: Error %d writing packet data to BAP\n", + dev->name, err); + stats->tx_errors++; + goto fail; + } + + + /* Finally, we actually initiate the send */ + err = hermes_docmd_wait(hw, HERMES_CMD_TX | HERMES_CMD_RECL, txfid, &resp); + if (err) { + printk(KERN_ERR "%s: Error %d transmitting packet\n", dev->name, err); + stats->tx_errors++; + goto fail; + } + + dev->trans_start = jiffies; + stats->tx_bytes += data_off + data_len; + + netif_stop_queue(dev); + + dldwd_unlock(priv); + + dev_kfree_skb(skb); + + return 0; + fail: + + dldwd_unlock(priv); + return err; +} + +void +dldwd_tx_timeout(struct net_device *dev) +{ + dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; + struct net_device_stats *stats = &priv->stats; + int err = 0; + + printk(KERN_WARNING "%s: Tx timeout! Resetting card.\n", dev->name); + + stats->tx_errors++; + + err = dldwd_reset(priv); + if (err) + printk(KERN_ERR "%s: Error %d resetting card on Tx timeout!\n", + dev->name, err); + else { + dev->trans_start = jiffies; + netif_wake_queue(dev); + } +} + +static int dldwd_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq) +{ + dldwd_priv_t *priv = dev->priv; + int err = 0; + int ptype; + struct iw_range range; + int numrates; + int i, k; + + TRACE_ENTER(dev->name); + + err = verify_area(VERIFY_WRITE, rrq->pointer, sizeof(range)); + if (err) + return err; + + rrq->length = sizeof(range); + + dldwd_lock(priv); + ptype = priv->port_type; + dldwd_unlock(priv); + + memset(&range, 0, sizeof(range)); + + /* Much of this shamelessly taken from wvlan_cs.c. No idea + * what it all means -dgibson */ +#if WIRELESS_EXT > 10 + range.we_version_compiled = WIRELESS_EXT; + range.we_version_source = 11; +#endif /* WIRELESS_EXT > 10 */ + + range.min_nwid = range.max_nwid = 0; /* We don't use nwids */ + + /* Set available channels/frequencies */ + range.num_channels = NUM_CHANNELS; + k = 0; + for (i = 0; i < NUM_CHANNELS; i++) { + if (priv->channel_mask & (1 << i)) { + range.freq[k].i = i + 1; + range.freq[k].m = channel_frequency[i] * 100000; + range.freq[k].e = 1; + k++; + } + + if (k >= IW_MAX_FREQUENCIES) + break; + } + range.num_frequency = k; + + range.sensitivity = 3; + + if ((ptype == 3) && (priv->spy_number == 0)){ + /* Quality stats meaningless in ad-hoc mode */ + range.max_qual.qual = 0; + range.max_qual.level = 0; + range.max_qual.noise = 0; + } else { + range.max_qual.qual = 0x8b - 0x2f; + range.max_qual.level = 0x2f - 0x95 - 1; + range.max_qual.noise = 0x2f - 0x95 - 1; + } + + err = dldwd_hw_get_bitratelist(priv, &numrates, + range.bitrate, IW_MAX_BITRATES); + if (err) + return err; + range.num_bitrates = numrates; + + /* Set an indication of the max TCP throughput in bit/s that we can + * expect using this interface. May be use for QoS stuff... + * Jean II */ + if(numrates > 2) + range.throughput = 5 * 1000 * 1000; /* ~5 Mb/s */ + else + range.throughput = 1.5 * 1000 * 1000; /* ~1.5 Mb/s */ + + range.min_rts = 0; + range.max_rts = 2347; + range.min_frag = 256; + range.max_frag = 2346; + + dldwd_lock(priv); + if (priv->has_wep) { + range.max_encoding_tokens = MAX_KEYS; + + range.encoding_size[0] = SMALL_KEY_SIZE; + range.num_encoding_sizes = 1; + + if (priv->has_big_wep) { + range.encoding_size[1] = LARGE_KEY_SIZE; + range.num_encoding_sizes = 2; + } + } else { + range.num_encoding_sizes = 0; + range.max_encoding_tokens = 0; + } + dldwd_unlock(priv); + + range.min_pmp = 0; + range.max_pmp = 65535000; + range.min_pmt = 0; + range.max_pmt = 65535 * 1000; /* ??? */ + range.pmp_flags = IW_POWER_PERIOD; + range.pmt_flags = IW_POWER_TIMEOUT; + range.pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_UNICAST_R; + + range.num_txpower = 1; + range.txpower[0] = 15; /* 15dBm */ + range.txpower_capa = IW_TXPOW_DBM; + +#if WIRELESS_EXT > 10 + range.retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME; + range.retry_flags = IW_RETRY_LIMIT; + range.r_time_flags = IW_RETRY_LIFETIME; + range.min_retry = 0; + range.max_retry = 65535; /* ??? */ + range.min_r_time = 0; + range.max_r_time = 65535 * 1000; /* ??? */ +#endif /* WIRELESS_EXT > 10 */ + + if (copy_to_user(rrq->pointer, &range, sizeof(range))) + return -EFAULT; + + TRACE_EXIT(dev->name); + + return 0; +} + +static int dldwd_ioctl_setiwencode(struct net_device *dev, struct iw_point *erq) +{ + dldwd_priv_t *priv = dev->priv; + int index = (erq->flags & IW_ENCODE_INDEX) - 1; + int setindex = priv->tx_key; + int enable = priv->wep_on; + int restricted = priv->wep_restrict; + uint16_t xlen = 0; + int err = 0; + char keybuf[MAX_KEY_SIZE]; + + if (erq->pointer) { + /* We actually have a key to set */ + + if (copy_from_user(keybuf, erq->pointer, erq->length)) + return -EFAULT; + } + + dldwd_lock(priv); + + if (erq->pointer) { + if (erq->length > MAX_KEY_SIZE) { + err = -E2BIG; + goto out; + } + + if ( (erq->length > LARGE_KEY_SIZE) + || ( ! priv->has_big_wep && (erq->length > SMALL_KEY_SIZE)) ) { + err = -EINVAL; + goto out; + } + + if ((index < 0) || (index >= MAX_KEYS)) + index = priv->tx_key; + + if (erq->length > SMALL_KEY_SIZE) { + xlen = LARGE_KEY_SIZE; + } else if (erq->length > 0) { + xlen = SMALL_KEY_SIZE; + } else + xlen = 0; + + /* Switch on WEP if off */ + if ((!enable) && (xlen > 0)) { + setindex = index; + enable = 1; + } + } else { + /* Important note : if the user do "iwconfig eth0 enc off", + * we will arrive there with an index of -1. This is valid + * but need to be taken care off... Jean II */ + if ((index < 0) || (index >= MAX_KEYS)) { + if((index != -1) || (erq->flags == 0)) { + err = -EINVAL; + goto out; + } + } else { + /* Set the index : Check that the key is valid */ + if(priv->keys[index].len == 0) { + err = -EINVAL; + goto out; + } + setindex = index; + } + } + + if (erq->flags & IW_ENCODE_DISABLED) + enable = 0; + /* Only for Prism2 & Symbol cards (so far) - Jean II */ + if (erq->flags & IW_ENCODE_OPEN) + restricted = 0; + if (erq->flags & IW_ENCODE_RESTRICTED) + restricted = 1; + + if (erq->pointer) { + priv->keys[index].len = cpu_to_le16(xlen); + memset(priv->keys[index].data, 0, sizeof(priv->keys[index].data)); + memcpy(priv->keys[index].data, keybuf, erq->length); + } + priv->tx_key = setindex; + priv->wep_on = enable; + priv->wep_restrict = restricted; + + out: + dldwd_unlock(priv); + + return 0; +} + +static int dldwd_ioctl_getiwencode(struct net_device *dev, struct iw_point *erq) +{ + dldwd_priv_t *priv = dev->priv; + int index = (erq->flags & IW_ENCODE_INDEX) - 1; + uint16_t xlen = 0; + char keybuf[MAX_KEY_SIZE]; + + + dldwd_lock(priv); + + if ((index < 0) || (index >= MAX_KEYS)) + index = priv->tx_key; + + erq->flags = 0; + if (! priv->wep_on) + erq->flags |= IW_ENCODE_DISABLED; + erq->flags |= index + 1; + + /* Only for symbol cards - Jean II */ + if (priv->firmware_type != FIRMWARE_TYPE_LUCENT) { + if(priv->wep_restrict) + erq->flags |= IW_ENCODE_RESTRICTED; + else + erq->flags |= IW_ENCODE_OPEN; + } + + xlen = le16_to_cpu(priv->keys[index].len); + + erq->length = xlen; + + if (erq->pointer) { + memcpy(keybuf, priv->keys[index].data, MAX_KEY_SIZE); + } + + dldwd_unlock(priv); + + if (erq->pointer) { + if (copy_to_user(erq->pointer, keybuf, xlen)) + return -EFAULT; + } + + return 0; +} + +static int dldwd_ioctl_setessid(struct net_device *dev, struct iw_point *erq) +{ + dldwd_priv_t *priv = dev->priv; + char essidbuf[IW_ESSID_MAX_SIZE+1]; + + /* Note : ESSID is ignored in Ad-Hoc demo mode, but we can set it + * anyway... - Jean II */ + + memset(&essidbuf, 0, sizeof(essidbuf)); + + if (erq->flags) { + if (erq->length > IW_ESSID_MAX_SIZE) + return -E2BIG; + + if (copy_from_user(&essidbuf, erq->pointer, erq->length)) + return -EFAULT; + + essidbuf[erq->length] = '\0'; + } + + dldwd_lock(priv); + + memcpy(priv->desired_essid, essidbuf, IW_ESSID_MAX_SIZE+1); + + dldwd_unlock(priv); + + return 0; +} + +static int dldwd_ioctl_getessid(struct net_device *dev, struct iw_point *erq) +{ + dldwd_priv_t *priv = dev->priv; + char essidbuf[IW_ESSID_MAX_SIZE+1]; + int active; + int err = 0; + + TRACE_ENTER(dev->name); + + err = dldwd_hw_get_essid(priv, &active, essidbuf); + if (err) + return err; + + erq->flags = 1; + erq->length = strlen(essidbuf) + 1; + if (erq->pointer) + if ( copy_to_user(erq->pointer, essidbuf, erq->length) ) + return -EFAULT; + + TRACE_EXIT(dev->name); + + return 0; +} + +static int dldwd_ioctl_setnick(struct net_device *dev, struct iw_point *nrq) +{ + dldwd_priv_t *priv = dev->priv; + char nickbuf[IW_ESSID_MAX_SIZE+1]; + + if (nrq->length > IW_ESSID_MAX_SIZE) + return -E2BIG; + + memset(nickbuf, 0, sizeof(nickbuf)); + + if (copy_from_user(nickbuf, nrq->pointer, nrq->length)) + return -EFAULT; + + nickbuf[nrq->length] = '\0'; + + dldwd_lock(priv); + + memcpy(priv->nick, nickbuf, sizeof(priv->nick)); + + dldwd_unlock(priv); + + return 0; +} + +static int dldwd_ioctl_getnick(struct net_device *dev, struct iw_point *nrq) +{ + dldwd_priv_t *priv = dev->priv; + char nickbuf[IW_ESSID_MAX_SIZE+1]; + + dldwd_lock(priv); + memcpy(nickbuf, priv->nick, IW_ESSID_MAX_SIZE+1); + dldwd_unlock(priv); + + nrq->length = strlen(nickbuf)+1; + + if (copy_to_user(nrq->pointer, nickbuf, sizeof(nickbuf))) + return -EFAULT; + + return 0; +} + +static int dldwd_ioctl_setfreq(struct net_device *dev, struct iw_freq *frq) +{ + dldwd_priv_t *priv = dev->priv; + int chan = -1; + + /* We can only use this in Ad-Hoc demo mode to set the operating + * frequency, or in IBSS mode to set the frequency where the IBSS + * will be created - Jean II */ + if (priv->iw_mode != IW_MODE_ADHOC) + return -EOPNOTSUPP; + + if ( (frq->e == 0) && (frq->m <= 1000) ) { + /* Setting by channel number */ + chan = frq->m; + } else { + /* Setting by frequency - search the table */ + int mult = 1; + int i; + + for (i = 0; i < (6 - frq->e); i++) + mult *= 10; + + for (i = 0; i < NUM_CHANNELS; i++) + if (frq->m == (channel_frequency[i] * mult)) + chan = i+1; + } + + if ( (chan < 1) || (chan > NUM_CHANNELS) || + ! (priv->channel_mask & (1 << (chan-1)) ) ) + return -EINVAL; + + dldwd_lock(priv); + priv->channel = chan; + dldwd_unlock(priv); + + return 0; +} + +static int dldwd_ioctl_getsens(struct net_device *dev, struct iw_param *srq) +{ + dldwd_priv_t *priv = dev->priv; + hermes_t *hw = &priv->hw; + uint16_t val; + int err; + + dldwd_lock(priv); + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYSTEM_SCALE, &val); + dldwd_unlock(priv); + + if (err) + return err; + + srq->value = val; + srq->fixed = 0; /* auto */ + + return 0; +} + +static int dldwd_ioctl_setsens(struct net_device *dev, struct iw_param *srq) +{ + dldwd_priv_t *priv = dev->priv; + int val = srq->value; + + if ((val < 1) || (val > 3)) + return -EINVAL; + + dldwd_lock(priv); + priv->ap_density = val; + dldwd_unlock(priv); + + return 0; +} + +static int dldwd_ioctl_setrts(struct net_device *dev, struct iw_param *rrq) +{ + dldwd_priv_t *priv = dev->priv; + int val = rrq->value; + + if (rrq->disabled) + val = 2347; + + if ( (val < 0) || (val > 2347) ) + return -EINVAL; + + dldwd_lock(priv); + priv->rts_thresh = val; + dldwd_unlock(priv); + + return 0; +} + +static int dldwd_ioctl_setfrag(struct net_device *dev, struct iw_param *frq) +{ + dldwd_priv_t *priv = dev->priv; + int err = 0; + + dldwd_lock(priv); + + if (priv->has_mwo) { + if (frq->disabled) + priv->mwo_robust = 0; + else { + if (frq->fixed) + printk(KERN_WARNING "%s: Fixed fragmentation not \ +supported on this firmware. Using MWO robust instead.\n", dev->name); + priv->mwo_robust = 1; + } + } else { + if (frq->disabled) + priv->frag_thresh = 2346; + else { + if ( (frq->value < 256) || (frq->value > 2346) ) + err = -EINVAL; + else + priv->frag_thresh = frq->value & ~0x1; /* must be even */ + } + } + + dldwd_unlock(priv); + + return err; +} + +static int dldwd_ioctl_getfrag(struct net_device *dev, struct iw_param *frq) +{ + dldwd_priv_t *priv = dev->priv; + hermes_t *hw = &priv->hw; + int err = 0; + uint16_t val; + + dldwd_lock(priv); + + if (priv->has_mwo) { + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_MWO_ROBUST, &val); + if (err) + val = 0; + + frq->value = val ? 2347 : 0; + frq->disabled = ! val; + frq->fixed = 0; + } else { + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_FRAG_THRESH, &val); + if (err) + val = 0; + + frq->value = val; + frq->disabled = (val >= 2346); + frq->fixed = 1; + } + + dldwd_unlock(priv); + + return err; +} + +static int dldwd_ioctl_setrate(struct net_device *dev, struct iw_param *rrq) +{ + dldwd_priv_t *priv = dev->priv; + int err = 0; + int rate_ctrl = -1; + int fixed, upto; + int brate; + int i; + + dldwd_lock(priv); + + /* Normalise value */ + brate = rrq->value / 500000; + + switch (priv->firmware_type) { + case FIRMWARE_TYPE_LUCENT: /* Lucent style rate */ + if (! rrq->fixed) { + if (brate > 0) + brate = -brate; + else + brate = -22; + } + + for (i = 0; i < NUM_RATES; i++) + if (rate_list[i] == brate) { + rate_ctrl = i; + break; + } + + if ( (rate_ctrl < 1) || (rate_ctrl >= NUM_RATES) ) + err = -EINVAL; + else + priv->tx_rate_ctrl = rate_ctrl; + break; + case FIRMWARE_TYPE_PRISM2: /* Prism II style rate */ + case FIRMWARE_TYPE_SYMBOL: /* Symbol style rate */ + switch(brate) { + case 0: + fixed = 0x0; + upto = 0x15; + break; + case 2: + fixed = 0x1; + upto = 0x1; + break; + case 4: + fixed = 0x2; + upto = 0x3; + break; + case 11: + fixed = 0x4; + upto = 0x7; + break; + case 22: + fixed = 0x8; + upto = 0x15; + break; + default: + fixed = 0x0; + upto = 0x0; + } + if (rrq->fixed) + rate_ctrl = fixed; + else + rate_ctrl = upto; + if (rate_ctrl == 0) + err = -EINVAL; + else + priv->tx_rate_ctrl = rate_ctrl; + break; + } + + dldwd_unlock(priv); + + return err; +} + +static int dldwd_ioctl_getrate(struct net_device *dev, struct iw_param *rrq) +{ + dldwd_priv_t *priv = dev->priv; + hermes_t *hw = &priv->hw; + int err = 0; + uint16_t val; + int brate = 0; + + dldwd_lock(priv); + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_TX_RATE_CTRL, &val); + if (err) + goto out; + + switch (priv->firmware_type) { + case FIRMWARE_TYPE_LUCENT: /* Lucent style rate */ + brate = rate_list[val]; + + if (brate < 0) { + rrq->fixed = 0; + + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENT_TX_RATE, &val); + if (err) + goto out; + + if (val == 6) + brate = 11; + else + brate = 2*val; + } else + rrq->fixed = 1; + break; + case FIRMWARE_TYPE_PRISM2: /* Prism II style rate */ + case FIRMWARE_TYPE_SYMBOL: /* Symbol style rate */ + /* Check if auto or fixed (crude approximation) */ + if((val & 0x1) && (val > 1)) { + rrq->fixed = 0; + + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENT_TX_RATE, &val); + if (err) + goto out; + } else + rrq->fixed = 1; + + if(val >= 8) + brate = 22; + else if(val >= 4) + brate = 11; + else if(val >= 2) + brate = 4; + else + brate = 2; + break; + } + + rrq->value = brate * 500000; + rrq->disabled = 0; + + out: + dldwd_unlock(priv); + + return err; +} + +static int dldwd_ioctl_setpower(struct net_device *dev, struct iw_param *prq) +{ + dldwd_priv_t *priv = dev->priv; + int err = 0; + + + dldwd_lock(priv); + + if (prq->disabled) { + priv->pm_on = 0; + } else { + switch (prq->flags & IW_POWER_MODE) { + case IW_POWER_UNICAST_R: + priv->pm_mcast = 0; + priv->pm_on = 1; + break; + case IW_POWER_ALL_R: + priv->pm_mcast = 1; + priv->pm_on = 1; + break; + case IW_POWER_ON: + /* No flags : but we may have a value - Jean II */ + break; + default: + err = -EINVAL; + } + if (err) + goto out; + + if (prq->flags & IW_POWER_TIMEOUT) { + priv->pm_on = 1; + priv->pm_timeout = prq->value / 1000; + } + if (prq->flags & IW_POWER_PERIOD) { + priv->pm_on = 1; + priv->pm_period = prq->value / 1000; + } + /* It's valid to not have a value if we are just toggling + * the flags... Jean II */ + if(!priv->pm_on) { + err = -EINVAL; + goto out; + } + } + + out: + dldwd_unlock(priv); + + return err; +} + +static int dldwd_ioctl_getpower(struct net_device *dev, struct iw_param *prq) +{ + dldwd_priv_t *priv = dev->priv; + hermes_t *hw = &priv->hw; + int err = 0; + uint16_t enable, period, timeout, mcast; + + dldwd_lock(priv); + + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_ENABLE, &enable); + if (err) + goto out; + + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_PERIOD, &period); + if (err) + goto out; + + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_HOLDOVER, &timeout); + if (err) + goto out; + + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_MCAST_RX, &mcast); + if (err) + goto out; + + prq->disabled = !enable; + /* Note : by default, display the period */ + if ((prq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) { + prq->flags = IW_POWER_TIMEOUT; + prq->value = timeout * 1000; + } else { + prq->flags = IW_POWER_PERIOD; + prq->value = period * 1000; + } + if (mcast) + prq->flags |= IW_POWER_ALL_R; + else + prq->flags |= IW_POWER_UNICAST_R; + + out: + dldwd_unlock(priv); + + return err; +} + +#if WIRELESS_EXT > 10 +static int dldwd_ioctl_getretry(struct net_device *dev, struct iw_param *rrq) +{ + dldwd_priv_t *priv = dev->priv; + hermes_t *hw = &priv->hw; + int err = 0; + uint16_t short_limit, long_limit, lifetime; + + dldwd_lock(priv); + + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_SHORT_RETRY_LIMIT, &short_limit); + if (err) + goto out; + + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_LONG_RETRY_LIMIT, &long_limit); + if (err) + goto out; + + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_MAX_TX_LIFETIME, &lifetime); + if (err) + goto out; + + rrq->disabled = 0; /* Can't be disabled */ + + /* Note : by default, display the retry number */ + if ((rrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) { + rrq->flags = IW_RETRY_LIFETIME; + rrq->value = lifetime * 1000; /* ??? */ + } else { + /* By default, display the min number */ + if ((rrq->flags & IW_RETRY_MAX)) { + rrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX; + rrq->value = long_limit; + } else { + rrq->flags = IW_RETRY_LIMIT; + rrq->value = short_limit; + if(short_limit != long_limit) + rrq->flags |= IW_RETRY_MIN; + } + } + + out: + dldwd_unlock(priv); + + return err; +} +#endif /* WIRELESS_EXT > 10 */ + +static int dldwd_ioctl_setport3(struct net_device *dev, struct iwreq *wrq) +{ + dldwd_priv_t *priv = dev->priv; + int val = *( (int *) wrq->u.name ); + int err = 0; + + dldwd_lock(priv); + switch (val) { + case 0: /* Try to do IEEE ad-hoc mode */ + if (! priv->has_ibss) { + err = -EINVAL; + break; + } + DEBUG(2, "%s: Prefer IBSS Ad-Hoc mode\n", dev->name); + priv->prefer_port3 = 0; + + break; + + case 1: /* Try to do Lucent proprietary ad-hoc mode */ + if (! priv->has_port3) { + err = -EINVAL; + break; + } + DEBUG(2, "%s: Prefer Ad-Hoc demo mode\n", dev->name); + priv->prefer_port3 = 1; + break; + + default: + err = -EINVAL; + } + + if (! err) + /* Actually update the mode we are using */ + set_port_type(priv); + + dldwd_unlock(priv); + + return err; +} + +static int dldwd_ioctl_getport3(struct net_device *dev, struct iwreq *wrq) +{ + dldwd_priv_t *priv = dev->priv; + int *val = (int *)wrq->u.name; + + dldwd_lock(priv); + *val = priv->prefer_port3; + dldwd_unlock(priv); + + return 0; +} + +/* Spy is used for link quality/strength measurements in Ad-Hoc mode + * Jean II */ +static int dldwd_ioctl_setspy(struct net_device *dev, struct iw_point *srq) +{ + dldwd_priv_t *priv = dev->priv; + struct sockaddr address[IW_MAX_SPY]; + int number = srq->length; + int i; + int err = 0; + + /* Check the number of addresses */ + if (number > IW_MAX_SPY) + return -E2BIG; + + /* Get the data in the driver */ + if (srq->pointer) { + if (copy_from_user(address, srq->pointer, + sizeof(struct sockaddr) * number)) + return -EFAULT; + } + + /* Make sure nobody mess with the structure while we do */ + dldwd_lock(priv); + + /* dldwd_lock() doesn't disable interrupts, so make sure the + * interrupt rx path don't get confused while we copy */ + priv->spy_number = 0; + + if (number > 0) { + /* Extract the addresses */ + for (i = 0; i < number; i++) + memcpy(priv->spy_address[i], address[i].sa_data, + ETH_ALEN); + /* Reset stats */ + memset(priv->spy_stat, 0, + sizeof(struct iw_quality) * IW_MAX_SPY); + /* Set number of addresses */ + priv->spy_number = number; + } + + /* Time to show what we have done... */ + DEBUG(0, "%s: New spy list:\n", dev->name); + for (i = 0; i < number; i++) { + DEBUG(0, "%s: %d - %02x:%02x:%02x:%02x:%02x:%02x\n", + dev->name, i+1, + priv->spy_address[i][0], priv->spy_address[i][1], + priv->spy_address[i][2], priv->spy_address[i][3], + priv->spy_address[i][4], priv->spy_address[i][5]); + } + + /* Now, let the others play */ + dldwd_unlock(priv); + + return err; +} + +static int dldwd_ioctl_getspy(struct net_device *dev, struct iw_point *srq) +{ + dldwd_priv_t *priv = dev->priv; + struct sockaddr address[IW_MAX_SPY]; + struct iw_quality spy_stat[IW_MAX_SPY]; + int number; + int i; + + dldwd_lock(priv); + + number = priv->spy_number; + if ((number > 0) && (srq->pointer)) { + /* Create address struct */ + for (i = 0; i < number; i++) { + memcpy(address[i].sa_data, priv->spy_address[i], + ETH_ALEN); + address[i].sa_family = AF_UNIX; + } + /* Copy stats */ + /* In theory, we should disable irqs while copying the stats + * because the rx path migh update it in the middle... + * Bah, who care ? - Jean II */ + memcpy(&spy_stat, priv->spy_stat, + sizeof(struct iw_quality) * IW_MAX_SPY); + for (i=0; i < number; i++) + priv->spy_stat[i].updated = 0; + } + + dldwd_unlock(priv); + + /* Push stuff to user space */ + srq->length = number; + if(copy_to_user(srq->pointer, address, + sizeof(struct sockaddr) * number)) + return -EFAULT; + if(copy_to_user(srq->pointer + (sizeof(struct sockaddr)*number), + &spy_stat, sizeof(struct iw_quality) * number)) + return -EFAULT; + + return 0; +} + +int +dldwd_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + dldwd_priv_t *priv = dev->priv; + struct iwreq *wrq = (struct iwreq *)rq; + int err = 0; + int changed = 0; + + TRACE_ENTER(dev->name); + + /* In theory, we could allow most of the the SET stuff to be done + * In practice, the laps of time at startup when the card is not + * ready is very short, so why bother... + * Note that hw_ready is different from up/down (ifconfig), when + * the device is not yet up, it is usually already ready... + * Jean II */ + if (!priv->hw_ready) + return -ENODEV; + + switch (cmd) { + case SIOCGIWNAME: + DEBUG(1, "%s: SIOCGIWNAME\n", dev->name); + strcpy(wrq->u.name, "IEEE 802.11-DS"); + break; + + case SIOCGIWAP: + DEBUG(1, "%s: SIOCGIWAP\n", dev->name); + wrq->u.ap_addr.sa_family = ARPHRD_ETHER; + err = dldwd_hw_get_bssid(priv, wrq->u.ap_addr.sa_data); + break; + + case SIOCGIWRANGE: + DEBUG(1, "%s: SIOCGIWRANGE\n", dev->name); + err = dldwd_ioctl_getiwrange(dev, &wrq->u.data); + break; + + case SIOCSIWMODE: + DEBUG(1, "%s: SIOCSIWMODE\n", dev->name); + dldwd_lock(priv); + switch (wrq->u.mode) { + case IW_MODE_ADHOC: + if (! (priv->has_ibss || priv->has_port3) ) + err = -EINVAL; + else { + priv->iw_mode = IW_MODE_ADHOC; + changed = 1; + } + break; + + case IW_MODE_INFRA: + priv->iw_mode = IW_MODE_INFRA; + changed = 1; + break; + + default: + err = -EINVAL; + break; + } + set_port_type(priv); + dldwd_unlock(priv); + break; + + case SIOCGIWMODE: + DEBUG(1, "%s: SIOCGIWMODE\n", dev->name); + dldwd_lock(priv); + wrq->u.mode = priv->iw_mode; + dldwd_unlock(priv); + break; + + case SIOCSIWENCODE: + DEBUG(1, "%s: SIOCSIWENCODE\n", dev->name); + if (! priv->has_wep) { + err = -EOPNOTSUPP; + break; + } + + err = dldwd_ioctl_setiwencode(dev, &wrq->u.encoding); + if (! err) + changed = 1; + break; + + case SIOCGIWENCODE: + DEBUG(1, "%s: SIOCGIWENCODE\n", dev->name); + if (! priv->has_wep) { + err = -EOPNOTSUPP; + break; + } + + if (! capable(CAP_NET_ADMIN)) { + err = -EPERM; + break; + } + + err = dldwd_ioctl_getiwencode(dev, &wrq->u.encoding); + break; + + case SIOCSIWESSID: + DEBUG(1, "%s: SIOCSIWESSID\n", dev->name); + err = dldwd_ioctl_setessid(dev, &wrq->u.essid); + if (! err) + changed = 1; + break; + + case SIOCGIWESSID: + DEBUG(1, "%s: SIOCGIWESSID\n", dev->name); + err = dldwd_ioctl_getessid(dev, &wrq->u.essid); + break; + + case SIOCSIWNICKN: + DEBUG(1, "%s: SIOCSIWNICKN\n", dev->name); + err = dldwd_ioctl_setnick(dev, &wrq->u.data); + if (! err) + changed = 1; + break; + + case SIOCGIWNICKN: + DEBUG(1, "%s: SIOCGIWNICKN\n", dev->name); + err = dldwd_ioctl_getnick(dev, &wrq->u.data); + break; + + case SIOCGIWFREQ: + DEBUG(1, "%s: SIOCGIWFREQ\n", dev->name); + wrq->u.freq.m = dldwd_hw_get_freq(priv); + wrq->u.freq.e = 1; + break; + + case SIOCSIWFREQ: + DEBUG(1, "%s: SIOCSIWFREQ\n", dev->name); + err = dldwd_ioctl_setfreq(dev, &wrq->u.freq); + if (! err) + changed = 1; + break; + + case SIOCGIWSENS: + DEBUG(1, "%s: SIOCGIWSENS\n", dev->name); + err = dldwd_ioctl_getsens(dev, &wrq->u.sens); + break; + + case SIOCSIWSENS: + DEBUG(1, "%s: SIOCSIWSENS\n", dev->name); + err = dldwd_ioctl_setsens(dev, &wrq->u.sens); + if (! err) + changed = 1; + break; + + case SIOCGIWRTS: + DEBUG(1, "%s: SIOCGIWRTS\n", dev->name); + wrq->u.rts.value = priv->rts_thresh; + wrq->u.rts.disabled = (wrq->u.rts.value == 2347); + wrq->u.rts.fixed = 1; + break; + + case SIOCSIWRTS: + DEBUG(1, "%s: SIOCSIWRTS\n", dev->name); + err = dldwd_ioctl_setrts(dev, &wrq->u.rts); + if (! err) + changed = 1; + break; + + case SIOCSIWFRAG: + DEBUG(1, "%s: SIOCSIWFRAG\n", dev->name); + err = dldwd_ioctl_setfrag(dev, &wrq->u.frag); + if (! err) + changed = 1; + break; + + case SIOCGIWFRAG: + DEBUG(1, "%s: SIOCGIWFRAG\n", dev->name); + err = dldwd_ioctl_getfrag(dev, &wrq->u.frag); + break; + + case SIOCSIWRATE: + DEBUG(1, "%s: SIOCSIWRATE\n", dev->name); + err = dldwd_ioctl_setrate(dev, &wrq->u.bitrate); + if (! err) + changed = 1; + break; + + case SIOCGIWRATE: + DEBUG(1, "%s: SIOCGIWRATE\n", dev->name); + err = dldwd_ioctl_getrate(dev, &wrq->u.bitrate); + break; + + case SIOCSIWPOWER: + DEBUG(1, "%s: SIOCSIWPOWER\n", dev->name); + err = dldwd_ioctl_setpower(dev, &wrq->u.power); + if (! err) + changed = 1; + break; + + case SIOCGIWPOWER: + DEBUG(1, "%s: SIOCGIWPOWER\n", dev->name); + err = dldwd_ioctl_getpower(dev, &wrq->u.power); + break; + + case SIOCGIWTXPOW: + DEBUG(1, "%s: SIOCGIWTXPOW\n", dev->name); + /* The card only supports one tx power, so this is easy */ + wrq->u.txpower.value = 15; /* dBm */ + wrq->u.txpower.fixed = 1; + wrq->u.txpower.disabled = 0; + wrq->u.txpower.flags = IW_TXPOW_DBM; + break; + +#if WIRELESS_EXT > 10 + case SIOCSIWRETRY: + DEBUG(1, "%s: SIOCSIWRETRY\n", dev->name); + err = -EOPNOTSUPP; + break; + + case SIOCGIWRETRY: + DEBUG(1, "%s: SIOCGIWRETRY\n", dev->name); + err = dldwd_ioctl_getretry(dev, &wrq->u.retry); + break; +#endif /* WIRELESS_EXT > 10 */ + + case SIOCSIWSPY: + DEBUG(1, "%s: SIOCSIWSPY\n", dev->name); + + err = dldwd_ioctl_setspy(dev, &wrq->u.data); + break; + + case SIOCGIWSPY: + DEBUG(1, "%s: SIOCGIWSPY\n", dev->name); + + err = dldwd_ioctl_getspy(dev, &wrq->u.data); + break; + + case SIOCGIWPRIV: + DEBUG(1, "%s: SIOCGIWPRIV\n", dev->name); + if (wrq->u.data.pointer) { + struct iw_priv_args privtab[] = { + { SIOCDEVPRIVATE + 0x0, 0, 0, "force_reset" }, + { SIOCDEVPRIVATE + 0x2, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "set_port3" }, + { SIOCDEVPRIVATE + 0x3, 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_port3" }, + { SIOCDEVPRIVATE + 0x4, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "set_preamble" }, + { SIOCDEVPRIVATE + 0x5, 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_preamble" } + }; + + err = verify_area(VERIFY_WRITE, wrq->u.data.pointer, sizeof(privtab)); + if (err) + break; + + wrq->u.data.length = sizeof(privtab) / sizeof(privtab[0]); + if (copy_to_user(wrq->u.data.pointer, privtab, sizeof(privtab))) + err = -EFAULT; + } + break; + + case SIOCDEVPRIVATE + 0x0: /* force_reset */ + DEBUG(1, "%s: SIOCDEVPRIVATE + 0x0 (force_reset)\n", + dev->name); + if (! capable(CAP_NET_ADMIN)) { + err = -EPERM; + break; + } + + printk(KERN_DEBUG "%s: Forcing reset!\n", dev->name); + dldwd_reset(priv); + break; + + case SIOCDEVPRIVATE + 0x2: /* set_port3 */ + DEBUG(1, "%s: SIOCDEVPRIVATE + 0x2 (set_port3)\n", + dev->name); + if (! capable(CAP_NET_ADMIN)) { + err = -EPERM; + break; + } + + err = dldwd_ioctl_setport3(dev, wrq); + if (! err) + changed = 1; + break; + + case SIOCDEVPRIVATE + 0x3: /* get_port3 */ + DEBUG(1, "%s: SIOCDEVPRIVATE + 0x3 (get_port3)\n", + dev->name); + err = dldwd_ioctl_getport3(dev, wrq); + break; + + case SIOCDEVPRIVATE + 0x4: /* set_preamble */ + DEBUG(1, "%s: SIOCDEVPRIVATE + 0x4 (set_preamble)\n", + dev->name); + if (! capable(CAP_NET_ADMIN)) { + err = -EPERM; + break; + } + + /* 802.11b has recently defined some short preamble. + * Basically, the Phy header has been reduced in size. + * This increase performance, especially at high rates + * (the preamble is transmitted at 1Mb/s), unfortunately + * this give compatibility troubles... - Jean II */ + if(priv->has_preamble) { + int val = *( (int *) wrq->u.name ); + + dldwd_lock(priv); + if(val) + priv->preamble = 1; + else + priv->preamble = 0; + dldwd_unlock(priv); + changed = 1; + } else + err = -EOPNOTSUPP; + break; + + case SIOCDEVPRIVATE + 0x5: /* get_preamble */ + DEBUG(1, "%s: SIOCDEVPRIVATE + 0x5 (get_preamble)\n", + dev->name); + if(priv->has_preamble) { + int *val = (int *)wrq->u.name; + + dldwd_lock(priv); + *val = priv->preamble; + dldwd_unlock(priv); + } else + err = -EOPNOTSUPP; + break; + + default: + err = -EOPNOTSUPP; + } + + if (! err && changed && netif_running(dev)) { + err = dldwd_reset(priv); + if (err) { + /* Ouch ! What are we supposed to do ? */ + printk(KERN_ERR "orinoco_cs: Failed to set parameters on %s\n", + dev->name); + netif_stop_queue(dev); + dldwd_shutdown(priv); + priv->hw_ready = 0; + } + } + + TRACE_EXIT(dev->name); + + return err; +} + +int +dldwd_change_mtu(struct net_device *dev, int new_mtu) +{ + TRACE_ENTER(dev->name); + + if ( (new_mtu < DLDWD_MIN_MTU) || (new_mtu > DLDWD_MAX_MTU) ) + return -EINVAL; + + dev->mtu = new_mtu; + + TRACE_EXIT(dev->name); + + return 0; +} + +static void +__dldwd_set_multicast_list(struct net_device *dev) +{ + dldwd_priv_t *priv = dev->priv; + hermes_t *hw = &priv->hw; + int err = 0; + int promisc, allmulti, mc_count; + + /* We'll wait until it's ready. Anyway, the network doesn't call us + * here until we are open - Jean II */ + if (!priv->hw_ready) + return; + + + TRACE_ENTER(dev->name); + + DEBUG(3, "dev->flags=0x%x, priv->promiscuous=%d, dev->mc_count=%d priv->mc_count=%d\n", + dev->flags, priv->promiscuous, dev->mc_count, priv->mc_count); + + /* The Hermes doesn't seem to have an allmulti mode, so we go + * into promiscuous mode and let the upper levels deal. */ + if ( (dev->flags & IFF_PROMISC) ) { + promisc = 1; + allmulti = 0; + mc_count = 0; + } else if ( (dev->flags & IFF_ALLMULTI) || + (dev->mc_count > HERMES_MAX_MULTICAST) ) { + promisc = 0; + allmulti = 1; + mc_count = HERMES_MAX_MULTICAST; + } else { + promisc = 0; + allmulti = 0; + mc_count = dev->mc_count; + } + + DEBUG(3, "promisc=%d mc_count=%d\n", + promisc, mc_count); + + if (promisc != priv->promiscuous) { /* Don't touch the hardware if we don't have to */ + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PROMISCUOUS, + promisc); + if (err) { + printk(KERN_ERR "%s: Error %d setting promiscuity to %d.\n", + dev->name, err, promisc); + } else + priv->promiscuous = promisc; + } + + if (allmulti) { + /* FIXME: This method of doing allmulticast reception + comes from the NetBSD driver. Haven't actually + tested whether it works or not. */ + hermes_multicast_t mclist; + + memset(&mclist, 0, sizeof(mclist)); + err = HERMES_WRITE_RECORD(hw, USER_BAP, HERMES_RID_CNF_MULTICAST_LIST, &mclist); + if (err) + printk(KERN_ERR "%s: Error %d setting multicast list.\n", + dev->name, err); + else + priv->allmulti = 1; + + } else if (mc_count || (! mc_count && priv->mc_count) ) { + struct dev_mc_list *p = dev->mc_list; + hermes_multicast_t mclist; + int i; + + for (i = 0; i < mc_count; i++) { + /* First some paranoid checks */ + if (! p) { + printk(KERN_ERR "%s: Multicast list shorter than mc_count.\n", + dev->name); + break; + } + if (p->dmi_addrlen != ETH_ALEN) { + + printk(KERN_ERR "%s: Bad address size (%d) in multicast list.\n", + dev->name, p->dmi_addrlen); + break; + } + + memcpy(mclist.addr[i], p->dmi_addr, ETH_ALEN); + p = p->next; + } + + /* More paranoia */ + if (p) + printk(KERN_ERR "%s: Multicast list longer than mc_count.\n", + dev->name); + + priv->mc_count = i; + + DEBUG(3, "priv->mc_count = %d\n", priv->mc_count); + + err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNF_MULTICAST_LIST, + HERMES_BYTES_TO_RECLEN(priv->mc_count * ETH_ALEN), + &mclist); + if (err) + printk(KERN_ERR "%s: Error %d setting multicast list.\n", + dev->name, err); + else + priv->allmulti = 0; + } + + /* Since we can set the promiscuous flag when it wasn't asked + for, make sure the net_device knows about it. */ + if (priv->promiscuous) + dev->flags |= IFF_PROMISC; + else + dev->flags &= ~IFF_PROMISC; + + if (priv->allmulti) + dev->flags |= IFF_ALLMULTI; + else + dev->flags &= ~IFF_ALLMULTI; + + TRACE_EXIT(dev->name); +} + +/* + * procfs stuff + */ + +static struct proc_dir_entry *dir_base = NULL; + +/* + * This function updates the total amount of data printed so far. It then + * determines if the amount of data printed into a buffer has reached the + * offset requested. If it hasn't, then the buffer is shifted over so that + * the next bit of data can be printed over the old bit. If the total + * amount printed so far exceeds the total amount requested, then this + * function returns 1, otherwise 0. + */ +static int + +shift_buffer(char *buffer, int requested_offset, int requested_len, + int *total, int *slop, char **buf) +{ + int printed; + + printed = *buf - buffer; + if (*total + printed <= requested_offset) { + *total += printed; + *buf = buffer; + } + else { + if (*total < requested_offset) { + *slop = requested_offset - *total; + } + *total = requested_offset + printed - *slop; + } + if (*total > requested_offset + requested_len) { + return 1; + } + else { + return 0; + } +} + +/* + * This function calculates the actual start of the requested data + * in the buffer. It also calculates actual length of data returned, + * which could be less that the amount of data requested. + */ +#define PROC_BUFFER_SIZE 4096 +#define PROC_SAFE_SIZE 3072 + +static int +calc_start_len(char *buffer, char **start, int requested_offset, + int requested_len, int total, char *buf) +{ + int return_len, buffer_len; + + buffer_len = buf - buffer; + if (buffer_len >= PROC_BUFFER_SIZE - 1) { + printk(KERN_ERR "calc_start_len: exceeded /proc buffer size\n"); + } + + /* + * There may be bytes before and after the + * chunk that was actually requested. + */ + return_len = total - requested_offset; + if (return_len < 0) { + return_len = 0; + } + *start = buf - return_len; + if (return_len > requested_len) { + return_len = requested_len; + } + return return_len; +} + +static int +dldwd_proc_get_hermes_regs(char *page, char **start, off_t requested_offset, + int requested_len, int *eof, void *data) +{ + dldwd_priv_t *dev = (dldwd_priv_t *)data; + hermes_t *hw = &dev->hw; + char *buf; + int total = 0, slop = 0; + + /* Hum, in this case hardware register are probably not readable... */ + if (!dev->hw_ready) + return -ENODEV; + + buf = page; + +#define DHERMESREG(name) buf += sprintf(buf, "%-16s: %04x\n", #name, hermes_read_regn(hw, name)) + + DHERMESREG(CMD); + DHERMESREG(PARAM0); + DHERMESREG(PARAM1); + DHERMESREG(PARAM2); + DHERMESREG(STATUS); + DHERMESREG(RESP0); + DHERMESREG(RESP1); + DHERMESREG(RESP2); + DHERMESREG(INFOFID); + DHERMESREG(RXFID); + DHERMESREG(ALLOCFID); + DHERMESREG(TXCOMPLFID); + DHERMESREG(SELECT0); + DHERMESREG(OFFSET0); + DHERMESREG(SELECT1); + DHERMESREG(OFFSET1); + DHERMESREG(EVSTAT); + DHERMESREG(INTEN); + DHERMESREG(EVACK); + DHERMESREG(CONTROL); + DHERMESREG(SWSUPPORT0); + DHERMESREG(SWSUPPORT1); + DHERMESREG(SWSUPPORT2); + DHERMESREG(AUXPAGE); + DHERMESREG(AUXOFFSET); + DHERMESREG(AUXDATA); +#undef DHERMESREG + + shift_buffer(page, requested_offset, requested_len, &total, + &slop, &buf); + return calc_start_len(page, start, requested_offset, requested_len, + total, buf); +} + +struct { + uint16_t rid; + char *name; + int minlen, maxlen; + int displaytype; +#define DISPLAY_WORDS 0 +#define DISPLAY_BYTES 1 +#define DISPLAY_STRING 2 +} record_table[] = { +#define RTCNFENTRY(name, type) { HERMES_RID_CNF_##name, #name, 0, LTV_BUF_SIZE, type } + RTCNFENTRY(PORTTYPE, DISPLAY_WORDS), + RTCNFENTRY(MACADDR, DISPLAY_BYTES), + RTCNFENTRY(DESIRED_SSID, DISPLAY_STRING), + RTCNFENTRY(CHANNEL, DISPLAY_WORDS), + RTCNFENTRY(OWN_SSID, DISPLAY_STRING), + RTCNFENTRY(SYSTEM_SCALE, DISPLAY_WORDS), + RTCNFENTRY(MAX_DATA_LEN, DISPLAY_WORDS), + RTCNFENTRY(PM_ENABLE, DISPLAY_WORDS), + RTCNFENTRY(PM_MCAST_RX, DISPLAY_WORDS), + RTCNFENTRY(PM_PERIOD, DISPLAY_WORDS), + RTCNFENTRY(NICKNAME, DISPLAY_STRING), + RTCNFENTRY(WEP_ON, DISPLAY_WORDS), + RTCNFENTRY(MWO_ROBUST, DISPLAY_WORDS), + RTCNFENTRY(MULTICAST_LIST, DISPLAY_BYTES), + RTCNFENTRY(CREATEIBSS, DISPLAY_WORDS), + RTCNFENTRY(FRAG_THRESH, DISPLAY_WORDS), + RTCNFENTRY(RTS_THRESH, DISPLAY_WORDS), + RTCNFENTRY(TX_RATE_CTRL, DISPLAY_WORDS), + RTCNFENTRY(PROMISCUOUS, DISPLAY_WORDS), + RTCNFENTRY(KEYS, DISPLAY_BYTES), + RTCNFENTRY(TX_KEY, DISPLAY_WORDS), + RTCNFENTRY(TICKTIME, DISPLAY_WORDS), + RTCNFENTRY(PRISM2_TX_KEY, DISPLAY_WORDS), + RTCNFENTRY(PRISM2_KEY0, DISPLAY_BYTES), + RTCNFENTRY(PRISM2_KEY1, DISPLAY_BYTES), + RTCNFENTRY(PRISM2_KEY2, DISPLAY_BYTES), + RTCNFENTRY(PRISM2_KEY3, DISPLAY_BYTES), + RTCNFENTRY(PRISM2_WEP_ON, DISPLAY_WORDS), +#undef RTCNFENTRY +#define RTINFENTRY(name,type) { HERMES_RID_##name, #name, 0, LTV_BUF_SIZE, type } + RTINFENTRY(CHANNEL_LIST, DISPLAY_WORDS), + RTINFENTRY(STAIDENTITY, DISPLAY_WORDS), + RTINFENTRY(CURRENT_SSID, DISPLAY_STRING), + RTINFENTRY(CURRENT_BSSID, DISPLAY_BYTES), + RTINFENTRY(COMMSQUALITY, DISPLAY_WORDS), + RTINFENTRY(CURRENT_TX_RATE, DISPLAY_WORDS), + RTINFENTRY(WEP_AVAIL, DISPLAY_WORDS), + RTINFENTRY(CURRENT_CHANNEL, DISPLAY_WORDS), + RTINFENTRY(DATARATES, DISPLAY_BYTES), +#undef RTINFENTRY +}; +#define NUM_RIDS ( sizeof(record_table) / sizeof(record_table[0]) ) + +static int +dldwd_proc_get_hermes_recs(char *page, char **start, off_t requested_offset, + int requested_len, int *eof, void *data) +{ + dldwd_priv_t *dev = (dldwd_priv_t *)data; + hermes_t *hw = &dev->hw; + char *buf; + int total = 0, slop = 0; + int i; + uint16_t length; + int err; + + /* Hum, in this case hardware register are probably not readable... */ + if (!dev->hw_ready) + return -ENODEV; + + buf = page; + + /* print out all the config RIDs */ + for (i = 0; i < NUM_RIDS; i++) { + uint16_t rid = record_table[i].rid; + int minlen = record_table[i].minlen; + int maxlen = record_table[i].maxlen; + int len; + uint8_t *val8; + uint16_t *val16; + int j; + + val8 = kmalloc(maxlen + 2, GFP_KERNEL); + if (! val8) + return -ENOMEM; + + err = hermes_read_ltv(hw, USER_BAP, rid, maxlen, + &length, val8); + if (err) { + DEBUG(0, "Error %d reading RID 0x%04x\n", err, rid); + continue; + } + val16 = (uint16_t *)val8; + + buf += sprintf(buf, "%-15s (0x%04x): length=%d (%d bytes)\tvalue=", record_table[i].name, + rid, length, (length-1)*2); + len = MIN( MAX(minlen, (length-1)*2), maxlen); + + switch (record_table[i].displaytype) { + case DISPLAY_WORDS: + for (j = 0; j < len / 2; j++) { + buf += sprintf(buf, "%04X-", le16_to_cpu(val16[j])); + } + buf--; + break; + + case DISPLAY_BYTES: + default: + for (j = 0; j < len; j++) { + buf += sprintf(buf, "%02X:", val8[j]); + } + buf--; + break; + + case DISPLAY_STRING: + len = MIN(len, le16_to_cpu(val16[0])+2); + val8[len] = '\0'; + buf += sprintf(buf, "\"%s\"", (char *)&val16[1]); + break; + } + + buf += sprintf(buf, "\n"); + + kfree(val8); + + if (shift_buffer(page, requested_offset, requested_len, + &total, &slop, &buf)) + break; + + if ( (buf - page) > PROC_SAFE_SIZE ) + break; + } + + return calc_start_len(page, start, requested_offset, requested_len, + total, buf); +} + +/* initialise the /proc subsystem for the hermes driver, creating the + * separate entries */ +static int +dldwd_proc_init(void) +{ + int err = 0; + + TRACE_ENTER("dldwd"); + + /* create the directory for it to sit in */ + dir_base = create_proc_entry("hermes", S_IFDIR, &proc_root); + if (dir_base == NULL) { + printk(KERN_ERR "Unable to initialise /proc/hermes.\n"); + dldwd_proc_cleanup(); + err = -ENOMEM; + } + + TRACE_EXIT("dldwd"); + + return err; +} + +int +dldwd_proc_dev_init(dldwd_priv_t *dev) +{ + struct net_device *ndev = &dev->ndev; + + dev->dir_dev = NULL; + /* create the directory for it to sit in */ + dev->dir_dev = create_proc_entry(ndev->name, S_IFDIR | S_IRUGO | S_IXUGO, + dir_base); + if (dev->dir_dev == NULL) { + printk(KERN_ERR "Unable to initialise /proc/hermes/%s.\n", ndev->name); + goto fail; + } + + dev->dir_regs = NULL; + dev->dir_regs = create_proc_read_entry("regs", S_IFREG | S_IRUGO, + dev->dir_dev, dldwd_proc_get_hermes_regs, dev); + if (dev->dir_regs == NULL) { + printk(KERN_ERR "Unable to initialise /proc/hermes/%s/regs.\n", ndev->name); + goto fail; + } + + dev->dir_recs = NULL; + dev->dir_recs = create_proc_read_entry("recs", S_IFREG | S_IRUGO, + dev->dir_dev, dldwd_proc_get_hermes_recs, dev); + if (dev->dir_recs == NULL) { + printk(KERN_ERR "Unable to initialise /proc/hermes/%s/recs.\n", ndev->name); + goto fail; + } + + return 0; + fail: + dldwd_proc_dev_cleanup(dev); + return -ENOMEM; +} + +void +dldwd_proc_dev_cleanup(dldwd_priv_t *priv) +{ + struct net_device *ndev = &priv->ndev; + + if (priv->dir_regs) { + remove_proc_entry("regs", priv->dir_dev); + priv->dir_regs = NULL; + } + if (priv->dir_recs) { + remove_proc_entry("recs", priv->dir_dev); + priv->dir_recs = NULL; + } + if (priv->dir_dev) { + remove_proc_entry(ndev->name, dir_base); + priv->dir_dev = NULL; + } +} + +static void +dldwd_proc_cleanup(void) +{ + TRACE_ENTER("dldwd"); + + if (dir_base) { + remove_proc_entry("hermes", &proc_root); + dir_base = NULL; + } + + TRACE_EXIT("dldwd"); +} + +int +dldwd_setup(dldwd_priv_t* priv) +{ + struct net_device *ndev = &priv->ndev;; + + spin_lock_init(&priv->lock); + + /* Set up the net_device */ + ether_setup(ndev); + ndev->priv = priv; + + /* Setup up default routines */ + ndev->init = dldwd_init; + ndev->open = NULL; /* Caller *must* override */ + ndev->stop = NULL; + ndev->hard_start_xmit = dldwd_xmit; + ndev->tx_timeout = dldwd_tx_timeout; + ndev->watchdog_timeo = 4*HZ; /* 4 second timeout */ + + ndev->get_stats = dldwd_get_stats; + ndev->get_wireless_stats = dldwd_get_wireless_stats; + + ndev->do_ioctl = dldwd_ioctl; + + ndev->change_mtu = dldwd_change_mtu; + ndev->set_multicast_list = dldwd_set_multicast_list; + + netif_stop_queue(ndev); + + return 0; +} + +#ifdef ORINOCO_DEBUG +EXPORT_SYMBOL(dldwd_debug); +#endif +EXPORT_SYMBOL(dldwd_init); +EXPORT_SYMBOL(dldwd_xmit); +EXPORT_SYMBOL(dldwd_tx_timeout); +EXPORT_SYMBOL(dldwd_ioctl); +EXPORT_SYMBOL(dldwd_change_mtu); +EXPORT_SYMBOL(dldwd_set_multicast_list); +EXPORT_SYMBOL(dldwd_shutdown); +EXPORT_SYMBOL(dldwd_reset); +EXPORT_SYMBOL(dldwd_setup); +EXPORT_SYMBOL(dldwd_proc_dev_init); +EXPORT_SYMBOL(dldwd_proc_dev_cleanup); +EXPORT_SYMBOL(dldwd_interrupt); + +static int __init init_dldwd(void) +{ + int err; + + err = dldwd_proc_init(); + + printk(KERN_INFO "%s\n", version); + + return 0; +} + +static void __exit exit_dldwd(void) +{ + dldwd_proc_cleanup(); +} + +module_init(init_dldwd); +module_exit(exit_dldwd); diff -Nru a/drivers/net/wireless/orinoco.h b/drivers/net/wireless/orinoco.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/orinoco.h Wed May 16 06:00:33 2001 @@ -0,0 +1,145 @@ +/* orinoco.h + * + * Common definitions to all pieces of the various orinoco + * drivers + */ + +#ifndef _ORINOCO_H +#define _ORINOCO_H + +/* To enable debug messages */ +//#define ORINOCO_DEBUG 3 + +#if (! defined (WIRELESS_EXT)) || (WIRELESS_EXT < 10) +#error "orinoco_cs requires Wireless extensions v10 or later." +#endif /* (! defined (WIRELESS_EXT)) || (WIRELESS_EXT < 10) */ +#define WIRELESS_SPY // enable iwspy support + + +#define DLDWD_MIN_MTU 256 +#define DLDWD_MAX_MTU (HERMES_FRAME_LEN_MAX - ENCAPS_OVERHEAD) + +#define LTV_BUF_SIZE 128 +#define USER_BAP 0 +#define IRQ_BAP 1 +#define DLDWD_MACPORT 0 +#define IRQ_LOOP_MAX 10 +#define TX_NICBUF_SIZE 2048 +#define TX_NICBUF_SIZE_BUG 1585 /* Bug in Intel firmware */ +#define MAX_KEYS 4 +#define MAX_KEY_SIZE 14 +#define LARGE_KEY_SIZE 13 +#define SMALL_KEY_SIZE 5 +#define MAX_FRAME_SIZE 2304 + +typedef struct dldwd_key { + uint16_t len; + char data[MAX_KEY_SIZE]; +} __attribute__ ((packed)) dldwd_key_t; + +typedef dldwd_key_t dldwd_keys_t[MAX_KEYS]; + +/*====================================================================*/ + + +typedef struct dldwd_priv { + void* card; /* Pointer to card dependant structure */ + + spinlock_t lock; + long state; +#define DLDWD_STATE_INIRQ 0 +#define DLDWD_STATE_DOIRQ 1 + int hw_ready; /* HW may be suspended by platform */ + + /* Net device stuff */ + struct net_device ndev; + struct net_device_stats stats; + struct iw_statistics wstats; + + + /* Hardware control variables */ + hermes_t hw; + uint16_t txfid; + + /* Capabilities of the hardware/firmware */ + hermes_identity_t firmware_info; + int firmware_type; +#define FIRMWARE_TYPE_LUCENT 1 +#define FIRMWARE_TYPE_PRISM2 2 +#define FIRMWARE_TYPE_SYMBOL 3 + int has_ibss, has_port3, prefer_port3, has_ibss_any; + int has_wep, has_big_wep; + int has_mwo; + int has_pm; + int has_preamble; + int broken_reset, broken_allocate; + uint16_t channel_mask; + + /* Current configuration */ + uint32_t iw_mode; + int port_type, allow_ibss; + uint16_t wep_on, wep_restrict, tx_key; + dldwd_keys_t keys; + char nick[IW_ESSID_MAX_SIZE+1]; + char desired_essid[IW_ESSID_MAX_SIZE+1]; + uint16_t frag_thresh, mwo_robust; + uint16_t channel; + uint16_t ap_density, rts_thresh; + uint16_t tx_rate_ctrl; + uint16_t pm_on, pm_mcast, pm_period, pm_timeout; + uint16_t preamble; + + int promiscuous, allmulti, mc_count; + +#ifdef WIRELESS_SPY + int spy_number; + u_char spy_address[IW_MAX_SPY][ETH_ALEN]; + struct iw_quality spy_stat[IW_MAX_SPY]; +#endif + + /* /proc based debugging stuff */ + struct proc_dir_entry *dir_dev; + struct proc_dir_entry *dir_regs; + struct proc_dir_entry *dir_recs; +} dldwd_priv_t; + +/*====================================================================*/ + +extern int dldwd_debug; +extern struct list_head dldwd_instances; + +#ifdef ORINOCO_DEBUG +#define DEBUG(n, args...) if (dldwd_debug>(n)) printk(KERN_DEBUG args) +#define DEBUGMORE(n, args...) do { if (dldwd_debug>(n)) printk(args); } while (0) +#else +#define DEBUG(n, args...) do { } while (0) +#define DEBUGMORE(n, args...) do { } while (0) +#endif /* ORINOCO_DEBUG */ + +#define TRACE_ENTER(devname) DEBUG(2, "%s: -> " __FUNCTION__ "()\n", devname); +#define TRACE_EXIT(devname) DEBUG(2, "%s: <- " __FUNCTION__ "()\n", devname); + +#define MAX(a, b) ( (a) > (b) ? (a) : (b) ) +#define MIN(a, b) ( (a) < (b) ? (a) : (b) ) + +#define RUP_EVEN(a) ( (a) % 2 ? (a) + 1 : (a) ) + +/* struct net_device methods */ +extern int dldwd_init(struct net_device *dev); +extern int dldwd_xmit(struct sk_buff *skb, struct net_device *dev); +extern void dldwd_tx_timeout(struct net_device *dev); + +extern int dldwd_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +extern int dldwd_change_mtu(struct net_device *dev, int new_mtu); +extern void dldwd_set_multicast_list(struct net_device *dev); + +/* utility routines */ +extern void dldwd_shutdown(dldwd_priv_t *dev); +extern int dldwd_reset(dldwd_priv_t *dev); +extern int dldwd_setup(dldwd_priv_t* priv); +extern int dldwd_proc_dev_init(dldwd_priv_t *dev); +extern void dldwd_proc_dev_cleanup(dldwd_priv_t *priv); +extern void dldwd_interrupt(int irq, void * dev_id, struct pt_regs *regs); + + +#endif diff -Nru a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/orinoco_cs.c Wed May 16 06:00:18 2001 @@ -0,0 +1,789 @@ +/* orinoco_cs.c 0.05 - (formerly known as dldwd_cs.c) + * + * A driver for "Hermes" chipset based PCMCIA wireless adaptors, such + * as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/ + * EnteraSys RoamAbout 802.11, ELSA Airlancer, Melco Buffalo and others). + * It should also be usable on various Prism II based cards such as the + * Linksys, D-Link and Farallon Skyline. It should also work on Symbol + * cards such as the 3Com AirConnect and Ericsson WLAN. + * + * Copyright notice & release notes in file orinoco.c + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "hermes.h" +#include "orinoco.h" + +/* Pcmcia specific structure */ +typedef struct dldwd_card { + dev_link_t link; + dev_node_t node; + int instance; + + /* Common structure (fully included), see orinoco.h */ + struct dldwd_priv priv; +} dldwd_card_t; + +static char *version = "orinoco_cs.c 0.05 (David Gibson and others)"; + +/*====================================================================*/ + +/* Parameters that can be set with 'insmod' */ + +/* The old way: bit map of interrupts to choose from */ +/* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4, and 3 */ +static uint irq_mask = 0xdeb8; +/* Newer, simpler way of listing specific interrupts */ +static int irq_list[4] = { -1 }; +/* Do a Pcmcia soft reset (may help some cards) */ +static int reset_cor = 0; +/* Some D-Link cards have buggy CIS. They do work at 5v properly, but + * don't have any CIS entry for it. This workaround it... */ +static int ignore_cis_vcc = 0; + +MODULE_PARM(irq_mask, "i"); +MODULE_PARM(irq_list, "1-4i"); +MODULE_PARM(reset_cor, "i"); +MODULE_PARM(ignore_cis_vcc, "i"); + +/* + * Function prototypes + */ + +/* struct net_device methods */ +static int dldwd_cs_open(struct net_device *dev); +static int dldwd_cs_stop(struct net_device *dev); + +/* PCMCIA gumpf */ +static void dldwd_cs_config(dev_link_t * link); +static void dldwd_cs_release(u_long arg); +static int dldwd_cs_event(event_t event, int priority, + event_callback_args_t * args); + +static dev_link_t *dldwd_cs_attach(void); +static void dldwd_cs_detach(dev_link_t *); + +/* + The dev_info variable is the "key" that is used to match up this + device driver with appropriate cards, through the card configuration + database. +*/ + +static dev_info_t dev_info = "orinoco_cs"; + +/* + A linked list of "instances" of the dummy device. Each actual + PCMCIA card corresponds to one device instance, and is described + by one dev_link_t structure (defined in ds.h). + + You may not want to use a linked list for this -- for example, the + memory card driver uses an array of dev_link_t pointers, where minor + device numbers are used to derive the corresponding array index. +*/ + +static dev_link_t *dev_list = NULL; +static int num_instances = 0; + +/*====================================================================*/ + +static void +cs_error(client_handle_t handle, int func, int ret) +{ + error_info_t err = { func, ret }; + CardServices(ReportError, handle, &err); +} + +static int +dldwd_cs_open(struct net_device *dev) +{ + dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; + dldwd_card_t* card = (dldwd_card_t *)priv->card; + dev_link_t *link = &card->link; + int err; + + TRACE_ENTER(priv->ndev.name); + + link->open++; + netif_device_attach(dev); + + err = dldwd_reset(priv); + if (err) + dldwd_cs_stop(dev); + else + netif_start_queue(dev); + + TRACE_EXIT(priv->ndev.name); + + return err; +} + +static int +dldwd_cs_stop(struct net_device *dev) +{ + dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; + dldwd_card_t* card = (dldwd_card_t *)priv->card; + dev_link_t *link = &card->link; + + TRACE_ENTER(priv->ndev.name); + + netif_stop_queue(dev); + + dldwd_shutdown(priv); + + link->open--; + + if (link->state & DEV_STALE_CONFIG) + mod_timer(&link->release, jiffies + HZ/20); + + TRACE_EXIT(priv->ndev.name); + + return 0; +} + +/*====================================================================== + dldwd_cs_attach() creates an "instance" of the driver, allocating + local data structures for one device. The device is registered + with Card Services. + + The dev_link structure is initialized, but we don't actually + configure the card at this point -- we wait until we receive a + card insertion event. + ======================================================================*/ + +static dev_link_t * +dldwd_cs_attach(void) +{ + dldwd_card_t *card; + dldwd_priv_t *priv; + dev_link_t *link; + struct net_device *ndev; + client_reg_t client_reg; + int ret, i; + + TRACE_ENTER("dldwd"); + + /* Allocate space for private device-specific data */ + card = kmalloc(sizeof(*card), GFP_KERNEL); + if (! card) { + link = NULL; + goto out; + } + memset(card, 0, sizeof(*card)); + + /* Link both structure together */ + priv = &(card->priv); + priv->card = card; + card->instance = num_instances++; /* FIXME: Racy? */ + link = &card->link; + ndev = &priv->ndev; + link->priv = priv; + + /* Initialize the dev_link_t structure */ + link->release.function = &dldwd_cs_release; + link->release.data = (u_long) link; + + /* Interrupt setup */ + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; + link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID; + if (irq_list[0] == -1) + link->irq.IRQInfo2 = irq_mask; + else + for (i = 0; i < 4; i++) + link->irq.IRQInfo2 |= 1 << irq_list[i]; + link->irq.Handler = NULL; + + /* + General socket configuration defaults can go here. In this + client, we assume very little, and rely on the CIS for almost + everything. In most clients, many details (i.e., number, sizes, + and attributes of IO windows) are fixed by the nature of the + device, and can be hard-wired here. + */ + link->conf.Attributes = 0; + link->conf.IntType = INT_MEMORY_AND_IO; + + /* Setup the common part */ + if(dldwd_setup(priv) < 0) { + kfree(card); + return NULL; + } + + /* Overrides */ + ndev->open = dldwd_cs_open; + ndev->stop = dldwd_cs_stop; + + /* Register with Card Services */ + link->next = dev_list; + dev_list = link; + client_reg.dev_info = &dev_info; + client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; + client_reg.EventMask = + CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | + CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | + CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; + client_reg.event_handler = &dldwd_cs_event; + client_reg.Version = 0x0210; + client_reg.event_callback_args.client_data = link; + ret = CardServices(RegisterClient, &link->handle, &client_reg); + if (ret != CS_SUCCESS) { + cs_error(link->handle, RegisterClient, ret); + dldwd_cs_detach(link); + link = NULL; + goto out; + } + + out: + TRACE_EXIT("dldwd"); + return link; +} /* dldwd_cs_attach */ + +/*====================================================================== + This deletes a driver "instance". The device is de-registered + with Card Services. If it has been released, all local data + structures are freed. Otherwise, the structures will be freed + when the device is released. + ======================================================================*/ + +static void +dldwd_cs_detach(dev_link_t * link) +{ + dev_link_t **linkp; + dldwd_priv_t *priv = link->priv; + + TRACE_ENTER("dldwd"); + + /* Locate device structure */ + for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) + if (*linkp == link) + break; + if (*linkp == NULL) + goto out; + + /* + If the device is currently configured and active, we won't + actually delete it yet. Instead, it is marked so that when + the release() function is called, that will trigger a proper + detach(). + */ + if (link->state & DEV_CONFIG) { +#ifdef PCMCIA_DEBUG + printk(KERN_DEBUG "orinoco_cs: detach postponed, '%s' " + "still locked\n", link->dev->dev_name); +#endif + link->state |= DEV_STALE_LINK; + goto out; + } + + /* Break the link with Card Services */ + if (link->handle) + CardServices(DeregisterClient, link->handle); + + /* Unlink device structure, and free it */ + *linkp = link->next; + DEBUG(0, "orinoco_cs: detach: link=%p link->dev=%p\n", link, link->dev); + if (link->dev) { + DEBUG(0, "orinoco_cs: About to unregister net device %p\n", + &priv->ndev); + unregister_netdev(&priv->ndev); + } + kfree(priv->card); + + num_instances--; /* FIXME: Racy? */ + + out: + TRACE_EXIT("dldwd"); +} /* dldwd_cs_detach */ + +/* + * Do a soft reset of the Pcmcia card using the Configuration Option Register + * Can't do any harm, and actually may do some good on some cards... + */ +static int +dldwd_cs_cor_reset(dev_link_t *link) +{ + conf_reg_t reg; + u_long default_cor; + + /* Save original COR value */ + reg.Function = 0; + reg.Action = CS_READ; + reg.Offset = CISREG_COR; + reg.Value = 0; + CardServices(AccessConfigurationRegister, link->handle, ®); + default_cor = reg.Value; + + DEBUG(2, "dldwd : dldwd_cs_cor_reset() : cor=0x%lX\n", default_cor); + + /* Soft-Reset card */ + reg.Action = CS_WRITE; + reg.Offset = CISREG_COR; + reg.Value = (default_cor | COR_SOFT_RESET); + CardServices(AccessConfigurationRegister, link->handle, ®); + + /* Wait until the card has acknowledged our reset */ + mdelay(1); + + /* Restore original COR configuration index */ + reg.Value = (default_cor & COR_CONFIG_MASK); + CardServices(AccessConfigurationRegister, link->handle, ®); + + /* Wait until the card has finished restarting */ + mdelay(1); + + return(0); +} + +/*====================================================================== + dldwd_cs_config() is scheduled to run after a CARD_INSERTION event + is received, to configure the PCMCIA socket, and to make the + device available to the system. + ======================================================================*/ + +#define CS_CHECK(fn, args...) \ +while ((last_ret=CardServices(last_fn=(fn),args))!=0) goto cs_failed + +#define CFG_CHECK(fn, args...) \ +if (CardServices(fn, args) != 0) goto next_entry + +static void +dldwd_cs_config(dev_link_t * link) +{ + client_handle_t handle = link->handle; + dldwd_priv_t *priv = link->priv; + dldwd_card_t *card = (dldwd_card_t *)priv->card; + hermes_t *hw = &priv->hw; + struct net_device *ndev = &priv->ndev; + tuple_t tuple; + cisparse_t parse; + int last_fn, last_ret; + u_char buf[64]; + config_info_t conf; + cistpl_cftable_entry_t dflt = { 0 }; + cisinfo_t info; + + TRACE_ENTER("dldwd"); + + CS_CHECK(ValidateCIS, handle, &info); + + /* + This reads the card's CONFIG tuple to find its configuration + registers. + */ + tuple.DesiredTuple = CISTPL_CONFIG; + tuple.Attributes = 0; + tuple.TupleData = buf; + tuple.TupleDataMax = sizeof(buf); + tuple.TupleOffset = 0; + CS_CHECK(GetFirstTuple, handle, &tuple); + CS_CHECK(GetTupleData, handle, &tuple); + CS_CHECK(ParseTuple, handle, &tuple, &parse); + link->conf.ConfigBase = parse.config.base; + link->conf.Present = parse.config.rmask[0]; + + /* Configure card */ + link->state |= DEV_CONFIG; + + /* Look up the current Vcc */ + CS_CHECK(GetConfigurationInfo, handle, &conf); + link->conf.Vcc = conf.Vcc; + + DEBUG(0, "dldwd_cs_config: ConfigBase = 0x%x link->conf.Vcc = %d\n", + link->conf.ConfigBase, link->conf.Vcc); + + /* + In this loop, we scan the CIS for configuration table entries, + each of which describes a valid card configuration, including + voltage, IO window, memory window, and interrupt settings. + + We make no assumptions about the card to be configured: we use + just the information available in the CIS. In an ideal world, + this would work for any PCMCIA card, but it requires a complete + and accurate CIS. In practice, a driver usually "knows" most of + these things without consulting the CIS, and most client drivers + will only use the CIS to fill in implementation-defined details. + */ + tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; + CS_CHECK(GetFirstTuple, handle, &tuple); + while (1) { + cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); + CFG_CHECK(GetTupleData, handle, &tuple); + CFG_CHECK(ParseTuple, handle, &tuple, &parse); + + DEBUG(0, "dldwd_cs_config: index = 0x%x, flags = 0x%x\n", + cfg->index, cfg->flags); + + if (cfg->flags & CISTPL_CFTABLE_DEFAULT) + dflt = *cfg; + if (cfg->index == 0) + goto next_entry; + link->conf.ConfigIndex = cfg->index; + + /* Does this card need audio output? */ + if (cfg->flags & CISTPL_CFTABLE_AUDIO) { + link->conf.Attributes |= CONF_ENABLE_SPKR; + link->conf.Status = CCSR_AUDIO_ENA; + } + + /* Use power settings for Vcc and Vpp if present */ + /* Note that the CIS values need to be rescaled */ + if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { + if (conf.Vcc != + cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) { + DEBUG(2, "dldwd_cs_config: Vcc mismatch (conf.Vcc = %d, CIS = %d)\n", conf.Vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000); + if(!ignore_cis_vcc) + goto next_entry; + } + } else if (dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) { + if (conf.Vcc != + dflt.vcc.param[CISTPL_POWER_VNOM] / 10000) { + DEBUG(2, "dldwd_cs_config: Vcc mismatch (conf.Vcc = %d, CIS = %d)\n", conf.Vcc, dflt.vcc.param[CISTPL_POWER_VNOM] / 10000); + if(!ignore_cis_vcc) + goto next_entry; + } + } + + if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) + link->conf.Vpp1 = link->conf.Vpp2 = + cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; + else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM)) + link->conf.Vpp1 = link->conf.Vpp2 = + dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000; + + DEBUG(0, "dldwd_cs_config: We seem to have configured Vcc and Vpp\n"); + + /* Do we need to allocate an interrupt? */ + if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) + link->conf.Attributes |= CONF_ENABLE_IRQ; + + /* IO window settings */ + link->io.NumPorts1 = link->io.NumPorts2 = 0; + if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { + cistpl_io_t *io = + (cfg->io.nwin) ? &cfg->io : &dflt.io; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + if (!(io->flags & CISTPL_IO_8BIT)) + link->io.Attributes1 = + IO_DATA_PATH_WIDTH_16; + if (!(io->flags & CISTPL_IO_16BIT)) + link->io.Attributes1 = + IO_DATA_PATH_WIDTH_8; + link->io.IOAddrLines = + io->flags & CISTPL_IO_LINES_MASK; + link->io.BasePort1 = io->win[0].base; + link->io.NumPorts1 = io->win[0].len; + if (io->nwin > 1) { + link->io.Attributes2 = + link->io.Attributes1; + link->io.BasePort2 = io->win[1].base; + link->io.NumPorts2 = io->win[1].len; + } + + /* This reserves IO space but doesn't actually enable it */ + CFG_CHECK(RequestIO, link->handle, &link->io); + } + + + /* If we got this far, we're cool! */ + + break; + + next_entry: + if (link->io.NumPorts1) + CardServices(ReleaseIO, link->handle, &link->io); + CS_CHECK(GetNextTuple, handle, &tuple); + } + + /* + Allocate an interrupt line. Note that this does not assign a + handler to the interrupt, unless the 'Handler' member of the + irq structure is initialized. + */ + if (link->conf.Attributes & CONF_ENABLE_IRQ) { + int i; + + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; + link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID; + if (irq_list[0] == -1) + link->irq.IRQInfo2 = irq_mask; + else + for (i=0; i<4; i++) + link->irq.IRQInfo2 |= 1 << irq_list[i]; + + link->irq.Handler = dldwd_interrupt; + link->irq.Instance = priv; + + CS_CHECK(RequestIRQ, link->handle, &link->irq); + } + + /* We initialize the hermes structure before completing PCMCIA + configuration just in case the interrupt handler gets + called. */ + hermes_struct_init(hw, link->io.BasePort1); + + /* + This actually configures the PCMCIA socket -- setting up + the I/O windows and the interrupt mapping, and putting the + card and host interface into "Memory and IO" mode. + */ + CS_CHECK(RequestConfiguration, link->handle, &link->conf); + + ndev->base_addr = link->io.BasePort1; + ndev->irq = link->irq.AssignedIRQ; + + /* Do a Pcmcia soft reset of the card (optional) */ + if(reset_cor) + dldwd_cs_cor_reset(link); + + /* register_netdev will give us an ethX name */ + ndev->name[0] = '\0'; + /* Tell the stack we exist */ + if (register_netdev(ndev) != 0) { + printk(KERN_ERR "orinoco_cs: register_netdev() failed\n"); + goto failed; + } + strcpy(card->node.dev_name, ndev->name); + + /* Finally, report what we've done */ + printk(KERN_INFO "%s: index 0x%02x: Vcc %d.%d", + ndev->name, link->conf.ConfigIndex, + link->conf.Vcc / 10, link->conf.Vcc % 10); + if (link->conf.Vpp1) + printk(", Vpp %d.%d", link->conf.Vpp1 / 10, + link->conf.Vpp1 % 10); + if (link->conf.Attributes & CONF_ENABLE_IRQ) + printk(", irq %d", link->irq.AssignedIRQ); + if (link->io.NumPorts1) + printk(", io 0x%04x-0x%04x", link->io.BasePort1, + link->io.BasePort1 + link->io.NumPorts1 - 1); + if (link->io.NumPorts2) + printk(" & 0x%04x-0x%04x", link->io.BasePort2, + link->io.BasePort2 + link->io.NumPorts2 - 1); + printk("\n"); + + /* Allow /proc & ioctls to act */ + priv->hw_ready = 1; + + /* And give us the proc nodes for debugging */ + if (dldwd_proc_dev_init(priv) != 0) { + printk(KERN_ERR "orinoco_cs: Failed to create /proc node for %s\n", + ndev->name); + goto failed; + } + + /* Note to myself : this replace MOD_INC_USE_COUNT/MOD_DEC_USE_COUNT */ + SET_MODULE_OWNER(ndev); + + /* + At this point, the dev_node_t structure(s) need to be + initialized and arranged in a linked list at link->dev. + */ + card->node.major = card->node.minor = 0; + link->dev = &card->node; + link->state &= ~DEV_CONFIG_PENDING; + + TRACE_EXIT("dldwd"); + + return; + + cs_failed: + cs_error(link->handle, last_fn, last_ret); + failed: + dldwd_cs_release((u_long) link); + + TRACE_EXIT("dldwd"); +} /* dldwd_cs_config */ + +/*====================================================================== + After a card is removed, dldwd_cs_release() will unregister the + device, and release the PCMCIA configuration. If the device is + still open, this will be postponed until it is closed. + ======================================================================*/ + +static void +dldwd_cs_release(u_long arg) +{ + dev_link_t *link = (dev_link_t *) arg; + dldwd_priv_t *priv = link->priv; + + TRACE_ENTER(link->dev->dev_name); + + /* + If the device is currently in use, we won't release until it + is actually closed, because until then, we can't be sure that + no one will try to access the device or its data structures. + */ + if (link->open) { + DEBUG(0, "orinoco_cs: release postponed, '%s' still open\n", + link->dev->dev_name); + link->state |= DEV_STALE_CONFIG; + return; + } + + /* Unregister proc entry */ + dldwd_proc_dev_cleanup(priv); + + /* Don't bother checking to see if these succeed or not */ + CardServices(ReleaseConfiguration, link->handle); + if (link->io.NumPorts1) + CardServices(ReleaseIO, link->handle, &link->io); + if (link->irq.AssignedIRQ) + CardServices(ReleaseIRQ, link->handle, &link->irq); + link->state &= ~DEV_CONFIG; + + TRACE_EXIT(link->dev->dev_name); +} /* dldwd_cs_release */ + +/*====================================================================== + The card status event handler. Mostly, this schedules other + stuff to run after an event is received. + + When a CARD_REMOVAL event is received, we immediately set a + private flag to block future accesses to this device. All the + functions that actually access the device should check this flag + to make sure the card is still present. + ======================================================================*/ + +static int +dldwd_cs_event(event_t event, int priority, + event_callback_args_t * args) +{ + dev_link_t *link = args->client_data; + dldwd_priv_t *priv = (dldwd_priv_t *)link->priv; + struct net_device *dev = &priv->ndev; + + TRACE_ENTER("dldwd"); + + switch (event) { + case CS_EVENT_CARD_REMOVAL: + priv->hw_ready = 0; + dldwd_shutdown(priv); + link->state &= ~DEV_PRESENT; + if (link->state & DEV_CONFIG) { + netif_stop_queue(dev); + netif_device_detach(dev); + mod_timer(&link->release, jiffies + HZ / 20); + } + break; + case CS_EVENT_CARD_INSERTION: + link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; + dldwd_cs_config(link); + break; + case CS_EVENT_PM_SUSPEND: + + link->state |= DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_RESET_PHYSICAL: + dldwd_shutdown(priv); + /* Mark the device as stopped, to block IO until later */ + + if (link->state & DEV_CONFIG) { + if (link->open) { + netif_stop_queue(dev); + netif_device_detach(dev); + } + CardServices(ReleaseConfiguration, link->handle); + } + break; + case CS_EVENT_PM_RESUME: + link->state &= ~DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_CARD_RESET: + if (link->state & DEV_CONFIG) { + CardServices(RequestConfiguration, link->handle, + &link->conf); + + if (link->open) { + if (dldwd_reset(priv) == 0) { + netif_device_attach(dev); + netif_start_queue(dev); + } else { + printk(KERN_ERR "%s: Error resetting device on PCMCIA event\n", + dev->name); + dldwd_cs_stop(dev); + } + } + } + /* + In a normal driver, additional code may go here to restore + the device state and restart IO. + */ + break; + } + + TRACE_EXIT("dldwd"); + + return 0; +} /* dldwd_cs_event */ + +static int __init +init_dldwd_cs(void) +{ + servinfo_t serv; + + TRACE_ENTER("dldwd"); + + printk(KERN_INFO "dldwd: David's Less Dodgy WaveLAN/IEEE Driver\n"); + + DEBUG(0, "%s\n", version); + + CardServices(GetCardServicesInfo, &serv); + if (serv.Revision != CS_RELEASE_CODE) { + printk(KERN_NOTICE "orinoco_cs: Card Services release " + "does not match!\n"); + return -1; + } + + register_pccard_driver(&dev_info, &dldwd_cs_attach, &dldwd_cs_detach); + + + TRACE_EXIT("dldwd"); + return 0; +} + +static void __exit +exit_dldwd_cs(void) +{ + TRACE_ENTER("dldwd"); + + unregister_pccard_driver(&dev_info); + + if (dev_list) + DEBUG(0, "orinoco_cs: Removing leftover devices.\n"); + while (dev_list != NULL) { + del_timer(&dev_list->release); + if (dev_list->state & DEV_CONFIG) + dldwd_cs_release((u_long) dev_list); + dldwd_cs_detach(dev_list); + } + + TRACE_EXIT("dldwd"); +} + +module_init(init_dldwd_cs); +module_exit(exit_dldwd_cs); diff -Nru a/drivers/net/wireless/todo.txt b/drivers/net/wireless/todo.txt --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/todo.txt Wed May 16 06:00:34 2001 @@ -0,0 +1,24 @@ + Wireless Todo + ------------- + +1) Bring other kernel Wireless LAN drivers here + Already done : + o hermes.c/orinoco.c -> Wavelan IEEE driver + Airport driver + Drivers I have control over : + o wavelan.c -> old Wavelan ISA driver + o wavelan_cs.c -> old Wavelan Pcmcia driver (warning : header) + o netwave_cs.c -> Netwave Pcmcia driver + Drivers likely to go : + o ray_cs.c -> Raytheon/Aviator driver (maintainer MIA) + Drivers I have absolutely no control over : + o arlan.c -> old Aironet Arlan 655 (need to ask Elmer) + o aironet4500_xxx.c -> Elmer's Aironet driver (need to ask Elmer) + o airo.c/airo_cs.c -> Ben's Aironet driver (not yet in kernel) + o strip.c -> Metricom's stuff. Not a wlan. Hum... + + ETA : Kernel 2.5.X + +2) Bring new Wireless LAN driver not yet in the kernel there + See my web page for details + + Jean II diff -Nru a/drivers/pci/Makefile b/drivers/pci/Makefile --- a/drivers/pci/Makefile Wed May 16 06:00:24 2001 +++ b/drivers/pci/Makefile Wed May 16 06:00:24 2001 @@ -22,6 +22,7 @@ obj-$(CONFIG_ALPHA) += setup-bus.o setup-irq.o obj-$(CONFIG_ARM) += setup-bus.o setup-irq.o obj-$(CONFIG_SUPERH) += setup-bus.o setup-irq.o +obj-$(CONFIG_PPC) += setup-bus.o setup-irq.o ifndef CONFIG_X86 obj-y += syscall.o diff -Nru a/drivers/pci/pci.ids b/drivers/pci/pci.ids --- a/drivers/pci/pci.ids Wed May 16 06:00:23 2001 +++ b/drivers/pci/pci.ids Wed May 16 06:00:23 2001 @@ -1069,6 +1069,13 @@ 000e Hydra Mac I/O 0010 Heathrow Mac I/O 0017 Paddington Mac I/O + 0018 UniNorth FireWire + 0019 KeyLargo USB + 001e UniNorth PCI + 001f UniNorth PCI + 0020 UniNorth AGP + 0021 UniNorth GMAC + 0022 KeyLargo Mac I/O 106c Hyundai Electronics America 8801 Dual Pentium ISA/PCI Motherboard 8802 PowerPC ISA/PCI Motherboard diff -Nru a/drivers/sbus/char/su.c b/drivers/sbus/char/su.c --- a/drivers/sbus/char/su.c Wed May 16 06:00:20 2001 +++ b/drivers/sbus/char/su.c Wed May 16 06:00:20 2001 @@ -1,4 +1,4 @@ -/* $Id: su.c,v 1.47 2001/04/18 21:06:15 davem Exp $ +/* $Id: su.c,v 1.48 2001/04/27 07:02:42 davem Exp $ * su.c: Small serial driver for keyboard/mouse interface on sparc32/PCI * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -2220,7 +2220,7 @@ */ static __inline__ void __init show_su_version(void) { - char *revision = "$Revision: 1.47 $"; + char *revision = "$Revision: 1.48 $"; char *version, *p; version = strchr(revision, ' '); diff -Nru a/drivers/sbus/char/zs.c b/drivers/sbus/char/zs.c --- a/drivers/sbus/char/zs.c Wed May 16 06:00:20 2001 +++ b/drivers/sbus/char/zs.c Wed May 16 06:00:20 2001 @@ -1,4 +1,4 @@ -/* $Id: zs.c,v 1.63 2001/04/17 06:30:36 davem Exp $ +/* $Id: zs.c,v 1.64 2001/04/27 07:02:42 davem Exp $ * zs.c: Zilog serial port driver for the Sparc. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -1922,7 +1922,7 @@ static void show_serial_version(void) { - char *revision = "$Revision: 1.63 $"; + char *revision = "$Revision: 1.64 $"; char *version, *p; version = strchr(revision, ' '); diff -Nru a/drivers/scsi/Makefile b/drivers/scsi/Makefile --- a/drivers/scsi/Makefile Wed May 16 06:00:17 2001 +++ b/drivers/scsi/Makefile Wed May 16 06:00:17 2001 @@ -6,6 +6,12 @@ # # 20 Sep 2000, Torben Mathiasen # Changed link order to reflect new scsi initialization. +# +# *!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*! +# The link order must be, SCSI Core, SCSI HBA drivers, and +# lastly SCSI peripheral drivers (disk/tape/cdrom/etc.) to +# satisfy certain initialization assumptions in the SCSI layer. +# *!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*! O_TARGET := scsidrv.o @@ -64,6 +70,9 @@ obj-$(CONFIG_SCSI_AHA152X) += aha152x.o obj-$(CONFIG_SCSI_AHA1542) += aha1542.o obj-$(CONFIG_SCSI_AHA1740) += aha1740.o +ifeq ($(CONFIG_SCSI_AIC7XXX),y) +obj-$(CONFIG_SCSI_AIC7XXX) += aic7xxx/aic7xxx_drv.o +endif obj-$(CONFIG_SCSI_AIC7XXX_OLD) += aic7xxx_old.o obj-$(CONFIG_SCSI_IPS) += ips.o obj-$(CONFIG_SCSI_FD_MCS) += fd_mcs.o diff -Nru a/drivers/scsi/aic7xxx/Config.in b/drivers/scsi/aic7xxx/Config.in --- a/drivers/scsi/aic7xxx/Config.in Wed May 16 06:00:18 2001 +++ b/drivers/scsi/aic7xxx/Config.in Wed May 16 06:00:18 2001 @@ -2,6 +2,7 @@ dep_tristate 'Adaptec AIC7xxx support' CONFIG_SCSI_AIC7XXX $CONFIG_SCSI if [ "$CONFIG_SCSI_AIC7XXX" != "n" ]; then int ' Maximum number of TCQ commands per device' CONFIG_AIC7XXX_CMDS_PER_DEVICE 253 - int ' Initial bus reset delay in milli-seconds' CONFIG_AIC7XXX_RESET_DELAY 5000 + int ' Initial bus reset delay in milli-seconds' CONFIG_AIC7XXX_RESET_DELAY_MS 15000 + bool ' Build Adapter Firmware with Kernel Build' CONFIG_AIC7XXX_BUILD_FIRMWARE fi fi diff -Nru a/drivers/scsi/aic7xxx/Makefile b/drivers/scsi/aic7xxx/Makefile --- a/drivers/scsi/aic7xxx/Makefile Wed May 16 06:00:20 2001 +++ b/drivers/scsi/aic7xxx/Makefile Wed May 16 06:00:20 2001 @@ -4,7 +4,7 @@ # Makefile for the Linux aic7xxx SCSI driver. # -O_TARGET = aic7xxx_drv.o +O_TARGET := aic7xxx_drv.o list-multi := aic7xxx_mod.o @@ -25,8 +25,13 @@ aic7xxx_mod.o: aic7xxx_seq.h aic7xxx_reg.h $(AIC7XXX_OBJS) $(LD) $(LD_RFLAG) -r -o $@ $(AIC7XXX_OBJS) +ifeq ($(CONFIG_AIC7XXX_BUILD_FIRMWARE),y) aic7xxx_seq.h aic7xxx_reg.h: aic7xxx.seq aic7xxx.reg aicasm/aicasm aicasm/aicasm -I. -r aic7xxx_reg.h -o aic7xxx_seq.h aic7xxx.seq +else +aic7xxx_seq.h aic7xxx_reg.h: aic7xxx.seq aic7xxx.reg + echo "Warning, generated aic7xxx firmware files may be out of date!\n" +endif aicasm/aicasm: aicasm/*.[chyl] $(MAKE) -C aicasm diff -Nru a/drivers/scsi/aic7xxx/aic7770.c b/drivers/scsi/aic7xxx/aic7770.c --- a/drivers/scsi/aic7xxx/aic7770.c Wed May 16 06:00:18 2001 +++ b/drivers/scsi/aic7xxx/aic7770.c Wed May 16 06:00:18 2001 @@ -29,7 +29,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: //depot/src/aic7xxx/aic7770.c#6 $ + * $Id: //depot/src/aic7xxx/aic7770.c#11 $ * * $FreeBSD: src/sys/dev/aic7xxx/aic7770.c,v 1.1 2000/09/16 20:02:27 gibbs Exp $ */ @@ -95,8 +95,6 @@ u_int hostconf; u_int irq; u_int intdef; - u_int hcntrl; - int shared; ahc_init_probe_config(&probe_config); error = entry->setup(ahc->dev_softc, &probe_config); @@ -107,15 +105,15 @@ if (error != 0) return (error); - /* Pause the card preseving the IRQ type */ - hcntrl = ahc_inb(ahc, HCNTRL) & IRQMS; - ahc_outb(ahc, HCNTRL, hcntrl | PAUSE); - while ((ahc_inb(ahc, HCNTRL) & PAUSE) == 0) - ; + probe_config.description = entry->name; + error = ahc_softc_init(ahc, &probe_config); + + error = ahc_reset(ahc); + if (error != 0) + return (error); /* Make sure we have a valid interrupt vector */ intdef = ahc_inb(ahc, INTDEF); - shared = (intdef & EDGE_TRIG) ? 0 : 1; irq = intdef & VECTOR; switch (irq) { case 9: @@ -130,16 +128,8 @@ return (ENXIO); } - probe_config.description = entry->name; - error = ahc_softc_init(ahc, &probe_config); - - error = aic7770_map_int(ahc, irq, shared); - if (error != 0) - return (error); - - error = ahc_reset(ahc); - if (error != 0) - return (error); + if ((intdef & EDGE_TRIG) != 0) + ahc->flags |= AHC_EDGE_INTERRUPT; switch (probe_config.chip & (AHC_EISA|AHC_VL)) { case AHC_EISA: @@ -154,7 +144,7 @@ /* Get the primary channel information */ if ((biosctrl & CHANNEL_B_PRIMARY) != 0) - ahc->flags |= AHC_CHANNEL_B_PRIMARY; + ahc->flags |= 1; if ((biosctrl & BIOSMODE) == BIOSDISABLED) { ahc->flags |= AHC_USEDEFAULTS; @@ -210,10 +200,19 @@ */ ahc_softc_insert(ahc); + error = aic7770_map_int(ahc, irq); + if (error != 0) + return (error); + /* * Enable the board's BUS drivers */ ahc_outb(ahc, BCTL, ENABLE); + + /* + * Allow interrupts. + */ + ahc_intr_enable(ahc, TRUE); return (0); } diff -Nru a/drivers/scsi/aic7xxx/aic7770_linux.c b/drivers/scsi/aic7xxx/aic7770_linux.c --- a/drivers/scsi/aic7xxx/aic7770_linux.c Wed May 16 06:00:20 2001 +++ b/drivers/scsi/aic7xxx/aic7770_linux.c Wed May 16 06:00:20 2001 @@ -28,7 +28,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7770_linux.c#5 $ + * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7770_linux.c#7 $ */ #include "aic7xxx_osm.h" @@ -128,19 +128,18 @@ } int -aic7770_map_int(struct ahc_softc *ahc, u_int irq, int shared) +aic7770_map_int(struct ahc_softc *ahc, u_int irq) { int error; + int shared; - if (shared) + shared = 0; + if ((ahc->flags & AHC_EDGE_INTERRUPT) == 0) shared = SA_SHIRQ; ahc->platform_data->irq = irq; - error = request_irq(ahc->platform_data->irq, aic7xxx_isr, - SA_INTERRUPT|shared, "aic7xxx", ahc); - if (error < 0) - error = request_irq(ahc->platform_data->irq, aic7xxx_isr, - shared, "aic7xxx", ahc); + error = request_irq(ahc->platform_data->irq, ahc_linux_isr, + shared, "aic7xxx", ahc); return (-error); } diff -Nru a/drivers/scsi/aic7xxx/aic7xxx.c b/drivers/scsi/aic7xxx/aic7xxx.c --- a/drivers/scsi/aic7xxx/aic7xxx.c Wed May 16 06:00:19 2001 +++ b/drivers/scsi/aic7xxx/aic7xxx.c Wed May 16 06:00:19 2001 @@ -28,7 +28,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: //depot/src/aic7xxx/aic7xxx.c#32 $ + * $Id: //depot/src/aic7xxx/aic7xxx.c#39 $ * * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.c,v 1.61 2000/11/13 03:35:43 gibbs Exp $ */ @@ -58,9 +58,17 @@ "aic7892", "aic7899" }; -const u_int num_chip_names = NUM_ELEMENTS(ahc_chip_names); +static const u_int num_chip_names = NUM_ELEMENTS(ahc_chip_names); -struct hard_error_entry hard_error[] = { +/* + * Hardware error codes. + */ +struct ahc_hard_error_entry { + uint8_t errno; + char *errmesg; +}; + +static struct ahc_hard_error_entry ahc_hard_errors[] = { { ILLHADDR, "Illegal Host Access" }, { ILLSADDR, "Illegal Sequencer Address referrenced" }, { ILLOPCODE, "Illegal Opcode in sequencer program" }, @@ -70,9 +78,9 @@ { PCIERRSTAT, "PCI Error detected" }, { CIOPARERR, "CIOBUS Parity Error" }, }; -const u_int num_errors = NUM_ELEMENTS(hard_error); +static const u_int num_errors = NUM_ELEMENTS(ahc_hard_errors); -struct phase_table_entry phase_table[] = +static struct ahc_phase_table_entry ahc_phase_table[] = { { P_DATAOUT, MSG_NOOP, "in Data-out phase" }, { P_DATAIN, MSG_INITIATOR_DET_ERR, "in Data-in phase" }, @@ -90,14 +98,14 @@ * In most cases we only wish to itterate over real phases, so * exclude the last element from the count. */ -const u_int num_phases = NUM_ELEMENTS(phase_table) - 1; +static const u_int num_phases = NUM_ELEMENTS(ahc_phase_table) - 1; /* * Valid SCSIRATE values. (p. 3-17) * Provides a mapping of tranfer periods in ns to the proper value to * stick in the scsixfer reg. */ -struct ahc_syncrate ahc_syncrates[] = +static struct ahc_syncrate ahc_syncrates[] = { /* ultra2 fast/ultra period rate */ { 0x42, 0x000, 9, "80.0" }, @@ -121,7 +129,7 @@ #include "aic7xxx_seq.h" /**************************** Function Declarations ***************************/ -static struct tmode_tstate* +static struct ahc_tmode_tstate* ahc_alloc_tstate(struct ahc_softc *ahc, u_int scsi_id, char channel); #ifdef AHC_TARGET_MODE @@ -134,12 +142,13 @@ u_int *period, u_int *ppr_options, role_t role); -static void ahc_update_pending_syncrates(struct ahc_softc *ahc); +static void ahc_update_pending_scbs(struct ahc_softc *ahc); static void ahc_fetch_devinfo(struct ahc_softc *ahc, struct ahc_devinfo *devinfo); static void ahc_scb_devinfo(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, struct scb *scb); +static void ahc_assert_atn(struct ahc_softc *ahc); static void ahc_setup_initiator_msgout(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, struct scb *scb); @@ -174,6 +183,11 @@ struct ahc_devinfo *devinfo, cam_status status, char *message, int verbose_level); +#if AHC_TARGET_MODE +static void ahc_setup_target_msgin(struct ahc_softc *ahc, + struct ahc_devinfo *devinfo, + struct scb *scb); +#endif static bus_dmamap_callback_t ahc_dmamap_cb; static void ahc_build_free_scb_list(struct ahc_softc *ahc); @@ -192,7 +206,6 @@ char channel, int lun, u_int tag, role_t role, uint32_t status); static void ahc_reset_current_bus(struct ahc_softc *ahc); -static void ahc_calc_residual(struct scb *scb); #ifdef AHC_DUMP_SEQ static void ahc_dumpseq(struct ahc_softc *ahc); #endif @@ -204,7 +217,7 @@ u_int instrptr, uint8_t *dconsts); #ifdef AHC_TARGET_MODE static void ahc_queue_lstate_event(struct ahc_softc *ahc, - struct tmode_lstate *lstate, + struct ahc_tmode_lstate *lstate, u_int initiator_id, u_int event_type, u_int event_arg); @@ -218,10 +231,10 @@ * Restart the sequencer program from address zero */ void -restart_sequencer(struct ahc_softc *ahc) +ahc_restart(struct ahc_softc *ahc) { - pause_sequencer(ahc); + ahc_pause(ahc); ahc_outb(ahc, SCSISIGO, 0); /* De-assert BSY */ ahc_outb(ahc, MSG_OUT, MSG_NOOP); /* No message to send */ @@ -259,7 +272,7 @@ ahc_outb(ahc, SEQCTL, FASTMODE); ahc_outb(ahc, SEQADDR0, 0); ahc_outb(ahc, SEQADDR1, 0); - unpause_sequencer(ahc); + ahc_unpause(ahc); } /************************* Input/Output Queues ********************************/ @@ -300,10 +313,7 @@ * Save off the residual * if there is one. */ - if (ahc_check_residual(scb) != 0) - ahc_calc_residual(scb); - else - ahc_set_residual(scb, 0); + ahc_update_residual(scb); ahc_done(ahc, scb); } } @@ -340,14 +350,14 @@ * We upset the sequencer :-( * Lookup the error message */ - int i, error, num_errors; + int i; + int error; error = ahc_inb(ahc, ERROR); - num_errors = sizeof(hard_error)/sizeof(hard_error[0]); for (i = 0; error != 1 && i < num_errors; i++) error >>= 1; printf("%s: brkadrint, %s at seqaddr = 0x%x\n", - ahc_name(ahc), hard_error[i].errmesg, + ahc_name(ahc), ahc_hard_errors[i].errmesg, ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8)); @@ -436,6 +446,12 @@ break; case SCSI_STATUS_CMD_TERMINATED: case SCSI_STATUS_CHECK_COND: + { + struct ahc_dma_seg *sg; + struct scsi_sense *sc; + struct ahc_initiator_tinfo *targ_info; + struct ahc_tmode_tstate *tstate; + struct ahc_transinfo *tinfo; #ifdef AHC_DEBUG if (ahc_debug & AHC_SHOWSENSE) { ahc_print_path(ahc, scb); @@ -444,99 +460,94 @@ } #endif - if (ahc_perform_autosense(scb)) { - struct ahc_dma_seg *sg; - struct scsi_sense *sc; - struct ahc_initiator_tinfo *targ_info; - struct tmode_tstate *tstate; - struct ahc_transinfo *tinfo; + if (ahc_perform_autosense(scb) == 0) + break; - targ_info = - ahc_fetch_transinfo(ahc, + targ_info = ahc_fetch_transinfo(ahc, devinfo.channel, devinfo.our_scsiid, devinfo.target, &tstate); - tinfo = &targ_info->current; - sg = scb->sg_list; - sc = (struct scsi_sense *) - (&hscb->shared_data.cdb); - /* - * Save off the residual if there is one. - */ - if (ahc_check_residual(scb)) - ahc_calc_residual(scb); - else - ahc_set_residual(scb, 0); + tinfo = &targ_info->curr; + sg = scb->sg_list; + sc = (struct scsi_sense *)(&hscb->shared_data.cdb); + /* + * Save off the residual if there is one. + */ + ahc_update_residual(scb); #ifdef AHC_DEBUG - if (ahc_debug & AHC_SHOWSENSE) { - ahc_print_path(ahc, scb); - printf("Sending Sense\n"); - } + if (ahc_debug & AHC_SHOWSENSE) { + ahc_print_path(ahc, scb); + printf("Sending Sense\n"); + } #endif - sg->addr = ahc_get_sense_bufaddr(ahc, scb); - sg->len = ahc_get_sense_bufsize(ahc, scb); - sg->len |= AHC_DMA_LAST_SEG; - - /* Fixup byte order */ - sg->addr = ahc_htole32(sg->addr); - sg->len = ahc_htole32(sg->len); - - sc->opcode = REQUEST_SENSE; - sc->byte2 = 0; - if (tinfo->protocol_version <= SCSI_REV_2 - && SCB_GET_LUN(scb) < 8) - sc->byte2 = SCB_GET_LUN(scb) << 5; - sc->unused[0] = 0; - sc->unused[1] = 0; - sc->length = sg->len; - sc->control = 0; + sg->addr = ahc_get_sense_bufaddr(ahc, scb); + sg->len = ahc_get_sense_bufsize(ahc, scb); + sg->len |= AHC_DMA_LAST_SEG; + + /* Fixup byte order */ + sg->addr = ahc_htole32(sg->addr); + sg->len = ahc_htole32(sg->len); + + sc->opcode = REQUEST_SENSE; + sc->byte2 = 0; + if (tinfo->protocol_version <= SCSI_REV_2 + && SCB_GET_LUN(scb) < 8) + sc->byte2 = SCB_GET_LUN(scb) << 5; + sc->unused[0] = 0; + sc->unused[1] = 0; + sc->length = sg->len; + sc->control = 0; - /* - * XXX Still true??? - * Would be nice to preserve DISCENB here, - * but due to the way we manage busy targets, - * we can't. - */ - hscb->control = 0; + /* + * We can't allow the target to disconnect. + * This will be an untagged transaction and + * having the target disconnect will make this + * transaction indestinguishable from outstanding + * tagged transactions. + */ + hscb->control = 0; - /* - * This request sense could be because the - * the device lost power or in some other - * way has lost our transfer negotiations. - * Renegotiate if appropriate. Unit attention - * errors will be reported before any data - * phases occur. - */ - if (ahc_get_residual(scb) - == ahc_get_transfer_length(scb)) { - ahc_update_target_msg_request(ahc, - &devinfo, - targ_info, - /*force*/TRUE, - /*paused*/TRUE); - } - hscb->cdb_len = sizeof(*sc); - hscb->dataptr = sg->addr; - hscb->datacnt = sg->len; - hscb->sgptr = scb->sg_list_phys | SG_FULL_RESID; - hscb->sgptr = ahc_htole32(hscb->sgptr); - scb->sg_count = 1; - scb->flags |= SCB_SENSE; - ahc_qinfifo_requeue_tail(ahc, scb); - ahc_outb(ahc, RETURN_1, SEND_SENSE); + /* + * This request sense could be because the + * the device lost power or in some other + * way has lost our transfer negotiations. + * Renegotiate if appropriate. Unit attention + * errors will be reported before any data + * phases occur. + */ + if (ahc_get_residual(scb) + == ahc_get_transfer_length(scb)) { + ahc_update_neg_request(ahc, &devinfo, + tstate, targ_info, + /*force*/TRUE); + } + if (tstate->auto_negotiate & devinfo.target_mask) { + hscb->control |= MK_MESSAGE; + scb->flags &= ~SCB_NEGOTIATE; + scb->flags |= SCB_AUTO_NEGOTIATE; + } + hscb->cdb_len = sizeof(*sc); + hscb->dataptr = sg->addr; + hscb->datacnt = sg->len; + hscb->sgptr = scb->sg_list_phys | SG_FULL_RESID; + hscb->sgptr = ahc_htole32(hscb->sgptr); + scb->sg_count = 1; + scb->flags |= SCB_SENSE; + ahc_qinfifo_requeue_tail(ahc, scb); + ahc_outb(ahc, RETURN_1, SEND_SENSE); #ifdef __FreeBSD__ - /* - * Ensure we have enough time to actually - * retrieve the sense. - */ - untimeout(ahc_timeout, (caddr_t)scb, - scb->io_ctx->ccb_h.timeout_ch); - scb->io_ctx->ccb_h.timeout_ch = - timeout(ahc_timeout, (caddr_t)scb, 5 * hz); + /* + * Ensure we have enough time to actually + * retrieve the sense. + */ + untimeout(ahc_timeout, (caddr_t)scb, + scb->io_ctx->ccb_h.timeout_ch); + scb->io_ctx->ccb_h.timeout_ch = + timeout(ahc_timeout, (caddr_t)scb, 5 * hz); #endif - } break; + } default: break; } @@ -577,7 +588,7 @@ ahc->msgout_index = 0; ahc->msg_type = MSG_TYPE_INITIATOR_MSGOUT; ahc_outb(ahc, MSG_OUT, HOST_MSG); - ahc_outb(ahc, SCSISIGO, ahc_inb(ahc, LASTPHASE) | ATNO); + ahc_assert_atn(ahc); break; } case SEND_REJECT: @@ -633,7 +644,7 @@ "Lastphase = 0x%x, Curphase = 0x%x\n", ahc_name(ahc), devinfo.channel, devinfo.target, lastphase, ahc_inb(ahc, SCSISIGI)); - restart_sequencer(ahc); + ahc_restart(ahc); return; } case HOST_MSG_LOOP: @@ -650,6 +661,8 @@ * loop. */ if (ahc->msg_type == MSG_TYPE_NONE) { + struct scb *scb; + u_int scb_index; u_int bus_phase; bus_phase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK; @@ -663,17 +676,13 @@ * we got here. Just punt the message. */ ahc_clear_intstat(ahc); - restart_sequencer(ahc); + ahc_restart(ahc); return; } + scb_index = ahc_inb(ahc, SCB_TAG); + scb = ahc_lookup_scb(ahc, scb_index); if (devinfo.role == ROLE_INITIATOR) { - struct scb *scb; - u_int scb_index; - - scb_index = ahc_inb(ahc, SCB_TAG); - scb = ahc_lookup_scb(ahc, scb_index); - if (scb == NULL) panic("HOST_MSG_LOOP with " "invalid SCB %x\n", scb_index); @@ -695,7 +704,9 @@ } #if AHC_TARGET_MODE else - ahc_setup_target_msgin(ahc, &devinfo); + ahc_setup_target_msgin(ahc, + &devinfo, + scb); #endif } } @@ -718,17 +729,20 @@ */ if ((intstat & SCSIINT) == 0 && (ahc_inb(ahc, SSTAT1) & SCSIPERR) != 0) { - u_int curphase; - /* - * The hardware will only let you ack bytes - * if the expected phase in SCSISIGO matches - * the current phase. Make sure this is - * currently the case. - */ - curphase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK; - ahc_outb(ahc, LASTPHASE, curphase); - ahc_outb(ahc, SCSISIGO, curphase); + if ((ahc->features & AHC_DT) == 0) { + u_int curphase; + + /* + * The hardware will only let you ack bytes + * if the expected phase in SCSISIGO matches + * the current phase. Make sure this is + * currently the case. + */ + curphase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK; + ahc_outb(ahc, LASTPHASE, curphase); + ahc_outb(ahc, SCSISIGO, curphase); + } ahc_inb(ahc, SCSIDATL); } break; @@ -749,13 +763,13 @@ scb = ahc_lookup_scb(ahc, scbindex); for (i = 0; i < num_phases; i++) { - if (lastphase == phase_table[i].phase) + if (lastphase == ahc_phase_table[i].phase) break; } ahc_print_path(ahc, scb); printf("data overrun detected %s." " Tag == 0x%x.\n", - phase_table[i].phasemsg, + ahc_phase_table[i].phasemsg, scb->hscb->tag); ahc_print_path(ahc, scb); printf("%s seen Data Phase. Length = %ld. NumSGs = %d.\n", @@ -858,7 +872,7 @@ * a SEQINT, so we should restart it when * we're done. */ - unpause_sequencer(ahc); + ahc_unpause(ahc); } void @@ -897,7 +911,7 @@ if (status == 0) { printf("%s: Spurious SCSI interrupt\n", ahc_name(ahc)); ahc_outb(ahc, CLRINT, CLRSCSIINT); - unpause_sequencer(ahc); + ahc_unpause(ahc); return; } } @@ -975,10 +989,10 @@ errorphase = lastphase; for (i = 0; i < num_phases; i++) { - if (errorphase == phase_table[i].phase) + if (errorphase == ahc_phase_table[i].phase) break; } - mesg_out = phase_table[i].mesg_out; + mesg_out = ahc_phase_table[i].mesg_out; if (scb != NULL) ahc_print_path(ahc, scb); else @@ -987,7 +1001,7 @@ scsirate = ahc_inb(ahc, SCSIRATE); printf("parity error detected %s. " "SEQADDR(0x%x) SCSIRATE(0x%x)\n", - phase_table[i].phasemsg, + ahc_phase_table[i].phasemsg, ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8), scsirate); @@ -1018,7 +1032,45 @@ ahc_outb(ahc, MSG_OUT, mesg_out); } ahc_outb(ahc, CLRINT, CLRSCSIINT); - unpause_sequencer(ahc); + ahc_unpause(ahc); + } else if ((status & SELTO) != 0) { + u_int scbptr; + + /* Stop the selection */ + ahc_outb(ahc, SCSISEQ, 0); + + /* No more pending messages */ + ahc_clear_msg_state(ahc); + + /* Clear interrupt state */ + ahc_outb(ahc, SIMODE1, ahc_inb(ahc, SIMODE1) & ~ENBUSFREE); + ahc_outb(ahc, CLRSINT1, CLRSELTIMEO|CLRBUSFREE|CLRSCSIPERR); + + /* + * Although the driver does not care about the + * 'Selection in Progress' status bit, the busy + * LED does. SELINGO is only cleared by a sucessful + * selection, so we must manually clear it to insure + * the LED turns off just incase no future successful + * selections occur (e.g. no devices on the bus). + */ + ahc_outb(ahc, CLRSINT0, CLRSELINGO); + + scbptr = ahc_inb(ahc, WAITING_SCBH); + ahc_outb(ahc, SCBPTR, scbptr); + scb_index = ahc_inb(ahc, SCB_TAG); + + scb = ahc_lookup_scb(ahc, scb_index); + if (scb == NULL) { + printf("%s: ahc_intr - referenced scb not " + "valid during SELTO scb(%d, %d)\n", + ahc_name(ahc), scbptr, scb_index); + } else { + ahc_set_transaction_status(scb, CAM_SEL_TIMEOUT); + ahc_freeze_devq(ahc, scb); + } + ahc_outb(ahc, CLRINT, CLRSCSIINT); + ahc_restart(ahc); } else if ((status & BUSFREE) != 0 && (ahc_inb(ahc, SIMODE1) & ENBUSFREE) != 0) { u_int lastphase; @@ -1113,7 +1165,7 @@ } else if (ahc_sent_msg(ahc, AHCMSG_EXT, MSG_EXT_PPR, FALSE)) { struct ahc_initiator_tinfo *tinfo; - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *tstate; /* * PPR Rejected. Try non-ppr negotiation @@ -1124,7 +1176,7 @@ devinfo.our_scsiid, devinfo.target, &tstate); - tinfo->current.transport_version = 2; + tinfo->curr.transport_version = 2; tinfo->goal.transport_version = 2; tinfo->goal.ppr_options = 0; ahc_qinfifo_requeue_tail(ahc, scb); @@ -1174,54 +1226,18 @@ printf("%s: ", ahc_name(ahc)); } for (i = 0; i < num_phases; i++) { - if (lastphase == phase_table[i].phase) + if (lastphase == ahc_phase_table[i].phase) break; } printf("Unexpected busfree %s\n" "SEQADDR == 0x%x\n", - phase_table[i].phasemsg, ahc_inb(ahc, SEQADDR0) + ahc_phase_table[i].phasemsg, + ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8)); } ahc_clear_msg_state(ahc); ahc_outb(ahc, CLRINT, CLRSCSIINT); - restart_sequencer(ahc); - } else if ((status & SELTO) != 0) { - u_int scbptr; - - /* Stop the selection */ - ahc_outb(ahc, SCSISEQ, 0); - - /* No more pending messages */ - ahc_clear_msg_state(ahc); - - /* Clear interrupt state */ - ahc_outb(ahc, CLRSINT1, CLRSELTIMEO|CLRBUSFREE|CLRSCSIPERR); - - /* - * Although the driver does not care about the - * 'Selection in Progress' status bit, the busy - * LED does. SELINGO is only cleared by a sucessful - * selection, so we must manually clear it to insure - * the LED turns off just incase no future successful - * selections occur (e.g. no devices on the bus). - */ - ahc_outb(ahc, CLRSINT0, CLRSELINGO); - - scbptr = ahc_inb(ahc, WAITING_SCBH); - ahc_outb(ahc, SCBPTR, scbptr); - scb_index = ahc_inb(ahc, SCB_TAG); - - scb = ahc_lookup_scb(ahc, scb_index); - if (scb == NULL) { - printf("%s: ahc_intr - referenced scb not " - "valid during SELTO scb(%d, %d)\n", - ahc_name(ahc), scbptr, scb_index); - } else { - ahc_set_transaction_status(scb, CAM_SEL_TIMEOUT); - ahc_freeze_devq(ahc, scb); - } - ahc_outb(ahc, CLRINT, CLRSCSIINT); - restart_sequencer(ahc); + ahc_restart(ahc); } else { printf("%s: Missing case in ahc_handle_scsiint. status = %x\n", ahc_name(ahc), status); @@ -1290,7 +1306,7 @@ ahc_outb(ahc, HCNTRL, ahc->unpause); do { ahc_delay(200); - } while (!sequencer_paused(ahc)); + } while (!ahc_is_paused(ahc)); } if (stepping) { ahc_outb(ahc, SIMODE0, simode0); @@ -1363,11 +1379,11 @@ * Allocate per target mode instance (ID we respond to as a target) * transfer negotiation data structures. */ -static struct tmode_tstate * +static struct ahc_tmode_tstate * ahc_alloc_tstate(struct ahc_softc *ahc, u_int scsi_id, char channel) { - struct tmode_tstate *master_tstate; - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *master_tstate; + struct ahc_tmode_tstate *tstate; int i; master_tstate = ahc->enabled_targets[ahc->our_id]; @@ -1394,8 +1410,8 @@ memset(tstate->enabled_luns, 0, sizeof(tstate->enabled_luns)); tstate->ultraenb = 0; for (i = 0; i < 16; i++) { - memset(&tstate->transinfo[i].current, 0, - sizeof(tstate->transinfo[i].current)); + memset(&tstate->transinfo[i].curr, 0, + sizeof(tstate->transinfo[i].curr)); memset(&tstate->transinfo[i].goal, 0, sizeof(tstate->transinfo[i].goal)); } @@ -1413,11 +1429,13 @@ static void ahc_free_tstate(struct ahc_softc *ahc, u_int scsi_id, char channel, int force) { - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *tstate; - /* Don't clean up the entry for our initiator role */ - if ((ahc->flags & AHC_INITIATORROLE) != 0 - && ((channel == 'B' && scsi_id == ahc->our_id_b) + /* + * Don't clean up our "master" tstate. + * It has our default user settings. + */ + if (((channel == 'B' && scsi_id == ahc->our_id_b) || (channel == 'A' && scsi_id == ahc->our_id)) && force == FALSE) return; @@ -1496,6 +1514,11 @@ if ((ahc->features & AHC_DT) == 0) *ppr_options &= ~MSG_EXT_PPR_DT_REQ; + + /* Skip all DT only entries if DT is not available */ + if ((*ppr_options & MSG_EXT_PPR_DT_REQ) == 0 + && maxsync < AHC_SYNCRATE_ULTRA2) + maxsync = AHC_SYNCRATE_ULTRA2; for (syncrate = &ahc_syncrates[maxsync]; syncrate->rate != NULL; @@ -1509,11 +1532,6 @@ && (syncrate->sxfr_u2 == 0)) break; - /* Skip any DT entries if DT is not available */ - if ((*ppr_options & MSG_EXT_PPR_DT_REQ) == 0 - && (syncrate->sxfr_u2 & DT_SXFR) != 0) - continue; - if (*period <= syncrate->period) { /* * When responding to a target that requests @@ -1647,44 +1665,31 @@ * means the next time we send the initial identify messages for * a new transaction. */ -void -ahc_update_target_msg_request(struct ahc_softc *ahc, - struct ahc_devinfo *devinfo, - struct ahc_initiator_tinfo *tinfo, - int force, int paused) -{ - u_int targ_msg_req_orig; - - targ_msg_req_orig = ahc->targ_msg_req; - if (tinfo->current.period != tinfo->goal.period - || tinfo->current.width != tinfo->goal.width - || tinfo->current.offset != tinfo->goal.offset - || tinfo->current.ppr_options != tinfo->goal.ppr_options +int +ahc_update_neg_request(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, + struct ahc_tmode_tstate *tstate, + struct ahc_initiator_tinfo *tinfo, int force) +{ + u_int auto_negotiate_orig; + + auto_negotiate_orig = tstate->auto_negotiate; + if (tinfo->curr.period != tinfo->goal.period + || tinfo->curr.width != tinfo->goal.width + || tinfo->curr.offset != tinfo->goal.offset + || tinfo->curr.ppr_options != tinfo->goal.ppr_options || (force && (tinfo->goal.period != 0 || tinfo->goal.width != MSG_EXT_WDTR_BUS_8_BIT || tinfo->goal.ppr_options != 0))) - ahc->targ_msg_req |= devinfo->target_mask; + tstate->auto_negotiate |= devinfo->target_mask; else - ahc->targ_msg_req &= ~devinfo->target_mask; + tstate->auto_negotiate &= ~devinfo->target_mask; - if (ahc->targ_msg_req != targ_msg_req_orig) { - /* Update the message request bit for this target */ - if (!paused) - pause_sequencer(ahc); - - ahc_outb(ahc, TARGET_MSG_REQUEST, - ahc->targ_msg_req & 0xFF); - ahc_outb(ahc, TARGET_MSG_REQUEST + 1, - (ahc->targ_msg_req >> 8) & 0xFF); - - if (!paused) - unpause_sequencer(ahc); - } + return (auto_negotiate_orig != tstate->auto_negotiate); } /* - * Update the user/goal/current tables of synchronous negotiation + * Update the user/goal/curr tables of synchronous negotiation * parameters as well as, in the case of a current or active update, * any data structures on the host controller. In the case of an * active update, the specified target is currently talking to us on @@ -1697,11 +1702,15 @@ u_int offset, u_int ppr_options, u_int type, int paused) { struct ahc_initiator_tinfo *tinfo; - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *tstate; u_int old_period; u_int old_offset; u_int old_ppr; - int active = (type & AHC_TRANS_ACTIVE) == AHC_TRANS_ACTIVE; + int active; + int update_needed; + + active = (type & AHC_TRANS_ACTIVE) == AHC_TRANS_ACTIVE; + update_needed = 0; if (syncrate == NULL) { period = 0; @@ -1723,9 +1732,9 @@ tinfo->goal.ppr_options = ppr_options; } - old_period = tinfo->current.period; - old_offset = tinfo->current.offset; - old_ppr = tinfo->current.ppr_options; + old_period = tinfo->curr.period; + old_offset = tinfo->curr.offset; + old_ppr = tinfo->curr.ppr_options; if ((type & AHC_TRANS_CUR) != 0 && (old_period != period @@ -1733,6 +1742,7 @@ || old_ppr != ppr_options)) { u_int scsirate; + update_needed++; scsirate = tinfo->scsirate; if ((ahc->features & AHC_ULTRA2) != 0) { @@ -1777,15 +1787,12 @@ } tinfo->scsirate = scsirate; - tinfo->current.period = period; - tinfo->current.offset = offset; - tinfo->current.ppr_options = ppr_options; - - /* Update the syncrates in any pending scbs */ - ahc_update_pending_syncrates(ahc); + tinfo->curr.period = period; + tinfo->curr.offset = offset; + tinfo->curr.ppr_options = ppr_options; ahc_send_async(ahc, devinfo->channel, devinfo->target, - CAM_LUN_WILDCARD, AC_TRANSFER_NEG); + CAM_LUN_WILDCARD, AC_TRANSFER_NEG, NULL); if (bootverbose) { if (offset != 0) { printf("%s: target %d synchronous at %sMHz%s, " @@ -1801,13 +1808,15 @@ } } - ahc_update_target_msg_request(ahc, devinfo, tinfo, - /*force*/FALSE, - paused); + update_needed += ahc_update_neg_request(ahc, devinfo, tstate, + tinfo, /*force*/FALSE); + + if (update_needed) + ahc_update_pending_scbs(ahc); } /* - * Update the user/goal/current tables of wide negotiation + * Update the user/goal/curr tables of wide negotiation * parameters as well as, in the case of a current or active update, * any data structures on the host controller. In the case of an * active update, the specified target is currently talking to us on @@ -1818,11 +1827,14 @@ ahc_set_width(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, u_int width, u_int type, int paused) { - struct ahc_initiator_tinfo *tinfo; - struct tmode_tstate *tstate; - u_int oldwidth; - int active = (type & AHC_TRANS_ACTIVE) == AHC_TRANS_ACTIVE; + struct ahc_initiator_tinfo *tinfo; + struct ahc_tmode_tstate *tstate; + u_int oldwidth; + int active; + int update_needed; + active = (type & AHC_TRANS_ACTIVE) == AHC_TRANS_ACTIVE; + update_needed = 0; tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, devinfo->our_scsiid, devinfo->target, &tstate); @@ -1832,10 +1844,11 @@ if ((type & AHC_TRANS_GOAL) != 0) tinfo->goal.width = width; - oldwidth = tinfo->current.width; + oldwidth = tinfo->curr.width; if ((type & AHC_TRANS_CUR) != 0 && oldwidth != width) { u_int scsirate; + update_needed++; scsirate = tinfo->scsirate; scsirate &= ~WIDEXFER; if (width == MSG_EXT_WDTR_BUS_16_BIT) @@ -1846,10 +1859,10 @@ if (active) ahc_outb(ahc, SCSIRATE, scsirate); - tinfo->current.width = width; + tinfo->curr.width = width; ahc_send_async(ahc, devinfo->channel, devinfo->target, - CAM_LUN_WILDCARD, AC_TRANSFER_NEG); + CAM_LUN_WILDCARD, AC_TRANSFER_NEG, NULL); if (bootverbose) { printf("%s: target %d using %dbit transfers\n", ahc_name(ahc), devinfo->target, @@ -1857,35 +1870,22 @@ } } - ahc_update_target_msg_request(ahc, devinfo, tinfo, - /*force*/FALSE, paused); + update_needed += ahc_update_neg_request(ahc, devinfo, tstate, + tinfo, /*force*/FALSE); + if (update_needed) + ahc_update_pending_scbs(ahc); } /* * Update the current state of tagged queuing for a given target. */ void -ahc_set_tags(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, int enable) +ahc_set_tags(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, + ahc_queue_alg alg) { - struct ahc_initiator_tinfo *tinfo; - struct tmode_tstate *tstate; - uint16_t orig_tagenable; - - tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, devinfo->our_scsiid, - devinfo->target, &tstate); - - orig_tagenable = tstate->tagenable; - if (enable) - tstate->tagenable |= devinfo->target_mask; - else - tstate->tagenable &= ~devinfo->target_mask; - - if (orig_tagenable != tstate->tagenable) { - ahc_platform_set_tags(ahc, devinfo, enable); - ahc_send_async(ahc, devinfo->channel, devinfo->target, - devinfo->lun, AC_TRANSFER_NEG); - } - + ahc_platform_set_tags(ahc, devinfo, alg); + ahc_send_async(ahc, devinfo->channel, devinfo->target, + devinfo->lun, AC_TRANSFER_NEG, &alg); } /* @@ -1894,11 +1894,12 @@ * be set correctly during future (re)selections. */ static void -ahc_update_pending_syncrates(struct ahc_softc *ahc) +ahc_update_pending_scbs(struct ahc_softc *ahc) { struct scb *pending_scb; int pending_scb_count; int i; + int paused; u_int saved_scbptr; /* @@ -1910,7 +1911,7 @@ struct ahc_devinfo devinfo; struct hardware_scb *pending_hscb; struct ahc_initiator_tinfo *tinfo; - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *tstate; ahc_scb_devinfo(ahc, &devinfo, pending_scb); tinfo = ahc_fetch_transinfo(ahc, devinfo.channel, @@ -1921,13 +1922,25 @@ if ((tstate->ultraenb & devinfo.target_mask) != 0) pending_hscb->control |= ULTRAENB; pending_hscb->scsirate = tinfo->scsirate; - pending_hscb->scsioffset = tinfo->current.offset; + pending_hscb->scsioffset = tinfo->curr.offset; + if ((tstate->auto_negotiate & devinfo.target_mask) == 0 + && (pending_scb->flags & SCB_AUTO_NEGOTIATE) != 0) { + pending_scb->flags &= ~SCB_AUTO_NEGOTIATE; + pending_hscb->control &= ~MK_MESSAGE; + } pending_scb_count++; } if (pending_scb_count == 0) return; + if (ahc_is_paused(ahc)) { + paused = 1; + } else { + paused = 0; + ahc_pause(ahc); + } + saved_scbptr = ahc_inb(ahc, SCBPTR); /* Ensure that the hscbs down on the card match the new information */ for (i = 0; i < ahc->scb_data->maxhscbs; i++) { @@ -1943,14 +1956,16 @@ pending_hscb = pending_scb->hscb; control = ahc_inb(ahc, SCB_CONTROL); - control &= ~ULTRAENB; - if ((pending_hscb->control & ULTRAENB) != 0) - control |= ULTRAENB; + control &= ~(ULTRAENB|MK_MESSAGE); + control |= pending_hscb->control & (ULTRAENB|MK_MESSAGE); ahc_outb(ahc, SCB_CONTROL, control); ahc_outb(ahc, SCB_SCSIRATE, pending_hscb->scsirate); ahc_outb(ahc, SCB_SCSIOFFSET, pending_hscb->scsioffset); } ahc_outb(ahc, SCBPTR, saved_scbptr); + + if (paused == 0) + ahc_unpause(ahc); } /**************************** Pathing Information *****************************/ @@ -1985,6 +2000,24 @@ role); } +struct ahc_phase_table_entry* +ahc_lookup_phase_entry(int phase) +{ + struct ahc_phase_table_entry *entry; + struct ahc_phase_table_entry *last_entry; + + /* + * num_phases doesn't include the default entry which + * will be returned if the phase doesn't match. + */ + last_entry = &ahc_phase_table[num_phases]; + for (entry = ahc_phase_table; entry < last_entry; entry++) { + if (phase == entry->phase) + break; + } + return (entry); +} + void ahc_compile_devinfo(struct ahc_devinfo *devinfo, u_int our_id, u_int target, u_int lun, char channel, role_t role) @@ -2017,6 +2050,17 @@ /************************ Message Phase Processing ****************************/ +static void +ahc_assert_atn(struct ahc_softc *ahc) +{ + u_int scsisigo; + + scsisigo = ATNO; + if ((ahc->features & AHC_DT) == 0) + scsisigo |= ahc_inb(ahc, SCSISIGI); + ahc_outb(ahc, SCSISIGO, scsisigo); +} + /* * When an initiator transaction with the MK_MESSAGE flag either reconnects * or enters the initial message out phase, we are interrupted. Fill our @@ -2083,8 +2127,7 @@ * away. */ ahc_outb(ahc, SCSISEQ, (ahc_inb(ahc, SCSISEQ) & ~ENSELO)); - } else if ((ahc->targ_msg_req & devinfo->target_mask) != 0 - || (scb->flags & SCB_NEGOTIATE) != 0) { + } else if ((scb->flags & (SCB_AUTO_NEGOTIATE|SCB_NEGOTIATE)) != 0) { ahc_build_transfer_msg(ahc, devinfo); } else { printf("ahc_intr: AWAITING_MSG for an SCB that " @@ -2101,6 +2144,7 @@ * asked to send this message again. */ ahc_outb(ahc, SCB_CONTROL, ahc_inb(ahc, SCB_CONTROL) & ~MK_MESSAGE); + scb->hscb->control &= ~MK_MESSAGE; ahc->msgout_index = 0; ahc->msg_type = MSG_TYPE_INITIATOR_MSGOUT; } @@ -2118,7 +2162,7 @@ * we want to renegotiate due to a check condition. */ struct ahc_initiator_tinfo *tinfo; - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *tstate; struct ahc_syncrate *rate; int dowide; int dosync; @@ -2130,9 +2174,19 @@ tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, devinfo->our_scsiid, devinfo->target, &tstate); - dowide = tinfo->current.width != tinfo->goal.width; - dosync = tinfo->current.period != tinfo->goal.period; - doppr = tinfo->current.ppr_options != tinfo->goal.ppr_options; + /* + * Filter our period based on the current connection. + * If we can't perform DT transfers on this segment (not in LVD + * mode for instance), then our decision to issue a PPR message + * may change. + */ + period = tinfo->goal.period; + ppr_options = tinfo->goal.ppr_options; + rate = ahc_devlimited_syncrate(ahc, tinfo, &period, + &ppr_options, devinfo->role); + dowide = tinfo->curr.width != tinfo->goal.width; + dosync = tinfo->curr.period != period; + doppr = tinfo->curr.ppr_options != ppr_options; if (!dowide && !dosync && !doppr) { dowide = tinfo->goal.width != MSG_EXT_WDTR_BUS_8_BIT; @@ -2145,7 +2199,7 @@ "but no negotiation needed\n"); } - use_ppr = (tinfo->current.transport_version >= 3) || doppr; + use_ppr = (tinfo->curr.transport_version >= 3) || doppr; /* Target initiated PPR is not allowed in the SCSI spec */ if (devinfo->role == ROLE_TARGET) use_ppr = 0; @@ -2160,16 +2214,10 @@ */ if (use_ppr || (dosync && !dowide)) { - period = tinfo->goal.period; - ppr_options = tinfo->goal.ppr_options; - if (use_ppr == 0) - ppr_options = 0; - rate = ahc_devlimited_syncrate(ahc, tinfo, &period, - &ppr_options, devinfo->role); offset = tinfo->goal.offset; ahc_validate_offset(ahc, tinfo, rate, &offset, use_ppr ? tinfo->goal.width - : tinfo->current.width, + : tinfo->curr.width, devinfo->role); if (use_ppr) { ahc_construct_ppr(ahc, devinfo, period, offset, @@ -2258,7 +2306,7 @@ ahc->msgout_len = 0; ahc->msgin_index = 0; ahc->msg_type = MSG_TYPE_NONE; - if ((ahc_inb(ahc, SCSISIGI) & ATNI) == 0) { + if ((ahc_inb(ahc, SCSISIGI) & ATNI) != 0) { /* * The target didn't care to respond to our * message request, so clear ATN. @@ -2327,7 +2375,7 @@ * 0, and try again. */ ahc->msgout_index = 0; - ahc_outb(ahc, SCSISIGO, ahc_inb(ahc, SCSISIGO) | ATNO); + ahc_assert_atn(ahc); } lastbyte = ahc->msgout_index == (ahc->msgout_len - 1); @@ -2382,8 +2430,7 @@ * message out phase. */ if (ahc->msgout_len != 0) - ahc_outb(ahc, SCSISIGO, - ahc_inb(ahc, SCSISIGO) | ATNO); + ahc_assert_atn(ahc); } else ahc->msgin_index++; @@ -2548,7 +2595,7 @@ found = TRUE; } index = end_index; - } else if (ahc->msgout_buf[index] >= MSG_SIMPLE_Q_TAG + } else if (ahc->msgout_buf[index] >= MSG_SIMPLE_TASK && ahc->msgout_buf[index] <= MSG_IGN_WIDE_RESIDUE) { /* Skip tag type and tag id or residue param*/ @@ -2575,7 +2622,7 @@ ahc_parse_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) { struct ahc_initiator_tinfo *tinfo; - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *tstate; int reject; int done; int response; @@ -2674,7 +2721,8 @@ /* * Send our own SDTR in reply */ - if (bootverbose) { + if (bootverbose + && devinfo->role == ROLE_INITIATOR) { printf("(%s:%c:%d:%d): Target " "Initiated SDTR\n", ahc_name(ahc), devinfo->channel, @@ -2744,7 +2792,8 @@ /* * Send our own WDTR in reply */ - if (bootverbose) { + if (bootverbose + && devinfo->role == ROLE_INITIATOR) { printf("(%s:%c:%d:%d): Target " "Initiated WDTR\n", ahc_name(ahc), devinfo->channel, @@ -2879,7 +2928,7 @@ "offset %x, options %x\n", ahc_name(ahc), devinfo->channel, devinfo->target, devinfo->lun, - ahc->msgin_buf[3], saved_width, + saved_width, ahc->msgin_buf[3], saved_offset, saved_ppr_options, bus_width, period, offset, ppr_options); } @@ -2906,7 +2955,7 @@ CAM_BDR_SENT, "Bus Device Reset Received", /*verbose_level*/0); - restart_sequencer(ahc); + ahc_restart(ahc); done = MSGLOOP_TERMINATED; break; case MSG_ABORT_TAG: @@ -2927,7 +2976,7 @@ tstate = ahc->enabled_targets[devinfo->our_scsiid]; if (tstate != NULL) { - struct tmode_lstate* lstate; + struct ahc_tmode_lstate* lstate; lstate = tstate->enabled_luns[devinfo->lun]; if (lstate != NULL) { @@ -2979,7 +3028,7 @@ */ struct scb *scb; struct ahc_initiator_tinfo *tinfo; - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *tstate; u_int scb_index; u_int last_msg; int response = 0; @@ -3004,7 +3053,7 @@ devinfo->target, devinfo->lun); } tinfo->goal.ppr_options = 0; - tinfo->current.transport_version = 2; + tinfo->curr.transport_version = 2; tinfo->goal.transport_version = 2; ahc->msgout_index = 0; ahc->msgout_len = 0; @@ -3046,24 +3095,39 @@ "Using asynchronous transfers\n", ahc_name(ahc), devinfo->channel, devinfo->target, devinfo->lun); - } else if ((scb->hscb->control & MSG_SIMPLE_Q_TAG) != 0) { - - printf("(%s:%c:%d:%d): refuses tagged commands. Performing " - "non-tagged I/O\n", ahc_name(ahc), - devinfo->channel, devinfo->target, devinfo->lun); - ahc_set_tags(ahc, devinfo, FALSE); + } else if ((scb->hscb->control & MSG_SIMPLE_TASK) != 0) { + int tag_type; + int mask; + + tag_type = (scb->hscb->control & MSG_SIMPLE_TASK); + + if (tag_type == MSG_SIMPLE_TASK) { + printf("(%s:%c:%d:%d): refuses tagged commands. " + "Performing non-tagged I/O\n", ahc_name(ahc), + devinfo->channel, devinfo->target, devinfo->lun); + ahc_set_tags(ahc, devinfo, AHC_QUEUE_NONE); + mask = ~0x23; + } else { + printf("(%s:%c:%d:%d): refuses %s tagged commands. " + "Performing simple queue tagged I/O only\n", + ahc_name(ahc), devinfo->channel, devinfo->target, + devinfo->lun, tag_type == MSG_ORDERED_TASK + ? "ordered" : "head of queue"); + ahc_set_tags(ahc, devinfo, AHC_QUEUE_BASIC); + mask = ~0x03; + } /* * Resend the identify for this CCB as the target * may believe that the selection is invalid otherwise. */ ahc_outb(ahc, SCB_CONTROL, - ahc_inb(ahc, SCB_CONTROL) & ~MSG_SIMPLE_Q_TAG); - scb->hscb->control &= ~MSG_SIMPLE_Q_TAG; + ahc_inb(ahc, SCB_CONTROL) & mask); + scb->hscb->control &= mask; ahc_set_transaction_tag(scb, /*enabled*/FALSE, - /*type*/MSG_SIMPLE_Q_TAG); + /*type*/MSG_SIMPLE_TASK); ahc_outb(ahc, MSG_OUT, MSG_IDENTIFYFLAG); - ahc_outb(ahc, SCSISIGO, ahc_inb(ahc, SCSISIGO) | ATNO); + ahc_assert_atn(ahc); /* * This transaction is now at the head of @@ -3225,7 +3289,7 @@ cam_status status, char *message, int verbose_level) { #ifdef AHC_TARGET_MODE - struct tmode_tstate* tstate; + struct ahc_tmode_tstate* tstate; u_int lun; #endif int found; @@ -3242,7 +3306,7 @@ tstate = ahc->enabled_targets[devinfo->our_scsiid]; if (tstate != NULL) { for (lun = 0; lun < AHC_NUM_LUNS; lun++) { - struct tmode_lstate* lstate; + struct ahc_tmode_lstate* lstate; lstate = tstate->enabled_luns[lun]; if (lstate == NULL) @@ -3265,7 +3329,7 @@ AHC_TRANS_CUR, /*paused*/TRUE); ahc_send_async(ahc, devinfo->channel, devinfo->target, - CAM_LUN_WILDCARD, AC_SENT_BDR); + CAM_LUN_WILDCARD, AC_SENT_BDR, NULL); if (message != NULL && (verbose_level <= bootverbose)) @@ -3274,9 +3338,11 @@ } #ifdef AHC_TARGET_MODE -void -ahc_setup_target_msgin(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) +static void +ahc_setup_target_msgin(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, + struct scb *scb) { + /* * To facilitate adding multiple messages together, * each routine should increment the index and len @@ -3285,7 +3351,7 @@ ahc->msgout_index = 0; ahc->msgout_len = 0; - if ((ahc->targ_msg_req & devinfo->target_mask) != 0) + if (scb != NULL && (scb->flags & SCB_AUTO_NEGOTIATE) != 0) ahc_build_transfer_msg(ahc, devinfo); else panic("ahc_intr: AWAITING target message with no message"); @@ -3319,6 +3385,7 @@ LIST_INIT(&ahc->pending_scbs); /* We don't know our unit number until the OSM sets it */ ahc->name = name; + ahc->unit = -1; for (i = 0; i < 16; i++) TAILQ_INIT(&ahc->untagged_queues[i]); if (ahc_platform_alloc(ahc, platform_arg) != 0) { @@ -3337,7 +3404,7 @@ ahc->bugs = config->bugs; ahc->flags = config->flags; ahc->channel = config->channel; - ahc->unpause = (ahc_inb(ahc, HCNTRL) & IRQMS) | INTEN; + ahc->unpause = (ahc_inb(ahc, HCNTRL) & IRQMS); ahc->description = config->description; /* The IRQMS bit is only valid on VL and EISA chips */ if ((ahc->chip & AHC_PCI) != 0) @@ -3360,29 +3427,37 @@ { struct ahc_softc *list_ahc; -#ifdef AHC_SUPPORT_PCI +#if AHC_PCI_CONFIG > 0 /* * Second Function PCI devices need to inherit some - * settings from function 0. We assume that function 0 - * will always be found prior to function 1. + * settings from function 0. */ if ((ahc->chip & AHC_BUS_MASK) == AHC_PCI - && ahc_get_pci_function(ahc->dev_softc) == 1) { + && (ahc->features & AHC_MULTI_FUNC) != 0) { TAILQ_FOREACH(list_ahc, &ahc_tailq, links) { ahc_dev_softc_t list_pci; ahc_dev_softc_t pci; list_pci = list_ahc->dev_softc; pci = ahc->dev_softc; - if (ahc_get_pci_bus(list_pci) == ahc_get_pci_bus(pci) - && ahc_get_pci_slot(list_pci) == ahc_get_pci_slot(pci) - && ahc_get_pci_function(list_pci) == 0) { - ahc->flags &= ~AHC_BIOS_ENABLED; - ahc->flags |= - list_ahc->flags & AHC_BIOS_ENABLED; - ahc->flags &= ~AHC_CHANNEL_B_PRIMARY; - ahc->flags |= - list_ahc->flags & AHC_CHANNEL_B_PRIMARY; + if (ahc_get_pci_slot(list_pci) == ahc_get_pci_slot(pci) + && ahc_get_pci_bus(list_pci) == ahc_get_pci_bus(pci)) { + struct ahc_softc *master; + struct ahc_softc *slave; + + if (ahc_get_pci_function(list_pci) == 0) { + master = list_ahc; + slave = ahc; + } else { + master = ahc; + slave = list_ahc; + } + slave->flags &= ~AHC_BIOS_ENABLED; + slave->flags |= + master->flags & AHC_BIOS_ENABLED; + slave->flags &= ~AHC_PRIMARY_CHANNEL; + slave->flags |= + master->flags & AHC_PRIMARY_CHANNEL; break; } } @@ -3455,7 +3530,7 @@ #endif ahc_platform_free(ahc); for (i = 0; i < AHC_NUM_TARGETS; i++) { - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *tstate; tstate = ahc->enabled_targets[i]; if (tstate != NULL) { @@ -3463,7 +3538,7 @@ int j; for (j = 0; j < AHC_NUM_LUNS; j++) { - struct tmode_lstate *lstate; + struct ahc_tmode_lstate *lstate; lstate = tstate->enabled_luns[j]; if (lstate != NULL) { @@ -3523,7 +3598,7 @@ * It contains settings that affect termination and we don't want * to disturb the integrity of the bus. */ - pause_sequencer(ahc); + ahc_pause(ahc); sxfrctl1_b = 0; if ((ahc->chip & AHC_CHIPID_MASK) == AHC_AIC7770) { u_int sblkctl; @@ -3961,17 +4036,26 @@ len = sprintf(buf, "Twin Channel, A SCSI Id=%d, " "B SCSI Id=%d, primary %c, ", ahc->our_id, ahc->our_id_b, - ahc->flags & AHC_CHANNEL_B_PRIMARY ? 'B': 'A'); + (ahc->flags & AHC_PRIMARY_CHANNEL) + 'A'); else { + const char *speed; const char *type; + speed = ""; + if ((ahc->features & AHC_ULTRA) != 0) { + speed = "Ultra "; + } else if ((ahc->features & AHC_DT) != 0) { + speed = "Ultra160 "; + } else if ((ahc->features & AHC_ULTRA2) != 0) { + speed = "Ultra2 "; + } if ((ahc->features & AHC_WIDE) != 0) { type = "Wide"; } else { type = "Single"; } - len = sprintf(buf, "%s Channel %c, SCSI Id=%d, ", - type, ahc->channel, ahc->our_id); + len = sprintf(buf, "%s%s Channel %c, SCSI Id=%d, ", + speed, type, ahc->channel, ahc->our_id); } buf += len; @@ -4124,16 +4208,16 @@ * data for any target mode initiator. */ if (ahc_alloc_tstate(ahc, ahc->our_id, 'A') == NULL) { - printf("%s: unable to allocate tmode_tstate. " + printf("%s: unable to allocate ahc_tmode_tstate. " "Failing attach\n", ahc_name(ahc)); - return (-1); + return (ENOMEM); } if ((ahc->features & AHC_TWIN) != 0) { if (ahc_alloc_tstate(ahc, ahc->our_id_b, 'B') == NULL) { - printf("%s: unable to allocate tmode_tstate. " + printf("%s: unable to allocate ahc_tmode_tstate. " "Failing attach\n", ahc_name(ahc)); - return (-1); + return (ENOMEM); } } @@ -4231,7 +4315,7 @@ for (i = 0; i <= max_targ; i++) { struct ahc_initiator_tinfo *tinfo; - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *tstate; u_int our_id; u_int target_id; char channel; @@ -4324,12 +4408,10 @@ tinfo->user.transport_version = 2; tinfo->goal.protocol_version = 2; tinfo->goal.transport_version = 2; - tinfo->current.protocol_version = 2; - tinfo->current.transport_version = 2; + tinfo->curr.protocol_version = 2; + tinfo->curr.transport_version = 2; } tstate->ultraenb = ultraenb; - tstate->discenable = discenable; - tstate->tagenable = 0; /* Wait until the XPT says its okay */ } ahc->user_discenable = discenable; ahc->user_tagenable = tagenable; @@ -4395,10 +4477,6 @@ ahc_outb(ahc, QINPOS, 0); ahc_outb(ahc, QOUTPOS, 0); - /* Don't have any special messages to send to targets */ - ahc_outb(ahc, TARGET_MSG_REQUEST, 0); - ahc_outb(ahc, TARGET_MSG_REQUEST + 1, 0); - /* * Use the built in queue management registers * if they are available. @@ -4450,16 +4528,33 @@ * never settle, so don't complain if we * fail here. */ - pause_sequencer(ahc); + ahc_pause(ahc); for (wait = 5000; (ahc_inb(ahc, SBLKCTL) & (ENAB40|ENAB20)) == 0 && wait; wait--) ahc_delay(100); - unpause_sequencer(ahc); + ahc_unpause(ahc); } return (0); } +void +ahc_intr_enable(struct ahc_softc *ahc, int enable) +{ + u_int hcntrl; + + hcntrl = ahc_inb(ahc, HCNTRL); + hcntrl &= ~INTEN; + ahc->pause &= ~INTEN; + ahc->unpause &= ~INTEN; + if (enable) { + hcntrl |= INTEN; + ahc->pause |= INTEN; + ahc->unpause |= INTEN; + } + ahc_outb(ahc, HCNTRL, hcntrl); +} + /* * Ensure that the card is paused in a location * outside of all critical sections and that all @@ -4478,7 +4573,7 @@ intstat = 0; do { ahc_intr(ahc); - pause_sequencer(ahc); + ahc_pause(ahc); ahc_clear_critical_section(ahc); if (intstat == 0xFF && (ahc->features & AHC_REMOVABLE) != 0) break; @@ -5409,7 +5504,7 @@ CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD, channel, ROLE_UNKNOWN); - pause_sequencer(ahc); + ahc_pause(ahc); /* Make sure the sequencer is in a safe location. */ ahc_clear_critical_section(ahc); @@ -5478,14 +5573,14 @@ * drivers affected by this action. */ for (target = 0; target <= max_scsiid; target++) { - struct tmode_tstate* tstate; + struct ahc_tmode_tstate* tstate; u_int lun; tstate = ahc->enabled_targets[target]; if (tstate == NULL) continue; for (lun = 0; lun < AHC_NUM_LUNS; lun++) { - struct tmode_lstate* lstate; + struct ahc_tmode_lstate* lstate; lstate = tstate->enabled_luns[lun]; if (lstate == NULL) @@ -5499,7 +5594,7 @@ #endif /* Notify the XPT that a bus reset occurred */ ahc_send_async(ahc, devinfo.channel, CAM_TARGET_WILDCARD, - CAM_LUN_WILDCARD, AC_BUS_RESET); + CAM_LUN_WILDCARD, AC_BUS_RESET, NULL); /* * Revert to async/narrow transfers until we renegotiate. @@ -5524,9 +5619,9 @@ } if (restart_needed) - restart_sequencer(ahc); + ahc_restart(ahc); else - unpause_sequencer(ahc); + ahc_unpause(ahc); return found; } @@ -5535,7 +5630,7 @@ /* * Calculate the residual for a just completed SCB. */ -static void +void ahc_calc_residual(struct scb *scb) { struct hardware_scb *hscb; @@ -5623,7 +5718,7 @@ * Add a target mode event to this lun's queue */ static void -ahc_queue_lstate_event(struct ahc_softc *ahc, struct tmode_lstate *lstate, +ahc_queue_lstate_event(struct ahc_softc *ahc, struct ahc_tmode_lstate *lstate, u_int initiator_id, u_int event_type, u_int event_arg) { struct ahc_tmode_event *event; @@ -5674,7 +5769,7 @@ * for immediate notify resources. */ void -ahc_send_lstate_events(struct ahc_softc *ahc, struct tmode_lstate *lstate) +ahc_send_lstate_events(struct ahc_softc *ahc, struct ahc_tmode_lstate *lstate) { struct ccb_hdr *ccbh; struct ccb_immed_notify *inot; @@ -5825,7 +5920,7 @@ memcpy(ahc->critical_sections, cs_table, cs_count); } ahc_outb(ahc, SEQCTL, PERRORDIS|FAILDIS|FASTMODE); - restart_sequencer(ahc); + ahc_restart(ahc); if (bootverbose) printf(" %d instructions downloaded\n", downloaded); @@ -6000,6 +6095,7 @@ int target; int maxtarget; int i; + uint8_t last_phase; uint8_t qinpos; uint8_t qintail; uint8_t qoutpos; @@ -6008,13 +6104,25 @@ saved_scbptr = ahc_inb(ahc, SCBPTR); - printf("%s: Dumping Card State at SEQADDR 0x%x\n", - ahc_name(ahc), + last_phase = ahc_inb(ahc, LASTPHASE); + printf("%s: Dumping Card State %s, at SEQADDR 0x%x\n", + ahc_name(ahc), ahc_lookup_phase_entry(last_phase)->phasemsg, ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8)); - - printf("SCSISEQ = 0x%x, SBLKCTL = 0x%x, SSTAT0 0x%x\n", - ahc_inb(ahc, SCSISEQ), ahc_inb(ahc, SBLKCTL), - ahc_inb(ahc, SSTAT0)); + printf("SCSISEQ = 0x%x, SBLKCTL = 0x%x\n", + ahc_inb(ahc, SCSISEQ), ahc_inb(ahc, SBLKCTL)); + printf(" DFCNTRL = 0x%x, DFSTATUS = 0x%x\n", + ahc_inb(ahc, DFCNTRL), ahc_inb(ahc, DFSTATUS)); + printf("LASTPHASE = 0x%x, SCSISIGI = 0x%x, SXFRCTL0 = 0x%x\n", + last_phase, ahc_inb(ahc, SCSISIGI), ahc_inb(ahc, SXFRCTL0)); + printf("SSTAT0 = 0x%x, SSTAT1 = 0x%x\n", + ahc_inb(ahc, SSTAT0), ahc_inb(ahc, SSTAT1)); + if ((ahc->features & AHC_DT) != 0) + printf("SCSIPHASE = 0x%x\n", ahc_inb(ahc, SCSIPHASE)); + printf("STACK == 0x%x, 0x%x, 0x%x, 0x%x\n", + ahc_inb(ahc, STACK) | (ahc_inb(ahc, STACK) << 8), + ahc_inb(ahc, STACK) | (ahc_inb(ahc, STACK) << 8), + ahc_inb(ahc, STACK) | (ahc_inb(ahc, STACK) << 8), + ahc_inb(ahc, STACK) | (ahc_inb(ahc, STACK) << 8)); printf("SCB count = %d\n", ahc->scb_data->numscbs); printf("Kernel NEXTQSCB = %d\n", ahc->next_queued_scb->hscb->tag); printf("Card NEXTQSCB = %d\n", ahc_inb(ahc, NEXT_QUEUED_SCB)); @@ -6112,7 +6220,8 @@ #ifdef AHC_TARGET_MODE cam_status ahc_find_tmode_devs(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb, - struct tmode_tstate **tstate, struct tmode_lstate **lstate, + struct ahc_tmode_tstate **tstate, + struct ahc_tmode_lstate **lstate, int notfound_failure) { @@ -6153,8 +6262,8 @@ void ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb) { - struct tmode_tstate *tstate; - struct tmode_lstate *lstate; + struct ahc_tmode_tstate *tstate; + struct ahc_tmode_lstate *lstate; struct ccb_en_lun *cel; cam_status status; u_int target; @@ -6227,7 +6336,7 @@ ahc->flags |= AHC_TARGETROLE; if ((ahc->features & AHC_MULTIROLE) == 0) ahc->flags &= ~AHC_INITIATORROLE; - pause_sequencer(ahc); + ahc_pause(ahc); ahc_loadseq(ahc); ahc_unlock(ahc, &s); } @@ -6296,7 +6405,7 @@ SLIST_INIT(&lstate->accept_tios); SLIST_INIT(&lstate->immed_notifies); ahc_lock(ahc, &s); - pause_sequencer(ahc); + ahc_pause(ahc); if (target != CAM_TARGET_WILDCARD) { tstate->enabled_luns[lun] = lstate; ahc->enabled_luns++; @@ -6360,7 +6469,7 @@ scsiseq |= ENSELI; ahc_outb(ahc, SCSISEQ, scsiseq); } - unpause_sequencer(ahc); + ahc_unpause(ahc); ahc_unlock(ahc, &s); ccb->ccb_h.status = CAM_REQ_CMP; xpt_print_path(ccb->ccb_h.path); @@ -6410,7 +6519,7 @@ xpt_free_path(lstate->path); free(lstate, M_DEVBUF); - pause_sequencer(ahc); + ahc_pause(ahc); /* Can we clean up the target too? */ if (target != CAM_TARGET_WILDCARD) { tstate->enabled_luns[lun] = NULL; @@ -6463,11 +6572,11 @@ printf("Configuring Initiator Mode\n"); ahc->flags &= ~AHC_TARGETROLE; ahc->flags |= AHC_INITIATORROLE; - pause_sequencer(ahc); + ahc_pause(ahc); ahc_loadseq(ahc); } } - unpause_sequencer(ahc); + ahc_unpause(ahc); ahc_unlock(ahc, &s); } } @@ -6549,11 +6658,11 @@ ahc_outb(ahc, HS_MAILBOX, hs_mailbox); } else { if (!paused) - pause_sequencer(ahc); + ahc_pause(ahc); ahc_outb(ahc, KERNEL_TQINPOS, ahc->tqinfifonext & HOST_TQINPOS); if (!paused) - unpause_sequencer(ahc); + ahc_unpause(ahc); } } } @@ -6562,8 +6671,8 @@ static int ahc_handle_target_cmd(struct ahc_softc *ahc, struct target_cmd *cmd) { - struct tmode_tstate *tstate; - struct tmode_lstate *lstate; + struct ahc_tmode_tstate *tstate; + struct ahc_tmode_lstate *lstate; struct ccb_accept_tio *atio; uint8_t *byte; int initiator; diff -Nru a/drivers/scsi/aic7xxx/aic7xxx.h b/drivers/scsi/aic7xxx/aic7xxx.h --- a/drivers/scsi/aic7xxx/aic7xxx.h Wed May 16 06:00:22 2001 +++ b/drivers/scsi/aic7xxx/aic7xxx.h Wed May 16 06:00:22 2001 @@ -28,7 +28,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: //depot/src/aic7xxx/aic7xxx.h#19 $ + * $Id: //depot/src/aic7xxx/aic7xxx.h#27 $ * * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.h,v 1.30 2000/11/10 20:13:40 gibbs Exp $ */ @@ -209,9 +209,15 @@ AHC_MULTIROLE = 0x40000, /* Space for two roles at a time */ AHC_REMOVABLE = 0x80000, /* Hot-Swap supported */ AHC_AIC7770_FE = AHC_FENONE, - AHC_AIC7850_FE = AHC_SPIOCAP|AHC_AUTOPAUSE|AHC_TARGETMODE, - AHC_AIC7855_FE = AHC_AIC7850_FE, - AHC_AIC7860_FE = AHC_AIC7850_FE|AHC_ULTRA, + /* + * The real 7850 does not support Ultra modes, but there are + * several cards that use the generic 7850 PCI ID even though + * they are using an Ultra capable chip (7859/7860). We start + * out with the AHC_ULTRA feature set and then check the DEVSTATUS + * register to determine if the capability is really present. + */ + AHC_AIC7850_FE = AHC_SPIOCAP|AHC_AUTOPAUSE|AHC_TARGETMODE|AHC_ULTRA, + AHC_AIC7860_FE = AHC_AIC7850_FE, AHC_AIC7870_FE = AHC_TARGETMODE, AHC_AIC7880_FE = AHC_AIC7870_FE|AHC_ULTRA, /* @@ -286,56 +292,56 @@ * chip/controller's configuration. */ typedef enum { - AHC_FNONE = 0x000, - AHC_PAGESCBS = 0x001,/* Enable SCB paging */ - AHC_CHANNEL_B_PRIMARY = 0x002,/* - * On twin channel adapters, probe - * channel B first since it is the - * primary bus. + AHC_FNONE = 0x000, + AHC_PRIMARY_CHANNEL = 0x003,/* + * The channel that should + * be probed first. */ - AHC_USEDEFAULTS = 0x004,/* + AHC_USEDEFAULTS = 0x004,/* * For cards without an seeprom * or a BIOS to initialize the chip's * SRAM, we use the default target * settings. */ - AHC_SEQUENCER_DEBUG = 0x008, - AHC_SHARED_SRAM = 0x010, - AHC_LARGE_SEEPROM = 0x020,/* Uses C56_66 not C46 */ - AHC_RESET_BUS_A = 0x040, - AHC_RESET_BUS_B = 0x080, - AHC_EXTENDED_TRANS_A = 0x100, - AHC_EXTENDED_TRANS_B = 0x200, - AHC_TERM_ENB_A = 0x400, - AHC_TERM_ENB_B = 0x800, - AHC_INITIATORROLE = 0x1000,/* + AHC_SEQUENCER_DEBUG = 0x008, + AHC_SHARED_SRAM = 0x010, + AHC_LARGE_SEEPROM = 0x020,/* Uses C56_66 not C46 */ + AHC_RESET_BUS_A = 0x040, + AHC_RESET_BUS_B = 0x080, + AHC_EXTENDED_TRANS_A = 0x100, + AHC_EXTENDED_TRANS_B = 0x200, + AHC_TERM_ENB_A = 0x400, + AHC_TERM_ENB_B = 0x800, + AHC_INITIATORROLE = 0x1000,/* * Allow initiator operations on * this controller. */ - AHC_TARGETROLE = 0x2000,/* + AHC_TARGETROLE = 0x2000,/* * Allow target operations on this * controller. */ - AHC_NEWEEPROM_FMT = 0x4000, - AHC_RESOURCE_SHORTAGE = 0x8000, - AHC_TQINFIFO_BLOCKED = 0x10000,/* Blocked waiting for ATIOs */ - AHC_INT50_SPEEDFLEX = 0x20000,/* + AHC_NEWEEPROM_FMT = 0x4000, + AHC_RESOURCE_SHORTAGE = 0x8000, + AHC_TQINFIFO_BLOCKED = 0x10000,/* Blocked waiting for ATIOs */ + AHC_INT50_SPEEDFLEX = 0x20000,/* * Internal 50pin connector * sits behind an aic3860 */ - AHC_SCB_BTT = 0x40000,/* + AHC_SCB_BTT = 0x40000,/* * The busy targets table is * stored in SCB space rather * than SRAM. */ - AHC_BIOS_ENABLED = 0x80000, - AHC_ALL_INTERRUPTS = 0x100000, - AHC_ULTRA_DISABLED = 0x200000/* + AHC_BIOS_ENABLED = 0x80000, + AHC_ALL_INTERRUPTS = 0x100000, + AHC_ULTRA_DISABLED = 0x200000, /* * The precision resistor for * ultra transmission speeds is * missing, so we must limit * ourselves to fast SCSI. */ + AHC_PAGESCBS = 0x400000, /* Enable SCB paging */ + AHC_EDGE_INTERRUPT = 0x800000 /* Device uses edge triggered ints */ } ahc_flag; /* @@ -515,8 +521,9 @@ SCB_DEVICE_RESET = 0x0004, SCB_SENSE = 0x0008, SCB_CDB32_PTR = 0x0010, - SCB_RECOVERY_SCB = 0x0040, - SCB_NEGOTIATE = 0x0080, + SCB_RECOVERY_SCB = 0x0020, + SCB_AUTO_NEGOTIATE = 0x0040,/* Negotiate to achieve goal. */ + SCB_NEGOTIATE = 0x0080,/* Negotiation forced for command. */ SCB_ABORT = 0x1000, SCB_UNTAGGEDQ = 0x2000, SCB_ACTIVE = 0x4000, @@ -625,7 +632,7 @@ * data structures. */ #ifdef AHC_TARGET_MODE -struct tmode_lstate { +struct ahc_tmode_lstate { struct cam_path *path; struct ccb_hdr_slist accept_tios; struct ccb_hdr_slist immed_notifies; @@ -634,7 +641,7 @@ uint8_t event_w_idx; }; #else -struct tmode_lstate; +struct ahc_tmode_lstate; #endif /******************** Transfer Negotiation Datastructures *********************/ @@ -659,7 +666,7 @@ * Per-initiator current, goal and user transfer negotiation information. */ struct ahc_initiator_tinfo { uint8_t scsirate; /* Computed value for SCSIRATE reg */ - struct ahc_transinfo current; + struct ahc_transinfo curr; struct ahc_transinfo goal; struct ahc_transinfo user; }; @@ -671,16 +678,17 @@ * that we are the target and the targets are the initiators since the * negotiation is the same regardless of role. */ -struct tmode_tstate { - struct tmode_lstate* enabled_luns[AHC_NUM_LUNS]; +struct ahc_tmode_tstate { + struct ahc_tmode_lstate* enabled_luns[AHC_NUM_LUNS]; struct ahc_initiator_tinfo transinfo[AHC_NUM_TARGETS]; /* * Per initiator state bitmasks. */ - uint16_t ultraenb; /* Using ultra sync rate */ - uint16_t discenable; /* Disconnection allowed */ - uint16_t tagenable; /* Tagged Queuing allowed */ + uint16_t auto_negotiate;/* Auto Negotiation Required */ + uint16_t ultraenb; /* Using ultra sync rate */ + uint16_t discenable; /* Disconnection allowed */ + uint16_t tagenable; /* Tagged Queuing allowed */ }; /* @@ -711,32 +719,14 @@ /***************************** Lookup Tables **********************************/ /* - * Textual descriptions of the different chips indexed by chip type. - */ -extern char *ahc_chip_names[]; -extern const u_int num_chip_names; - -/* - * Hardware error codes. - */ -struct hard_error_entry { - uint8_t errno; - char *errmesg; -}; -extern struct hard_error_entry hard_error[]; -extern const u_int num_errors; - -/* * Phase -> name and message out response * to parity errors in each phase table. */ -struct phase_table_entry { +struct ahc_phase_table_entry { uint8_t phase; uint8_t mesg_out; /* Message response to parity errors */ char *phasemsg; }; -extern struct phase_table_entry phase_table[]; -extern const u_int num_phases; /************************** Serial EEPROM Format ******************************/ @@ -765,12 +755,19 @@ #define CFSUPREM 0x0001 /* support all removeable drives */ #define CFSUPREMB 0x0002 /* support removeable boot drives */ #define CFBIOSEN 0x0004 /* BIOS enabled */ -/* UNUSED 0x0008 */ +#define CFBIOS_BUSSCAN 0x0008 /* Have the BIOS Scan the Bus */ #define CFSM2DRV 0x0010 /* support more than two drives */ -#define CF284XEXTEND 0x0020 /* extended translation (284x cards) */ #define CFSTPWLEVEL 0x0010 /* Termination level control */ +#define CF284XEXTEND 0x0020 /* extended translation (284x cards) */ +#define CFCTRL_A 0x0020 /* BIOS displays Ctrl-A message */ +#define CFTERM_MENU 0x0040 /* BIOS displays termination menu */ #define CFEXTEND 0x0080 /* extended translation enabled */ #define CFSCAMEN 0x0100 /* SCAM enable */ +#define CFMSG_LEVEL 0x0600 /* BIOS Message Level */ +#define CFMSG_VERBOSE 0x0000 +#define CFMSG_SILENT 0x0200 +#define CFMSG_DIAG 0x0400 +#define CFBOOTCD 0x0800 /* Support Bootable CD-ROM */ /* UNUSED 0xff00 */ /* @@ -785,10 +782,11 @@ #define CFWSTERM 0x0008 /* SCSI high byte termination */ #define CFSPARITY 0x0010 /* SCSI parity */ #define CF284XSTERM 0x0020 /* SCSI low byte term (284x cards) */ -#define CFMULTILUN 0x0020 /* SCSI low byte term (284x cards) */ +#define CFMULTILUN 0x0020 #define CFRESETB 0x0040 /* reset SCSI bus at boot */ #define CFCLUSTERENB 0x0080 /* Cluster Enable */ -#define CFCHNLBPRIMARY 0x0100 /* aic7895 probe B channel first */ +#define CFBOOTCHAN 0x0300 /* probe this channel first */ +#define CFBOOTCHANSHIFT 8 #define CFSEAUTOTERM 0x0400 /* Ultra2 Perform secondary Auto Term*/ #define CFSELOWTERM 0x0800 /* Ultra2 secondary low term */ #define CFSEHIGHTERM 0x1000 /* Ultra2 secondary high term */ @@ -812,6 +810,7 @@ uint16_t res_1[10]; /* words 20-29 */ uint16_t signature; /* Signature == 0x250 */ #define CFSIGNATURE 0x250 +#define CFSIGNATURE2 0x300 uint16_t checksum; /* word 31 */ }; @@ -857,6 +856,8 @@ uint8_t *btt; }; +typedef void (*ahc_bus_intr_t)(struct ahc_softc *); + struct ahc_softc { bus_space_tag_t tag; bus_space_handle_t bsh; @@ -900,24 +901,29 @@ ahc_dev_softc_t dev_softc; /* + * Bus specific device information. + */ + ahc_bus_intr_t bus_intr; + + /* * Target mode related state kept on a per enabled lun basis. * Targets that are not enabled will have null entries. * As an initiator, we keep one target entry for our initiator * ID to store our sync/wide transfer settings. */ - struct tmode_tstate* enabled_targets[AHC_NUM_TARGETS]; + struct ahc_tmode_tstate *enabled_targets[AHC_NUM_TARGETS]; /* * The black hole device responsible for handling requests for * disabled luns on enabled targets. */ - struct tmode_lstate* black_hole; + struct ahc_tmode_lstate *black_hole; /* * Device instance currently on the bus awaiting a continue TIO * for a command that was not given the disconnect priveledge. */ - struct tmode_lstate* pending_device; + struct ahc_tmode_lstate *pending_device; /* * Card characteristics @@ -952,9 +958,6 @@ uint8_t our_id; uint8_t our_id_b; - /* Targets that need negotiation messages */ - uint16_t targ_msg_req; - /* * PCI error detection. */ @@ -1102,6 +1105,7 @@ struct ahc_probe_config*); void ahc_controller_info(struct ahc_softc *ahc, char *buf); int ahc_init(struct ahc_softc *ahc); +void ahc_intr_enable(struct ahc_softc *ahc, int enable); void ahc_pause_and_flushwork(struct ahc_softc *ahc); int ahc_suspend(struct ahc_softc *ahc); int ahc_resume(struct ahc_softc *ahc); @@ -1143,8 +1147,11 @@ void ahc_freeze_devq(struct ahc_softc *ahc, struct scb *scb); int ahc_reset_channel(struct ahc_softc *ahc, char channel, int initiate_reset); -void restart_sequencer(struct ahc_softc *ahc); +void ahc_restart(struct ahc_softc *ahc); +void ahc_calc_residual(struct scb *scb); /*************************** Utility Functions ********************************/ +struct ahc_phase_table_entry* + ahc_lookup_phase_entry(int phase); void ahc_compile_devinfo(struct ahc_devinfo *devinfo, u_int our_id, u_int target, u_int lun, char channel, @@ -1163,10 +1170,11 @@ struct ahc_initiator_tinfo *tinfo, u_int *bus_width, role_t role); -void ahc_update_target_msg_request(struct ahc_softc *ahc, - struct ahc_devinfo *dinfo, - struct ahc_initiator_tinfo *tinfo, - int force, int paused); +int ahc_update_neg_request(struct ahc_softc*, + struct ahc_devinfo*, + struct ahc_tmode_tstate*, + struct ahc_initiator_tinfo*, + int /*force*/); void ahc_set_width(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, u_int width, u_int type, int paused); @@ -1176,22 +1184,27 @@ u_int period, u_int offset, u_int ppr_options, u_int type, int paused); +typedef enum { + AHC_QUEUE_NONE, + AHC_QUEUE_BASIC, + AHC_QUEUE_TAGGED +} ahc_queue_alg; + void ahc_set_tags(struct ahc_softc *ahc, - struct ahc_devinfo *devinfo, int enable); + struct ahc_devinfo *devinfo, + ahc_queue_alg alg); /**************************** Target Mode *************************************/ #ifdef AHC_TARGET_MODE void ahc_send_lstate_events(struct ahc_softc *, - struct tmode_lstate *); + struct ahc_tmode_lstate *); void ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb); cam_status ahc_find_tmode_devs(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb, - struct tmode_tstate **tstate, - struct tmode_lstate **lstate, + struct ahc_tmode_tstate **tstate, + struct ahc_tmode_lstate **lstate, int notfound_failure); -void ahc_setup_target_msgin(struct ahc_softc *ahc, - struct ahc_devinfo *devinfo); #ifndef AHC_TMODE_ENABLE #define AHC_TMODE_ENABLE 0 #endif diff -Nru a/drivers/scsi/aic7xxx/aic7xxx.reg b/drivers/scsi/aic7xxx/aic7xxx.reg --- a/drivers/scsi/aic7xxx/aic7xxx.reg Wed May 16 06:00:20 2001 +++ b/drivers/scsi/aic7xxx/aic7xxx.reg Wed May 16 06:00:20 2001 @@ -28,7 +28,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: //depot/src/aic7xxx/aic7xxx.reg#13 $ + * $Id: //depot/src/aic7xxx/aic7xxx.reg#17 $ * * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.reg,v 1.31 2000/11/10 20:13:40 gibbs Exp $ */ @@ -877,7 +877,8 @@ address 0x094 access_mode RO bit PRELOAD_AVAIL 0x80 - bit DWORDEMP 0x20 + bit DFCACHETH 0x40 + bit FIFOQWDEMP 0x20 bit MREQPEND 0x10 bit HDONE 0x08 bit DFTHRESH 0x04 @@ -969,6 +970,7 @@ bit MSG_OUT_PHASE 0x04 bit DATA_IN_PHASE 0x02 bit DATA_OUT_PHASE 0x01 + mask DATA_PHASE_MASK 0x03 } /* @@ -1415,15 +1417,6 @@ */ LAST_MSG { size 1 - } - - /* - * Interrupt kernel for a message to this target on - * the next transaction. This is usually used for - * negotiation requests. - */ - TARGET_MSG_REQUEST { - size 2 } /* diff -Nru a/drivers/scsi/aic7xxx/aic7xxx.seq b/drivers/scsi/aic7xxx/aic7xxx.seq --- a/drivers/scsi/aic7xxx/aic7xxx.seq Wed May 16 06:00:20 2001 +++ b/drivers/scsi/aic7xxx/aic7xxx.seq Wed May 16 06:00:20 2001 @@ -28,7 +28,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: //depot/src/aic7xxx/aic7xxx.seq#22 $ + * $Id: //depot/src/aic7xxx/aic7xxx.seq#27 $ * * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.seq,v 1.106 2000/11/12 05:19:46 gibbs Exp $ */ @@ -153,7 +153,9 @@ * the kernel driver if it happens. */ mvi CLRSINT1,CLRBUSFREE; - or SIMODE1, ENBUSFREE; + if ((ahc->features & AHC_DT) == 0) { + or SIMODE1, ENBUSFREE; + } /* * Guard against a bus free after (re)selection @@ -479,6 +481,9 @@ */ mov SEQ_FLAGS, SCB_TARGET_INFO[SCB_TARGET_PHASES]; + test SCB_CONTROL, MK_MESSAGE jz target_ITloop; + mvi P_MESGIN|BSYO call change_phase; + jmp host_target_message_loop; target_ITloop: /* * Start honoring ATN signals now that @@ -494,12 +499,12 @@ * on the state of NO_DISCONNECT. */ test SEQ_FLAGS, NO_DISCONNECT jz target_disconnect; - if ((ahc->flags & AHC_PAGESCBS) != 0) { - mov ALLZEROS call get_free_or_disc_scb; - } mov RETURN_1, ALLZEROS; call complete_target_cmd; cmp RETURN_1, CONT_MSG_LOOP jne .; + if ((ahc->flags & AHC_PAGESCBS) != 0) { + mov ALLZEROS call get_free_or_disc_scb; + } mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; mov SCB_TAG call dma_scb; jmp target_synccmd; @@ -703,6 +708,11 @@ test CCSGCTL, CCSGEN jnz .; ret; idle_loop: + /* + * Do we need any more segments for this transfer? + */ + test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jnz return; + /* Did we just finish fetching segs? */ cmp CCSGCTL, CCSGEN|CCSGDONE je idle_sgfetch_complete; @@ -710,11 +720,6 @@ test CCSGCTL, CCSGEN jnz return; /* - * Do we need any more segments? - */ - test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jnz return; - - /* * Do we have any prefetch left??? */ cmp CCSGADDR, SG_PREFETCH_CNT jne idle_sg_avail; @@ -758,8 +763,8 @@ test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz . + 2; or SINDEX, LAST_SEG; mov SG_CACHE_PRE, SINDEX; - /* Load the segment by writing DFCNTRL again */ - mov DFCNTRL, DMAPARAMS; + /* Load the segment */ + or DFCNTRL, PRELOADEN; } ret; } @@ -882,7 +887,11 @@ and DMAPARAMS, DIRECTION; mov DFCNTRL, DMAPARAMS; or SXFRCTL1,BITBUCKET; - test SSTAT1,PHASEMIS jz .; + if ((ahc->features & AHC_DT) == 0) { + test SSTAT1,PHASEMIS jz .; + } else { + test SCSIPHASE, DATA_PHASE_MASK jnz .; + } and SXFRCTL1, ~BITBUCKET; mvi DATA_OVERRUN call set_seqint; jmp ITloop; @@ -903,54 +912,48 @@ * completes or the target changes phase. */ test SG_CACHE_SHADOW, LAST_SEG_DONE jnz ultra2_dmafinish; - if ((ahc->flags & AHC_TARGETROLE) != 0) { - /* - * As a target, we control the phases, - * so ignore PHASEMIS. - */ - test SSTAT0, TARGET jnz ultra2_dma_loop; - } - if ((ahc->flags & AHC_INITIATORROLE) != 0) { - test SSTAT1,PHASEMIS jz ultra2_dma_loop; + if ((ahc->features & AHC_DT) == 0) { + if ((ahc->flags & AHC_TARGETROLE) != 0) { + /* + * As a target, we control the phases, + * so ignore PHASEMIS. + */ + test SSTAT0, TARGET jnz ultra2_dma_loop; + } + if ((ahc->flags & AHC_INITIATORROLE) != 0) { + test SSTAT1,PHASEMIS jz ultra2_dma_loop; + } + } else { + test DFCNTRL, SCSIEN jnz ultra2_dma_loop; } ultra2_dmafinish: - test DFCNTRL, DIRECTION jnz ultra2_dmafifoempty; - if ((ahc->features & AHC_DT) == 0) { - and DFCNTRL, ~SCSIEN; - test DFCNTRL, SCSIEN jnz .; - } -ultra2_dmafifoflush: + /* + * The transfer has terminated either due to a phase + * change, and/or the completion of the last segment. + * We have two goals here. Do as much other work + * as possible while the data fifo drains on a read + * and respond as quickly as possible to the standard + * messages (save data pointers/disconnect and command + * complete) that usually follow a data phase. + */ if ((ahc->bugs & AHC_AUTOFLUSH_BUG) != 0) { /* - * On Rev A of the aic7890, the autoflush - * features doesn't function correctly. - * Perform an explicit manual flush. During - * a manual flush, the FIFOEMP bit becomes - * true every time the PCI FIFO empties - * regardless of the state of the SCSI FIFO. - * It can take up to 4 clock cycles for the - * SCSI FIFO to get data into the PCI FIFO - * and for FIFOEMP to de-assert. Here we - * guard against this condition by making - * sure the FIFOEMP bit stays on for 5 full - * clock cycles. + * On chips with broken auto-flush, start + * the flushing process now. We'll poke + * the chip from time to time to keep the + * flush process going as we complete the + * data phase. */ or DFCNTRL, FIFOFLUSH; - test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; - test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; - test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; - test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; } - test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; -ultra2_dmafifoempty: - /* Don't clobber an inprogress host data transfer */ - test DFSTATUS, MREQPEND jnz ultra2_dmafifoempty; -ultra2_dmahalt: - and DFCNTRL, ~(SCSIEN|HDMAEN); - test DFCNTRL, HDMAEN jnz .; - /* + * We assume that, even though data may still be + * transferring to the host, that the SCSI side of + * the DMA engine is now in a static state. This + * allows us to update our notion of where we are + * in this transfer. + * * If, by chance, we stopped before being able * to fetch additional segments for this transfer, * yet the last S/G was completely exhausted, @@ -961,14 +964,14 @@ * If we happened to stop on the last segment, then * our residual information is still correct from * the idle loop and there is no need to perform - * any fixups. Just jump to data_phase_finish. + * any fixups. */ ultra2_ensure_sg: test SG_CACHE_SHADOW, LAST_SEG jz ultra2_shvalid; /* Record if we've consumed all S/G entries */ - test SG_CACHE_SHADOW, LAST_SEG_DONE jz data_phase_finish; + test SSTAT2, SHVALID jnz residuals_correct; or SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL; - jmp data_phase_finish; + jmp residuals_correct; ultra2_shvalid: test SSTAT2, SHVALID jnz sgptr_fixup; @@ -998,6 +1001,62 @@ test SG_CACHE_SHADOW, ODD_SEG jz . + 2; or DATA_COUNT_ODD, 0x1; clr SCB_RESIDUAL_DATACNT[3]; /* We are not the last seg */ +residuals_correct: + /* + * Go ahead and shut down the DMA engine now. + * In the future, we'll want to handle end of + * transfer messages prior to doing this, but this + * requires similar restructuring for pre-ULTRA2 + * controllers. + */ + test DMAPARAMS, DIRECTION jnz ultra2_fifoempty; +ultra2_fifoflush: + if ((ahc->features & AHC_DT) == 0) { + if ((ahc->bugs & AHC_AUTOFLUSH_BUG) != 0) { + /* + * On Rev A of the aic7890, the autoflush + * feature doesn't function correctly. + * Perform an explicit manual flush. During + * a manual flush, the FIFOEMP bit becomes + * true every time the PCI FIFO empties + * regardless of the state of the SCSI FIFO. + * It can take up to 4 clock cycles for the + * SCSI FIFO to get data into the PCI FIFO + * and for FIFOEMP to de-assert. Here we + * guard against this condition by making + * sure the FIFOEMP bit stays on for 5 full + * clock cycles. + */ + or DFCNTRL, FIFOFLUSH; + test DFSTATUS, FIFOEMP jz ultra2_fifoflush; + test DFSTATUS, FIFOEMP jz ultra2_fifoflush; + test DFSTATUS, FIFOEMP jz ultra2_fifoflush; + test DFSTATUS, FIFOEMP jz ultra2_fifoflush; + } + test DFSTATUS, FIFOEMP jz ultra2_fifoflush; + } else { + /* + * We enable the auto-ack feature on DT capable + * controllers. This means that the controller may + * have already transferred some overrun bytes into + * the data FIFO and acked them on the bus. The only + * way to detect this situation is to wait for + * LAST_SEG_DONE to come true on a completed transfer + * and then test to see if the data FIFO is non-empty. + */ + test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz . + 4; + test SG_CACHE_SHADOW, LAST_SEG_DONE jz .; + test DFSTATUS, FIFOEMP jnz ultra2_fifoempty; + /* Overrun */ + jmp data_phase_loop; + test DFSTATUS, FIFOEMP jz .; + } +ultra2_fifoempty: + /* Don't clobber an inprogress host data transfer */ + test DFSTATUS, MREQPEND jnz ultra2_fifoempty; +ultra2_dmahalt: + and DFCNTRL, ~(SCSIEN|HDMAEN); + test DFCNTRL, SCSIEN|HDMAEN jnz .; } else { /* If we are the last SG block, tell the hardware. */ if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 @@ -1156,7 +1215,11 @@ } if ((ahc->flags & AHC_INITIATORROLE) != 0) { test SSTAT1, REQINIT jz .; - test SSTAT1,PHASEMIS jz data_phase_loop; + if ((ahc->features & AHC_DT) == 0) { + test SSTAT1,PHASEMIS jz data_phase_loop; + } else { + test SCSIPHASE, DATA_PHASE_MASK jnz data_phase_loop; + } } data_phase_done: @@ -1296,13 +1359,17 @@ or DFCNTRL, FIFOFLUSH; } p_command_loop: - test SSTAT0, SDONE jnz . + 2; - test SSTAT1, PHASEMIS jz p_command_loop; - /* - * Wait for our ACK to go-away on it's own - * instead of being killed by SCSIEN getting cleared. - */ - test SCSISIGI, ACKI jnz .; + if ((ahc->features & AHC_DT) == 0) { + test SSTAT0, SDONE jnz . + 2; + test SSTAT1, PHASEMIS jz p_command_loop; + /* + * Wait for our ACK to go-away on it's own + * instead of being killed by SCSIEN getting cleared. + */ + test SCSISIGI, ACKI jnz .; + } else { + test DFCNTRL, SCSIEN jnz p_command_loop; + } and DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN); test DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz .; if ((ahc->features & AHC_ULTRA2) != 0) { @@ -1346,23 +1413,16 @@ * reason. */ p_mesgout_retry: - or SCSISIGO,ATNO,LASTPHASE;/* turn on ATN for the retry */ + /* Turn on ATN for the retry */ + if ((ahc->features & AHC_DT) == 0) { + or SCSISIGO, ATNO, LASTPHASE; + } else { + mvi SCSISIGO, ATNO; + } p_mesgout: mov SINDEX, MSG_OUT; cmp SINDEX, MSG_IDENTIFYFLAG jne p_mesgout_from_host; test SCB_CONTROL,MK_MESSAGE jnz host_message_loop; - mov FUNCTION1, SCB_SCSIID; - mov A, FUNCTION1; - mov SINDEX, TARGET_MSG_REQUEST[0]; - if ((ahc->features & AHC_TWIN) != 0) { - /* Second Channel uses high byte bits */ - test SCB_SCSIID, TWIN_CHNLB jz . + 2; - mov SINDEX, TARGET_MSG_REQUEST[1]; - } else if ((ahc->features & AHC_WIDE) != 0) { - test SCB_SCSIID, 0x80 jz . + 2; /* target > 7 */ - mov SINDEX, TARGET_MSG_REQUEST[1]; - } - test SINDEX, A jnz host_message_loop; p_mesgout_identify: or SINDEX, MSG_IDENTIFYFLAG|DISCENB, SCB_LUN; test SCB_CONTROL, DISCENB jnz . + 2; @@ -1555,10 +1615,17 @@ * only if we've actually been into a data phase to change them. This * protects against bogus data in scratch ram and the residual counts * since they are only initialized when we go into data_in or data_out. + * Ack the message as soon as possible. For chips without S/G pipelining, + * we can only ack the message after SHADDR has been saved. On these + * chips, SHADDR increments with every bus transaction, even PIO. */ mesgin_sdptrs: - test SEQ_FLAGS, DPHASE jz mesgin_done; - + if ((ahc->features & AHC_ULTRA2) != 0) { + mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ + test SEQ_FLAGS, DPHASE jz ITloop; + } else { + test SEQ_FLAGS, DPHASE jz mesgin_done; + } /* * The SCB_SGPTR becomes the next one we'll download, * and the SCB_DATAPTR becomes the current SHADDR. @@ -1567,13 +1634,17 @@ */ if ((ahc->features & AHC_CMD_CHAN) != 0) { bmov SCB_DATAPTR, SHADDR, 4; + if ((ahc->features & AHC_ULTRA2) == 0) { + mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ + } bmov SCB_DATACNT, SCB_RESIDUAL_DATACNT, 8; } else { mvi DINDEX, SCB_DATAPTR; mvi SHADDR call bcopy_4; + mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ mvi SCB_RESIDUAL_DATACNT call bcopy_8; } - jmp mesgin_done; + jmp ITloop; /* * Restore pointers message? Data pointers are recopied from the @@ -1751,7 +1822,11 @@ jmp mesgin_done; mk_mesg: - or SCSISIGO,ATNO,LASTPHASE;/* turn on ATNO */ + if ((ahc->features & AHC_DT) == 0) { + or SCSISIGO, ATNO, LASTPHASE; + } else { + mvi SCSISIGO, ATNO; + } mov MSG_OUT,SINDEX ret; /* @@ -1924,7 +1999,9 @@ test SSTAT1, REQINIT jz phase_lock; test SSTAT1, SCSIPERR jnz phase_lock_perr; phase_lock_latch_phase: - and SCSISIGO, PHASE_MASK, SCSISIGI; + if ((ahc->features & AHC_DT) == 0) { + and SCSISIGO, PHASE_MASK, SCSISIGI; + } and LASTPHASE, PHASE_MASK, SCSISIGI ret; if ((ahc->features & AHC_CMD_CHAN) == 0) { @@ -2068,9 +2145,9 @@ * latch is full. */ clr A; - /* Wait for some data to arrive. */ + /* Wait for at least 8 bytes of data to arrive. */ dma_scb_hang_fifo: - test DFSTATUS, FIFOEMP jnz dma_scb_hang_fifo; + test DFSTATUS, FIFOQWDEMP jnz dma_scb_hang_fifo; dma_scb_hang_wait: test DFSTATUS, MREQPEND jnz dma_scb_hang_wait; test DFSTATUS, HDONE jnz dma_scb_hang_dma_done; @@ -2078,8 +2155,7 @@ test DFSTATUS, HDONE jnz dma_scb_hang_dma_done; /* * The PCI module no longer intends to perform - * a PCI transaction and HDONE has not come true. - * We are hung. Drain the fifo. + * a PCI transaction. Drain the fifo. */ dma_scb_hang_empty_fifo: /* @@ -2101,6 +2177,7 @@ */ not SINDEX; add A, 5, SINDEX; + cmp A, 4 je dma_finish_nowait; jmp dma_scb_hang_fifo; dma_scb_hang_dma_done: and DFCNTRL, ~HDMAEN; @@ -2146,6 +2223,7 @@ */ dma_finish: test DFSTATUS,HDONE jz dma_finish; +dma_finish_nowait: /* Turn off DMA */ and DFCNTRL, ~HDMAEN; test DFCNTRL, HDMAEN jnz .; diff -Nru a/drivers/scsi/aic7xxx/aic7xxx_inline.h b/drivers/scsi/aic7xxx/aic7xxx_inline.h --- a/drivers/scsi/aic7xxx/aic7xxx_inline.h Wed May 16 06:00:24 2001 +++ b/drivers/scsi/aic7xxx/aic7xxx_inline.h Wed May 16 06:00:24 2001 @@ -28,7 +28,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: //depot/src/aic7xxx/aic7xxx_inline.h#15 $ + * $Id: //depot/src/aic7xxx/aic7xxx_inline.h#21 $ * * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx_inline.h,v 1.8 2000/11/12 05:19:46 gibbs Exp $ */ @@ -37,10 +37,10 @@ #define _AIC7XXX_INLINE_H_ /************************* Sequencer Execution Control ************************/ -static __inline int sequencer_paused(struct ahc_softc *ahc); +static __inline int ahc_is_paused(struct ahc_softc *ahc); static __inline void ahc_pause_bug_fix(struct ahc_softc *ahc); -static __inline void pause_sequencer(struct ahc_softc *ahc); -static __inline void unpause_sequencer(struct ahc_softc *ahc); +static __inline void ahc_pause(struct ahc_softc *ahc); +static __inline void ahc_unpause(struct ahc_softc *ahc); /* * Work around any chip bugs related to halting sequencer execution. @@ -62,7 +62,7 @@ * Returns non-zero status if the sequencer is stopped. */ static __inline int -sequencer_paused(struct ahc_softc *ahc) +ahc_is_paused(struct ahc_softc *ahc) { return ((ahc_inb(ahc, HCNTRL) & PAUSE) != 0); } @@ -75,7 +75,7 @@ * for critical sections. */ static __inline void -pause_sequencer(struct ahc_softc *ahc) +ahc_pause(struct ahc_softc *ahc) { ahc_outb(ahc, HCNTRL, ahc->pause); @@ -83,7 +83,7 @@ * Since the sequencer can disable pausing in a critical section, we * must loop until it actually stops. */ - while (sequencer_paused(ahc) == 0) + while (ahc_is_paused(ahc) == 0) ; ahc_pause_bug_fix(ahc); @@ -100,7 +100,7 @@ * condition. */ static __inline void -unpause_sequencer(struct ahc_softc *ahc) +ahc_unpause(struct ahc_softc *ahc) { if ((ahc_inb(ahc, INTSTAT) & (SCSIINT | SEQINT | BRKADRINT)) == 0) ahc_outb(ahc, HCNTRL, ahc->unpause); @@ -188,12 +188,12 @@ /*********************** Miscelaneous Support Functions ***********************/ -static __inline int ahc_check_residual(struct scb *scb); +static __inline void ahc_update_residual(struct scb *scb); static __inline struct ahc_initiator_tinfo * ahc_fetch_transinfo(struct ahc_softc *ahc, char channel, u_int our_id, u_int remote_id, - struct tmode_tstate **tstate); + struct ahc_tmode_tstate **tstate); static __inline struct scb* ahc_get_scb(struct ahc_softc *ahc); static __inline void ahc_free_scb(struct ahc_softc *ahc, struct scb *scb); @@ -211,15 +211,16 @@ * Determine whether the sequencer reported a residual * for this SCB/transaction. */ -static __inline int -ahc_check_residual(struct scb *scb) +static __inline void +ahc_update_residual(struct scb *scb) { - struct status_pkt *sp; + uint32_t sgptr; - sp = &scb->hscb->shared_data.status; - if ((scb->hscb->sgptr & SG_RESID_VALID) != 0) - return (1); - return (0); + sgptr = ahc_le32toh(scb->hscb->sgptr); + if ((sgptr & SG_RESID_VALID) != 0) + ahc_calc_residual(scb); + else + ahc_set_residual(scb, 0); } /* @@ -228,7 +229,7 @@ */ static __inline struct ahc_initiator_tinfo * ahc_fetch_transinfo(struct ahc_softc *ahc, char channel, u_int our_id, - u_int remote_id, struct tmode_tstate **tstate) + u_int remote_id, struct ahc_tmode_tstate **tstate) { /* * Transfer data structures are stored from the perspective @@ -345,10 +346,10 @@ ahc_outb(ahc, HNSCB_QOFF, ahc->qinfifonext); } else { if ((ahc->features & AHC_AUTOPAUSE) == 0) - pause_sequencer(ahc); + ahc_pause(ahc); ahc_outb(ahc, KERNEL_QINPOS, ahc->qinfifonext); if ((ahc->features & AHC_AUTOPAUSE) == 0) - unpause_sequencer(ahc); + ahc_unpause(ahc); } } @@ -412,19 +413,28 @@ * completion queues. This avoids a costly PCI bus read in * most cases. */ - intstat = 0; - if ((queuestat = ahc_check_cmdcmpltqueues(ahc)) != 0) + if ((ahc->flags & (AHC_ALL_INTERRUPTS|AHC_EDGE_INTERRUPT)) == 0 + && (queuestat = ahc_check_cmdcmpltqueues(ahc)) != 0) intstat = CMDCMPLT; - - if ((intstat & INT_PEND) == 0 - || (ahc->flags & AHC_ALL_INTERRUPTS) != 0) { - + else { intstat = ahc_inb(ahc, INTSTAT); + /* + * We can't generate queuestat once above + * or we are exposed to a race when our + * interrupt is shared with another device. + * if instat showed a command complete interrupt, + * but our first generation of queue stat + * "just missed" the delivery of this transaction, + * we would clear the command complete interrupt + * below without ever servicing the completed + * command. + */ + queuestat = ahc_check_cmdcmpltqueues(ahc); #if AHC_PCI_CONFIG > 0 if (ahc->unsolicited_ints > 500 && (ahc->chip & AHC_PCI) != 0 && (ahc_inb(ahc, ERROR) & PCIERRSTAT) != 0) - ahc_pci_intr(ahc); + ahc->bus_intr(ahc); #endif } diff -Nru a/drivers/scsi/aic7xxx/aic7xxx_linux.c b/drivers/scsi/aic7xxx/aic7xxx_linux.c --- a/drivers/scsi/aic7xxx/aic7xxx_linux.c Wed May 16 06:00:18 2001 +++ b/drivers/scsi/aic7xxx/aic7xxx_linux.c Wed May 16 06:00:18 2001 @@ -1,7 +1,7 @@ /* * Adaptec AIC7xxx device driver for Linux. * - * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux.c#54 $ + * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux.c#66 $ * * Copyright (c) 1994 John Aycock * The University of Calgary Department of Computer Science. @@ -112,7 +112,6 @@ * 8: SMP friendliness has been improved * */ -#include /* * The next three defines are user configurable. These should be the only @@ -158,8 +157,8 @@ * The scsi error recovery code performs its own bus settle * delay handling for error recovery actions. */ -#ifdef CONFIG_AIC7XXX_RESET_DELAY -#define AIC7XXX_RESET_DELAY CONFIG_AIC7XXX_RESET_DELAY +#ifdef CONFIG_AIC7XXX_RESET_DELAY_MS +#define AIC7XXX_RESET_DELAY CONFIG_AIC7XXX_RESET_DELAY_MS #else #define AIC7XXX_RESET_DELAY 5000 #endif @@ -479,45 +478,48 @@ #endif -static void ahc_handle_scsi_status(struct ahc_softc *, - struct ahc_linux_device *, struct scb *); -static void ahc_filter_command(struct ahc_softc *ahc, Scsi_Cmnd *cmd); -static void ahc_sem_timeout(u_long arg); -static void ahc_release_sim_queue(u_long arg); -static int aic7xxx_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag); -static void aic7xxx_initialize_scsi_bus(struct ahc_softc *ahc); -static void aic7xxx_select_queue_depth(struct Scsi_Host *host, - Scsi_Device *scsi_devs); -static void aic7xxx_device_queue_depth(struct ahc_softc *ahc, - Scsi_Device *device); -static struct ahc_linux_target* ahc_alloc_target(struct ahc_softc *, - u_int, u_int); -static void ahc_free_target(struct ahc_softc *ahc, - struct ahc_linux_target *targ); -static struct ahc_linux_device* ahc_alloc_device(struct ahc_softc *, - struct ahc_linux_target *, - u_int); -static void ahc_free_device(struct ahc_softc *ahc, - struct ahc_linux_device *dev); -static void ahc_run_device_queue(struct ahc_softc *ahc, - struct ahc_linux_device *dev); -static void ahc_setup_tag_info(char *p, char *end); -static int ahc_next_unit(void); +static void ahc_linux_handle_scsi_status(struct ahc_softc *, + struct ahc_linux_device *, + struct scb *); +static void ahc_linux_filter_command(struct ahc_softc *ahc, Scsi_Cmnd *cmd); +static void ahc_linux_sem_timeout(u_long arg); +static void ahc_linux_freeze_sim_queue(struct ahc_softc *ahc); +static void ahc_linux_release_sim_queue(u_long arg); +static int ahc_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag); +static void ahc_linux_initialize_scsi_bus(struct ahc_softc *ahc); +static void ahc_linux_select_queue_depth(struct Scsi_Host *host, + Scsi_Device *scsi_devs); +static void ahc_linux_device_queue_depth(struct ahc_softc *ahc, + Scsi_Device *device); +static struct ahc_linux_target* ahc_linux_alloc_target(struct ahc_softc*, + u_int, u_int); +static void ahc_linux_free_target(struct ahc_softc*, + struct ahc_linux_target*); +static struct ahc_linux_device* ahc_linux_alloc_device(struct ahc_softc*, + struct ahc_linux_target*, + u_int); +static void ahc_linux_free_device(struct ahc_softc*, + struct ahc_linux_device*); +static void ahc_linux_run_device_queue(struct ahc_softc*, + struct ahc_linux_device*); +static void ahc_linux_setup_tag_info(char *p, char *end); +static int ahc_linux_next_unit(void); +static int ahc_linux_halt(struct notifier_block *nb, u_long event, void *buf); static __inline struct ahc_linux_device* - ahc_get_device(struct ahc_softc *ahc, u_int channel, - u_int target, u_int lun, int /*alloc*/); -static __inline void ahc_queue_cmd_complete(struct ahc_softc *ahc, - Scsi_Cmnd *cmd); -static __inline void ahc_run_complete_queue(struct ahc_softc *ahc, - struct ahc_cmd *acmd); -static __inline void ahc_check_device_queue(struct ahc_softc *ahc, - struct ahc_linux_device *dev); -static __inline void ahc_sniff_command(struct ahc_softc *ahc, Scsi_Cmnd *cmd); -static __inline void ahc_unmap_scb(struct ahc_softc *ahc, struct scb *scb); + ahc_linux_get_device(struct ahc_softc *ahc, u_int channel, + u_int target, u_int lun, int alloc); +static __inline void ahc_linux_queue_cmd_complete(struct ahc_softc *ahc, + Scsi_Cmnd *cmd); +static __inline void ahc_linux_run_complete_queue(struct ahc_softc *ahc, + struct ahc_cmd *acmd); +static __inline void ahc_linux_check_device_queue(struct ahc_softc *ahc, + struct ahc_linux_device *dev); +static __inline void ahc_linux_sniff_command(struct ahc_softc*, Scsi_Cmnd*); +static __inline void ahc_linux_unmap_scb(struct ahc_softc*, struct scb*); static __inline struct ahc_linux_device* -ahc_get_device(struct ahc_softc *ahc, u_int channel, u_int target, +ahc_linux_get_device(struct ahc_softc *ahc, u_int channel, u_int target, u_int lun, int alloc) { struct ahc_linux_target *targ; @@ -530,7 +532,7 @@ targ = ahc->platform_data->targets[target_offset]; if (targ == NULL) { if (alloc != 0) { - targ = ahc_alloc_target(ahc, channel, target); + targ = ahc_linux_alloc_target(ahc, channel, target); if (targ == NULL) return (NULL); } else @@ -538,17 +540,17 @@ } dev = targ->devices[lun]; if (dev == NULL && alloc != 0) - dev = ahc_alloc_device(ahc, targ, lun); + dev = ahc_linux_alloc_device(ahc, targ, lun); return (dev); } static __inline void -ahc_queue_cmd_complete(struct ahc_softc *ahc, Scsi_Cmnd *cmd) +ahc_linux_queue_cmd_complete(struct ahc_softc *ahc, Scsi_Cmnd *cmd) { /* * Typically, the complete queue has very few entries * queued to it before the queue is emptied by - * ahc_run_complete_queue, so sorting the entries + * ahc_linux_run_complete_queue, so sorting the entries * by generation number should be inexpensive. * We perform the sort so that commands that complete * with an error are retuned in the order origionally @@ -584,7 +586,7 @@ } static __inline void -ahc_run_complete_queue(struct ahc_softc *ahc, struct ahc_cmd *acmd) +ahc_linux_run_complete_queue(struct ahc_softc *ahc, struct ahc_cmd *acmd) { u_long done_flags; @@ -601,7 +603,8 @@ } static __inline void -ahc_check_device_queue(struct ahc_softc *ahc, struct ahc_linux_device *dev) +ahc_linux_check_device_queue(struct ahc_softc *ahc, + struct ahc_linux_device *dev) { if ((dev->flags & AHC_DEV_FREEZE_TIL_EMPTY) != 0 && dev->active == 0) { @@ -613,11 +616,11 @@ || dev->openings == 0 || dev->qfrozen != 0) return; - ahc_run_device_queue(ahc, dev); + ahc_linux_run_device_queue(ahc, dev); } static __inline void -ahc_run_device_queues(struct ahc_softc *ahc) +ahc_linux_run_device_queues(struct ahc_softc *ahc) { struct ahc_linux_device *dev; @@ -626,25 +629,25 @@ && (dev = LIST_FIRST(&ahc->platform_data->device_runq)) != NULL) { LIST_REMOVE(dev, links); dev->flags &= ~AHC_DEV_ON_RUN_LIST; - ahc_check_device_queue(ahc, dev); + ahc_linux_check_device_queue(ahc, dev); } } static __inline void -ahc_sniff_command(struct ahc_softc *ahc, Scsi_Cmnd *cmd) +ahc_linux_sniff_command(struct ahc_softc *ahc, Scsi_Cmnd *cmd) { /* * Determine whether we care to filter * information out of this command. If so, - * pass it on to ahc_filter_command() for more + * pass it on to ahc_linux_filter_command() for more * heavy weight processing. */ if (cmd->cmnd[0] == INQUIRY) - ahc_filter_command(ahc, cmd); + ahc_linux_filter_command(ahc, cmd); } static __inline void -ahc_unmap_scb(struct ahc_softc *ahc, struct scb *scb) +ahc_linux_unmap_scb(struct ahc_softc *ahc, struct scb *scb) { Scsi_Cmnd *cmd; @@ -662,6 +665,24 @@ scsi_to_pci_dma_dir(cmd->sc_data_direction)); } +/************************ Shutdown/halt/reboot hook ***************************/ +#include +#include + +static struct notifier_block ahc_linux_notifier = { + ahc_linux_halt, NULL, 0 +}; + +static int ahc_linux_halt(struct notifier_block *nb, u_long event, void *buf) +{ + struct ahc_softc *ahc; + + TAILQ_FOREACH(ahc, &ahc_tailq, links) { + ahc_shutdown(ahc); + } + return (NOTIFY_OK); +} + /******************************** Macros **************************************/ #define BUILD_SCSIID(ahc, cmd) \ ((((cmd)->target << TID_SHIFT) & TID) \ @@ -820,6 +841,9 @@ /* Still equal. Sort by BIOS address, ioport, or bus/slot/func. */ switch (rvalue) { case AHC_PCI: + { + char primary_channel; + value = ahc_get_pci_bus(lahc->dev_softc) - ahc_get_pci_bus(rahc->dev_softc); if (value != 0) @@ -828,19 +852,18 @@ - ahc_get_pci_slot(rahc->dev_softc); if (value != 0) break; - value = ahc_get_pci_function(lahc->dev_softc) - - ahc_get_pci_function(rahc->dev_softc); /* * On multi-function devices, the user can choose * to have function 1 probed before function 0. - * Function 0 is the only one that will have - * CHANNEL_B_PRIMARY set. + * Give whichever channel is the primary channel + * the lowest priority. */ - if (value < 0 - && (lahc->flags & AHC_CHANNEL_B_PRIMARY) != 0) - /* Swap the two */ - value = -value; + primary_channel = (lahc->flags & AHC_PRIMARY_CHANNEL) + 'A'; + value = 1; + if (lahc->channel == primary_channel) + value = -1; break; + } case AHC_EISA: if ((rahc->flags & AHC_BIOS_ENABLED) != 0) { value = lahc->platform_data->bios_address @@ -857,7 +880,7 @@ } static void -ahc_setup_tag_info(char *p, char *end) +ahc_linux_setup_tag_info(char *p, char *end) { char *base; char *tok; @@ -865,7 +888,7 @@ char *tok_end2; int i; int instance; - int device; + int targ; int done; char tok_list[] = {'.', ',', '{', '}', '\0'}; @@ -873,7 +896,7 @@ return; instance = -1; - device = -1; + targ = -1; done = FALSE; base = p; /* Forward us just past the ':' */ @@ -886,13 +909,13 @@ case '{': if (instance == -1) instance = 0; - else if (device == -1) - device = 0; + else if (targ == -1) + targ = 0; tok++; break; case '}': - if (device != -1) - device = -1; + if (targ != -1) + targ = -1; else if (instance != -1) instance = -1; tok++; @@ -901,11 +924,11 @@ case '.': if (instance == -1) done = TRUE; - else if (device >= 0) - device++; + else if (targ >= 0) + targ++; else if (instance >= 0) instance++; - if ((device >= AHC_NUM_TARGETS) || + if ((targ >= AHC_NUM_TARGETS) || (instance >= NUM_ELEMENTS(aic7xxx_tag_info))) done = TRUE; tok++; @@ -926,11 +949,12 @@ done = FALSE; } } - if ((instance >= 0) && (device >= 0) && - (instance < NUM_ELEMENTS(aic7xxx_tag_info)) && - (device < AHC_NUM_TARGETS)) - aic7xxx_tag_info[instance].tag_commands[device] = + if ((instance >= 0) && (targ >= 0) + && (instance < NUM_ELEMENTS(aic7xxx_tag_info)) + && (targ < AHC_NUM_TARGETS)) { + aic7xxx_tag_info[instance].tag_commands[targ] = simple_strtoul(tok, NULL, 0) & 0xff; + } tok = tok_end; break; } @@ -980,7 +1004,7 @@ continue; if (strncmp(p, "tag_info", n) == 0) { - ahc_setup_tag_info(p + n, end); + ahc_linux_setup_tag_info(p + n, end); } else if (p[n] == ':') { *(options[i].flag) = simple_strtoul(p + n + 1, NULL, 0); @@ -989,8 +1013,10 @@ } else { *(options[i].flag) = ~(*(options[i].flag)); } + break; } } + register_reboot_notifier(&ahc_linux_notifier); return 1; } @@ -1004,7 +1030,7 @@ * Try to detect an Adaptec 7XXX controller. */ int -aic7xxx_detect(Scsi_Host_Template *template) +ahc_linux_detect(Scsi_Host_Template *template) { struct ahc_softc *ahc; int found; @@ -1016,8 +1042,8 @@ */ if (offsetof(struct ahc_cmd_internal, end) > offsetof(struct scsi_cmnd, host_scribble)) { - printf("aic7xxx_detect: SCSI data structures changed.\n"); - printf("aic7xxx_detect: Unable to attach\n"); + printf("ahc_linux_detect: SCSI data structures changed.\n"); + printf("ahc_linux_detect: Unable to attach\n"); return (0); } #ifdef MODULE @@ -1054,7 +1080,7 @@ found = 0; TAILQ_FOREACH(ahc, &ahc_tailq, links) { - if (aic7xxx_register_host(ahc, template) == 0) + if (ahc_linux_register_host(ahc, template) == 0) found++; } aic7xxx_detect_complete++; @@ -1062,7 +1088,7 @@ } int -aic7xxx_register_host(struct ahc_softc *ahc, Scsi_Host_Template *template) +ahc_linux_register_host(struct ahc_softc *ahc, Scsi_Host_Template *template) { char buf[80]; struct Scsi_Host *host; @@ -1081,12 +1107,13 @@ host->can_queue = AHC_MAX_QUEUE; host->cmd_per_lun = 2; host->sg_tablesize = AHC_NSEG; - host->select_queue_depths = aic7xxx_select_queue_depth; + host->select_queue_depths = ahc_linux_select_queue_depth; + /* XXX No way to communicate the ID for multiple channels */ host->this_id = ahc->our_id; host->irq = ahc->platform_data->irq; host->max_id = (ahc->features & AHC_WIDE) ? 16 : 8; host->max_channel = (ahc->features & AHC_TWIN) ? 1 : 0; - ahc_set_unit(ahc, ahc_next_unit()); + ahc_set_unit(ahc, ahc_linux_next_unit()); sprintf(buf, "scsi%d", host->host_no); new_name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT); if (new_name != NULL) { @@ -1094,8 +1121,10 @@ ahc_set_name(ahc, new_name); } host->unique_id = ahc->unit; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,4) scsi_set_pci_device(host, ahc->dev_softc); - aic7xxx_initialize_scsi_bus(ahc); +#endif + ahc_linux_initialize_scsi_bus(ahc); ahc_unlock(ahc, &s); return (0); } @@ -1107,7 +1136,7 @@ * scenario. */ static int -ahc_next_unit() +ahc_linux_next_unit() { struct ahc_softc *ahc; int unit; @@ -1129,7 +1158,7 @@ * target. */ void -aic7xxx_initialize_scsi_bus(struct ahc_softc *ahc) +ahc_linux_initialize_scsi_bus(struct ahc_softc *ahc) { int i; int numtarg; @@ -1159,7 +1188,7 @@ for (; i < numtarg; i++) { struct ahc_devinfo devinfo; struct ahc_initiator_tinfo *tinfo; - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *tstate; u_int our_id; u_int target_id; char channel; @@ -1175,20 +1204,27 @@ tinfo = ahc_fetch_transinfo(ahc, channel, our_id, target_id, &tstate); tinfo->goal = tinfo->user; + /* + * Don't try negotiations that require PPR messages + * until we successfully retrieve Inquiry data. + */ + tinfo->goal.ppr_options = 0; + if (tinfo->goal.transport_version > SCSI_REV_2) + tinfo->goal.transport_version = SCSI_REV_2; ahc_compile_devinfo(&devinfo, our_id, target_id, CAM_LUN_WILDCARD, channel, ROLE_INITIATOR); - ahc_update_target_msg_request(ahc, &devinfo, tinfo, - /*force*/FALSE, /*paused*/FALSE); + ahc_update_neg_request(ahc, &devinfo, tstate, + tinfo, /*force*/FALSE); } /* Give the bus some time to recover */ if ((ahc->flags & (AHC_RESET_BUS_A|AHC_RESET_BUS_B)) != 0) { - ahc->platform_data->qfrozen++; + ahc_linux_freeze_sim_queue(ahc); init_timer(&ahc->platform_data->reset_timer); ahc->platform_data->reset_timer.data = (u_long)ahc; ahc->platform_data->reset_timer.expires = jiffies + (AIC7XXX_RESET_DELAY * HZ)/1000; ahc->platform_data->reset_timer.function = - ahc_release_sim_queue; + ahc_linux_release_sim_queue; add_timer(&ahc->platform_data->reset_timer); } } @@ -1238,6 +1274,11 @@ 0x1000); #endif } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + /* XXX Need an instance detach in the PCI code */ + if (ahc->dev_softc != NULL) + ahc->dev_softc->driver = NULL; +#endif free(ahc->platform_data, M_DEVBUF); } } @@ -1252,28 +1293,41 @@ } void -ahc_platform_set_tags(struct ahc_softc *ahc, - struct ahc_devinfo *devinfo, int enable) +ahc_platform_set_tags(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, + ahc_queue_alg alg) { struct ahc_linux_device *dev; + int was_queuing; + int now_queuing; - dev = ahc_get_device(ahc, devinfo->channel - 'A', - devinfo->target, - devinfo->lun, /*alloc*/FALSE); + dev = ahc_linux_get_device(ahc, devinfo->channel - 'A', + devinfo->target, + devinfo->lun, /*alloc*/FALSE); + was_queuing = dev->flags & (AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED); + now_queuing = alg != AHC_QUEUE_NONE; if ((dev->flags & AHC_DEV_FREEZE_TIL_EMPTY) == 0 + && (was_queuing != now_queuing) && (dev->active != 0)) { dev->flags |= AHC_DEV_FREEZE_TIL_EMPTY; dev->qfrozen++; } - if (enable) { - /* - * Start out agressively and allow our - * dynamic queue depth algorithm take - * care of the rest. - */ - dev->maxtags = AHC_MAX_QUEUE; - dev->openings = dev->maxtags - dev->active; + dev->flags &= ~(AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED); + if (now_queuing) { + + if (!was_queuing) { + /* + * Start out agressively and allow our + * dynamic queue depth algorithm to take + * care of the rest. + */ + dev->maxtags = AHC_MAX_QUEUE; + dev->openings = dev->maxtags - dev->active; + } + if (alg == AHC_QUEUE_TAGGED) + dev->flags |= AHC_DEV_Q_TAGGED; + else + dev->flags |= AHC_DEV_Q_BASIC; } else { /* We can only have one opening */ dev->maxtags = 0; @@ -1326,9 +1380,9 @@ struct ahc_busyq *busyq; struct ahc_cmd *acmd; - dev = ahc_get_device(ahc, chan, targ, - clun, /*alloc*/FALSE); - + dev = ahc_linux_get_device(ahc, chan, + targ, clun, + /*alloc*/FALSE); if (dev == NULL) continue; @@ -1341,7 +1395,7 @@ acmd_links.tqe); count++; cmd->result = status << 16; - ahc_queue_cmd_complete(ahc, cmd); + ahc_linux_queue_cmd_complete(ahc, cmd); } } } @@ -1355,8 +1409,8 @@ * off the input host adapter. */ static void -aic7xxx_select_queue_depth(struct Scsi_Host * host, - Scsi_Device * scsi_devs) +ahc_linux_select_queue_depth(struct Scsi_Host * host, + Scsi_Device * scsi_devs) { Scsi_Device *device; struct ahc_softc *ahc; @@ -1368,7 +1422,7 @@ scbnum = 0; for (device = scsi_devs; device != NULL; device = device->next) { if (device->host == host) { - aic7xxx_device_queue_depth(ahc, device); + ahc_linux_device_queue_depth(ahc, device); scbnum += device->queue_depth; } } @@ -1379,11 +1433,11 @@ * Determines the queue depth for a given device. */ static void -aic7xxx_device_queue_depth(struct ahc_softc *ahc, Scsi_Device * device) +ahc_linux_device_queue_depth(struct ahc_softc *ahc, Scsi_Device * device) { struct ahc_devinfo devinfo; struct ahc_initiator_tinfo *targ_info; - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *tstate; uint8_t tags; ahc_compile_devinfo(&devinfo, @@ -1397,7 +1451,7 @@ tags = 0; if (device->tagged_supported != 0 - && (tstate->discenable & devinfo.target_mask) != 0) { + && (ahc->user_discenable & devinfo.target_mask) != 0) { if (ahc->unit >= NUM_ELEMENTS(aic7xxx_tag_info)) { printf("aic7xxx: WARNING, insufficient " @@ -1418,7 +1472,7 @@ } if (tags != 0) { device->queue_depth = tags; - ahc_set_tags(ahc, &devinfo, TRUE); + ahc_set_tags(ahc, &devinfo, AHC_QUEUE_TAGGED); printf("scsi%d:%d:%d:%d: Tagged Queuing enabled. Depth %d\n", ahc->platform_data->host->host_no, device->channel, device->id, device->lun, tags); @@ -1437,7 +1491,7 @@ * Queue an SCB to the controller. */ int -aic7xxx_queue(Scsi_Cmnd * cmd, void (*scsi_done) (Scsi_Cmnd *)) +ahc_linux_queue(Scsi_Cmnd * cmd, void (*scsi_done) (Scsi_Cmnd *)) { struct ahc_softc *ahc; struct ahc_linux_device *dev; @@ -1451,29 +1505,29 @@ cmd->scsi_done = scsi_done; ahc_lock(ahc, &flags); - dev = ahc_get_device(ahc, cmd->channel, cmd->target, - cmd->lun, /*alloc*/TRUE); + dev = ahc_linux_get_device(ahc, cmd->channel, cmd->target, + cmd->lun, /*alloc*/TRUE); if (dev == NULL) { ahc_unlock(ahc, &flags); - printf("aic7xxx_queue: Unable to allocate device!\n"); + printf("aic7xxx_linux_queue: Unable to allocate device!\n"); return (-ENOMEM); } cmd->result = CAM_REQ_INPROG << 16; TAILQ_INSERT_TAIL(&dev->busyq, (struct ahc_cmd *)cmd, acmd_links.tqe); - ahc_run_device_queue(ahc, dev); + ahc_linux_run_device_queue(ahc, dev); ahc_unlock(ahc, &flags); return (0); } static void -ahc_run_device_queue(struct ahc_softc *ahc, struct ahc_linux_device *dev) +ahc_linux_run_device_queue(struct ahc_softc *ahc, struct ahc_linux_device *dev) { struct ahc_cmd *acmd; struct scsi_cmnd *cmd; struct scb *scb; struct hardware_scb *hscb; struct ahc_initiator_tinfo *tinfo; - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *tstate; uint16_t mask; while ((acmd = TAILQ_FIRST(&dev->busyq)) != NULL @@ -1524,19 +1578,26 @@ SCB_GET_OUR_ID(scb), SCB_GET_TARGET(ahc, scb), &tstate); hscb->scsirate = tinfo->scsirate; - hscb->scsioffset = tinfo->current.offset; + hscb->scsioffset = tinfo->curr.offset; if ((tstate->ultraenb & mask) != 0) hscb->control |= ULTRAENB; - if ((tstate->discenable & mask) != 0) + if ((ahc->user_discenable & mask) != 0) hscb->control |= DISCENB; - if ((tstate->tagenable & mask) != 0) { - /* XXX What about devices that dislike ordered tags? */ - if ((dev->num_commands % 256) == 0) - hscb->control |= MSG_ORDERED_Q_TAG; - else - hscb->control |= MSG_SIMPLE_Q_TAG; + if ((tstate->auto_negotiate & mask) != 0) { + scb->flags |= SCB_AUTO_NEGOTIATE; + scb->hscb->control |= MK_MESSAGE; + } + + if ((dev->flags & (AHC_DEV_Q_TAGGED|AHC_DEV_Q_BASIC)) != 0) { + if (dev->commands_since_idle_or_otag == AHC_OTAG_THRESH + && (dev->flags & AHC_DEV_Q_TAGGED) != 0) { + hscb->control |= MSG_ORDERED_TASK; + dev->commands_since_idle_or_otag = 0; + } else { + hscb->control |= MSG_SIMPLE_TASK; + } } hscb->cdb_len = cmd->cmd_len; @@ -1632,7 +1693,8 @@ LIST_INSERT_HEAD(&ahc->pending_scbs, scb, pending_links); dev->openings--; dev->active++; - dev->num_commands++; + dev->commands_issued++; + dev->commands_since_idle_or_otag++; /* * We only allow one untagged transaction @@ -1661,7 +1723,7 @@ * SCSI controller interrupt handler. */ void -aic7xxx_isr(int irq, void *dev_id, struct pt_regs * regs) +ahc_linux_isr(int irq, void *dev_id, struct pt_regs * regs) { struct ahc_softc *ahc; struct ahc_cmd *acmd; @@ -1676,12 +1738,12 @@ * dynamically register one, we'll have to postpone * that until we get integrated into the kernel. */ - ahc_run_device_queues(ahc); + ahc_linux_run_device_queues(ahc); acmd = TAILQ_FIRST(&ahc->platform_data->completeq); TAILQ_INIT(&ahc->platform_data->completeq); ahc_unlock(ahc, &flags); if (acmd != NULL) - ahc_run_complete_queue(ahc, acmd); + ahc_linux_run_complete_queue(ahc, acmd); } void @@ -1692,11 +1754,11 @@ acmd = TAILQ_FIRST(&ahc->platform_data->completeq); TAILQ_INIT(&ahc->platform_data->completeq); if (acmd != NULL) - ahc_run_complete_queue(ahc, acmd); + ahc_linux_run_complete_queue(ahc, acmd); } static struct ahc_linux_target* -ahc_alloc_target(struct ahc_softc *ahc, u_int channel, u_int target) +ahc_linux_alloc_target(struct ahc_softc *ahc, u_int channel, u_int target) { struct ahc_linux_target *targ; u_int target_offset; @@ -1715,7 +1777,7 @@ } static void -ahc_free_target(struct ahc_softc *ahc, struct ahc_linux_target *targ) +ahc_linux_free_target(struct ahc_softc *ahc, struct ahc_linux_target *targ) { u_int target_offset; @@ -1727,7 +1789,7 @@ } static struct ahc_linux_device* -ahc_alloc_device(struct ahc_softc *ahc, +ahc_linux_alloc_device(struct ahc_softc *ahc, struct ahc_linux_target *targ, u_int lun) { struct ahc_linux_device *dev; @@ -1760,7 +1822,7 @@ } static void -ahc_free_device(struct ahc_softc *ahc, struct ahc_linux_device *dev) +ahc_linux_free_device(struct ahc_softc *ahc, struct ahc_linux_device *dev) { struct ahc_linux_target *targ; @@ -1769,14 +1831,14 @@ free(dev, M_DEVBUF); targ->refcount--; if (targ->refcount == 0) - ahc_free_target(ahc, targ); + ahc_linux_free_target(ahc, targ); } /* * Return a string describing the driver. */ const char * -aic7xxx_info(struct Scsi_Host *host) +ahc_linux_info(struct Scsi_Host *host) { static char buffer[512]; char ahc_info[256]; @@ -1802,7 +1864,7 @@ void ahc_send_async(struct ahc_softc *ahc, char channel, - u_int target, u_int lun, ac_code code) + u_int target, u_int lun, ac_code code, void *arg) { switch (code) { case AC_TRANSFER_NEG: @@ -1811,7 +1873,7 @@ struct ahc_linux_target *targ; struct info_str info; struct ahc_initiator_tinfo *tinfo; - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *tstate; int target_offset; info.buffer = buf; @@ -1827,10 +1889,10 @@ * Don't bother reporting results while * negotiations are still pending. */ - if (tinfo->current.period != tinfo->goal.period - || tinfo->current.width != tinfo->goal.width - || tinfo->current.offset != tinfo->goal.offset - || tinfo->current.ppr_options != tinfo->goal.ppr_options) + if (tinfo->curr.period != tinfo->goal.period + || tinfo->curr.width != tinfo->goal.width + || tinfo->curr.offset != tinfo->goal.offset + || tinfo->curr.ppr_options != tinfo->goal.ppr_options) if (bootverbose == 0) break; @@ -1843,24 +1905,24 @@ target_offset += 8; targ = ahc->platform_data->targets[target_offset]; if (targ != NULL - && tinfo->current.period == targ->last_tinfo.period - && tinfo->current.width == targ->last_tinfo.width - && tinfo->current.offset == targ->last_tinfo.offset - && tinfo->current.ppr_options == targ->last_tinfo.ppr_options) + && tinfo->curr.period == targ->last_tinfo.period + && tinfo->curr.width == targ->last_tinfo.width + && tinfo->curr.offset == targ->last_tinfo.offset + && tinfo->curr.ppr_options == targ->last_tinfo.ppr_options) if (bootverbose == 0) break; - targ->last_tinfo.period = tinfo->current.period; - targ->last_tinfo.width = tinfo->current.width; - targ->last_tinfo.offset = tinfo->current.offset; - targ->last_tinfo.ppr_options = tinfo->current.ppr_options; + targ->last_tinfo.period = tinfo->curr.period; + targ->last_tinfo.width = tinfo->curr.width; + targ->last_tinfo.offset = tinfo->curr.offset; + targ->last_tinfo.ppr_options = tinfo->curr.ppr_options; printf("(%s:%c:", ahc_name(ahc), channel); if (target == CAM_TARGET_WILDCARD) printf("*): "); else printf("%d): ", target); - ahc_format_transinfo(&info, &tinfo->current); + ahc_format_transinfo(&info, &tinfo->curr); if (info.pos < info.length) *info.buffer = '\0'; else @@ -1909,7 +1971,7 @@ dev = scb->platform_data->dev; dev->active--; dev->openings++; - ahc_unmap_scb(ahc, scb); + ahc_linux_unmap_scb(ahc, scb); if (scb->flags & SCB_SENSE) { memcpy(cmd->sense_buffer, ahc_get_sense_buf(ahc, scb), MIN(sizeof(struct scsi_sense_data), @@ -1928,10 +1990,19 @@ ahc_set_transaction_status(scb, CAM_DATA_RUN_ERR); } else { ahc_set_transaction_status(scb, CAM_REQ_CMP); - ahc_sniff_command(ahc, cmd); + ahc_linux_sniff_command(ahc, cmd); } } else if (ahc_get_transaction_status(scb) == DID_OK) { - ahc_handle_scsi_status(ahc, dev, scb); + ahc_linux_handle_scsi_status(ahc, dev, scb); + } else if (ahc_get_transaction_status(scb) == DID_NO_CONNECT) { + /* + * Should a selection timeout kill the device? + * That depends on whether the selection timeout + * is persistent. Since we have no guarantee that + * the mid-layer will issue an inquiry for this device + * again, we can't just kill it off. + dev->flags |= AHC_DEV_UNCONFIGURED; + */ } if (dev->openings == 1 @@ -1950,10 +2021,14 @@ dev->openings++; } - if (dev->active == 0 - && (dev->flags & AHC_DEV_UNCONFIGURED) != 0) - ahc_free_device(ahc, dev); - else if ((dev->flags & AHC_DEV_ON_RUN_LIST) == 0) { + if (dev->active == 0) + dev->commands_since_idle_or_otag = 0; + + if (TAILQ_EMPTY(&dev->busyq)) { + if ((dev->flags & AHC_DEV_UNCONFIGURED) != 0 + && dev->active == 0) + ahc_linux_free_device(ahc, dev); + } else if ((dev->flags & AHC_DEV_ON_RUN_LIST) == 0) { LIST_INSERT_HEAD(&ahc->platform_data->device_runq, dev, links); dev->flags |= AHC_DEV_ON_RUN_LIST; } @@ -1964,12 +2039,12 @@ } ahc_free_scb(ahc, scb); - ahc_queue_cmd_complete(ahc, cmd); + ahc_linux_queue_cmd_complete(ahc, cmd); } static void -ahc_handle_scsi_status(struct ahc_softc *ahc, - struct ahc_linux_device *dev, struct scb *scb) +ahc_linux_handle_scsi_status(struct ahc_softc *ahc, + struct ahc_linux_device *dev, struct scb *scb) { /* * We don't currently trust the mid-layer to @@ -2050,7 +2125,7 @@ } static void -ahc_filter_command(struct ahc_softc *ahc, Scsi_Cmnd *cmd) +ahc_linux_filter_command(struct ahc_softc *ahc, Scsi_Cmnd *cmd) { switch (cmd->cmnd[0]) { case INQUIRY: @@ -2058,8 +2133,9 @@ struct ahc_devinfo devinfo; struct scsi_inquiry_data *sid; struct ahc_initiator_tinfo *targ_info; - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *tstate; struct ahc_syncrate *syncrate; + struct ahc_linux_device *dev; u_int scsiid; u_int maxsync; int minlen; @@ -2078,15 +2154,20 @@ /* * Determine if this lun actually exists. If so, * hold on to its corresponding device structure. - */ + * If not, make sure we release the device and + * don't bother processing the rest of this inquiry + * command. + */ + dev = ahc_linux_get_device(ahc, cmd->channel, + cmd->target, cmd->lun, + /*alloc*/FALSE); if (cmd->request_bufflen >= 1 && SID_QUAL(sid) == SID_QUAL_LU_CONNECTED) { - struct ahc_linux_device *dev; - dev = ahc_get_device(ahc, cmd->channel, - cmd->target, cmd->lun, - /*alloc*/FALSE); dev->flags &= ~AHC_DEV_UNCONFIGURED; + } else { + dev->flags |= AHC_DEV_UNCONFIGURED; + break; } /* @@ -2108,17 +2189,17 @@ ppr_options = targ_info->user.ppr_options; minlen = offsetof(struct scsi_inquiry_data, version) + 1; if (cmd->request_bufflen >= minlen) { - targ_info->current.protocol_version = SID_ANSI_REV(sid); + targ_info->curr.protocol_version = SID_ANSI_REV(sid); /* * Only attempt SPI3 once we've verified that * the device claims to support SPI3 features. */ - if (targ_info->current.protocol_version < SCSI_REV_2) - targ_info->current.transport_version = + if (targ_info->curr.protocol_version < SCSI_REV_2) + targ_info->curr.transport_version = SID_ANSI_REV(sid); else - targ_info->current.transport_version = + targ_info->curr.transport_version = SCSI_REV_2; } @@ -2137,18 +2218,26 @@ break; } minlen = offsetof(struct scsi_inquiry_data, spi3data) + 1; - if (cmd->request_bufflen >= minlen - && (sid->additional_length + 4) >= minlen) { - if ((sid->spi3data & SID_SPI_CLOCK_DT) == 0) + /* + * This is a kludge to deal with inquiry requests that + * are not large enough for us to pull the spi3 bits. + * In this case, we assume that a device that tells us + * they can provide inquiry data that spans the SPI3 + * bits can handle a PPR request. If the inquiry + * request has sufficient buffer space to cover these + * bits, we check them to see if any ppr options are + * available. + */ + if ((sid->additional_length + 4) >= minlen) { + if (cmd->request_bufflen >= minlen + && (sid->spi3data & SID_SPI_CLOCK_DT) == 0) ppr_options = 0; - if ((sid->spi3data & SID_SPI_MASK) != 0 - && targ_info->current.protocol_version > SCSI_REV_2) - targ_info->current.transport_version = 3; + if (targ_info->curr.protocol_version > SCSI_REV_2) + targ_info->curr.transport_version = 3; } else { ppr_options = 0; } - ahc_validate_width(ahc, /*tinfo limit*/NULL, &width, ROLE_UNKNOWN); if ((ahc->features & AHC_ULTRA2) != 0) @@ -2162,6 +2251,11 @@ &ppr_options, maxsync); ahc_validate_offset(ahc, /*tinfo limit*/NULL, syncrate, &offset, width, ROLE_UNKNOWN); + if (offset == 0 || period == 0) { + period = 0; + offset = 0; + ppr_options = 0; + } /* Apply our filtered user settings. */ ahc_set_width(ahc, &devinfo, width, AHC_TRANS_GOAL, /*paused*/FALSE); @@ -2171,14 +2265,14 @@ break; } default: - panic("ahc_filter_command: Unexpected Command type %x\n", + panic("ahc_linux_filter_command: Unexpected Command type %x\n", cmd->cmnd[0]); break; } } static void -ahc_sem_timeout(u_long arg) +ahc_linux_sem_timeout(u_long arg) { struct semaphore *sem; @@ -2187,22 +2281,42 @@ } static void -ahc_release_sim_queue(u_long arg) +ahc_linux_freeze_sim_queue(struct ahc_softc *ahc) +{ + ahc->platform_data->qfrozen++; + if (ahc->platform_data->qfrozen == 1) + scsi_block_requests(ahc->platform_data->host); +} + +static void +ahc_linux_release_sim_queue(u_long arg) { struct ahc_softc *ahc; u_long s; + int unblock_reqs; ahc = (struct ahc_softc *)arg; + unblock_reqs = 0; ahc_lock(ahc, &s); if (ahc->platform_data->qfrozen > 0) ahc->platform_data->qfrozen--; - if (ahc->platform_data->qfrozen == 0) - ahc_run_device_queues(ahc); + if (ahc->platform_data->qfrozen == 0) { + unblock_reqs = 1; + ahc_linux_run_device_queues(ahc); + } ahc_unlock(ahc, &s); + /* + * There is still a race here. The mid-layer + * should keep its own freeze count and use + * a bottom half handler to run the queues + * so we can unblock with our own lock held. + */ + if (unblock_reqs) + scsi_unblock_requests(ahc->platform_data->host); } static int -aic7xxx_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag) +ahc_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag) { struct ahc_softc *ahc; struct ahc_cmd *acmd; @@ -2242,8 +2356,8 @@ * at all, and the system wanted us to just abort the * command return success. */ - dev = ahc_get_device(ahc, cmd->channel, cmd->target, - cmd->lun, /*alloc*/FALSE); + dev = ahc_linux_get_device(ahc, cmd->channel, cmd->target, + cmd->lun, /*alloc*/FALSE); if (dev == NULL) { /* @@ -2267,7 +2381,7 @@ if (flag == SCB_ABORT) { TAILQ_REMOVE(&dev->busyq, list_acmd, acmd_links.tqe); cmd->result = DID_ABORT << 16; - ahc_queue_cmd_complete(ahc, cmd); + ahc_linux_queue_cmd_complete(ahc, cmd); retval = SUCCESS; goto done; } @@ -2315,7 +2429,7 @@ ahc->flags |= AHC_ALL_INTERRUPTS; do { ahc_intr(ahc); - pause_sequencer(ahc); + ahc_pause(ahc); ahc_clear_critical_section(ahc); } while (ahc_inb(ahc, INTSTAT) & INT_PEND); ahc->flags &= ~AHC_ALL_INTERRUPTS; @@ -2455,7 +2569,7 @@ retval = SUCCESS; done: if (paused) - unpause_sequencer(ahc); + ahc_unpause(ahc); if (wait) { struct timer_list timer; int ret; @@ -2464,7 +2578,7 @@ init_timer(&timer); timer.data = (u_long)&ahc->platform_data->eh_sem; timer.expires = jiffies + (5 * HZ); - timer.function = ahc_sem_timeout; + timer.function = ahc_linux_sem_timeout; add_timer(&timer); printf("Recovery code sleeping\n"); down(&ahc->platform_data->eh_sem); @@ -2476,12 +2590,12 @@ } ahc_lock(ahc, &s); } - ahc_run_device_queues(ahc); + ahc_linux_run_device_queues(ahc); acmd = TAILQ_FIRST(&ahc->platform_data->completeq); TAILQ_INIT(&ahc->platform_data->completeq); ahc_unlock(ahc, &s); if (acmd != NULL) - ahc_run_complete_queue(ahc, acmd); + ahc_linux_run_complete_queue(ahc, acmd); spin_lock_irq(&io_request_lock); return (retval); } @@ -2490,11 +2604,11 @@ * Abort the current SCSI command(s). */ int -aic7xxx_abort(Scsi_Cmnd *cmd) +ahc_linux_abort(Scsi_Cmnd *cmd) { int error; - error = aic7xxx_queue_recovery_cmd(cmd, SCB_ABORT); + error = ahc_linux_queue_recovery_cmd(cmd, SCB_ABORT); if (error != 0) printf("aic7xxx_abort returns %d\n", error); return (error); @@ -2504,11 +2618,11 @@ * Attempt to send a target reset message to the device that timed out. */ int -aic7xxx_dev_reset(Scsi_Cmnd *cmd) +ahc_linux_dev_reset(Scsi_Cmnd *cmd) { int error; - error = aic7xxx_queue_recovery_cmd(cmd, SCB_DEVICE_RESET); + error = ahc_linux_queue_recovery_cmd(cmd, SCB_DEVICE_RESET); if (error != 0) printf("aic7xxx_dev_reset returns %d\n", error); return (error); @@ -2518,7 +2632,7 @@ * Reset the SCSI bus. */ int -aic7xxx_bus_reset(Scsi_Cmnd *cmd) +ahc_linux_bus_reset(Scsi_Cmnd *cmd) { struct ahc_softc *ahc; struct ahc_cmd *acmd; @@ -2543,7 +2657,7 @@ "%d SCBs aborted.\n", ahc_name(ahc), found); if (acmd != NULL) - ahc_run_complete_queue(ahc, acmd); + ahc_linux_run_complete_queue(ahc, acmd); spin_lock_irq(&io_request_lock); return SUCCESS; @@ -2553,7 +2667,7 @@ * Return the disk geometry for the given SCSI device. */ int -aic7xxx_biosparam(Disk *disk, kdev_t dev, int geom[]) +ahc_linux_biosparam(Disk *disk, kdev_t dev, int geom[]) { int heads; int sectors; @@ -2597,14 +2711,23 @@ * module. */ int -aic7xxx_release(struct Scsi_Host * host) +ahc_linux_release(struct Scsi_Host * host) { struct ahc_softc *ahc; if (host != NULL) { + ahc = *(struct ahc_softc **)host->hostdata; ahc_free(ahc); } + if (TAILQ_EMPTY(&ahc_tailq)) { + unregister_reboot_notifier(&ahc_linux_notifier); +#ifdef CONFIG_PCI +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + pci_unregister_driver(&aic7xxx_pci_driver); +#endif +#endif + } return (0); } @@ -2626,8 +2749,8 @@ for (lun = 0; lun < AHC_NUM_LUNS; lun++) { struct ahc_cmd *acmd; - dev = ahc_get_device(ahc, channel, target, - lun, /*alloc*/FALSE); + dev = ahc_linux_get_device(ahc, channel, target, + lun, /*alloc*/FALSE); if (dev == NULL) continue; diff -Nru a/drivers/scsi/aic7xxx/aic7xxx_linux_host.h b/drivers/scsi/aic7xxx/aic7xxx_linux_host.h --- a/drivers/scsi/aic7xxx/aic7xxx_linux_host.h Wed May 16 06:00:21 2001 +++ b/drivers/scsi/aic7xxx/aic7xxx_linux_host.h Wed May 16 06:00:21 2001 @@ -28,24 +28,24 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux_host.h#2 $ + * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux_host.h#3 $ */ #ifndef _AIC7XXX_LINUX_HOST_H_ #define _AIC7XXX_LINUX_HOST_H_ -int aic7xxx_proc_info(char *, char **, off_t, int, int, int); -int aic7xxx_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *)); -int aic7xxx_detect(Scsi_Host_Template *); -int aic7xxx_release(struct Scsi_Host *); -const char *aic7xxx_info(struct Scsi_Host *); -int aic7xxx_biosparam(Disk *, kdev_t, int[]); -int aic7xxx_bus_reset(Scsi_Cmnd *); -int aic7xxx_dev_reset(Scsi_Cmnd *); -int aic7xxx_abort(Scsi_Cmnd *); +int ahc_linux_proc_info(char *, char **, off_t, int, int, int); +int ahc_linux_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *)); +int ahc_linux_detect(Scsi_Host_Template *); +int ahc_linux_release(struct Scsi_Host *); +const char *ahc_linux_info(struct Scsi_Host *); +int ahc_linux_biosparam(Disk *, kdev_t, int[]); +int ahc_linux_bus_reset(Scsi_Cmnd *); +int ahc_linux_dev_reset(Scsi_Cmnd *); +int ahc_linux_abort(Scsi_Cmnd *); #if defined(__i386__) -# define AIC7XXX_BIOSPARAM aic7xxx_biosparam +# define AIC7XXX_BIOSPARAM ahc_linux_biosparam #else # define AIC7XXX_BIOSPARAM NULL #endif @@ -58,23 +58,23 @@ next: NULL, \ module: NULL, \ proc_dir: NULL, \ - proc_info: aic7xxx_proc_info, \ + proc_info: ahc_linux_proc_info, \ name: NULL, \ - detect: aic7xxx_detect, \ - release: aic7xxx_release, \ - info: aic7xxx_info, \ + detect: ahc_linux_detect, \ + release: ahc_linux_release, \ + info: ahc_linux_info, \ command: NULL, \ - queuecommand: aic7xxx_queue, \ + queuecommand: ahc_linux_queue, \ eh_strategy_handler: NULL, \ - eh_abort_handler: aic7xxx_abort, \ - eh_device_reset_handler: aic7xxx_dev_reset, \ - eh_bus_reset_handler: aic7xxx_bus_reset, \ + eh_abort_handler: ahc_linux_abort, \ + eh_device_reset_handler: ahc_linux_dev_reset, \ + eh_bus_reset_handler: ahc_linux_bus_reset, \ eh_host_reset_handler: NULL, \ abort: NULL, \ reset: NULL, \ slave_attach: NULL, \ bios_param: AIC7XXX_BIOSPARAM, \ - can_queue: 254, /* max simultaneous cmds */\ + can_queue: 253, /* max simultaneous cmds */\ this_id: -1, /* scsi id of host adapter */\ sg_tablesize: 0, /* max scatter-gather cmds */\ cmd_per_lun: 2, /* cmds per lun */\ diff -Nru a/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c b/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c --- a/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c Wed May 16 06:00:22 2001 +++ b/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c Wed May 16 06:00:22 2001 @@ -28,7 +28,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c#15 $ + * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c#17 $ */ #include "aic7xxx_osm.h" @@ -57,7 +57,7 @@ { 0 } }; -static struct pci_driver aic7xxx_pci_driver = { +struct pci_driver aic7xxx_pci_driver = { name: "aic7xxx", probe: ahc_linux_pci_dev_probe, remove: ahc_linux_pci_dev_remove, @@ -133,7 +133,7 @@ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) pdev->driver_data = ahc; if (aic7xxx_detect_complete) - aic7xxx_register_host(ahc, aic7xxx_driver_template); + ahc_linux_register_host(ahc, aic7xxx_driver_template); #endif return (0); } @@ -191,11 +191,9 @@ { uint32_t command; u_long base; -#ifdef MMAPIO u_long start; u_long base_page; u_long base_offset; -#endif uint8_t *maddr; command = ahc_pci_read_config(ahc->dev_softc, PCIR_COMMAND, 4); @@ -306,11 +304,47 @@ int error; ahc->platform_data->irq = ahc->dev_softc->irq; - error = request_irq(ahc->platform_data->irq, aic7xxx_isr, - SA_INTERRUPT|SA_SHIRQ, "aic7xxx", ahc); - if (error < 0) - error = request_irq(ahc->platform_data->irq, aic7xxx_isr, - SA_SHIRQ, "aic7xxx", ahc); + error = request_irq(ahc->platform_data->irq, ahc_linux_isr, + SA_SHIRQ, "aic7xxx", ahc); return (-error); +} + +void +ahc_power_state_change(struct ahc_softc *ahc, ahc_power_state new_state) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + pci_set_power_state(ahc->dev_softc, new_state); +#else + uint32_t cap; + u_int cap_offset; + + /* + * Traverse the capability list looking for + * the power management capability. + */ + cap = 0; + cap_offset = ahc_pci_read_config(ahc->dev_softc, + PCIR_CAP_PTR, /*bytes*/1); + while (cap_offset != 0) { + + cap = ahc_pci_read_config(ahc->dev_softc, + cap_offset, /*bytes*/4); + if ((cap & 0xFF) == 1 + && ((cap >> 16) & 0x3) > 0) { + uint32_t pm_control; + + pm_control = ahc_pci_read_config(ahc->dev_softc, + cap_offset + 4, + /*bytes*/4); + pm_control &= ~0x3; + pm_control |= new_state; + ahc_pci_write_config(ahc->dev_softc, + cap_offset + 4, + pm_control, /*bytes*/2); + break; + } + cap_offset = (cap >> 8) & 0xFF; + } +#endif } diff -Nru a/drivers/scsi/aic7xxx/aic7xxx_osm.h b/drivers/scsi/aic7xxx/aic7xxx_osm.h --- a/drivers/scsi/aic7xxx/aic7xxx_osm.h Wed May 16 06:00:17 2001 +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.h Wed May 16 06:00:17 2001 @@ -18,7 +18,7 @@ * along with this program; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux.h#45 $ + * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux.h#59 $ * * Copyright (c) 2000, 2001 Adaptec Inc. * All rights reserved. @@ -47,7 +47,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux.h#45 $ + * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux.h#59 $ * */ #ifndef _AIC7XXX_LINUX_H_ @@ -62,6 +62,10 @@ #include #include +#ifndef KERNEL_VERSION +#define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z)) +#endif + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) #include #endif @@ -79,14 +83,6 @@ #include "queue.h" #include "scsi_message.h" -/* - * We never have to reference the current task, and the driver core - * makes ample use of this "name". - */ -#ifdef current -#undef current -#endif - /************************* Forward Declarations *******************************/ struct ahc_softc; typedef struct pci_dev *ahc_dev_softc_t; @@ -114,7 +110,7 @@ /***************************** Bus Space/DMA **********************************/ -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,2,16) +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,2,17) typedef dma_addr_t bus_addr_t; #else typedef uint32_t bus_addr_t; @@ -353,11 +349,7 @@ #include #endif -#define AIC7XXX_DRIVER_VERSION "6.1.5" - -#ifndef KERNEL_VERSION -#define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z)) -#endif +#define AIC7XXX_DRIVER_VERSION "6.1.13" /**************************** Front End Queues ********************************/ /* @@ -401,7 +393,9 @@ AHC_DEV_UNCONFIGURED = 0x01, AHC_DEV_FREEZE_TIL_EMPTY = 0x02, /* Freeze queue until active == 0 */ AHC_DEV_TIMER_ACTIVE = 0x04, /* Our timer is active */ - AHC_DEV_ON_RUN_LIST = 0x08 /* Queued to be run later */ + AHC_DEV_ON_RUN_LIST = 0x08, /* Queued to be run later */ + AHC_DEV_Q_BASIC = 0x10, /* Allow basic device queuing */ + AHC_DEV_Q_TAGGED = 0x20 /* Allow full SCSI2 command queueing */ } ahc_dev_flags; struct ahc_linux_target; @@ -434,7 +428,7 @@ /* * Cumulative command counter. */ - u_int num_commands; + u_long commands_issued; /* * The number of tagged transactions when @@ -465,8 +459,16 @@ * on devices with a fixed number of tags. */ u_int last_queuefull_same_count; - #define AHC_LOCK_TAGS_COUNT 50 + + /* + * How many transactions have been queued + * without the device going idle. We use + * this statistic to + */ + u_int commands_since_idle_or_otag; +#define AHC_OTAG_THRESH 250 + int lun; struct ahc_linux_target *target; }; @@ -570,9 +572,6 @@ #endif #define mb() \ __asm__ __volatile__("mb": : :"memory") -#elif defined(__sparc__) -#define MMAPIO -/* The default mb() define does what this driver wants. -DaveM */ #endif static __inline uint8_t ahc_inb(struct ahc_softc * ahc, long port); @@ -644,8 +643,8 @@ } /**************************** Initialization **********************************/ -int aic7xxx_register_host(struct ahc_softc *ahc, - Scsi_Host_Template *template); +int ahc_linux_register_host(struct ahc_softc *, + Scsi_Host_Template *); /*************************** Pretty Printing **********************************/ struct info_str { @@ -784,11 +783,24 @@ #define PCIR_SUBVEND_0 0x2c #define PCIR_SUBDEV_0 0x2e +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) +extern struct pci_driver aic7xxx_pci_driver; +#endif + +typedef enum +{ + AHC_POWER_STATE_D0, + AHC_POWER_STATE_D1, + AHC_POWER_STATE_D2, + AHC_POWER_STATE_D3 +} ahc_power_state; + +void ahc_power_state_change(struct ahc_softc *ahc, + ahc_power_state new_state); /**************************** VL/EISA Routines ********************************/ int aic7770_linux_probe(Scsi_Host_Template *); int aic7770_map_registers(struct ahc_softc *ahc); -int aic7770_map_int(struct ahc_softc *ahc, - u_int irq, int shared); +int aic7770_map_int(struct ahc_softc *ahc, u_int irq); /******************************* PCI Routines *********************************/ /* @@ -1047,16 +1059,16 @@ } void ahc_platform_set_tags(struct ahc_softc *ahc, - struct ahc_devinfo *devinfo, int enable); + struct ahc_devinfo *devinfo, ahc_queue_alg); int ahc_platform_abort_scbs(struct ahc_softc *ahc, int target, char channel, int lun, u_int tag, role_t role, uint32_t status); -void aic7xxx_isr(int irq, void *dev_id, struct pt_regs * regs); +void ahc_linux_isr(int irq, void *dev_id, struct pt_regs * regs); void ahc_platform_flushwork(struct ahc_softc *ahc); int ahc_softc_comp(struct ahc_softc *, struct ahc_softc *); void ahc_done(struct ahc_softc*, struct scb*); void ahc_send_async(struct ahc_softc *, char channel, - u_int target, u_int lun, ac_code); + u_int target, u_int lun, ac_code, void *); void ahc_print_path(struct ahc_softc *, struct scb *); void ahc_platform_dump_card_state(struct ahc_softc *ahc); diff -Nru a/drivers/scsi/aic7xxx/aic7xxx_pci.c b/drivers/scsi/aic7xxx/aic7xxx_pci.c --- a/drivers/scsi/aic7xxx/aic7xxx_pci.c Wed May 16 06:00:16 2001 +++ b/drivers/scsi/aic7xxx/aic7xxx_pci.c Wed May 16 06:00:16 2001 @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: //depot/src/aic7xxx/aic7xxx_pci.c#17 $ + * $Id: //depot/src/aic7xxx/aic7xxx_pci.c#24 $ * * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx_pci.c,v 1.6 2000/11/10 20:13:41 gibbs Exp $ */ @@ -263,7 +263,7 @@ { ID_AHA_2930C_VAR & ID_DEV_VENDOR_MASK, ID_DEV_VENDOR_MASK, - "Adaptec 2930C SCSI adapter (VAR)", + "Adaptec 2930C Ultra SCSI adapter (VAR)", ahc_aic7860_setup }, /* aic7870 based controllers */ @@ -452,7 +452,7 @@ { ID_AIC7892_ARO, ID_ALL_MASK, - "Adaptec aic7892 Ultra2 SCSI adapter (ARO)", + "Adaptec aic7892 Ultra160 SCSI adapter (ARO)", ahc_aic7892_setup }, /* aic7895 based controllers */ @@ -546,13 +546,13 @@ { ID_AIC7859 & ID_DEV_VENDOR_MASK, ID_DEV_VENDOR_MASK, - "Adaptec aic7859 Ultra SCSI adapter", + "Adaptec aic7859 SCSI adapter", ahc_aic7860_setup }, { ID_AIC7860 & ID_DEV_VENDOR_MASK, ID_DEV_VENDOR_MASK, - "Adaptec aic7860 SCSI adapter", + "Adaptec aic7860 Ultra SCSI adapter", ahc_aic7860_setup }, { @@ -644,16 +644,6 @@ #define CACHESIZE 0x0000003ful /* only 5 bits */ #define LATTIME 0x0000ff00ul -typedef enum -{ - AHC_POWER_STATE_D0, - AHC_POWER_STATE_D1, - AHC_POWER_STATE_D2, - AHC_POWER_STATE_D3 -} ahc_power_state; - -static void ahc_power_state_change(struct ahc_softc *ahc, - ahc_power_state new_state); static int ahc_ext_scbram_present(struct ahc_softc *ahc); static void ahc_scbram_config(struct ahc_softc *ahc, int enable, int pcheck, int fast, int large); @@ -761,9 +751,11 @@ if (error != 0) return (error); + ahc->bus_intr = ahc_pci_intr; + /* Remeber how the card was setup in case there is no SEEPROM */ if ((ahc_inb(ahc, HCNTRL) & POWRDN) == 0) { - pause_sequencer(ahc); + ahc_pause(ahc); if ((ahc->features & AHC_ULTRA2) != 0) our_id = ahc_inb(ahc, SCSIID_ULTRA2) & OID; else @@ -786,7 +778,8 @@ /* Perform ALT-Mode Setup */ sfunct = ahc_inb(ahc, SFUNCT) & ~ALT_MODE; ahc_outb(ahc, SFUNCT, sfunct | ALT_MODE); - ahc_outb(ahc, OPTIONMODE, OPTIONMODE_DEFAULTS); + ahc_outb(ahc, OPTIONMODE, + OPTIONMODE_DEFAULTS|AUTOACKEN|BUSFREEREV|EXPPHASEDIS); ahc_outb(ahc, SFUNCT, sfunct); /* Normal mode setup */ @@ -794,9 +787,6 @@ |TARGCRCENDEN); } - error = ahc_pci_map_int(ahc); - if (error != 0) - return (error); dscommand0 = ahc_inb(ahc, DSCOMMAND0); dscommand0 |= MPARCKEN|CACHETHEN; if ((ahc->features & AHC_ULTRA2) != 0) { @@ -825,6 +815,19 @@ /*bytes*/1) & CACHESIZE; ahc->pci_cachesize *= 4; + /* + * We cannot perform ULTRA speeds without the presense + * of the external precision resistor. + */ + if ((ahc->features & AHC_ULTRA) != 0) { + uint32_t devconfig; + + devconfig = ahc_pci_read_config(ahc->dev_softc, + DEVCONFIG, /*bytes*/4); + if ((devconfig & REXTVALID) == 0) + ahc->features &= ~AHC_ULTRA; + } + /* See if we have a SEEPROM and perform auto-term */ check_extport(ahc, &sxfrctl1); @@ -879,20 +882,6 @@ if ((sxfrctl1 & STPWEN) != 0) ahc->flags |= AHC_TERM_ENB_A; - /* - * We cannot perform ULTRA speeds without - * the presense of the external precision - * resistor. - */ - if ((ahc->features & AHC_ULTRA) != 0) { - uint32_t devconfig; - - devconfig = ahc_pci_read_config(ahc->dev_softc, - DEVCONFIG, /*bytes*/4); - if ((devconfig & REXTVALID) == 0) - ahc->flags |= AHC_ULTRA_DISABLED; - } - /* Core initialization */ error = ahc_init(ahc); if (error != 0) @@ -903,42 +892,16 @@ */ ahc_softc_insert(ahc); - return (0); -} - -static void -ahc_power_state_change(struct ahc_softc *ahc, ahc_power_state new_state) -{ - uint32_t cap; - u_int cap_offset; - /* - * Traverse the capability list looking for - * the power management capability. + * Allow interrupts now that we are completely setup. */ - cap = 0; - cap_offset = ahc_pci_read_config(ahc->dev_softc, - PCIR_CAP_PTR, /*bytes*/1); - while (cap_offset != 0) { - - cap = ahc_pci_read_config(ahc->dev_softc, - cap_offset, /*bytes*/4); - if ((cap & 0xFF) == 1 - && ((cap >> 16) & 0x3) > 0) { - uint32_t pm_control; - - pm_control = ahc_pci_read_config(ahc->dev_softc, - cap_offset + 4, - /*bytes*/4); - pm_control &= ~0x3; - pm_control |= new_state; - ahc_pci_write_config(ahc->dev_softc, - cap_offset + 4, - pm_control, /*bytes*/2); - break; - } - cap_offset = (cap >> 8) & 0xFF; - } + error = ahc_pci_map_int(ahc); + if (error != 0) + return (error); + + ahc_intr_enable(ahc, TRUE); + + return (0); } /* @@ -1190,32 +1153,37 @@ } sd.sd_chip = C56_66; } + release_seeprom(&sd); } -#if 0 if (!have_seeprom) { /* * Pull scratch ram settings and treat them as * if they are the contents of an seeprom if * the 'ADPT' signature is found in SCB2. + * We manually compose the data as 16bit values + * to avoid endian issues. */ ahc_outb(ahc, SCBPTR, 2); if (ahc_inb(ahc, SCB_BASE) == 'A' && ahc_inb(ahc, SCB_BASE + 1) == 'D' && ahc_inb(ahc, SCB_BASE + 2) == 'P' && ahc_inb(ahc, SCB_BASE + 3) == 'T') { - uint8_t *sc_bytes; + uint16_t *sc_data; int i; - sc_bytes = (uint8_t *)≻ - for (i = 0; i < 64; i++) - sc_bytes[i] = ahc_inb(ahc, TARG_SCSIRATE + i); - /* Byte 0x1c is stored in byte 4 of SCB2 */ - sc_bytes[0x1c] = ahc_inb(ahc, SCB_BASE + 4); + sc_data = (uint16_t *)≻ + for (i = 0; i < 32; i++) { + uint16_t val; + int j; + + j = i * 2; + val = ahc_inb(ahc, SRAM_BASE + j) + | ahc_inb(ahc, SRAM_BASE + j + 1) << 8; + } have_seeprom = verify_cksum(&sc); } } -#endif if (!have_seeprom) { if (bootverbose) @@ -1301,9 +1269,8 @@ if (sc.adapter_control & CFRESETB) scsi_conf |= RESET_SCSI; - if ((sc.adapter_control & CFCHNLBPRIMARY) != 0 - && (ahc->features & AHC_MULTI_FUNC) != 0) - ahc->flags |= AHC_CHANNEL_B_PRIMARY; + ahc->flags |= + (sc.adapter_control & CFBOOTCHAN) >> CFBOOTCHANSHIFT; if (sc.bios_control & CFEXTEND) ahc->flags |= AHC_EXTENDED_TRANS_A; @@ -1318,7 +1285,8 @@ ultraenb = 0; } - if (sc.signature == CFSIGNATURE) { + if (sc.signature == CFSIGNATURE + || sc.signature == CFSIGNATURE2) { uint32_t devconfig; /* Honor the STPWLEVEL settings */ @@ -1362,10 +1330,11 @@ have_autoterm = FALSE; } - if (have_autoterm) + if (have_autoterm) { + acquire_seeprom(ahc, &sd); configure_termination(ahc, &sd, adapter_control, sxfrctl1); - - release_seeprom(&sd); + release_seeprom(&sd); + } } static void @@ -1806,7 +1775,7 @@ ahc_outb(ahc, CLRINT, CLRPARERR); } - unpause_sequencer(ahc); + ahc_unpause(ahc); } static int diff -Nru a/drivers/scsi/aic7xxx/aic7xxx_proc.c b/drivers/scsi/aic7xxx/aic7xxx_proc.c --- a/drivers/scsi/aic7xxx/aic7xxx_proc.c Wed May 16 06:00:18 2001 +++ b/drivers/scsi/aic7xxx/aic7xxx_proc.c Wed May 16 06:00:18 2001 @@ -29,7 +29,7 @@ * String handling code courtesy of Gerard Roudier's * sym driver. * - * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_proc.c#7 $ + * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_proc.c#11 $ */ #include "aic7xxx_osm.h" #include "aic7xxx_inline.h" @@ -174,7 +174,7 @@ { struct ahc_linux_target *targ; struct ahc_initiator_tinfo *tinfo; - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *tstate; int lun; tinfo = ahc_fetch_transinfo(ahc, channel, our_id, @@ -190,7 +190,7 @@ copy_info(info, "\tGoal: "); ahc_format_transinfo(info, &tinfo->goal); copy_info(info, "\tCurr: "); - ahc_format_transinfo(info, &tinfo->current); + ahc_format_transinfo(info, &tinfo->curr); for (lun = 0; lun < AHC_NUM_LUNS; lun++) { struct ahc_linux_device *dev; @@ -210,7 +210,7 @@ copy_info(info, "\tChannel %c Target %d Lun %d Settings\n", dev->target->channel + 'A', dev->target->target, dev->lun); - copy_info(info, "\t\tCommands Queued %d\n", dev->num_commands); + copy_info(info, "\t\tCommands Queued %ld\n", dev->commands_issued); copy_info(info, "\t\tCommands Active %d\n", dev->active); copy_info(info, "\t\tCommand Openings %d\n", dev->openings); copy_info(info, "\t\tMax Tagged Openings %d\n", dev->maxtags); @@ -221,7 +221,7 @@ * Return information to handle /proc support for the driver. */ int -aic7xxx_proc_info(char *buffer, char **start, off_t offset, +ahc_linux_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout) { struct ahc_softc *ahc; diff -Nru a/drivers/scsi/aic7xxx/aic7xxx_reg.h b/drivers/scsi/aic7xxx/aic7xxx_reg.h --- a/drivers/scsi/aic7xxx/aic7xxx_reg.h Wed May 16 06:00:17 2001 +++ b/drivers/scsi/aic7xxx/aic7xxx_reg.h Wed May 16 06:00:17 2001 @@ -86,8 +86,8 @@ #define SELDO 0x40 #define SELDI 0x20 #define SELINGO 0x10 -#define IOERR 0x08 #define SWRAP 0x08 +#define IOERR 0x08 #define SDONE 0x04 #define SPIORDY 0x02 #define DMADONE 0x01 @@ -191,8 +191,8 @@ #define BRDDAT5 0x20 #define BRDDAT4 0x10 #define BRDSTB 0x10 -#define BRDCS 0x08 #define BRDDAT3 0x08 +#define BRDCS 0x08 #define BRDDAT2 0x04 #define BRDRW 0x04 #define BRDRW_ULTRA2 0x02 @@ -242,8 +242,8 @@ #define PRELOADEN 0x80 #define WIDEODD 0x40 #define SCSIEN 0x20 -#define SDMAENACK 0x10 #define SDMAEN 0x10 +#define SDMAENACK 0x10 #define HDMAEN 0x08 #define HDMAENACK 0x08 #define DIRECTION 0x04 @@ -271,8 +271,8 @@ #define P_MESGOUT 0xa0 #define P_COMMAND 0x80 #define CDI 0x80 -#define IOI 0x40 #define P_DATAIN 0x40 +#define IOI 0x40 #define MSGI 0x20 #define P_BUSFREE 0x01 #define P_DATAOUT 0x00 @@ -314,9 +314,7 @@ #define LAST_MSG 0x53 -#define TARGET_MSG_REQUEST 0x54 - -#define SCSISEQ_TEMPLATE 0x56 +#define SCSISEQ_TEMPLATE 0x54 #define ENSELO 0x40 #define ENSELI 0x20 #define ENRSELI 0x10 @@ -324,11 +322,11 @@ #define ENAUTOATNI 0x04 #define ENAUTOATNP 0x02 -#define DATA_COUNT_ODD 0x57 +#define DATA_COUNT_ODD 0x55 -#define INITIATOR_TAG 0x58 +#define INITIATOR_TAG 0x56 -#define SEQ_FLAGS2 0x59 +#define SEQ_FLAGS2 0x57 #define SCB_DMA 0x01 #define SCSICONF 0x5a @@ -345,8 +343,8 @@ #define HOSTCONF 0x5d #define HA_274_BIOSCTRL 0x5f -#define BIOSMODE 0x30 #define BIOSDISABLED 0x30 +#define BIOSMODE 0x30 #define CHANNEL_B_PRIMARY 0x08 #define SEQCTL 0x60 @@ -483,7 +481,8 @@ #define DFSTATUS 0x94 #define PRELOAD_AVAIL 0x80 -#define DWORDEMP 0x20 +#define DFCACHETH 0x40 +#define FIFOQWDEMP 0x20 #define MREQPEND 0x10 #define HDONE 0x08 #define DFTHRESH 0x04 @@ -521,18 +520,19 @@ #define COMMAND_PHASE 0x10 #define MSG_IN_PHASE 0x08 #define MSG_OUT_PHASE 0x04 +#define DATA_PHASE_MASK 0x03 #define DATA_IN_PHASE 0x02 #define DATA_OUT_PHASE 0x01 #define SFUNCT 0x9f #define ALT_MODE 0x80 +#define SCB_BASE 0xa0 + #define SCB_CDB_PTR 0xa0 +#define SCB_RESIDUAL_DATACNT 0xa0 #define SCB_CDB_STORE 0xa0 #define SCB_TARGET_INFO 0xa0 -#define SCB_RESIDUAL_DATACNT 0xa0 - -#define SCB_BASE 0xa0 #define SCB_RESIDUAL_SGPTR 0xa4 @@ -579,13 +579,13 @@ #define SCB_NEXT 0xbf +#define SCB_64_SPARE 0xc0 + #define SEECTL_2840 0xc0 #define CS_2840 0x04 #define CK_2840 0x02 #define DO_2840 0x01 -#define SCB_64_SPARE 0xc0 - #define STATUS_2840 0xc1 #define EEPROM_TF 0x80 #define BIOS_SEL 0x60 @@ -648,8 +648,8 @@ #define WR_DFTHRSH_63 0x30 #define WR_DFTHRSH_50 0x20 #define WR_DFTHRSH_25 0x10 -#define RD_DFTHRSH_MAX 0x07 #define RD_DFTHRSH 0x07 +#define RD_DFTHRSH_MAX 0x07 #define RD_DFTHRSH_90 0x06 #define RD_DFTHRSH_85 0x05 #define RD_DFTHRSH_75 0x04 @@ -668,39 +668,39 @@ #define SG_CACHE_PRE 0xfc -#define CMD_GROUP_CODE_SHIFT 0x05 +#define SCB_INITIATOR_TAG 0x03 +#define SCB_TARGET_DATA_DIR 0x01 +#define SCB_TARGET_PHASES 0x00 +#define MAX_OFFSET_ULTRA2 0x7f +#define MAX_OFFSET_16BIT 0x08 #define BUS_8_BIT 0x00 -#define CCSGRAM_MAXSEGS 0x10 -#define TARGET_DATA_IN 0x01 +#define TARGET_CMD_CMPLT 0xfe #define STATUS_QUEUE_FULL 0x28 #define STATUS_BUSY 0x08 #define MAX_OFFSET_8BIT 0x0f -#define BUS_16_BIT 0x01 +#define BUS_32_BIT 0x02 +#define CCSGADDR_MAX 0x80 #define TID_SHIFT 0x04 #define SCB_DOWNLOAD_SIZE_64 0x30 -#define SCB_UPLOAD_SIZE 0x20 #define HOST_MAILBOX_SHIFT 0x04 -#define SCB_INITIATOR_TAG 0x03 #define SCB_TARGET_STATUS 0x02 -#define SCB_TARGET_DATA_DIR 0x01 -#define SCB_TARGET_PHASES 0x00 -#define MAX_OFFSET_ULTRA2 0x7f -#define MAX_OFFSET_16BIT 0x08 -#define TARGET_CMD_CMPLT 0xfe +#define CMD_GROUP_CODE_SHIFT 0x05 +#define CCSGRAM_MAXSEGS 0x10 #define SCB_LIST_NULL 0xff #define SG_SIZEOF 0x08 #define SCB_DOWNLOAD_SIZE 0x20 #define SEQ_MAILBOX_SHIFT 0x00 +#define TARGET_DATA_IN 0x01 #define HOST_MSG 0xff -#define BUS_32_BIT 0x02 -#define CCSGADDR_MAX 0x80 +#define BUS_16_BIT 0x01 +#define SCB_UPLOAD_SIZE 0x20 /* Downloaded Constant Definitions */ +#define INVERTED_CACHESIZE_MASK 0x03 #define SG_PREFETCH_ADDR_MASK 0x06 #define SG_PREFETCH_ALIGN_MASK 0x05 #define QOUTFIFO_OFFSET 0x00 #define SG_PREFETCH_CNT 0x04 -#define INVERTED_CACHESIZE_MASK 0x03 #define CACHESIZE_MASK 0x02 #define QINFIFO_OFFSET 0x01 diff -Nru a/drivers/scsi/aic7xxx/aic7xxx_seq.h b/drivers/scsi/aic7xxx/aic7xxx_seq.h --- a/drivers/scsi/aic7xxx/aic7xxx_seq.h Wed May 16 06:00:25 2001 +++ b/drivers/scsi/aic7xxx/aic7xxx_seq.h Wed May 16 06:00:25 2001 @@ -4,7 +4,7 @@ static uint8_t seqprog[] = { 0xb2, 0x00, 0x00, 0x08, 0xf7, 0x11, 0x22, 0x08, - 0x00, 0x65, 0xde, 0x59, + 0x00, 0x65, 0xe4, 0x59, 0xf7, 0x01, 0x02, 0x08, 0xff, 0x6a, 0x24, 0x08, 0x40, 0x00, 0x40, 0x68, @@ -17,21 +17,21 @@ 0x01, 0x4d, 0xc8, 0x30, 0x00, 0x4c, 0x12, 0x70, 0x01, 0x39, 0xa2, 0x30, - 0x00, 0x6a, 0x7e, 0x5e, + 0x00, 0x6a, 0x92, 0x5e, 0x01, 0x51, 0x20, 0x31, - 0x01, 0x59, 0xb2, 0x00, + 0x01, 0x57, 0xae, 0x00, 0x0d, 0x6a, 0x76, 0x00, - 0x00, 0x51, 0xda, 0x5d, + 0x00, 0x51, 0xec, 0x5d, 0x01, 0x51, 0xc8, 0x30, 0x00, 0x39, 0xde, 0x60, 0x00, 0xbb, 0x30, 0x70, - 0xc1, 0x6a, 0x96, 0x5e, + 0xc1, 0x6a, 0xaa, 0x5e, 0x01, 0xbf, 0x72, 0x30, 0x01, 0x40, 0x7e, 0x31, 0x01, 0x90, 0x80, 0x30, 0x01, 0xf6, 0xd4, 0x30, 0x01, 0x4d, 0x9a, 0x18, - 0xfe, 0x59, 0xb2, 0x08, + 0xfe, 0x57, 0xae, 0x08, 0x01, 0x40, 0x20, 0x31, 0x00, 0x65, 0xe2, 0x58, 0x60, 0x0b, 0x40, 0x78, @@ -48,10 +48,10 @@ 0x08, 0x3c, 0x78, 0x00, 0x01, 0x50, 0xc8, 0x30, 0xe0, 0x6a, 0xcc, 0x00, - 0x48, 0x6a, 0xc4, 0x5d, + 0x48, 0x6a, 0xd6, 0x5d, 0x01, 0x6a, 0xdc, 0x01, 0x88, 0x6a, 0xcc, 0x00, - 0x48, 0x6a, 0xc4, 0x5d, + 0x48, 0x6a, 0xd6, 0x5d, 0x01, 0x6a, 0x26, 0x01, 0xf0, 0x19, 0x7a, 0x08, 0x0f, 0x18, 0xc8, 0x08, @@ -62,7 +62,7 @@ 0x80, 0x3d, 0x7a, 0x00, 0x01, 0x3d, 0xd8, 0x31, 0x01, 0x3d, 0x32, 0x31, - 0x10, 0x03, 0x56, 0x79, + 0x10, 0x03, 0x5c, 0x79, 0x00, 0x65, 0x0a, 0x59, 0x80, 0x66, 0xa8, 0x78, 0x01, 0x66, 0xd8, 0x31, @@ -77,33 +77,33 @@ 0x00, 0x65, 0xb0, 0x48, 0x01, 0x66, 0xd8, 0x31, 0x01, 0x66, 0x32, 0x31, - 0x10, 0x03, 0x56, 0x79, + 0x10, 0x03, 0x5c, 0x79, 0x00, 0x65, 0x0a, 0x59, 0x01, 0x66, 0xd8, 0x31, 0x01, 0x66, 0x32, 0x31, - 0x01, 0x66, 0xb0, 0x30, + 0x01, 0x66, 0xac, 0x30, 0x40, 0x3c, 0x78, 0x00, 0x10, 0x03, 0xa6, 0x78, 0x00, 0x65, 0x0a, 0x59, 0x00, 0x65, 0xb0, 0x40, - 0x61, 0x6a, 0x96, 0x5e, - 0x08, 0x51, 0x2e, 0x71, + 0x61, 0x6a, 0xaa, 0x5e, + 0x08, 0x51, 0x34, 0x71, 0x02, 0x0b, 0xac, 0x78, 0x00, 0x65, 0xa8, 0x40, 0x80, 0x86, 0xc8, 0x08, 0x01, 0x4f, 0xc8, 0x30, 0x00, 0x50, 0xc2, 0x60, - 0xc4, 0x6a, 0x32, 0x5d, + 0xc4, 0x6a, 0x44, 0x5d, 0x40, 0x3c, 0xbe, 0x78, - 0x28, 0x6a, 0x48, 0x5d, - 0x00, 0x65, 0x54, 0x41, - 0x08, 0x6a, 0x48, 0x5d, - 0x00, 0x65, 0x54, 0x41, + 0x28, 0x6a, 0x5a, 0x5d, + 0x00, 0x65, 0x5a, 0x41, + 0x08, 0x6a, 0x5a, 0x5d, + 0x00, 0x65, 0x5a, 0x41, 0xff, 0x6a, 0xd8, 0x01, 0xff, 0x6a, 0x32, 0x01, 0x90, 0x3c, 0x78, 0x00, - 0x10, 0x03, 0x4a, 0x69, - 0x00, 0x65, 0x2e, 0x41, + 0x10, 0x03, 0x50, 0x69, + 0x00, 0x65, 0x34, 0x41, 0x1a, 0x01, 0x02, 0x00, 0xf0, 0x19, 0x7a, 0x08, 0x0f, 0x0f, 0xc8, 0x08, @@ -112,8 +112,8 @@ 0x08, 0x1f, 0xda, 0x78, 0x80, 0x3d, 0x7a, 0x00, 0x20, 0x6a, 0x16, 0x00, - 0x00, 0x65, 0xbe, 0x41, - 0x00, 0x65, 0x76, 0x5e, + 0x00, 0x65, 0xc4, 0x41, + 0x00, 0x65, 0x8a, 0x5e, 0x00, 0x65, 0x12, 0x40, 0x20, 0x11, 0xe8, 0x68, 0x20, 0x6a, 0x18, 0x00, @@ -125,11 +125,11 @@ 0x01, 0xb9, 0x1e, 0x30, 0x7f, 0xb9, 0x0a, 0x08, 0x01, 0xb9, 0x0a, 0x30, - 0x01, 0x56, 0xca, 0x30, + 0x01, 0x54, 0xca, 0x30, 0x80, 0xb8, 0xfc, 0x78, 0x80, 0x65, 0xca, 0x00, 0x01, 0x65, 0x00, 0x34, - 0x01, 0x56, 0x00, 0x34, + 0x01, 0x54, 0x00, 0x34, 0x1a, 0x01, 0x02, 0x00, 0x08, 0xb8, 0x06, 0x79, 0x20, 0x01, 0x02, 0x00, @@ -146,40 +146,43 @@ 0x01, 0xb9, 0x7a, 0x30, 0x01, 0xba, 0x7c, 0x30, 0x00, 0x65, 0x00, 0x59, - 0x80, 0x0b, 0xba, 0x79, - 0xe4, 0x6a, 0x32, 0x5d, - 0x80, 0xba, 0x48, 0x5d, + 0x80, 0x0b, 0xc0, 0x79, + 0xe4, 0x6a, 0x44, 0x5d, + 0x80, 0xba, 0x5a, 0x5d, 0x20, 0xb8, 0x2c, 0x79, - 0x20, 0x6a, 0x48, 0x5d, - 0x00, 0xa3, 0x48, 0x5d, + 0x20, 0x6a, 0x5a, 0x5d, + 0x00, 0xa3, 0x5a, 0x5d, 0x01, 0xa0, 0x78, 0x30, - 0x10, 0x03, 0x46, 0x69, - 0x08, 0x3c, 0x62, 0x69, - 0x04, 0x3c, 0x88, 0x69, - 0x02, 0x3c, 0x8e, 0x69, - 0x01, 0x3c, 0x4c, 0x79, - 0x00, 0x6a, 0x7e, 0x5e, + 0x10, 0xb8, 0x34, 0x79, + 0xe4, 0x6a, 0x44, 0x5d, + 0x00, 0x65, 0xa8, 0x40, + 0x10, 0x03, 0x4c, 0x69, + 0x08, 0x3c, 0x68, 0x69, + 0x04, 0x3c, 0x8e, 0x69, + 0x02, 0x3c, 0x94, 0x69, + 0x01, 0x3c, 0x52, 0x79, 0x01, 0x6a, 0xa2, 0x30, - 0x00, 0x65, 0x9a, 0x59, - 0x04, 0x51, 0x3e, 0x61, + 0x00, 0x65, 0xa0, 0x59, + 0x04, 0x51, 0x42, 0x61, + 0x00, 0x6a, 0x92, 0x5e, 0x0d, 0x6a, 0x76, 0x00, - 0x00, 0xbb, 0xda, 0x5d, + 0x00, 0xbb, 0xec, 0x5d, 0x00, 0x65, 0x2c, 0x41, 0xa4, 0x6a, 0x06, 0x00, 0x00, 0x65, 0x0a, 0x59, 0x00, 0x65, 0xa8, 0x40, - 0xe4, 0x6a, 0x32, 0x5d, - 0x20, 0x3c, 0x52, 0x79, - 0x02, 0x6a, 0x48, 0x5d, - 0x04, 0x6a, 0x48, 0x5d, - 0x01, 0x03, 0x54, 0x69, + 0xe4, 0x6a, 0x44, 0x5d, + 0x20, 0x3c, 0x58, 0x79, + 0x02, 0x6a, 0x5a, 0x5d, + 0x04, 0x6a, 0x5a, 0x5d, + 0x01, 0x03, 0x5a, 0x69, 0xf7, 0x11, 0x22, 0x08, 0xff, 0x6a, 0x24, 0x08, 0xff, 0x6a, 0x06, 0x08, 0x01, 0x6a, 0x7e, 0x00, - 0x00, 0x65, 0x9a, 0x59, + 0x00, 0x65, 0xa0, 0x59, 0x00, 0x65, 0x04, 0x40, - 0x84, 0x6a, 0x32, 0x5d, + 0x84, 0x6a, 0x44, 0x5d, 0x00, 0x65, 0x0a, 0x59, 0x01, 0x66, 0xc8, 0x30, 0x01, 0x64, 0xd8, 0x31, @@ -187,60 +190,60 @@ 0x5b, 0x64, 0xc8, 0x28, 0x30, 0x64, 0xca, 0x18, 0x01, 0x6c, 0xc8, 0x30, - 0xff, 0x64, 0x84, 0x79, + 0xff, 0x64, 0x8a, 0x79, 0x08, 0x01, 0x02, 0x00, - 0x02, 0x0b, 0x76, 0x79, - 0x01, 0x64, 0x7c, 0x61, + 0x02, 0x0b, 0x7c, 0x79, + 0x01, 0x64, 0x82, 0x61, 0xf7, 0x01, 0x02, 0x08, 0x01, 0x06, 0xd8, 0x31, 0x01, 0x06, 0x32, 0x31, 0xff, 0x64, 0xc8, 0x18, - 0xff, 0x64, 0x76, 0x69, + 0xff, 0x64, 0x7c, 0x69, 0xf7, 0x3c, 0x78, 0x08, - 0x00, 0x65, 0x2e, 0x41, + 0x00, 0x65, 0x34, 0x41, 0x40, 0xa1, 0x7e, 0x10, - 0x04, 0xa1, 0x32, 0x5d, - 0x00, 0x65, 0x62, 0x42, - 0xc4, 0x6a, 0x32, 0x5d, + 0x04, 0xa1, 0x44, 0x5d, + 0x00, 0x65, 0x68, 0x42, + 0xc4, 0x6a, 0x44, 0x5d, 0xc0, 0x6a, 0x7e, 0x00, - 0x00, 0xa2, 0x48, 0x5d, + 0x00, 0xa2, 0x5a, 0x5d, 0xe4, 0x6a, 0x06, 0x00, - 0x00, 0x6a, 0x48, 0x5d, - 0x00, 0x65, 0x54, 0x41, - 0x10, 0x3c, 0x9e, 0x69, - 0x00, 0xbb, 0x64, 0x44, + 0x00, 0x6a, 0x5a, 0x5d, + 0x00, 0x65, 0x5a, 0x41, + 0x10, 0x3c, 0xa4, 0x69, + 0x00, 0xbb, 0x6c, 0x44, 0x18, 0x6a, 0xda, 0x01, 0x01, 0x69, 0xd8, 0x31, 0x1c, 0x6a, 0xd0, 0x01, 0x09, 0xee, 0xdc, 0x01, - 0x80, 0xee, 0xa6, 0x79, + 0x80, 0xee, 0xac, 0x79, 0xff, 0x6a, 0xdc, 0x09, 0x01, 0x93, 0x26, 0x01, 0x03, 0x6a, 0x2a, 0x01, 0x01, 0x69, 0x32, 0x31, - 0x1c, 0x6a, 0xa8, 0x5d, + 0x1c, 0x6a, 0xba, 0x5d, 0x0a, 0x93, 0x26, 0x01, - 0x00, 0x65, 0x6c, 0x5e, + 0x00, 0x65, 0x80, 0x5e, 0x01, 0x50, 0xa0, 0x18, 0x02, 0x6a, 0x22, 0x05, 0x80, 0x6a, 0x74, 0x00, 0x80, 0x3c, 0x78, 0x00, - 0x00, 0x65, 0xa0, 0x5d, + 0x00, 0x65, 0xb2, 0x5d, 0x01, 0x3f, 0xc8, 0x30, - 0xbf, 0x64, 0x62, 0x7a, - 0x80, 0x64, 0x82, 0x73, - 0xa0, 0x64, 0xd8, 0x73, - 0xc0, 0x64, 0xd0, 0x73, - 0xe0, 0x64, 0x18, 0x74, - 0x01, 0x6a, 0x96, 0x5e, - 0x00, 0x65, 0xbe, 0x41, + 0xbf, 0x64, 0x68, 0x7a, + 0x80, 0x64, 0x96, 0x73, + 0xa0, 0x64, 0xf0, 0x73, + 0xc0, 0x64, 0xe6, 0x73, + 0xe0, 0x64, 0x20, 0x74, + 0x01, 0x6a, 0xaa, 0x5e, + 0x00, 0x65, 0xc4, 0x41, 0xf7, 0x11, 0x22, 0x08, 0x01, 0x06, 0xd4, 0x30, 0xff, 0x6a, 0x24, 0x08, 0xf7, 0x01, 0x02, 0x08, - 0x09, 0x0c, 0xd8, 0x79, + 0x09, 0x0c, 0xde, 0x79, 0x08, 0x0c, 0x04, 0x68, - 0xb1, 0x6a, 0x96, 0x5e, + 0xb1, 0x6a, 0xaa, 0x5e, 0xff, 0x6a, 0x26, 0x09, 0x12, 0x01, 0x02, 0x00, 0x02, 0x6a, 0x08, 0x30, @@ -253,47 +256,47 @@ 0x00, 0xa5, 0x4a, 0x21, 0x00, 0xa6, 0x4c, 0x21, 0x00, 0xa7, 0x4e, 0x25, - 0x08, 0xeb, 0x9a, 0x7e, - 0x80, 0xeb, 0xf8, 0x79, + 0x08, 0xeb, 0xae, 0x7e, + 0x80, 0xeb, 0xfe, 0x79, 0xff, 0x6a, 0xd6, 0x09, - 0x08, 0xeb, 0xfc, 0x69, + 0x08, 0xeb, 0x02, 0x6a, 0xff, 0x6a, 0xd4, 0x0c, - 0x88, 0xeb, 0x12, 0x72, - 0x08, 0xeb, 0x9a, 0x6e, - 0x80, 0xa3, 0x9a, 0x6e, - 0x04, 0xea, 0x16, 0xe2, - 0x08, 0xee, 0x9a, 0x6e, + 0x80, 0xa3, 0xae, 0x6e, + 0x88, 0xeb, 0x18, 0x72, + 0x08, 0xeb, 0xae, 0x6e, + 0x04, 0xea, 0x1c, 0xe2, + 0x08, 0xee, 0xae, 0x6e, 0x04, 0x6a, 0xd0, 0x81, 0x05, 0xa4, 0xc0, 0x89, 0x03, 0xa5, 0xc2, 0x31, 0x09, 0x6a, 0xd6, 0x05, - 0x00, 0x65, 0xfa, 0x59, + 0x00, 0x65, 0x00, 0x5a, 0x06, 0xa4, 0xd4, 0x89, - 0x80, 0x94, 0x9a, 0x7e, + 0x80, 0x94, 0xae, 0x7e, 0x04, 0xe9, 0x10, 0x31, 0x01, 0xe9, 0xca, 0x30, - 0x01, 0x65, 0x20, 0x7a, - 0x01, 0x57, 0xae, 0x10, + 0x01, 0x65, 0x26, 0x7a, + 0x01, 0x55, 0xaa, 0x10, 0x01, 0x65, 0x18, 0x31, 0x02, 0xe9, 0x1a, 0x31, 0x01, 0xe9, 0x46, 0x31, - 0x00, 0x65, 0xec, 0x59, + 0x00, 0x65, 0xf2, 0x59, 0x01, 0xa4, 0xca, 0x30, - 0x01, 0x57, 0x2e, 0x7a, + 0x01, 0x55, 0x34, 0x7a, 0x04, 0x65, 0xca, 0x00, - 0x80, 0xa3, 0x32, 0x7a, + 0x80, 0xa3, 0x38, 0x7a, 0x02, 0x65, 0xca, 0x00, 0x01, 0x65, 0xf8, 0x31, - 0x01, 0x3b, 0x26, 0x31, + 0x80, 0x93, 0x26, 0x01, 0xff, 0x6a, 0xd4, 0x0c, 0x01, 0x8c, 0xc8, 0x30, 0x00, 0x88, 0xc8, 0x18, 0x02, 0x64, 0xc8, 0x88, - 0xff, 0x64, 0x9a, 0x7e, - 0xff, 0x8d, 0x48, 0x6a, - 0xff, 0x8e, 0x48, 0x6a, + 0xff, 0x64, 0xae, 0x7e, + 0xff, 0x8d, 0x4e, 0x6a, + 0xff, 0x8e, 0x4e, 0x6a, 0x03, 0x8c, 0xd4, 0x98, - 0x00, 0x65, 0x9a, 0x56, + 0x00, 0x65, 0xae, 0x56, 0x01, 0x64, 0x70, 0x30, 0xff, 0x64, 0xc8, 0x10, 0x01, 0x64, 0xc8, 0x18, @@ -304,139 +307,146 @@ 0x03, 0xa0, 0x18, 0x31, 0x03, 0xa0, 0x10, 0x30, 0x08, 0x6a, 0xcc, 0x00, - 0xa0, 0x6a, 0xbe, 0x5d, - 0x01, 0xa0, 0xae, 0x08, - 0x00, 0x65, 0x88, 0x42, + 0xa0, 0x6a, 0xd0, 0x5d, + 0x01, 0xa0, 0xaa, 0x08, + 0x00, 0x65, 0x8e, 0x42, 0xa8, 0x6a, 0x76, 0x00, 0x79, 0x6a, 0x76, 0x00, - 0x40, 0x3f, 0x6a, 0x6a, + 0x40, 0x3f, 0x70, 0x6a, 0x04, 0x3b, 0x76, 0x00, - 0x00, 0x65, 0x52, 0x5d, + 0x00, 0x65, 0x64, 0x5d, 0x04, 0x6a, 0xd4, 0x81, - 0x20, 0x3c, 0x54, 0x6a, + 0x20, 0x3c, 0x5a, 0x6a, 0x20, 0x3c, 0x78, 0x00, 0x07, 0xac, 0x10, 0x31, 0x05, 0xb3, 0x46, 0x31, 0x88, 0x6a, 0xcc, 0x00, - 0xac, 0x6a, 0xb6, 0x5d, + 0xac, 0x6a, 0xc8, 0x5d, 0xa3, 0x6a, 0xcc, 0x00, - 0xb3, 0x6a, 0xba, 0x5d, - 0x00, 0x65, 0x38, 0x5a, + 0xb3, 0x6a, 0xcc, 0x5d, + 0x00, 0x65, 0x3e, 0x5a, 0xfd, 0xa4, 0x48, 0x09, - 0x01, 0x8c, 0xae, 0x08, + 0x01, 0x8c, 0xaa, 0x08, 0x03, 0x8c, 0x10, 0x30, - 0x00, 0x65, 0xae, 0x5d, - 0x01, 0xa4, 0x98, 0x7a, + 0x00, 0x65, 0xc0, 0x5d, + 0x01, 0xa4, 0xa0, 0x7a, 0x04, 0x3b, 0x76, 0x08, 0x01, 0x3b, 0x26, 0x31, 0x80, 0x02, 0x04, 0x00, - 0x10, 0x0c, 0x90, 0x7a, + 0x10, 0x0c, 0x96, 0x7a, + 0x03, 0x9e, 0x98, 0x6a, 0x7f, 0x02, 0x04, 0x08, - 0x91, 0x6a, 0x96, 0x5e, - 0x00, 0x65, 0xbe, 0x41, + 0x91, 0x6a, 0xaa, 0x5e, + 0x00, 0x65, 0xc4, 0x41, 0x01, 0xa4, 0xca, 0x30, - 0x80, 0xa3, 0x9e, 0x7a, + 0x80, 0xa3, 0xa6, 0x7a, 0x02, 0x65, 0xca, 0x00, - 0x01, 0x57, 0xa2, 0x7a, + 0x01, 0x55, 0xaa, 0x7a, 0x04, 0x65, 0xca, 0x00, 0x01, 0x65, 0xf8, 0x31, 0x01, 0x3b, 0x26, 0x31, - 0x00, 0x65, 0x00, 0x5a, - 0x01, 0xfc, 0xae, 0x6a, - 0x80, 0x0b, 0xa6, 0x6a, - 0x10, 0x0c, 0xa6, 0x7a, - 0x04, 0x93, 0xc0, 0x6a, - 0xdf, 0x93, 0x26, 0x09, - 0x20, 0x93, 0xb2, 0x6a, + 0x00, 0x65, 0x06, 0x5a, + 0x01, 0xfc, 0xb8, 0x6a, + 0x80, 0x0b, 0xae, 0x6a, + 0x10, 0x0c, 0xae, 0x7a, + 0x20, 0x93, 0xae, 0x6a, 0x02, 0x93, 0x26, 0x01, - 0x01, 0x94, 0xb4, 0x7a, - 0x01, 0x94, 0xb4, 0x7a, - 0x01, 0x94, 0xb4, 0x7a, - 0x01, 0x94, 0xb4, 0x7a, - 0x01, 0x94, 0xb4, 0x7a, - 0x10, 0x94, 0xc0, 0x6a, - 0xd7, 0x93, 0x26, 0x09, - 0x08, 0x93, 0xc4, 0x6a, - 0x02, 0xfc, 0xce, 0x7a, - 0x01, 0xfc, 0x4e, 0x7b, + 0x02, 0xfc, 0xc2, 0x7a, + 0x40, 0x0d, 0xdc, 0x6a, 0x01, 0xa4, 0x48, 0x01, - 0x00, 0x65, 0x4e, 0x43, - 0x40, 0x0d, 0xd4, 0x6a, - 0x00, 0x65, 0x00, 0x5a, - 0x00, 0x65, 0xc6, 0x42, - 0x80, 0xfc, 0xde, 0x7a, - 0x80, 0xa4, 0xde, 0x6a, + 0x00, 0x65, 0xdc, 0x42, + 0x40, 0x0d, 0xc8, 0x6a, + 0x00, 0x65, 0x06, 0x5a, + 0x00, 0x65, 0xba, 0x42, + 0x80, 0xfc, 0xd2, 0x7a, + 0x80, 0xa4, 0xd2, 0x6a, 0xff, 0xa5, 0x4a, 0x19, 0xff, 0xa6, 0x4c, 0x21, 0xff, 0xa7, 0x4e, 0x21, 0xf8, 0xfc, 0x48, 0x09, - 0xff, 0x6a, 0xae, 0x08, - 0x04, 0xfc, 0xe6, 0x7a, - 0x01, 0x57, 0xae, 0x00, + 0xff, 0x6a, 0xaa, 0x08, + 0x04, 0xfc, 0xda, 0x7a, + 0x01, 0x55, 0xaa, 0x00, 0xff, 0x6a, 0x46, 0x09, - 0xff, 0x38, 0xf2, 0x6a, - 0x80, 0xa3, 0xf2, 0x7a, - 0x80, 0x0b, 0xf0, 0x7a, - 0x04, 0x3b, 0xf2, 0x7a, + 0x04, 0x3b, 0xf4, 0x6a, + 0x02, 0x93, 0x26, 0x01, + 0x01, 0x94, 0xde, 0x7a, + 0x01, 0x94, 0xde, 0x7a, + 0x01, 0x94, 0xde, 0x7a, + 0x01, 0x94, 0xde, 0x7a, + 0x01, 0x94, 0xde, 0x7a, + 0x01, 0xa4, 0xf2, 0x7a, + 0x01, 0xfc, 0xec, 0x7a, + 0x01, 0x94, 0xf4, 0x6a, + 0x00, 0x65, 0x8e, 0x42, + 0x01, 0x94, 0xf2, 0x7a, + 0x10, 0x94, 0xf4, 0x6a, + 0xd7, 0x93, 0x26, 0x09, + 0x28, 0x93, 0xf8, 0x6a, + 0xff, 0x38, 0x04, 0x6b, + 0x80, 0xa3, 0x04, 0x7b, + 0x80, 0x0b, 0x02, 0x7b, + 0x04, 0x3b, 0x04, 0x7b, 0xbf, 0x3b, 0x76, 0x08, 0x01, 0x3b, 0x26, 0x31, - 0x00, 0x65, 0x00, 0x5a, - 0x01, 0x0b, 0x00, 0x6b, - 0x10, 0x0c, 0xf4, 0x7a, - 0x04, 0x93, 0xfe, 0x6a, - 0x01, 0x94, 0xfc, 0x7a, - 0x10, 0x94, 0xfe, 0x6a, + 0x00, 0x65, 0x06, 0x5a, + 0x01, 0x0b, 0x12, 0x6b, + 0x10, 0x0c, 0x06, 0x7b, + 0x04, 0x93, 0x10, 0x6b, + 0x01, 0x94, 0x0e, 0x7b, + 0x10, 0x94, 0x10, 0x6b, 0xc7, 0x93, 0x26, 0x09, 0x01, 0x99, 0xd4, 0x30, - 0x38, 0x93, 0x02, 0x6b, - 0xff, 0x08, 0x4e, 0x6b, - 0xff, 0x09, 0x4e, 0x6b, - 0xff, 0x0a, 0x4e, 0x6b, - 0xff, 0x38, 0x1e, 0x7b, + 0x38, 0x93, 0x14, 0x6b, + 0xff, 0x08, 0x60, 0x6b, + 0xff, 0x09, 0x60, 0x6b, + 0xff, 0x0a, 0x60, 0x6b, + 0xff, 0x38, 0x30, 0x7b, 0x04, 0x14, 0x10, 0x31, 0x01, 0x38, 0x18, 0x31, 0x02, 0x6a, 0x1a, 0x31, 0x88, 0x6a, 0xcc, 0x00, - 0x14, 0x6a, 0xbc, 0x5d, - 0x00, 0x38, 0xa8, 0x5d, + 0x14, 0x6a, 0xce, 0x5d, + 0x00, 0x38, 0xba, 0x5d, 0xff, 0x6a, 0x70, 0x08, - 0x00, 0x65, 0x44, 0x43, - 0x80, 0xa3, 0x24, 0x7b, + 0x00, 0x65, 0x56, 0x43, + 0x80, 0xa3, 0x36, 0x7b, 0x01, 0xa4, 0x48, 0x01, - 0x00, 0x65, 0x4e, 0x43, - 0x08, 0xeb, 0x2a, 0x7b, - 0x00, 0x65, 0x00, 0x5a, - 0x08, 0xeb, 0x26, 0x6b, + 0x00, 0x65, 0x60, 0x43, + 0x08, 0xeb, 0x3c, 0x7b, + 0x00, 0x65, 0x06, 0x5a, + 0x08, 0xeb, 0x38, 0x6b, 0x07, 0xe9, 0x10, 0x31, - 0x80, 0xe9, 0x30, 0x7b, + 0x80, 0xe9, 0x42, 0x7b, 0x80, 0xa3, 0x46, 0x01, 0x88, 0x6a, 0xcc, 0x00, - 0xa4, 0x6a, 0xbc, 0x5d, - 0x08, 0x6a, 0xa8, 0x5d, + 0xa4, 0x6a, 0xce, 0x5d, + 0x08, 0x6a, 0xba, 0x5d, 0x0d, 0x93, 0x26, 0x01, - 0x00, 0x65, 0x6c, 0x5e, + 0x00, 0x65, 0x80, 0x5e, 0x88, 0x6a, 0xcc, 0x00, - 0x00, 0x65, 0x4e, 0x5e, + 0x00, 0x65, 0x62, 0x5e, 0x01, 0x99, 0x46, 0x31, - 0x00, 0x65, 0x38, 0x5a, - 0x00, 0x65, 0xec, 0x59, + 0x00, 0x65, 0x3e, 0x5a, + 0x00, 0x65, 0xf2, 0x59, 0x03, 0x8c, 0x10, 0x30, - 0x00, 0x65, 0xae, 0x5d, - 0x01, 0x8c, 0x4c, 0x7b, - 0x01, 0x57, 0xae, 0x10, - 0x80, 0x0b, 0x88, 0x6a, - 0x80, 0x0b, 0x54, 0x6b, - 0x01, 0x0c, 0x50, 0x7b, - 0x10, 0x0c, 0x88, 0x7a, - 0x00, 0x65, 0xf6, 0x59, - 0xff, 0x38, 0x66, 0x7b, + 0x00, 0x65, 0xc0, 0x5d, + 0x01, 0x8c, 0x5e, 0x7b, + 0x01, 0x55, 0xaa, 0x10, + 0x80, 0x0b, 0x8e, 0x6a, + 0x80, 0x0b, 0x68, 0x6b, + 0x01, 0x0c, 0x62, 0x7b, + 0x10, 0x0c, 0x8e, 0x7a, + 0x03, 0x9e, 0x8e, 0x6a, + 0x00, 0x65, 0xfc, 0x59, + 0xff, 0x38, 0x7a, 0x7b, 0x01, 0x38, 0xc8, 0x30, 0x00, 0x08, 0x40, 0x19, 0xff, 0x6a, 0xc8, 0x08, 0x00, 0x09, 0x42, 0x21, 0x00, 0x0a, 0x44, 0x21, 0xff, 0x6a, 0x70, 0x08, - 0x00, 0x65, 0x68, 0x43, + 0x00, 0x65, 0x7c, 0x43, 0x03, 0x08, 0x40, 0x31, 0x03, 0x08, 0x40, 0x31, 0x01, 0x08, 0x40, 0x31, @@ -445,13 +455,13 @@ 0xfd, 0xb4, 0x68, 0x09, 0x12, 0x01, 0x02, 0x00, 0x12, 0x01, 0x02, 0x00, - 0x04, 0x3c, 0xbe, 0x79, + 0x04, 0x3c, 0xc4, 0x79, 0xfb, 0x3c, 0x78, 0x08, - 0x04, 0x93, 0x2e, 0x79, - 0x01, 0x0c, 0x7c, 0x6b, - 0x00, 0x65, 0x2e, 0x41, - 0x00, 0x65, 0xbe, 0x41, - 0x00, 0x65, 0x52, 0x5d, + 0x04, 0x93, 0x34, 0x79, + 0x01, 0x0c, 0x90, 0x6b, + 0x00, 0x65, 0x34, 0x41, + 0x00, 0x65, 0xc4, 0x41, + 0x00, 0x65, 0x64, 0x5d, 0x01, 0xbc, 0x18, 0x31, 0x02, 0x6a, 0x1a, 0x31, 0x02, 0x6a, 0xf8, 0x01, @@ -461,16 +471,16 @@ 0xff, 0x6a, 0x12, 0x08, 0xff, 0x6a, 0x14, 0x08, 0xf3, 0xbc, 0xd4, 0x18, - 0xa0, 0x6a, 0xaa, 0x53, + 0xa0, 0x6a, 0xbe, 0x53, 0x04, 0xa0, 0x10, 0x31, 0xac, 0x6a, 0x26, 0x01, 0x04, 0xa0, 0x10, 0x31, 0x03, 0x08, 0x18, 0x31, 0x88, 0x6a, 0xcc, 0x00, - 0xa0, 0x6a, 0xbc, 0x5d, - 0x00, 0xbc, 0xa8, 0x5d, + 0xa0, 0x6a, 0xce, 0x5d, + 0x00, 0xbc, 0xba, 0x5d, 0x3d, 0x6a, 0x26, 0x01, - 0x00, 0x65, 0xc2, 0x43, + 0x00, 0x65, 0xd6, 0x43, 0xff, 0x6a, 0x10, 0x09, 0xa4, 0x6a, 0x26, 0x01, 0x0c, 0xa0, 0x32, 0x31, @@ -480,114 +490,112 @@ 0x36, 0x6a, 0x26, 0x01, 0x02, 0x93, 0x26, 0x01, 0x35, 0x6a, 0x26, 0x01, - 0x00, 0x65, 0x60, 0x5e, - 0x00, 0x65, 0x60, 0x5e, + 0x00, 0x65, 0x74, 0x5e, + 0x00, 0x65, 0x74, 0x5e, 0x02, 0x93, 0x26, 0x01, - 0x04, 0x0b, 0xc6, 0x6b, - 0x10, 0x0c, 0xc2, 0x7b, - 0x01, 0x03, 0xc6, 0x6b, + 0x04, 0x0b, 0xda, 0x6b, + 0x10, 0x0c, 0xd6, 0x7b, + 0x01, 0x03, 0xda, 0x6b, + 0x20, 0x93, 0xd6, 0x6b, 0xc7, 0x93, 0x26, 0x09, - 0x38, 0x93, 0xca, 0x6b, + 0x38, 0x93, 0xe0, 0x6b, 0x10, 0x01, 0x02, 0x00, - 0x00, 0x65, 0xbe, 0x41, - 0x00, 0x65, 0x52, 0x5d, + 0x00, 0x65, 0xc4, 0x41, + 0x00, 0x65, 0x64, 0x5d, 0x01, 0x06, 0x50, 0x31, - 0x00, 0x65, 0xbe, 0x41, + 0x00, 0x65, 0xc4, 0x41, 0x10, 0x3f, 0x06, 0x00, + 0x10, 0x6a, 0x06, 0x00, 0x01, 0x3a, 0xca, 0x30, - 0x80, 0x65, 0x04, 0x64, - 0x10, 0xb8, 0x28, 0x6c, - 0x01, 0xb9, 0xdc, 0x30, - 0x01, 0x6e, 0xc8, 0x30, - 0x01, 0x54, 0xca, 0x30, - 0x80, 0xb9, 0xe8, 0x7b, - 0x01, 0x55, 0xca, 0x30, - 0x80, 0xb9, 0xec, 0x7b, - 0x01, 0x55, 0xca, 0x30, - 0x00, 0x65, 0x28, 0x6c, + 0x80, 0x65, 0x0c, 0x64, + 0x10, 0xb8, 0x30, 0x6c, 0xc0, 0xba, 0xca, 0x00, - 0x40, 0xb8, 0xf4, 0x6b, + 0x40, 0xb8, 0xfc, 0x6b, 0xbf, 0x65, 0xca, 0x08, - 0x20, 0xb8, 0x08, 0x7c, + 0x20, 0xb8, 0x10, 0x7c, 0x01, 0x65, 0x0c, 0x30, - 0x00, 0x65, 0xa0, 0x5d, - 0xa0, 0x3f, 0x10, 0x64, + 0x00, 0x65, 0xb2, 0x5d, + 0xa0, 0x3f, 0x18, 0x64, 0x23, 0xb8, 0x0c, 0x08, - 0x00, 0x65, 0xa0, 0x5d, - 0xa0, 0x3f, 0x10, 0x64, - 0x00, 0xbb, 0x08, 0x44, - 0xff, 0x65, 0x08, 0x64, - 0x00, 0x65, 0x28, 0x44, + 0x00, 0x65, 0xb2, 0x5d, + 0xa0, 0x3f, 0x18, 0x64, + 0x00, 0xbb, 0x10, 0x44, + 0xff, 0x65, 0x10, 0x64, + 0x00, 0x65, 0x30, 0x44, 0x40, 0x6a, 0x18, 0x00, 0x01, 0x65, 0x0c, 0x30, - 0x00, 0x65, 0xa0, 0x5d, - 0xa0, 0x3f, 0xd6, 0x73, + 0x00, 0x65, 0xb2, 0x5d, + 0xa0, 0x3f, 0xec, 0x73, 0x40, 0x6a, 0x18, 0x00, 0x01, 0x3a, 0xa6, 0x30, 0x08, 0x6a, 0x74, 0x00, - 0x00, 0x65, 0xbe, 0x41, - 0x64, 0x6a, 0x2c, 0x5d, - 0x80, 0x64, 0x9e, 0x6c, - 0x04, 0x64, 0x74, 0x74, - 0x02, 0x64, 0x82, 0x74, - 0x00, 0x6a, 0x44, 0x74, - 0x03, 0x64, 0x90, 0x74, - 0x23, 0x64, 0x30, 0x74, - 0x08, 0x64, 0x40, 0x74, - 0x61, 0x6a, 0x96, 0x5e, - 0x00, 0x65, 0xa0, 0x5d, - 0x08, 0x51, 0xc0, 0x71, - 0x00, 0x65, 0x28, 0x44, - 0x80, 0x04, 0x3e, 0x7c, - 0x51, 0x6a, 0x22, 0x5d, - 0x01, 0x51, 0x3e, 0x64, - 0x01, 0xa4, 0x3a, 0x7c, - 0x01, 0x57, 0x40, 0x7c, - 0x41, 0x6a, 0x96, 0x5e, - 0x00, 0x65, 0x40, 0x44, - 0x07, 0x6a, 0x1a, 0x5d, + 0x00, 0x65, 0xc4, 0x41, + 0x64, 0x6a, 0x3e, 0x5d, + 0x80, 0x64, 0xae, 0x6c, + 0x04, 0x64, 0x7c, 0x74, + 0x02, 0x64, 0x8a, 0x74, + 0x00, 0x6a, 0x4c, 0x74, + 0x03, 0x64, 0xa0, 0x74, + 0x23, 0x64, 0x38, 0x74, + 0x08, 0x64, 0x48, 0x74, + 0x61, 0x6a, 0xaa, 0x5e, + 0x00, 0x65, 0xb2, 0x5d, + 0x08, 0x51, 0xc6, 0x71, + 0x00, 0x65, 0x30, 0x44, + 0x80, 0x04, 0x46, 0x7c, + 0x51, 0x6a, 0x34, 0x5d, + 0x01, 0x51, 0x46, 0x64, + 0x01, 0xa4, 0x42, 0x7c, + 0x01, 0x55, 0x48, 0x7c, + 0x41, 0x6a, 0xaa, 0x5e, + 0x00, 0x65, 0x48, 0x44, + 0x07, 0x6a, 0x2a, 0x5d, 0x01, 0x06, 0xd4, 0x30, - 0x00, 0x65, 0xbe, 0x41, - 0x10, 0xb8, 0x48, 0x7c, - 0xa1, 0x6a, 0x96, 0x5e, - 0x01, 0xb4, 0x4e, 0x6c, - 0x02, 0xb4, 0x50, 0x6c, - 0x01, 0xa4, 0x50, 0x7c, - 0xff, 0xa8, 0x60, 0x7c, + 0x00, 0x65, 0xc4, 0x41, + 0x10, 0xb8, 0x50, 0x7c, + 0xa1, 0x6a, 0xaa, 0x5e, + 0x01, 0xb4, 0x56, 0x6c, + 0x02, 0xb4, 0x58, 0x6c, + 0x01, 0xa4, 0x58, 0x7c, + 0xff, 0xa8, 0x68, 0x7c, 0x04, 0xb4, 0x68, 0x01, 0x01, 0x6a, 0x76, 0x00, - 0x00, 0xbb, 0xda, 0x5d, - 0xff, 0xa8, 0x60, 0x7c, - 0x71, 0x6a, 0x96, 0x5e, - 0x40, 0x51, 0x60, 0x64, - 0x00, 0x65, 0x76, 0x5e, - 0x00, 0x65, 0xd0, 0x41, - 0x00, 0xbb, 0x64, 0x5c, - 0x00, 0x65, 0xd0, 0x41, - 0x00, 0x65, 0x76, 0x5e, + 0x00, 0xbb, 0xec, 0x5d, + 0xff, 0xa8, 0x68, 0x7c, + 0x71, 0x6a, 0xaa, 0x5e, + 0x40, 0x51, 0x68, 0x64, + 0x00, 0x65, 0x8a, 0x5e, + 0x00, 0x65, 0xd6, 0x41, + 0x00, 0xbb, 0x6c, 0x5c, + 0x00, 0x65, 0xd6, 0x41, + 0x00, 0x65, 0x8a, 0x5e, 0x01, 0x65, 0xa2, 0x30, 0x01, 0xf8, 0xc8, 0x30, 0x01, 0x4e, 0xc8, 0x30, - 0x00, 0x6a, 0x7e, 0xdd, - 0x00, 0x51, 0x90, 0x5d, + 0x00, 0x6a, 0x90, 0xdd, + 0x00, 0x51, 0xa2, 0x5d, 0x01, 0x4e, 0x9c, 0x18, 0x02, 0x6a, 0x22, 0x05, 0x04, 0xb8, 0x70, 0x01, - 0x00, 0x65, 0x92, 0x5e, - 0x20, 0xb8, 0xd0, 0x69, + 0x00, 0x65, 0xa6, 0x5e, + 0x20, 0xb8, 0xd6, 0x69, 0x01, 0xbb, 0xa2, 0x30, 0x01, 0xba, 0x7c, 0x30, - 0x00, 0xb9, 0x94, 0x5c, - 0x00, 0x65, 0xd0, 0x41, - 0x20, 0x3c, 0x40, 0x7c, + 0x00, 0xb9, 0xa4, 0x5c, + 0x00, 0x65, 0xd6, 0x41, + 0x01, 0x06, 0xd4, 0x30, + 0x20, 0x3c, 0xc4, 0x79, + 0x20, 0x3c, 0x48, 0x7c, 0x04, 0x14, 0x58, 0x31, + 0x01, 0x06, 0xd4, 0x30, 0x08, 0xa0, 0x60, 0x31, 0xac, 0x6a, 0xcc, 0x00, - 0x14, 0x6a, 0xbc, 0x5d, - 0xa0, 0x6a, 0xb4, 0x5d, - 0x00, 0x65, 0x40, 0x44, + 0x14, 0x6a, 0xce, 0x5d, + 0x01, 0x06, 0xd4, 0x30, + 0xa0, 0x6a, 0xc6, 0x5d, + 0x00, 0x65, 0xc4, 0x41, 0xdf, 0x3c, 0x78, 0x08, - 0x00, 0x65, 0x40, 0x44, + 0x00, 0x65, 0x48, 0x44, 0x4c, 0x65, 0xcc, 0x28, 0x01, 0x3e, 0x20, 0x31, 0xd0, 0x66, 0xcc, 0x18, @@ -598,103 +606,104 @@ 0xd0, 0x65, 0xca, 0x18, 0x01, 0x3e, 0x20, 0x31, 0x30, 0x65, 0xd4, 0x18, - 0x00, 0x65, 0xac, 0x4c, + 0x00, 0x65, 0xbc, 0x4c, 0xe1, 0x6a, 0x22, 0x01, 0xff, 0x6a, 0xd4, 0x08, 0x20, 0x65, 0xd4, 0x18, - 0x00, 0x65, 0xb4, 0x54, + 0x00, 0x65, 0xc4, 0x54, 0xe1, 0x6a, 0x22, 0x01, 0xff, 0x6a, 0xd4, 0x08, 0x20, 0x65, 0xca, 0x18, 0xe0, 0x65, 0xd4, 0x18, - 0x00, 0x65, 0xbe, 0x4c, + 0x00, 0x65, 0xce, 0x4c, 0xe1, 0x6a, 0x22, 0x01, 0xff, 0x6a, 0xd4, 0x08, 0xd0, 0x65, 0xd4, 0x18, - 0x00, 0x65, 0xc6, 0x54, + 0x00, 0x65, 0xd6, 0x54, 0xe1, 0x6a, 0x22, 0x01, 0xff, 0x6a, 0xd4, 0x08, 0x01, 0x6c, 0xa2, 0x30, - 0xff, 0x51, 0xd8, 0x74, - 0x00, 0x51, 0x56, 0x5d, + 0xff, 0x51, 0xe8, 0x74, + 0x00, 0x51, 0x68, 0x5d, 0x01, 0x51, 0x20, 0x31, - 0x00, 0x65, 0xfa, 0x44, + 0x00, 0x65, 0x0a, 0x45, 0x01, 0xba, 0xc8, 0x30, - 0x00, 0x3e, 0xfa, 0x74, - 0x00, 0x65, 0x74, 0x5e, + 0x00, 0x3e, 0x0a, 0x75, + 0x00, 0x65, 0x88, 0x5e, 0x80, 0x3c, 0x78, 0x00, 0x01, 0x06, 0xd4, 0x30, - 0x00, 0x65, 0xa0, 0x5d, + 0x00, 0x65, 0xb2, 0x5d, 0x01, 0x3c, 0x78, 0x00, - 0xe0, 0x3f, 0x16, 0x65, + 0xe0, 0x3f, 0x26, 0x65, 0x02, 0x3c, 0x78, 0x00, - 0x20, 0x12, 0x16, 0x65, - 0x51, 0x6a, 0x22, 0x5d, - 0x00, 0x51, 0x56, 0x5d, - 0x51, 0x6a, 0x22, 0x5d, + 0x20, 0x12, 0x26, 0x65, + 0x51, 0x6a, 0x34, 0x5d, + 0x00, 0x51, 0x68, 0x5d, + 0x51, 0x6a, 0x34, 0x5d, 0x01, 0x51, 0x20, 0x31, 0x04, 0x3c, 0x78, 0x00, 0x01, 0xb9, 0xc8, 0x30, - 0x00, 0x3d, 0x14, 0x65, + 0x00, 0x3d, 0x24, 0x65, 0x08, 0x3c, 0x78, 0x00, 0x01, 0xba, 0xc8, 0x30, - 0x00, 0x3e, 0x14, 0x65, + 0x00, 0x3e, 0x24, 0x65, 0x10, 0x3c, 0x78, 0x00, - 0x04, 0xb8, 0x14, 0x7d, + 0x04, 0xb8, 0x24, 0x7d, 0xfb, 0xb8, 0x70, 0x09, - 0x20, 0xb8, 0x0a, 0x6d, + 0x20, 0xb8, 0x1a, 0x6d, 0x01, 0x90, 0xc8, 0x30, 0xff, 0x6a, 0xa2, 0x00, - 0x00, 0x3d, 0x94, 0x5c, + 0x00, 0x3d, 0xa4, 0x5c, 0x01, 0x64, 0x20, 0x31, 0x80, 0x6a, 0x78, 0x00, 0x00, 0x65, 0x02, 0x59, - 0x10, 0xb8, 0x40, 0x7c, - 0xff, 0x6a, 0x1a, 0x5d, - 0x00, 0x65, 0x40, 0x44, - 0x00, 0x65, 0x74, 0x5e, - 0x31, 0x6a, 0x96, 0x5e, - 0x00, 0x65, 0x40, 0x44, + 0x10, 0xb8, 0x48, 0x7c, + 0xff, 0x6a, 0x2a, 0x5d, + 0x00, 0x65, 0x48, 0x44, + 0x00, 0x65, 0x88, 0x5e, + 0x31, 0x6a, 0xaa, 0x5e, + 0x00, 0x65, 0x48, 0x44, 0x10, 0x3f, 0x06, 0x00, + 0x10, 0x6a, 0x06, 0x00, 0x01, 0x65, 0x74, 0x34, - 0x81, 0x6a, 0x96, 0x5e, - 0x00, 0x65, 0x24, 0x45, + 0x81, 0x6a, 0xaa, 0x5e, + 0x00, 0x65, 0x36, 0x45, 0x01, 0x06, 0xd4, 0x30, - 0x01, 0x0c, 0x24, 0x7d, - 0x04, 0x0c, 0x1e, 0x6d, + 0x01, 0x0c, 0x36, 0x7d, + 0x04, 0x0c, 0x30, 0x6d, 0xe0, 0x03, 0x7e, 0x08, - 0xe0, 0x3f, 0xbe, 0x61, + 0xe0, 0x3f, 0xc4, 0x61, 0x01, 0x65, 0xcc, 0x30, 0x01, 0x12, 0xda, 0x34, 0x01, 0x06, 0xd4, 0x34, - 0x01, 0x03, 0x32, 0x6d, + 0x01, 0x03, 0x44, 0x6d, 0x40, 0x03, 0xcc, 0x08, 0x01, 0x65, 0x06, 0x30, 0x40, 0x65, 0xc8, 0x08, - 0x00, 0x66, 0x40, 0x75, - 0x40, 0x65, 0x40, 0x7d, - 0x00, 0x65, 0x40, 0x5d, + 0x00, 0x66, 0x52, 0x75, + 0x40, 0x65, 0x52, 0x7d, + 0x00, 0x65, 0x52, 0x5d, 0xff, 0x6a, 0xd4, 0x08, 0xff, 0x6a, 0xd4, 0x08, 0xff, 0x6a, 0xd4, 0x08, 0xff, 0x6a, 0xd4, 0x0c, 0x08, 0x01, 0x02, 0x00, - 0x02, 0x0b, 0x4a, 0x7d, + 0x02, 0x0b, 0x5c, 0x7d, 0x01, 0x65, 0x0c, 0x30, - 0x02, 0x0b, 0x4e, 0x7d, + 0x02, 0x0b, 0x60, 0x7d, 0xf7, 0x01, 0x02, 0x0c, - 0x80, 0x3c, 0x9a, 0x6e, - 0x21, 0x6a, 0x96, 0x46, + 0x80, 0x3c, 0xae, 0x6e, + 0x21, 0x6a, 0xaa, 0x46, 0x01, 0x65, 0xc8, 0x30, - 0xff, 0x41, 0x76, 0x75, + 0xff, 0x41, 0x88, 0x75, 0x01, 0x41, 0x20, 0x31, 0xff, 0x6a, 0xa4, 0x00, - 0x00, 0x65, 0x66, 0x45, - 0xff, 0xbf, 0x76, 0x75, + 0x00, 0x65, 0x78, 0x45, + 0xff, 0xbf, 0x88, 0x75, 0x01, 0x90, 0xa4, 0x30, 0x01, 0xbf, 0x20, 0x31, - 0x00, 0xbb, 0x60, 0x65, - 0xff, 0x52, 0x74, 0x75, + 0x00, 0xbb, 0x72, 0x65, + 0xff, 0x52, 0x86, 0x75, 0x01, 0xbf, 0xcc, 0x30, 0x01, 0x90, 0xca, 0x30, 0x01, 0x52, 0x20, 0x31, @@ -702,28 +711,28 @@ 0x01, 0x65, 0x20, 0x35, 0x01, 0xbf, 0x82, 0x34, 0x01, 0x64, 0xa2, 0x30, - 0x00, 0x6a, 0x7e, 0x5e, + 0x00, 0x6a, 0x92, 0x5e, 0x0d, 0x6a, 0x76, 0x00, - 0x00, 0x51, 0xda, 0x45, + 0x00, 0x51, 0xec, 0x45, 0x01, 0x65, 0xa4, 0x30, 0xe0, 0x6a, 0xcc, 0x00, - 0x48, 0x6a, 0xce, 0x5d, + 0x48, 0x6a, 0xe0, 0x5d, 0x01, 0x6a, 0xd0, 0x01, 0x01, 0x6a, 0xdc, 0x05, 0x88, 0x6a, 0xcc, 0x00, - 0x48, 0x6a, 0xce, 0x5d, - 0x01, 0x6a, 0xa8, 0x5d, + 0x48, 0x6a, 0xe0, 0x5d, + 0x01, 0x6a, 0xba, 0x5d, 0x01, 0x6a, 0x26, 0x05, 0x01, 0x65, 0xd8, 0x31, 0x09, 0xee, 0xdc, 0x01, - 0x80, 0xee, 0x94, 0x7d, + 0x80, 0xee, 0xa6, 0x7d, 0xff, 0x6a, 0xdc, 0x0d, 0x01, 0x65, 0x32, 0x31, 0x0a, 0x93, 0x26, 0x01, - 0x00, 0x65, 0x6c, 0x46, - 0x81, 0x6a, 0x96, 0x5e, - 0x01, 0x0c, 0xa0, 0x7d, - 0x04, 0x0c, 0x9e, 0x6d, + 0x00, 0x65, 0x80, 0x46, + 0x81, 0x6a, 0xaa, 0x5e, + 0x01, 0x0c, 0xb2, 0x7d, + 0x04, 0x0c, 0xb0, 0x6d, 0xe0, 0x03, 0x06, 0x08, 0xe0, 0x03, 0x7e, 0x0c, 0x01, 0x65, 0x18, 0x31, @@ -742,7 +751,7 @@ 0x01, 0x6c, 0xda, 0x34, 0x3d, 0x64, 0xa4, 0x28, 0x55, 0x64, 0xc8, 0x28, - 0x00, 0x65, 0xce, 0x45, + 0x00, 0x65, 0xe0, 0x45, 0x2e, 0x64, 0xa4, 0x28, 0x66, 0x64, 0xc8, 0x28, 0x00, 0x6c, 0xda, 0x18, @@ -753,61 +762,62 @@ 0x00, 0x6c, 0xda, 0x24, 0x01, 0x65, 0xc8, 0x30, 0xe0, 0x6a, 0xcc, 0x00, - 0x44, 0x6a, 0xca, 0x5d, + 0x44, 0x6a, 0xdc, 0x5d, 0x01, 0x90, 0xe2, 0x31, - 0x04, 0x3b, 0xee, 0x7d, + 0x04, 0x3b, 0x00, 0x7e, 0x30, 0x6a, 0xd0, 0x01, 0x20, 0x6a, 0xd0, 0x01, 0x1d, 0x6a, 0xdc, 0x01, - 0xdc, 0xee, 0xea, 0x65, - 0x00, 0x65, 0x06, 0x46, + 0xdc, 0xee, 0xfc, 0x65, + 0x00, 0x65, 0x18, 0x46, 0x20, 0x6a, 0xd0, 0x01, 0x01, 0x6a, 0xdc, 0x01, 0x20, 0xa0, 0xd8, 0x31, 0x09, 0xee, 0xdc, 0x01, - 0x80, 0xee, 0xf6, 0x7d, + 0x80, 0xee, 0x08, 0x7e, 0x11, 0x6a, 0xdc, 0x01, - 0x50, 0xee, 0xfa, 0x65, + 0x50, 0xee, 0x0c, 0x66, 0x20, 0x6a, 0xd0, 0x01, 0x09, 0x6a, 0xdc, 0x01, - 0x88, 0xee, 0x00, 0x66, + 0x88, 0xee, 0x12, 0x66, 0x19, 0x6a, 0xdc, 0x01, - 0xd8, 0xee, 0x04, 0x66, + 0xd8, 0xee, 0x16, 0x66, 0xff, 0x6a, 0xdc, 0x09, - 0x18, 0xee, 0x08, 0x6e, + 0x18, 0xee, 0x1a, 0x6e, 0xff, 0x6a, 0xd4, 0x0c, 0x88, 0x6a, 0xcc, 0x00, - 0x44, 0x6a, 0xca, 0x5d, - 0x20, 0x6a, 0xa8, 0x5d, + 0x44, 0x6a, 0xdc, 0x5d, + 0x20, 0x6a, 0xba, 0x5d, 0x01, 0x3b, 0x26, 0x31, - 0x04, 0x3b, 0x22, 0x6e, + 0x04, 0x3b, 0x34, 0x6e, 0xa0, 0x6a, 0xca, 0x00, 0x20, 0x65, 0xc8, 0x18, - 0x00, 0x65, 0x5c, 0x5e, - 0x00, 0x65, 0x1a, 0x66, + 0x00, 0x65, 0x70, 0x5e, + 0x00, 0x65, 0x2c, 0x66, 0x0a, 0x93, 0x26, 0x01, - 0x00, 0x65, 0x6c, 0x46, + 0x00, 0x65, 0x80, 0x46, 0xa0, 0x6a, 0xcc, 0x00, 0xff, 0x6a, 0xc8, 0x08, - 0x01, 0x94, 0x26, 0x6e, - 0x10, 0x94, 0x28, 0x6e, - 0x08, 0x94, 0x3e, 0x6e, - 0x08, 0x94, 0x3e, 0x6e, - 0x08, 0x94, 0x3e, 0x6e, + 0x20, 0x94, 0x38, 0x6e, + 0x10, 0x94, 0x3a, 0x6e, + 0x08, 0x94, 0x52, 0x6e, + 0x08, 0x94, 0x52, 0x6e, + 0x08, 0x94, 0x52, 0x6e, 0x07, 0x8c, 0xca, 0x18, 0x3d, 0x65, 0xca, 0x28, 0x00, 0x65, 0xc8, 0x18, - 0x00, 0x65, 0x42, 0x5e, + 0x00, 0x65, 0x56, 0x5e, 0xff, 0x65, 0xca, 0x10, 0x05, 0x65, 0xc8, 0x18, - 0x00, 0x65, 0x26, 0x46, + 0x04, 0x64, 0x82, 0x76, + 0x00, 0x65, 0x38, 0x46, 0xf7, 0x93, 0x26, 0x09, - 0x08, 0x93, 0x40, 0x6e, + 0x08, 0x93, 0x54, 0x6e, 0x00, 0x62, 0xc4, 0x18, - 0x00, 0x65, 0x6c, 0x5e, - 0x00, 0x65, 0x4c, 0x5e, - 0x00, 0x65, 0x4c, 0x5e, - 0x00, 0x65, 0x4c, 0x5e, + 0x00, 0x65, 0x80, 0x5e, + 0x00, 0x65, 0x60, 0x5e, + 0x00, 0x65, 0x60, 0x5e, + 0x00, 0x65, 0x60, 0x5e, 0x01, 0x99, 0xda, 0x30, 0x01, 0x99, 0xda, 0x30, 0x01, 0x99, 0xda, 0x30, @@ -824,23 +834,23 @@ 0x01, 0x6c, 0x32, 0x31, 0x01, 0x6c, 0x32, 0x31, 0x01, 0x6c, 0x32, 0x35, - 0x08, 0x94, 0x6c, 0x7e, + 0x08, 0x94, 0x80, 0x7e, 0xf7, 0x93, 0x26, 0x09, - 0x08, 0x93, 0x70, 0x6e, + 0x08, 0x93, 0x84, 0x6e, 0xff, 0x6a, 0xd4, 0x0c, - 0x04, 0xb8, 0x92, 0x6e, + 0x04, 0xb8, 0xa6, 0x6e, 0x01, 0x42, 0x7e, 0x31, 0xff, 0x6a, 0x76, 0x01, 0x01, 0x90, 0x84, 0x34, 0xff, 0x6a, 0x76, 0x05, - 0xff, 0x42, 0x8e, 0x66, - 0xff, 0x41, 0x86, 0x66, - 0xd1, 0x6a, 0x96, 0x5e, + 0xff, 0x42, 0xa2, 0x66, + 0xff, 0x41, 0x9a, 0x66, + 0xd1, 0x6a, 0xaa, 0x5e, 0xff, 0x6a, 0xca, 0x04, 0x01, 0x41, 0x20, 0x31, 0x01, 0xbf, 0x82, 0x30, 0x01, 0x6a, 0x76, 0x00, - 0x00, 0xbb, 0xda, 0x45, + 0x00, 0xbb, 0xec, 0x45, 0x01, 0x42, 0x20, 0x31, 0x01, 0xbf, 0x84, 0x34, 0x01, 0x41, 0x7e, 0x31, @@ -919,7 +929,7 @@ static int ahc_patch14_func(struct ahc_softc *ahc) { - return ((ahc->features & AHC_DT) == 0); + return ((ahc->features & AHC_ULTRA2) == 0); } static int ahc_patch13_func(struct ahc_softc *ahc); @@ -927,7 +937,7 @@ static int ahc_patch13_func(struct ahc_softc *ahc) { - return ((ahc->features & AHC_ULTRA2) == 0); + return ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 && ahc->pci_cachesize != 0); } static int ahc_patch12_func(struct ahc_softc *ahc); @@ -935,7 +945,7 @@ static int ahc_patch12_func(struct ahc_softc *ahc) { - return ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 && ahc->pci_cachesize != 0); + return ((ahc->features & AHC_ULTRA) != 0); } static int ahc_patch11_func(struct ahc_softc *ahc); @@ -943,7 +953,7 @@ static int ahc_patch11_func(struct ahc_softc *ahc) { - return ((ahc->features & AHC_ULTRA) != 0); + return ((ahc->features & AHC_HS_MAILBOX) != 0); } static int ahc_patch10_func(struct ahc_softc *ahc); @@ -951,7 +961,7 @@ static int ahc_patch10_func(struct ahc_softc *ahc) { - return ((ahc->features & AHC_HS_MAILBOX) != 0); + return ((ahc->features & AHC_MULTI_TID) != 0); } static int ahc_patch9_func(struct ahc_softc *ahc); @@ -959,7 +969,7 @@ static int ahc_patch9_func(struct ahc_softc *ahc) { - return ((ahc->features & AHC_MULTI_TID) != 0); + return ((ahc->features & AHC_CMD_CHAN) != 0); } static int ahc_patch8_func(struct ahc_softc *ahc); @@ -967,7 +977,7 @@ static int ahc_patch8_func(struct ahc_softc *ahc) { - return ((ahc->features & AHC_CMD_CHAN) != 0); + return ((ahc->flags & AHC_INITIATORROLE) != 0); } static int ahc_patch7_func(struct ahc_softc *ahc); @@ -975,7 +985,7 @@ static int ahc_patch7_func(struct ahc_softc *ahc) { - return ((ahc->flags & AHC_INITIATORROLE) != 0); + return ((ahc->flags & AHC_TARGETROLE) != 0); } static int ahc_patch6_func(struct ahc_softc *ahc); @@ -983,7 +993,7 @@ static int ahc_patch6_func(struct ahc_softc *ahc) { - return ((ahc->flags & AHC_TARGETROLE) != 0); + return ((ahc->features & AHC_DT) == 0); } static int ahc_patch5_func(struct ahc_softc *ahc); @@ -1051,28 +1061,29 @@ { ahc_patch5_func, 22, 2, 1 }, { ahc_patch3_func, 27, 1, 2 }, { ahc_patch0_func, 28, 1, 1 }, - { ahc_patch6_func, 37, 65, 21 }, - { ahc_patch7_func, 37, 1, 1 }, - { ahc_patch8_func, 45, 3, 2 }, + { ahc_patch6_func, 34, 1, 1 }, + { ahc_patch7_func, 37, 65, 21 }, + { ahc_patch8_func, 37, 1, 1 }, + { ahc_patch9_func, 45, 3, 2 }, { ahc_patch0_func, 48, 3, 1 }, - { ahc_patch9_func, 52, 1, 2 }, + { ahc_patch10_func, 52, 1, 2 }, { ahc_patch0_func, 53, 2, 3 }, { ahc_patch1_func, 53, 1, 2 }, { ahc_patch0_func, 54, 1, 1 }, { ahc_patch2_func, 56, 2, 1 }, - { ahc_patch8_func, 58, 1, 2 }, + { ahc_patch9_func, 58, 1, 2 }, { ahc_patch0_func, 59, 1, 1 }, - { ahc_patch8_func, 63, 1, 2 }, + { ahc_patch9_func, 63, 1, 2 }, { ahc_patch0_func, 64, 1, 1 }, - { ahc_patch8_func, 73, 1, 2 }, + { ahc_patch9_func, 73, 1, 2 }, { ahc_patch0_func, 74, 1, 1 }, - { ahc_patch8_func, 77, 1, 2 }, + { ahc_patch9_func, 77, 1, 2 }, { ahc_patch0_func, 78, 1, 1 }, - { ahc_patch10_func, 88, 1, 2 }, + { ahc_patch11_func, 88, 1, 2 }, { ahc_patch0_func, 89, 1, 1 }, - { ahc_patch8_func, 97, 1, 2 }, + { ahc_patch9_func, 97, 1, 2 }, { ahc_patch0_func, 98, 1, 1 }, - { ahc_patch7_func, 102, 9, 4 }, + { ahc_patch8_func, 102, 9, 4 }, { ahc_patch1_func, 104, 1, 2 }, { ahc_patch0_func, 105, 1, 1 }, { ahc_patch2_func, 107, 2, 1 }, @@ -1081,147 +1092,162 @@ { ahc_patch0_func, 121, 2, 3 }, { ahc_patch2_func, 121, 1, 2 }, { ahc_patch0_func, 122, 1, 1 }, - { ahc_patch6_func, 123, 4, 2 }, + { ahc_patch7_func, 123, 4, 2 }, { ahc_patch0_func, 127, 1, 1 }, - { ahc_patch11_func, 129, 2, 1 }, + { ahc_patch12_func, 129, 2, 1 }, { ahc_patch1_func, 131, 1, 2 }, { ahc_patch0_func, 132, 1, 1 }, - { ahc_patch6_func, 133, 4, 1 }, - { ahc_patch6_func, 144, 77, 9 }, - { ahc_patch4_func, 156, 1, 1 }, - { ahc_patch1_func, 172, 1, 1 }, - { ahc_patch8_func, 180, 1, 2 }, - { ahc_patch0_func, 181, 1, 1 }, - { ahc_patch8_func, 190, 1, 2 }, - { ahc_patch0_func, 191, 1, 1 }, - { ahc_patch8_func, 207, 6, 2 }, - { ahc_patch0_func, 213, 6, 1 }, - { ahc_patch7_func, 221, 18, 2 }, - { ahc_patch1_func, 234, 1, 1 }, - { ahc_patch1_func, 241, 1, 2 }, - { ahc_patch0_func, 242, 2, 2 }, - { ahc_patch11_func, 243, 1, 1 }, - { ahc_patch8_func, 251, 33, 2 }, - { ahc_patch1_func, 267, 16, 1 }, - { ahc_patch12_func, 284, 14, 1 }, - { ahc_patch1_func, 298, 2, 2 }, - { ahc_patch0_func, 300, 3, 3 }, - { ahc_patch8_func, 300, 1, 2 }, - { ahc_patch0_func, 301, 2, 1 }, - { ahc_patch1_func, 305, 1, 2 }, - { ahc_patch0_func, 306, 1, 1 }, - { ahc_patch8_func, 310, 1, 1 }, - { ahc_patch8_func, 313, 2, 2 }, - { ahc_patch0_func, 315, 4, 1 }, - { ahc_patch12_func, 319, 1, 1 }, - { ahc_patch13_func, 322, 2, 3 }, - { ahc_patch8_func, 322, 1, 2 }, - { ahc_patch0_func, 323, 1, 1 }, - { ahc_patch1_func, 332, 40, 6 }, - { ahc_patch6_func, 341, 1, 1 }, - { ahc_patch7_func, 342, 1, 1 }, - { ahc_patch14_func, 344, 2, 1 }, - { ahc_patch15_func, 346, 5, 1 }, - { ahc_patch0_func, 372, 51, 15 }, - { ahc_patch12_func, 372, 1, 1 }, - { ahc_patch6_func, 374, 2, 2 }, - { ahc_patch16_func, 375, 1, 1 }, - { ahc_patch8_func, 378, 1, 1 }, - { ahc_patch17_func, 385, 1, 1 }, - { ahc_patch12_func, 390, 9, 3 }, - { ahc_patch8_func, 391, 3, 2 }, - { ahc_patch0_func, 394, 3, 1 }, - { ahc_patch8_func, 402, 6, 2 }, - { ahc_patch0_func, 408, 8, 1 }, - { ahc_patch12_func, 416, 1, 1 }, - { ahc_patch8_func, 418, 1, 2 }, - { ahc_patch0_func, 419, 1, 1 }, - { ahc_patch6_func, 422, 1, 1 }, - { ahc_patch6_func, 423, 1, 1 }, - { ahc_patch7_func, 424, 2, 1 }, - { ahc_patch8_func, 426, 1, 1 }, - { ahc_patch12_func, 427, 9, 4 }, - { ahc_patch8_func, 427, 1, 1 }, - { ahc_patch8_func, 434, 2, 1 }, - { ahc_patch0_func, 436, 4, 3 }, - { ahc_patch8_func, 436, 1, 2 }, - { ahc_patch0_func, 437, 3, 1 }, - { ahc_patch1_func, 441, 2, 1 }, - { ahc_patch6_func, 443, 5, 2 }, - { ahc_patch0_func, 448, 1, 1 }, - { ahc_patch7_func, 449, 113, 22 }, - { ahc_patch1_func, 450, 3, 2 }, - { ahc_patch0_func, 453, 5, 3 }, - { ahc_patch8_func, 453, 2, 2 }, - { ahc_patch0_func, 455, 3, 1 }, - { ahc_patch1_func, 460, 2, 2 }, - { ahc_patch0_func, 462, 6, 3 }, - { ahc_patch8_func, 462, 2, 2 }, - { ahc_patch0_func, 464, 3, 1 }, + { ahc_patch7_func, 133, 4, 1 }, + { ahc_patch7_func, 144, 80, 9 }, + { ahc_patch4_func, 162, 1, 1 }, + { ahc_patch1_func, 175, 1, 1 }, + { ahc_patch9_func, 183, 1, 2 }, + { ahc_patch0_func, 184, 1, 1 }, + { ahc_patch9_func, 193, 1, 2 }, + { ahc_patch0_func, 194, 1, 1 }, + { ahc_patch9_func, 210, 6, 2 }, + { ahc_patch0_func, 216, 6, 1 }, + { ahc_patch8_func, 224, 18, 2 }, + { ahc_patch1_func, 237, 1, 1 }, + { ahc_patch1_func, 244, 1, 2 }, + { ahc_patch0_func, 245, 2, 2 }, + { ahc_patch12_func, 246, 1, 1 }, + { ahc_patch9_func, 254, 33, 2 }, + { ahc_patch1_func, 270, 16, 1 }, + { ahc_patch13_func, 287, 14, 1 }, + { ahc_patch1_func, 301, 2, 2 }, + { ahc_patch0_func, 303, 3, 3 }, + { ahc_patch9_func, 303, 1, 2 }, + { ahc_patch0_func, 304, 2, 1 }, + { ahc_patch1_func, 308, 1, 2 }, + { ahc_patch0_func, 309, 1, 1 }, + { ahc_patch9_func, 313, 1, 1 }, + { ahc_patch9_func, 316, 2, 2 }, + { ahc_patch0_func, 318, 4, 1 }, + { ahc_patch13_func, 322, 1, 1 }, + { ahc_patch14_func, 325, 2, 3 }, + { ahc_patch9_func, 325, 1, 2 }, + { ahc_patch0_func, 326, 1, 1 }, + { ahc_patch6_func, 331, 1, 2 }, + { ahc_patch0_func, 332, 1, 1 }, + { ahc_patch1_func, 336, 45, 10 }, + { ahc_patch6_func, 345, 2, 4 }, + { ahc_patch7_func, 345, 1, 1 }, + { ahc_patch8_func, 346, 1, 1 }, + { ahc_patch0_func, 347, 1, 1 }, + { ahc_patch15_func, 348, 1, 1 }, + { ahc_patch6_func, 367, 6, 3 }, + { ahc_patch15_func, 367, 5, 1 }, + { ahc_patch0_func, 373, 5, 1 }, + { ahc_patch0_func, 381, 51, 15 }, + { ahc_patch13_func, 381, 1, 1 }, + { ahc_patch7_func, 383, 2, 2 }, + { ahc_patch16_func, 384, 1, 1 }, + { ahc_patch9_func, 387, 1, 1 }, + { ahc_patch17_func, 394, 1, 1 }, + { ahc_patch13_func, 399, 9, 3 }, + { ahc_patch9_func, 400, 3, 2 }, + { ahc_patch0_func, 403, 3, 1 }, + { ahc_patch9_func, 411, 6, 2 }, + { ahc_patch0_func, 417, 8, 1 }, + { ahc_patch13_func, 425, 1, 1 }, + { ahc_patch9_func, 427, 1, 2 }, + { ahc_patch0_func, 428, 1, 1 }, + { ahc_patch7_func, 431, 1, 1 }, + { ahc_patch7_func, 432, 1, 1 }, + { ahc_patch8_func, 433, 3, 3 }, + { ahc_patch6_func, 434, 1, 2 }, + { ahc_patch0_func, 435, 1, 1 }, + { ahc_patch9_func, 436, 1, 1 }, + { ahc_patch13_func, 437, 9, 4 }, + { ahc_patch9_func, 437, 1, 1 }, + { ahc_patch9_func, 444, 2, 1 }, + { ahc_patch0_func, 446, 4, 3 }, + { ahc_patch9_func, 446, 1, 2 }, + { ahc_patch0_func, 447, 3, 1 }, + { ahc_patch1_func, 451, 2, 1 }, + { ahc_patch7_func, 453, 5, 2 }, + { ahc_patch0_func, 458, 1, 1 }, + { ahc_patch8_func, 459, 107, 23 }, + { ahc_patch1_func, 460, 3, 2 }, + { ahc_patch0_func, 463, 5, 3 }, + { ahc_patch9_func, 463, 2, 2 }, + { ahc_patch0_func, 465, 3, 1 }, { ahc_patch1_func, 470, 2, 2 }, - { ahc_patch0_func, 472, 9, 7 }, - { ahc_patch8_func, 472, 5, 6 }, - { ahc_patch18_func, 472, 1, 2 }, - { ahc_patch0_func, 473, 1, 1 }, - { ahc_patch18_func, 475, 1, 2 }, - { ahc_patch0_func, 476, 1, 1 }, - { ahc_patch0_func, 477, 4, 1 }, - { ahc_patch1_func, 486, 1, 1 }, - { ahc_patch2_func, 498, 2, 2 }, - { ahc_patch0_func, 500, 2, 2 }, - { ahc_patch19_func, 500, 2, 1 }, - { ahc_patch19_func, 536, 7, 1 }, - { ahc_patch3_func, 564, 1, 2 }, - { ahc_patch0_func, 565, 1, 1 }, - { ahc_patch20_func, 568, 1, 1 }, - { ahc_patch7_func, 570, 95, 26 }, - { ahc_patch4_func, 571, 1, 1 }, - { ahc_patch8_func, 578, 2, 2 }, - { ahc_patch0_func, 580, 3, 1 }, - { ahc_patch18_func, 587, 2, 2 }, - { ahc_patch0_func, 589, 1, 1 }, - { ahc_patch18_func, 593, 10, 3 }, - { ahc_patch5_func, 595, 8, 1 }, - { ahc_patch0_func, 603, 9, 2 }, - { ahc_patch5_func, 604, 8, 1 }, - { ahc_patch4_func, 614, 1, 2 }, - { ahc_patch0_func, 615, 1, 1 }, - { ahc_patch18_func, 616, 1, 2 }, - { ahc_patch0_func, 617, 3, 2 }, - { ahc_patch4_func, 619, 1, 1 }, - { ahc_patch5_func, 620, 1, 1 }, - { ahc_patch5_func, 623, 1, 1 }, - { ahc_patch5_func, 625, 1, 1 }, - { ahc_patch4_func, 627, 2, 2 }, - { ahc_patch0_func, 629, 2, 1 }, + { ahc_patch0_func, 472, 6, 3 }, + { ahc_patch9_func, 472, 2, 2 }, + { ahc_patch0_func, 474, 3, 1 }, + { ahc_patch1_func, 480, 2, 2 }, + { ahc_patch0_func, 482, 9, 7 }, + { ahc_patch9_func, 482, 5, 6 }, + { ahc_patch18_func, 482, 1, 2 }, + { ahc_patch0_func, 483, 1, 1 }, + { ahc_patch18_func, 485, 1, 2 }, + { ahc_patch0_func, 486, 1, 1 }, + { ahc_patch0_func, 487, 4, 1 }, + { ahc_patch6_func, 491, 3, 2 }, + { ahc_patch0_func, 494, 1, 1 }, + { ahc_patch1_func, 497, 1, 1 }, + { ahc_patch6_func, 502, 1, 2 }, + { ahc_patch0_func, 503, 1, 1 }, + { ahc_patch19_func, 540, 7, 1 }, + { ahc_patch3_func, 568, 1, 2 }, + { ahc_patch0_func, 569, 1, 1 }, + { ahc_patch20_func, 572, 1, 1 }, + { ahc_patch8_func, 574, 100, 31 }, + { ahc_patch4_func, 575, 1, 1 }, + { ahc_patch1_func, 581, 2, 2 }, + { ahc_patch0_func, 583, 1, 1 }, + { ahc_patch9_func, 584, 3, 3 }, + { ahc_patch14_func, 585, 1, 1 }, + { ahc_patch0_func, 587, 4, 1 }, + { ahc_patch18_func, 595, 2, 2 }, + { ahc_patch0_func, 597, 1, 1 }, + { ahc_patch18_func, 601, 10, 3 }, + { ahc_patch5_func, 603, 8, 1 }, + { ahc_patch0_func, 611, 9, 2 }, + { ahc_patch5_func, 612, 8, 1 }, + { ahc_patch4_func, 622, 1, 2 }, + { ahc_patch0_func, 623, 1, 1 }, + { ahc_patch18_func, 624, 1, 2 }, + { ahc_patch0_func, 625, 3, 2 }, + { ahc_patch4_func, 627, 1, 1 }, + { ahc_patch5_func, 628, 1, 1 }, { ahc_patch5_func, 631, 1, 1 }, - { ahc_patch5_func, 634, 1, 1 }, - { ahc_patch5_func, 637, 1, 1 }, - { ahc_patch18_func, 641, 1, 1 }, - { ahc_patch18_func, 644, 1, 1 }, - { ahc_patch4_func, 650, 1, 1 }, - { ahc_patch6_func, 665, 16, 1 }, - { ahc_patch4_func, 683, 20, 1 }, - { ahc_patch8_func, 704, 4, 2 }, - { ahc_patch0_func, 708, 4, 1 }, - { ahc_patch8_func, 712, 4, 2 }, - { ahc_patch0_func, 716, 3, 1 }, - { ahc_patch21_func, 724, 14, 1 }, - { ahc_patch6_func, 738, 3, 1 }, - { ahc_patch8_func, 750, 24, 8 }, - { ahc_patch18_func, 754, 1, 2 }, - { ahc_patch0_func, 755, 1, 1 }, - { ahc_patch13_func, 760, 4, 2 }, - { ahc_patch0_func, 764, 7, 3 }, - { ahc_patch22_func, 764, 5, 2 }, - { ahc_patch0_func, 769, 2, 1 }, - { ahc_patch0_func, 774, 40, 3 }, - { ahc_patch17_func, 786, 16, 2 }, - { ahc_patch0_func, 802, 1, 1 }, - { ahc_patch4_func, 826, 1, 1 }, - { ahc_patch4_func, 827, 3, 2 }, - { ahc_patch0_func, 830, 1, 1 }, - { ahc_patch4_func, 831, 12, 1 } + { ahc_patch5_func, 633, 1, 1 }, + { ahc_patch4_func, 635, 2, 2 }, + { ahc_patch0_func, 637, 2, 1 }, + { ahc_patch5_func, 639, 1, 1 }, + { ahc_patch5_func, 642, 1, 1 }, + { ahc_patch5_func, 645, 1, 1 }, + { ahc_patch18_func, 649, 1, 1 }, + { ahc_patch18_func, 652, 1, 1 }, + { ahc_patch4_func, 658, 1, 1 }, + { ahc_patch6_func, 661, 1, 2 }, + { ahc_patch0_func, 662, 1, 1 }, + { ahc_patch7_func, 674, 16, 1 }, + { ahc_patch4_func, 692, 20, 1 }, + { ahc_patch9_func, 713, 4, 2 }, + { ahc_patch0_func, 717, 4, 1 }, + { ahc_patch9_func, 721, 4, 2 }, + { ahc_patch0_func, 725, 3, 1 }, + { ahc_patch6_func, 731, 1, 1 }, + { ahc_patch21_func, 733, 14, 1 }, + { ahc_patch7_func, 747, 3, 1 }, + { ahc_patch9_func, 759, 24, 8 }, + { ahc_patch18_func, 763, 1, 2 }, + { ahc_patch0_func, 764, 1, 1 }, + { ahc_patch14_func, 769, 4, 2 }, + { ahc_patch0_func, 773, 7, 3 }, + { ahc_patch22_func, 773, 5, 2 }, + { ahc_patch0_func, 778, 2, 1 }, + { ahc_patch0_func, 783, 41, 3 }, + { ahc_patch17_func, 795, 17, 2 }, + { ahc_patch0_func, 812, 1, 1 }, + { ahc_patch4_func, 836, 1, 1 }, + { ahc_patch4_func, 837, 3, 2 }, + { ahc_patch0_func, 840, 1, 1 }, + { ahc_patch4_func, 841, 12, 1 } }; struct cs { u_int16_t begin; @@ -1229,11 +1255,11 @@ } critical_sections[] = { { 11, 18 }, { 21, 30 }, - { 683, 699 }, - { 827, 830 }, - { 831, 837 }, - { 839, 841 }, - { 841, 843 } + { 692, 708 }, + { 837, 840 }, + { 841, 847 }, + { 849, 851 }, + { 851, 853 } }; const int num_critical_sections = sizeof(critical_sections) / sizeof(*critical_sections); diff -Nru a/drivers/scsi/aic7xxx/aicasm/Makefile b/drivers/scsi/aic7xxx/aicasm/Makefile --- a/drivers/scsi/aic7xxx/aicasm/Makefile Wed May 16 06:00:18 2001 +++ b/drivers/scsi/aic7xxx/aicasm/Makefile Wed May 16 06:00:18 2001 @@ -2,17 +2,23 @@ CSRCS= aicasm.c aicasm_symbol.c GENSRCS= aicasm_gram.c aicasm_scan.c - -GENHDRS= y.tab.h +DEPHDRS= aicdb.h +GENHDRS= y.tab.h aicdb.h SRCS= ${GENSRCS} ${CSRCS} CLEANFILES= ${GENSRCS} ${GENHDRS} y.output # Override default kernel CFLAGS. This is a userland app. -AICASM_CFLAGS:= -I/usr/include -ldb1 +AICASM_CFLAGS:= -I/usr/include -I. -ldb YFLAGS= -d NOMAN= noman +ifneq ($(HOSTCC),) +AICASM_CC= $(HOSTCC) +else +AICASM_CC= $(CC) +endif + ifdef DEBUG CFLAGS+= -DDEBUG -g YFLAGS+= -t -v @@ -21,8 +27,21 @@ .SUFFIXES= .l .y .c -$(PROG): $(SRCS) - $(HOSTCC) $(AICASM_CFLAGS) $(SRCS) -o $(PROG) +$(PROG): $(SRCS) $(DEPHDRS) + $(AICASM_CC) $(AICASM_CFLAGS) $(SRCS) -o $(PROG) + +aicdb.h: + @if [ -e "/usr/include/db3/db_185.h" ]; then \ + echo "#include " > aicdb.h; \ + elif [ -e "/usr/include/db2/db_185.h" ]; then \ + echo "#include " > aicdb.h; \ + elif [ -e "/usr/include/db/db_185.h" ]; then \ + echo "#include " > aicdb.h; \ + elif [ -e "/usr/include/db_185.h" ]; then \ + echo "#include " > aicdb.h; \ + else \ + echo "*** Install db development libraries"; \ + fi clean: rm -f $(CLEANFILES) $(PROG) diff -Nru a/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c b/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c --- a/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c Wed May 16 06:00:18 2001 +++ b/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c Wed May 16 06:00:18 2001 @@ -28,7 +28,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: //depot/src/aic7xxx/aicasm/aicasm_symbol.c#4 $ + * $Id: //depot/src/aic7xxx/aicasm/aicasm_symbol.c#5 $ * * $FreeBSD: src/sys/dev/aic7xxx/aicasm/aicasm_symbol.c,v 1.11 2000/09/22 22:19:54 gibbs Exp $ */ @@ -36,7 +36,7 @@ #include #ifdef __linux__ -#include +#include "aicdb.h" #else #include #endif diff -Nru a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c --- a/drivers/scsi/fdomain.c Wed May 16 06:00:18 2001 +++ b/drivers/scsi/fdomain.c Wed May 16 06:00:18 2001 @@ -587,9 +587,7 @@ static void do_pause( unsigned amount ) /* Pause for amount*10 milliseconds */ { - do { - udelay(10*1000); - } while (--amount); + mdelay(10*amount); } inline static void fdomain_make_bus_idle( void ) @@ -971,7 +969,7 @@ return 0; shpnt->irq = interrupt_level; shpnt->io_port = port_base; - scsi_set_pci_device(shpnt->pci_dev, pdev); + scsi_set_pci_device(shpnt, pdev); shpnt->n_io_port = 0x10; print_banner( shpnt ); diff -Nru a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c --- a/drivers/scsi/scsi_lib.c Wed May 16 06:00:24 2001 +++ b/drivers/scsi/scsi_lib.c Wed May 16 06:00:24 2001 @@ -1108,9 +1108,13 @@ */ void scsi_unblock_requests(struct Scsi_Host * SHpnt) { + Scsi_Device *SDloop; + SHpnt->host_self_blocked = FALSE; + /* Now that we are unblocked, try to start the queues. */ + for (SDloop = SHpnt->host_queue; SDloop; SDloop = SDloop->next) + scsi_queue_next_request(&SDloop->request_queue, NULL); } - /* * Function: scsi_report_bus_reset() diff -Nru a/drivers/scsi/sym53c8xx_defs.h b/drivers/scsi/sym53c8xx_defs.h --- a/drivers/scsi/sym53c8xx_defs.h Wed May 16 06:00:22 2001 +++ b/drivers/scsi/sym53c8xx_defs.h Wed May 16 06:00:22 2001 @@ -168,16 +168,12 @@ #endif /* - * Use normal IO if configured. Forced for alpha and powerpc. - * Powerpc fails copying to on-chip RAM using memcpy_toio(). + * Use normal IO if configured. Forced for alpha. */ #if defined(CONFIG_SCSI_NCR53C8XX_IOMAPPED) #define SCSI_NCR_IOMAPPED #elif defined(__alpha__) #define SCSI_NCR_IOMAPPED -#elif defined(__powerpc__) -#define SCSI_NCR_IOMAPPED -#define SCSI_NCR_PCI_MEM_NOT_SUPPORTED #elif defined(__sparc__) #undef SCSI_NCR_IOMAPPED #endif diff -Nru a/drivers/sgi/char/linux_logo.h b/drivers/sgi/char/linux_logo.h --- a/drivers/sgi/char/linux_logo.h Wed May 16 06:00:17 2001 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,909 +0,0 @@ -/* This is a linux logo to be displayed on boot. - * - * You can put anything here, but: - * LINUX_LOGO_COLORS has to be less than 224 - * image size has to be 80x80 - * values have to start from0x20 - * (i.e. RGB(linux_logo_red[0], - * linux_logo_green[0], - * linux_logo_blue[0]) is color0x20) - */ - -#define LINUX_LOGO_COLORS 221 - -unsigned char linux_logo_red[] = { - 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[] = { - 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[] = { - 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[] = { - 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, -}; - diff -Nru a/drivers/sound/dmasound/Makefile b/drivers/sound/dmasound/Makefile --- a/drivers/sound/dmasound/Makefile Wed May 16 06:00:25 2001 +++ b/drivers/sound/dmasound/Makefile Wed May 16 06:00:25 2001 @@ -7,15 +7,21 @@ # # Note 2! The CFLAGS definitions are now in the main makefile... +O_TARGET = dmasound.o + export-objs := dmasound_core.o -obj-$(CONFIG_DMASOUND_ATARI) += dmasound_core.o dmasound_atari.o -obj-$(CONFIG_DMASOUND_AWACS) += dmasound_core.o dmasound_awacs.o -obj-$(CONFIG_DMASOUND_PAULA) += dmasound_core.o dmasound_paula.o -obj-$(CONFIG_DMASOUND_Q40) += dmasound_core.o dmasound_q40.o - -ifeq ($(CONFIG_DMASOUND),y) - O_TARGET = dmasound.o -endif +list-multi := dmasound_pmac.o + +dmasound_pmac-objs := dmasound_awacs.o + +obj-$(CONFIG_DMASOUND) += dmasound_core.o +obj-$(CONFIG_DMASOUND_ATARI) += dmasound_atari.o +obj-$(CONFIG_DMASOUND_AWACS) += dmasound_pmac.o +obj-$(CONFIG_DMASOUND_PAULA) += dmasound_paula.o +obj-$(CONFIG_DMASOUND_Q40) += dmasound_q40.o include $(TOPDIR)/Rules.make + +dmasound_pmac.o: $(dmasound_pmac-objs) + $(LD) $(EXTRA_LDFLAGS) -r -o $@ $(dmasound_pmac-objs) diff -Nru a/drivers/sound/dmasound/dmasound.h b/drivers/sound/dmasound/dmasound.h --- a/drivers/sound/dmasound/dmasound.h Wed May 16 06:00:21 2001 +++ b/drivers/sound/dmasound/dmasound.h Wed May 16 06:00:21 2001 @@ -29,6 +29,9 @@ #define SND_DEV_SNDPROC 9 /* /dev/sndproc for programmable devices */ #define SND_DEV_PSS SND_DEV_SNDPROC +#define DMASOUND_CORE_REVISION 1 +#define DMASOUND_CORE_EDITION 1 + #define DSP_DEFAULT_SPEED 8000 #define ON 1 @@ -121,12 +124,13 @@ void (*record)(void); /* optional */ void (*mixer_init)(void); /* optional */ int (*mixer_ioctl)(u_int, u_long); /* optional */ - void (*write_sq_setup)(void); /* optional */ - void (*read_sq_setup)(void); /* optional */ + int (*write_sq_setup)(void); /* optional */ + int (*read_sq_setup)(void); /* optional */ void (*sq_open)(void); /* optional */ int (*state_info)(char *); /* optional */ void (*abort_read)(void); /* optional */ int min_dsp_speed; + int version; } MACHINE; diff -Nru a/drivers/sound/dmasound/dmasound_atari.c b/drivers/sound/dmasound/dmasound_atari.c --- a/drivers/sound/dmasound/dmasound_atari.c Wed May 16 06:00:17 2001 +++ b/drivers/sound/dmasound/dmasound_atari.c Wed May 16 06:00:17 2001 @@ -1438,9 +1438,10 @@ return AtaMixerIoctl(cmd, arg); } -static void AtaWriteSqSetup(void) +static int AtaWriteSqSetup(void) { write_sq_ignore_int = 0; + return 0; } static void AtaSqOpen(void) diff -Nru a/drivers/sound/dmasound/dmasound_awacs.c b/drivers/sound/dmasound/dmasound_awacs.c --- a/drivers/sound/dmasound/dmasound_awacs.c Wed May 16 06:00:25 2001 +++ b/drivers/sound/dmasound/dmasound_awacs.c Wed May 16 06:00:25 2001 @@ -4,7 +4,14 @@ * * PowerMac `AWACS' and `Burgundy' DMA Sound Driver * - * See linux/drivers/sound/dmasound/dmasound_core.c for copyright and credits + * See linux/drivers/sound/dmasound/dmasound_core.c for copyright and + * history prior to 2001/01/26. + * + * 26/01/2001 ed 0.1 Iain Sandoe + * - added version info. + * - moved dbdma command buffer allocation to PMacXXXSqSetup() + * - fixed up beep dbdma cmd buffers + * */ @@ -18,6 +25,7 @@ #include #include #include +#include #ifdef CONFIG_ADB_CUDA #include #endif @@ -36,6 +44,8 @@ #include "awacs_defs.h" #include "dmasound.h" +#define DMASOUND_AWACS_REVISION 0 +#define DMASOUND_AWACS_EDITION 1 /* * Interrupt numbers and addresses, obtained from the device tree. @@ -54,15 +64,18 @@ int awacs_device_id = 0; int awacs_has_iic = 0; #define AWACS_BURGUNDY 100 /* fake revision # for burgundy */ +#define AWACS_DACA 80 /* fake revision # for daca (ibook)? */ /* * Space for the DBDMA command blocks. */ static void *awacs_tx_cmd_space; static volatile struct dbdma_cmd *awacs_tx_cmds; +static int number_of_tx_cmd_buffers = 0; static void *awacs_rx_cmd_space; static volatile struct dbdma_cmd *awacs_rx_cmds; +static int number_of_rx_cmd_buffers = 0; /* * Cached values of AWACS registers (we can't read them). @@ -121,6 +134,7 @@ static int beep_playing = 0; static int awacs_beep_state = 0; static short *beep_buf; +static void *beep_dbdma_cmd_space; static volatile struct dbdma_cmd *beep_dbdma_cmd; static void (*orig_mksound)(unsigned int, unsigned int); static int is_pbook_3400; @@ -246,8 +260,8 @@ static int PMacMixerIoctl(u_int cmd, u_long arg); -static void PMacWriteSqSetup(void); -static void PMacReadSqSetup(void); +static int PMacWriteSqSetup(void); +static int PMacReadSqSetup(void); static void PMacAbortRead(void); @@ -850,12 +864,16 @@ free_irq(awacs_irq, 0); free_irq(awacs_tx_irq, 0); free_irq(awacs_rx_irq, 0); - kfree(awacs_tx_cmd_space); + if (awacs_tx_cmd_space) + kfree(awacs_tx_cmd_space); if (awacs_rx_cmd_space) kfree(awacs_rx_cmd_space); - if (beep_buf) + if (beep_dbdma_cmd_space) + kfree(beep_dbdma_cmd_space); + if (beep_buf) { kfree(beep_buf); - kd_mksound = orig_mksound; + kd_mksound = orig_mksound; + } #ifdef CONFIG_PMAC_PBOOK pmu_unregister_sleep_notifier(&awacs_sleep_notifier); #endif @@ -1017,6 +1035,8 @@ if (awacs_beep_state) { /* sound takes precedence over beeps */ out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16); + while (in_le32(&awacs_txdma->status) & RUN) + udelay(1); out_le32(&awacs->control, (in_le32(&awacs->control) & ~0x1f00) | (awacs_rate_index << 8)); @@ -1043,6 +1063,7 @@ out_le16(&cp->command, OUTPUT_MORE + INTR_ALWAYS); if (write_sq.active == 0) out_le32(&awacs_txdma->cmdptr, virt_to_bus(cp)); + (void)in_le32(&awacs_txdma->status); out_le32(&awacs_txdma->control, ((RUN|WAKE) << 16) + (RUN|WAKE)); ++write_sq.active; } @@ -1099,7 +1120,6 @@ static void pmac_awacs_rx_intr(int irq, void *devid, struct pt_regs *regs) { - /* For some reason on my PowerBook G3, I get one interrupt * when the interrupt vector is installed (like something is * pending). This happens before the dbdma is initialize by @@ -1167,7 +1187,7 @@ static void awacs_write(int val) { - if (awacs_revision >= AWACS_BURGUNDY) + if (awacs_revision >= AWACS_DACA) return; while (in_le32(&awacs->codec_ctrl) & MASK_NEWECMD) ; /* XXX should have timeout */ @@ -1182,6 +1202,8 @@ if (beep_playing) { st_le16(&beep_dbdma_cmd->command, DBDMA_STOP); out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16); + while (in_le32(&awacs_txdma->status) & RUN) + udelay(1); out_le32(&awacs->control, (in_le32(&awacs->control) & ~0x1f00) | (awacs_rate_index << 8)); @@ -1207,6 +1229,8 @@ static int beep_nsamples_cache; static int beep_volume_cache; + if (beep_buf == NULL) + return; for (i = 0; i < 8 && awacs_freqs[i] >= BEEP_SRATE; ++i) if (awacs_freqs_ok[i]) beep_speed = i; @@ -1264,11 +1288,14 @@ save_flags(flags); cli(); if (beep_playing) { /* i.e. haven't been terminated already */ out_le32(&awacs_txdma->control, (RUN|WAKE|FLUSH|PAUSE) << 16); + while (in_le32(&awacs_txdma->status) & RUN) + udelay(1); out_le32(&awacs->control, (in_le32(&awacs->control) & ~0x1f00) | (beep_speed << 8)); out_le32(&awacs->byteswap, 0); out_le32(&awacs_txdma->cmdptr, virt_to_bus(beep_dbdma_cmd)); + (void)in_le32(&awacs_txdma->status); out_le32(&awacs_txdma->control, RUN | (RUN << 16)); } restore_flags(flags); @@ -1558,13 +1585,13 @@ static void awacs_enable_amp(int spkr_vol) { +#ifdef CONFIG_ADB_CUDA struct adb_request req; awacs_spkr_vol = spkr_vol; if (sys_ctrler != SYS_CTRLER_CUDA) return; -#ifdef CONFIG_ADB_CUDA /* turn on headphones */ cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC, 0x8a, 4, 0); @@ -1871,11 +1898,53 @@ } -static void PMacWriteSqSetup(void) +/* Write/Read sq setup functions: + Check to see if we have enough (or any) dbdma cmd buffers for the + user's fragment settings. If not, allocate some. If this fails we will + point at the beep buffer - as an emergency provision - to stop dma tromping + on some random bit of memory (if someone lets it go anyway). + The command buffers are then set up to point to the fragment buffers + (allocated elsewhere). We need n+1 commands the last of which holds + a NOP + loop to start. +*/ + +static int PMacWriteSqSetup(void) { int i; volatile struct dbdma_cmd *cp; + /* stop the controller from doing any output - if it isn't already. + it _should_ be before this is called anyway */ + + out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16); + while (in_le32(&awacs_txdma->status) & RUN) + udelay(1); + + if ((write_sq.numBufs+1) > number_of_tx_cmd_buffers) { + if (awacs_tx_cmd_space) + kfree(awacs_tx_cmd_space); + number_of_tx_cmd_buffers = 0; + + /* we need nbufs + 1 (for the loop) and we should request + 1 again + because the DBDMA_ALIGN might pull the start up by up to + sizeof(struct dbdma_cmd) - 4 (assuming kmalloc aligns 32 bits). + */ + + awacs_tx_cmd_space = kmalloc + ((write_sq.numBufs + 1 + 1) * sizeof(struct dbdma_cmd), + GFP_KERNEL); + if (awacs_tx_cmd_space == NULL) { + /* don't leave it dangling - nasty but better than a random address */ + out_le32(&awacs_txdma->cmdptr, virt_to_bus(beep_dbdma_cmd)); + printk(KERN_ERR + "dmasound_pmac: can't allocate dbdma cmd buffers, driver disabled\n"); + return -ENOMEM; + } + awacs_tx_cmds = (volatile struct dbdma_cmd *) + DBDMA_ALIGN(awacs_tx_cmd_space); + number_of_tx_cmd_buffers = write_sq.numBufs + 1; + } + cp = awacs_tx_cmds; memset((void *)cp, 0, (write_sq.numBufs+1) * sizeof(struct dbdma_cmd)); for (i = 0; i < write_sq.numBufs; ++i, ++cp) { @@ -1883,15 +1952,47 @@ } st_le16(&cp->command, DBDMA_NOP + BR_ALWAYS); st_le32(&cp->cmd_dep, virt_to_bus(awacs_tx_cmds)); - out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16); + /* point the controller at the command stack - ready to go */ out_le32(&awacs_txdma->cmdptr, virt_to_bus(awacs_tx_cmds)); + return 0; } -static void PMacReadSqSetup(void) +static int PMacReadSqSetup(void) { int i; volatile struct dbdma_cmd *cp; + /* stop the controller from doing any input - if it isn't already. + it _should_ be before this is called anyway */ + + out_le32(&awacs_rxdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16); + while (in_le32(&awacs_rxdma->status) & RUN) + udelay(1); + + if( (read_sq.numBufs+1) > number_of_rx_cmd_buffers ) { + if (awacs_rx_cmd_space) + kfree(awacs_rx_cmd_space); + number_of_rx_cmd_buffers = 0; + + /* we need nbufs + 1 (for the loop) and we should request + 1 again + because the DBDMA_ALIGN might pull the start up by up to + sizeof(struct dbdma_cmd) - 4 (assuming kmalloc aligns 32 bits). + */ + + awacs_rx_cmd_space = kmalloc + ((read_sq.numBufs + 1 + 1) * sizeof(struct dbdma_cmd), + GFP_KERNEL); + if (awacs_rx_cmd_space == NULL) { + /* don't leave it dangling - nasty but better than a random address */ + out_le32(&awacs_rxdma->cmdptr, virt_to_bus(beep_dbdma_cmd)); + printk(KERN_ERR + "dmasound_pmac: can't allocate dbdma cmd buffers, driver disabled\n"); + return -ENOMEM; + } + awacs_rx_cmds = (volatile struct dbdma_cmd *) + DBDMA_ALIGN(awacs_rx_cmd_space); + number_of_rx_cmd_buffers = read_sq.numBufs+1 ; + } cp = awacs_rx_cmds; memset((void *)cp, 0, (read_sq.numBufs+1) * sizeof(struct dbdma_cmd)); @@ -1907,14 +2008,9 @@ */ st_le16(&cp->command, DBDMA_NOP + BR_ALWAYS); st_le32(&cp->cmd_dep, virt_to_bus(awacs_rx_cmds)); - - /* Don't start until the first read is done. - * This will also abort any operations in progress if the DMA - * happens to be running (and it shouldn't). - */ - out_le32(&awacs_rxdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16); + /* point the controller at the command stack - ready to go */ out_le32(&awacs_rxdma->cmdptr, virt_to_bus(awacs_rx_cmds)); - + return 0; } static void PMacAbortRead(void) @@ -1937,7 +2033,7 @@ static MACHINE machPMac = { name: awacs_name, - name2: "AWACS", + name2: "Built-in Sound", open: PMacOpen, release: PMacRelease, dma_alloc: PMacAlloc, @@ -1956,7 +2052,8 @@ write_sq_setup: PMacWriteSqSetup, read_sq_setup: PMacReadSqSetup, abort_read: PMacAbortRead, - min_dsp_speed: 8000 + min_dsp_speed: 8000, + version: ((DMASOUND_AWACS_REVISION<<8) + DMASOUND_AWACS_EDITION) }; @@ -1966,6 +2063,7 @@ int __init dmasound_awacs_init(void) { struct device_node *np; + int vol; if (_machine != _MACH_Pmac) return -ENODEV; @@ -1974,203 +2072,218 @@ awacs_revision = 0; np = find_devices("awacs"); if (np == 0) { + unsigned int *prop, l, i; + /* * powermac G3 models have a node called "davbus" * with a child called "sound". */ struct device_node *sound; np = find_devices("davbus"); + /* + * if we didn't find a davbus device, try 'i2s-a' since + * this seems to be what iBooks have + */ + if (np == NULL) { + np = find_devices("i2s-a"); + } + if (np == NULL) + return -ENODEV; sound = find_devices("sound"); - if (sound != 0 && sound->parent == np) { - unsigned int *prop, l, i; - prop = (unsigned int *) - get_property(sound, "sub-frame", 0); - if (prop != 0 && *prop >= 0 && *prop < 16) - awacs_subframe = *prop; - if (device_is_compatible(sound, "burgundy")) - awacs_revision = AWACS_BURGUNDY; - /* This should be verified on older screamers */ - if (device_is_compatible(sound, "screamer")) - awacs_is_screamer = 1; - prop = (unsigned int *)get_property(sound, "device-id", 0); - if (prop != 0) - awacs_device_id = *prop; - awacs_has_iic = (find_devices("perch") != NULL); - - /* look for a property saying what sample rates - are available */ - for (i = 0; i < 8; ++i) - awacs_freqs_ok[i] = 0; + while (sound != 0 && sound->parent != np) + sound = sound->next; + if (sound == 0) + return -ENODEV; + prop = (unsigned int *) get_property(sound, "sub-frame", 0); + if (prop != 0 && *prop >= 0 && *prop < 16) + awacs_subframe = *prop; + if (device_is_compatible(sound, "burgundy")) + awacs_revision = AWACS_BURGUNDY; + if (device_is_compatible(sound, "daca")) + awacs_revision = AWACS_DACA; + /* This should be verified on older screamers */ + if (device_is_compatible(sound, "screamer")) + awacs_is_screamer = 1; + prop = (unsigned int *)get_property(sound, "device-id", 0); + if (prop != 0) + awacs_device_id = *prop; + awacs_has_iic = (find_devices("perch") != NULL); + + /* look for a property saying what sample rates + are available */ + for (i = 0; i < 8; ++i) + awacs_freqs_ok[i] = 0; + prop = (unsigned int *)get_property(sound, "sample-rates", &l); + if (prop == 0) prop = (unsigned int *) get_property - (sound, "sample-rates", &l); - if (prop == 0) - prop = (unsigned int *) get_property - (sound, "output-frame-rates", &l); - if (prop != 0) { - for (l /= sizeof(int); l > 0; --l) { - /* sometimes the rate is in the - high-order 16 bits (?) */ - unsigned int r = *prop++; - if (r >= 0x10000) - r >>= 16; - for (i = 0; i < 8; ++i) { - if (r == awacs_freqs[i]) { - awacs_freqs_ok[i] = 1; - break; - } + (sound, "output-frame-rates", &l); + if (prop != 0) { + for (l /= sizeof(int); l > 0; --l) { + /* sometimes the rate is in the + high-order 16 bits (?) */ + unsigned int r = *prop++; + if (r >= 0x10000) + r >>= 16; + for (i = 0; i < 8; ++i) { + if (r == awacs_freqs[i]) { + awacs_freqs_ok[i] = 1; + break; } } - } else { - /* assume just 44.1k is OK */ - awacs_freqs_ok[0] = 1; } + } else { + /* assume just 44.1k is OK */ + awacs_freqs_ok[0] = 1; } } - if (np != NULL && np->n_addrs >= 3 && np->n_intrs >= 3) { - int vol; - dmasound.mach = machPMac; - - awacs = (volatile struct awacs_regs *) - ioremap(np->addrs[0].address, 0x80); - awacs_txdma = (volatile struct dbdma_regs *) - ioremap(np->addrs[1].address, 0x100); - awacs_rxdma = (volatile struct dbdma_regs *) - ioremap(np->addrs[2].address, 0x100); - - awacs_irq = np->intrs[0].line; - awacs_tx_irq = np->intrs[1].line; - awacs_rx_irq = np->intrs[2].line; - - awacs_tx_cmd_space = kmalloc((write_sq.numBufs + 4) * sizeof(struct dbdma_cmd), - GFP_KERNEL); - if (awacs_tx_cmd_space == NULL) { - printk(KERN_ERR "DMA sound driver: Not enough buffer memory, driver disabled!\n"); - return -ENOMEM; - } - awacs_node = np; -#ifdef CONFIG_PMAC_PBOOK - if (machine_is_compatible("PowerBook1,1") - || machine_is_compatible("AAPL,PowerBook1998")) { - pmu_suspend(); - feature_set(np, FEATURE_Sound_CLK_enable); - feature_set(np, FEATURE_Sound_power); - /* Shorter delay will not work */ - mdelay(1000); - pmu_resume(); - } -#endif - awacs_tx_cmds = (volatile struct dbdma_cmd *) - DBDMA_ALIGN(awacs_tx_cmd_space); + if (np->n_addrs < 3 || np->n_intrs < 3) { + printk(KERN_ERR "AWACS: can't use %s (%d addrs, %d intrs)\n", + np->full_name, np->n_addrs, np->n_intrs); + return -ENODEV; + } + dmasound.mach = machPMac; - awacs_rx_cmd_space = kmalloc((read_sq.numBufs + 4) * sizeof(struct dbdma_cmd), - GFP_KERNEL); - if (awacs_rx_cmd_space == NULL) { - printk("DMA sound driver: No memory for input"); - } - awacs_rx_cmds = (volatile struct dbdma_cmd *) - DBDMA_ALIGN(awacs_rx_cmd_space); + awacs = (volatile struct awacs_regs *) + ioremap(np->addrs[0].address, 0x80); + awacs_txdma = (volatile struct dbdma_regs *) + ioremap(np->addrs[1].address, 0x100); + awacs_rxdma = (volatile struct dbdma_regs *) + ioremap(np->addrs[2].address, 0x100); + + awacs_irq = np->intrs[0].line; + awacs_tx_irq = np->intrs[1].line; + awacs_rx_irq = np->intrs[2].line; + awacs_node = np; +#ifdef CONFIG_PMAC_PBOOK + if (machine_is_compatible("PowerBook1,1") + || machine_is_compatible("AAPL,PowerBook1998")) { + feature_set(np, FEATURE_Sound_CLK_enable); + feature_set(np, FEATURE_Sound_power); + /* Shorter delay will not work */ + mdelay(1000); + } +#endif - awacs_reg[0] = MASK_MUX_CD; - /* FIXME: Only machines with external SRS module need MASK_PAROUT */ - awacs_reg[1] = MASK_LOOPTHRU; - if (awacs_has_iic || awacs_device_id == 0x5 || /*awacs_device_id == 0x8 - || */awacs_device_id == 0xb) - awacs_reg[1] |= MASK_PAROUT; - /* get default volume from nvram */ - vol = (~nvram_read_byte(0x1308) & 7) << 1; - awacs_reg[2] = vol + (vol << 6); - awacs_reg[4] = vol + (vol << 6); - awacs_reg[5] = 0; - awacs_reg[6] = 0; - awacs_reg[7] = 0; - out_le32(&awacs->control, 0x11); - awacs_write(awacs_reg[0] + MASK_ADDR0); - awacs_write(awacs_reg[1] + MASK_ADDR1); - awacs_write(awacs_reg[2] + MASK_ADDR2); - awacs_write(awacs_reg[4] + MASK_ADDR4); - if (awacs_is_screamer) { - awacs_write(awacs_reg[5] + MASK_ADDR5); - awacs_write(awacs_reg[6] + MASK_ADDR6); - awacs_write(awacs_reg[7] + MASK_ADDR7); + awacs_reg[0] = MASK_MUX_CD; + /* FIXME: Only machines with external SRS module need MASK_PAROUT */ + awacs_reg[1] = MASK_LOOPTHRU; + if (awacs_has_iic || awacs_device_id == 0x5 + || /*awacs_device_id == 0x8 ||*/ awacs_device_id == 0xb) + awacs_reg[1] |= MASK_PAROUT; + /* get default volume from nvram */ + vol = (~nvram_read_byte(0x1308) & 7) << 1; + awacs_reg[2] = vol + (vol << 6); + awacs_reg[4] = vol + (vol << 6); + awacs_reg[5] = 0; + awacs_reg[6] = 0; + awacs_reg[7] = 0; + out_le32(&awacs->control, 0x11); + awacs_write(awacs_reg[0] + MASK_ADDR0); + awacs_write(awacs_reg[1] + MASK_ADDR1); + awacs_write(awacs_reg[2] + MASK_ADDR2); + awacs_write(awacs_reg[4] + MASK_ADDR4); + if (awacs_is_screamer) { + awacs_write(awacs_reg[5] + MASK_ADDR5); + awacs_write(awacs_reg[6] + MASK_ADDR6); + awacs_write(awacs_reg[7] + MASK_ADDR7); + } + + /* Initialize recent versions of the awacs */ + if (awacs_revision == 0) { + awacs_revision = (in_le32(&awacs->codec_stat) >> 12) & 0xf; + if (awacs_revision == 3) { + mdelay(100); + awacs_write(0x6000); + mdelay(2); + awacs_write(awacs_reg[1] + MASK_ADDR1); + awacs_enable_amp(100 * 0x101); } + } + if (awacs_revision >= AWACS_BURGUNDY) + awacs_burgundy_init(); - /* Initialize recent versions of the awacs */ - if (awacs_revision == 0) { - awacs_revision = - (in_le32(&awacs->codec_stat) >> 12) & 0xf; - if (awacs_revision == 3) { - mdelay(100); - awacs_write(0x6000); - mdelay(2); - awacs_write(awacs_reg[1] + MASK_ADDR1); - awacs_enable_amp(100 * 0x101); - } - } - if (awacs_revision >= AWACS_BURGUNDY) - awacs_burgundy_init(); + /* Reset dbdma channels */ + out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE|DEAD) << 16); + while (in_le32(&awacs_txdma->status) & RUN) + udelay(1); + out_le32(&awacs_rxdma->control, (RUN|PAUSE|FLUSH|WAKE|DEAD) << 16); + while (in_le32(&awacs_rxdma->status) & RUN) + udelay(1); + + /* Initialize beep stuff */ + /* need to ask for two buffers to cater for potential pull-up + by DBDMA_ALIGN + */ + beep_dbdma_cmd_space = kmalloc((1 + 1) * sizeof(struct dbdma_cmd), + GFP_KERNEL); + if (beep_dbdma_cmd_space == NULL) { + printk(KERN_ERR "dmasound_pmac: no beep dbdma cmd space\n") ; + return -ENOMEM; + } + beep_dbdma_cmd = (volatile struct dbdma_cmd *) + DBDMA_ALIGN(beep_dbdma_cmd_space); + beep_buf = (short *) kmalloc(BEEP_BUFLEN * 4, GFP_KERNEL); + if (beep_buf == NULL) { + printk(KERN_ERR "dmasound_pmac: no memory for beep buffer\n"); + kfree(beep_dbdma_cmd_space); + return -ENOMEM; + } + /* OK, we should be safe to claim the mksound vector now */ + orig_mksound = kd_mksound; + kd_mksound = awacs_mksound; - /* Initialize beep stuff */ - beep_dbdma_cmd = awacs_tx_cmds + (write_sq.numBufs + 1); - orig_mksound = kd_mksound; - kd_mksound = awacs_mksound; - beep_buf = (short *) kmalloc(BEEP_BUFLEN * 4, GFP_KERNEL); - if (beep_buf == NULL) - printk(KERN_WARNING "dmasound: no memory for " - "beep buffer\n"); #ifdef CONFIG_PMAC_PBOOK - pmu_register_sleep_notifier(&awacs_sleep_notifier); + pmu_register_sleep_notifier(&awacs_sleep_notifier); #endif /* CONFIG_PMAC_PBOOK */ - /* Powerbooks have odd ways of enabling inputs such as - an expansion-bay CD or sound from an internal modem - or a PC-card modem. */ - if (machine_is_compatible("AAPL,3400/2400") - || machine_is_compatible("AAPL,3500")) { - is_pbook_3400 = 1; - /* - * Enable CD and PC-card sound inputs. - * This is done by reading from address - * f301a000, + 0x10 to enable the expansion-bay - * CD sound input, + 0x80 to enable the PC-card - * sound input. The 0x100 enables the SCSI bus - * terminator power. - */ - latch_base = (unsigned char *) ioremap - (0xf301a000, 0x1000); - in_8(latch_base + 0x190); - } else if (machine_is_compatible("PowerBook1,1") - || machine_is_compatible("AAPL,PowerBook1998")) { - struct device_node* mio; - macio_base = 0; - is_pbook_G3 = 1; - for (mio = np->parent; mio; mio = mio->parent) { - if (strcmp(mio->name, "mac-io") == 0 - && mio->n_addrs > 0) { - macio_base = (unsigned char *) ioremap - (mio->addrs[0].address, 0x40); - break; - } + /* Powerbooks have odd ways of enabling inputs such as + an expansion-bay CD or sound from an internal modem + or a PC-card modem. */ + if (machine_is_compatible("AAPL,3400/2400") + || machine_is_compatible("AAPL,3500")) { + is_pbook_3400 = 1; + /* + * Enable CD and PC-card sound inputs. + * This is done by reading from address + * f301a000, + 0x10 to enable the expansion-bay + * CD sound input, + 0x80 to enable the PC-card + * sound input. The 0x100 enables the SCSI bus + * terminator power. + */ + latch_base = (unsigned char *) ioremap (0xf301a000, 0x1000); + in_8(latch_base + 0x190); + + } else if (machine_is_compatible("PowerBook1,1") + || machine_is_compatible("AAPL,PowerBook1998")) { + struct device_node* mio; + macio_base = 0; + is_pbook_G3 = 1; + for (mio = np->parent; mio; mio = mio->parent) { + if (strcmp(mio->name, "mac-io") == 0 + && mio->n_addrs > 0) { + macio_base = (unsigned char *) ioremap + (mio->addrs[0].address, 0x40); + break; } - /* - * Enable CD sound input. - * The relevant bits for writing to this byte are 0x8f. - * I haven't found out what the 0x80 bit does. - * For the 0xf bits, writing 3 or 7 enables the CD - * input, any other value disables it. Values - * 1, 3, 5, 7 enable the microphone. Values 0, 2, - * 4, 6, 8 - f enable the input from the modem. - */ - if (macio_base) - out_8(macio_base + 0x37, 3); - } - sprintf(awacs_name, "PowerMac (AWACS rev %d) ", - awacs_revision); - return dmasound_init(); + } + /* + * Enable CD sound input. + * The relevant bits for writing to this byte are 0x8f. + * I haven't found out what the 0x80 bit does. + * For the 0xf bits, writing 3 or 7 enables the CD + * input, any other value disables it. Values + * 1, 3, 5, 7 enable the microphone. Values 0, 2, + * 4, 6, 8 - f enable the input from the modem. + * -- paulus. + */ + if (macio_base) + out_8(macio_base + 0x37, 3); } - return -ENODEV; + sprintf(awacs_name, "PowerMac (AWACS rev %d) ", awacs_revision); + return dmasound_init(); } static void __exit dmasound_awacs_cleanup(void) diff -Nru a/drivers/sound/dmasound/dmasound_core.c b/drivers/sound/dmasound/dmasound_core.c --- a/drivers/sound/dmasound/dmasound_core.c Wed May 16 06:00:25 2001 +++ b/drivers/sound/dmasound/dmasound_core.c Wed May 16 06:00:25 2001 @@ -103,6 +103,13 @@ * 2000/3/25 Geert Uytterhoeven: * - Integration of dmasound_q40 * - Small clean ups + * + * 2001/01/26 [rev 1.0] Iain Sandoe + * - make /dev/sndstat show revision & edition information. + * - since dmasound.mach.sq_setup() can fail on pmac its type + * has been changed to int and the returns are checked. + * [1.1] - stop missing translations from being called. + * */ @@ -117,7 +124,6 @@ #include "dmasound.h" - /* * Declarations */ @@ -480,7 +486,12 @@ default: return 0; } - return ct_func(userPtr, userCount, frame, frameUsed, frameLeft); + /* if the user has requested a non-existent translation don't try + to call it but just return 0 bytes moved + */ + if (ct_func) + return ct_func(userPtr, userCount, frame, frameUsed, frameLeft); + return 0; } @@ -606,10 +617,10 @@ } } -static void sq_setup(struct sound_queue *sq, int max_count, int max_active, - int block_size) +static int sq_setup(struct sound_queue *sq, int max_count, int max_active, + int block_size) { - void (*setup_func)(void); + int (*setup_func)(void); sq->max_count = max_count; sq->max_active = max_active; @@ -627,7 +638,8 @@ setup_func = dmasound.mach.read_sq_setup; } if (setup_func) - setup_func(); + return setup_func(); + return 0; } static inline void sq_play(void) @@ -817,7 +829,8 @@ return rc; } - sq_setup(sq, numbufs, numbufs, bufsize); + if ((rc = sq_setup(sq, numbufs, numbufs, bufsize))) + return rc; sq->open_mode = file->f_mode; } return rc; @@ -936,7 +949,7 @@ static int sq_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long arg) { - int val; + int val, result; u_long fmt; int data; int size, nbufs; @@ -1013,7 +1026,9 @@ size = write_sq.bufSize; } else size = write_sq.bufSize; - sq_setup(&write_sq, write_sq.numBufs, nbufs, size); + result = sq_setup(&write_sq, write_sq.numBufs, nbufs, size); + if (result) + return result; return IOCTL_OUT(arg,write_sq.bufSize | write_sq.numBufs << 16); case SNDCTL_DSP_GETOSPACE: info.fragments = write_sq.max_active - write_sq.count; @@ -1081,9 +1096,11 @@ * /dev/sndstat */ +#define STAT_BUFF_LEN 512 + static struct { int busy; - char buf[512]; /* state.buf should not overflow! */ + char buf[STAT_BUFF_LEN]; /* state.buf should not overflow! */ int len, ptr; } state; @@ -1099,7 +1116,13 @@ state.ptr = 0; state.busy = 1; - len += sprintf(buffer+len, "%sDMA sound driver:\n", dmasound.mach.name); + len += sprintf(buffer+len, "%sDMA sound driver rev %03d :\n", + dmasound.mach.name, (DMASOUND_CORE_REVISION<<4) + + ((dmasound.mach.version>>8) & 0x0f)); + len += sprintf(buffer+len, + "Core driver edition %02d.%02d : %s driver edition %02d.%02d\n", + DMASOUND_CORE_REVISION, DMASOUND_CORE_EDITION, dmasound.mach.name2, + (dmasound.mach.version >> 8), (dmasound.mach.version & 0xff)) ; len += sprintf(buffer+len, "\tsound.format = 0x%x", dmasound.soft.format); @@ -1145,6 +1168,9 @@ write_sq.count, write_sq.rear_size); len += sprintf(buffer+len, "\tsq.active = %d sq.syncing = %d\n", write_sq.active, write_sq.syncing); + if (len >= STAT_BUFF_LEN) + printk(KERN_ERR "dmasound_core: stat buffer overflowed!\n") +; state.len = len; return 0; } @@ -1237,6 +1263,7 @@ if (irq_installed) { sound_silence(); dmasound.mach.irqcleanup(); + irq_installed = 0; } write_sq_release_buffers(); diff -Nru a/drivers/sound/ymfpci.c b/drivers/sound/ymfpci.c --- a/drivers/sound/ymfpci.c Wed May 16 06:00:23 2001 +++ b/drivers/sound/ymfpci.c Wed May 16 06:00:23 2001 @@ -989,11 +989,6 @@ status = ymfpci_readl(codec, YDSXGR_STATUS); if (status & 0x80000000) { - spin_lock(&codec->reg_lock); - ymfpci_writel(codec, YDSXGR_STATUS, 0x80000000); - mode = ymfpci_readl(codec, YDSXGR_MODE) | 2; - ymfpci_writel(codec, YDSXGR_MODE, mode); - spin_unlock(&codec->reg_lock); codec->active_bank = ymfpci_readl(codec, YDSXGR_CTRLSELECT) & 1; spin_lock(&codec->voice_lock); for (nvoice = 0; nvoice < 64; nvoice++) { @@ -1007,6 +1002,11 @@ ymf_cap_interrupt(codec, cap); } spin_unlock(&codec->voice_lock); + spin_lock(&codec->reg_lock); + ymfpci_writel(codec, YDSXGR_STATUS, 0x80000000); + mode = ymfpci_readl(codec, YDSXGR_MODE) | 2; + ymfpci_writel(codec, YDSXGR_MODE, mode); + spin_unlock(&codec->reg_lock); } status = ymfpci_readl(codec, YDSXGR_INTFLAG); @@ -2106,6 +2106,8 @@ pci_write_config_byte(pci, PCIR_DSXGCTRL, cmd | 0x03); pci_write_config_byte(pci, PCIR_DSXGCTRL, cmd & 0xfc); } + pci_write_config_word(pci, PCIR_DSXPWRCTRL1, 0); + pci_write_config_word(pci, PCIR_DSXPWRCTRL2, 0); } static void ymfpci_enable_dsp(ymfpci_t *codec) diff -Nru a/drivers/video/aty128.h b/drivers/video/aty128.h --- a/drivers/video/aty128.h Wed May 16 06:00:18 2001 +++ b/drivers/video/aty128.h Wed May 16 06:00:18 2001 @@ -267,7 +267,6 @@ #define DAC_MASK 0xFF000000 #define DAC_BLANKING 0x00000004 #define DAC_RANGE_CNTL 0x00000003 -#define DAC_RANGE_CNTL 0x00000003 #define DAC_PALETTE_ACCESS_CNTL 0x00000020 #define DAC_PDWN 0x00008000 diff -Nru a/drivers/video/aty128fb.c b/drivers/video/aty128fb.c --- a/drivers/video/aty128fb.c Wed May 16 06:00:21 2001 +++ b/drivers/video/aty128fb.c Wed May 16 06:00:21 2001 @@ -67,6 +67,9 @@ #ifdef CONFIG_FB_COMPAT_XPMAC #include #endif +#ifdef CONFIG_BOOTX_TEXT +#include +#endif /* CONFIG_BOOTX_TEXT */ #include