summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CREDITS22
-rw-r--r--Documentation/00-INDEX2
-rw-r--r--Documentation/Changes42
-rw-r--r--Documentation/Configure.help82
-rw-r--r--Documentation/devices.tex58
-rw-r--r--Documentation/devices.txt37
-rw-r--r--Documentation/digiepca.txt96
-rw-r--r--Documentation/ioctl-number.txt10
-rw-r--r--Documentation/locks.txt70
-rw-r--r--Documentation/m68k/00-INDEX9
-rw-r--r--Documentation/m68k/amiboot.txt (renamed from Documentation/m68k/amiboot.README)75
-rw-r--r--Documentation/m68k/framebuffer.txt370
-rw-r--r--Documentation/m68k/kernel-options.txt12
-rw-r--r--Documentation/networking/net-modules.txt21
-rw-r--r--Documentation/serial-console.txt2
-rw-r--r--Documentation/svga.txt142
-rw-r--r--MAINTAINERS18
-rw-r--r--Makefile12
-rw-r--r--arch/alpha/defconfig32
-rw-r--r--arch/alpha/kernel/entry.S31
-rw-r--r--arch/alpha/kernel/head.S24
-rw-r--r--arch/alpha/kernel/process.c20
-rw-r--r--arch/alpha/kernel/ptrace.c35
-rw-r--r--arch/alpha/kernel/setup.c2
-rw-r--r--arch/alpha/mm/fault.c2
-rw-r--r--arch/alpha/mm/init.c3
-rw-r--r--arch/alpha/vmlinux.lds6
-rw-r--r--arch/i386/Makefile4
-rw-r--r--arch/i386/boot/video.S13
-rw-r--r--arch/i386/defconfig1
-rw-r--r--arch/i386/kernel/Makefile2
-rw-r--r--arch/i386/kernel/bios32.c72
-rw-r--r--arch/i386/kernel/entry.S81
-rw-r--r--arch/i386/kernel/head.S136
-rw-r--r--arch/i386/kernel/i386_ksyms.c10
-rw-r--r--arch/i386/kernel/init_task.c22
-rw-r--r--arch/i386/kernel/irq.c271
-rw-r--r--arch/i386/kernel/irq.h187
-rw-r--r--arch/i386/kernel/process.c26
-rw-r--r--arch/i386/kernel/ptrace.c28
-rw-r--r--arch/i386/kernel/setup.c14
-rw-r--r--arch/i386/kernel/signal.c10
-rw-r--r--arch/i386/kernel/smp.c773
-rw-r--r--arch/i386/kernel/time.c7
-rw-r--r--arch/i386/kernel/trampoline.S43
-rw-r--r--arch/i386/kernel/traps.c77
-rw-r--r--arch/i386/kernel/vm86.c20
-rw-r--r--arch/i386/lib/locks.S5
-rw-r--r--arch/i386/lib/semaphore.S8
-rw-r--r--arch/i386/mm/fault.c15
-rw-r--r--arch/i386/mm/init.c23
-rw-r--r--arch/i386/vmlinux.lds1
-rw-r--r--arch/m68k/Makefile14
-rw-r--r--arch/m68k/amiga/amifb.c6
-rw-r--r--arch/m68k/amiga/amiints.c3
-rw-r--r--arch/m68k/amiga/amikeyb.c3
-rw-r--r--arch/m68k/amiga/amisound.c5
-rw-r--r--arch/m68k/amiga/chipram.c10
-rw-r--r--arch/m68k/amiga/cia.c3
-rw-r--r--arch/m68k/amiga/config.c9
-rw-r--r--arch/m68k/amiga/cyberfb.c7
-rw-r--r--arch/m68k/amiga/retz3fb.c1754
-rw-r--r--arch/m68k/amiga/retz3fb.h286
-rw-r--r--arch/m68k/amiga/zorro.c10
-rw-r--r--arch/m68k/atari/atafb.c5
-rw-r--r--arch/m68k/atari/ataints.c21
-rw-r--r--arch/m68k/atari/atakeyb.c3
-rw-r--r--arch/m68k/atari/config.c21
-rw-r--r--arch/m68k/atari/joystick.c3
-rw-r--r--arch/m68k/atari/stdma.c4
-rw-r--r--arch/m68k/atari/stram.c3
-rw-r--r--arch/m68k/boot/amiga/linuxboot.c17
-rw-r--r--arch/m68k/boot/amiga/linuxboot.h2
-rw-r--r--arch/m68k/fpsp040/skeleton.S26
-rw-r--r--arch/m68k/ifpsp060/iskeleton.S15
-rw-r--r--arch/m68k/kernel/entry.S109
-rw-r--r--arch/m68k/kernel/head.S14
-rw-r--r--arch/m68k/kernel/ints.c3
-rw-r--r--arch/m68k/kernel/m68k_ksyms.c4
-rw-r--r--arch/m68k/kernel/process.c39
-rw-r--r--arch/m68k/kernel/ptrace.c30
-rw-r--r--arch/m68k/kernel/setup.c29
-rw-r--r--arch/m68k/kernel/signal.c6
-rw-r--r--arch/m68k/kernel/sys_m68k.c5
-rw-r--r--arch/m68k/kernel/time.c21
-rw-r--r--arch/m68k/kernel/traps.c10
-rw-r--r--arch/m68k/lib/semaphore.S7
-rw-r--r--arch/m68k/mm/fault.c16
-rw-r--r--arch/m68k/mm/init.c42
-rw-r--r--arch/m68k/mm/memory.c8
-rw-r--r--arch/m68k/vmlinux.lds60
-rw-r--r--arch/mips/Makefile4
-rw-r--r--arch/mips/boot/Makefile6
-rw-r--r--arch/mips/boot/mkboot.c8
-rw-r--r--arch/mips/config.in32
-rw-r--r--arch/mips/defconfig1
-rw-r--r--arch/mips/deskstation/io.c68
-rw-r--r--arch/mips/deskstation/setup.c14
-rw-r--r--arch/mips/jazz/.cvsignore1
-rw-r--r--arch/mips/jazz/io.c136
-rw-r--r--arch/mips/jazz/setup.c11
-rw-r--r--arch/mips/kernel/Makefile2
-rw-r--r--arch/mips/kernel/entry.S5
-rw-r--r--arch/mips/kernel/head.S42
-rw-r--r--arch/mips/kernel/init_task.c22
-rw-r--r--arch/mips/kernel/irix5sys.h2
-rw-r--r--arch/mips/kernel/irixelf.c48
-rw-r--r--arch/mips/kernel/irixioctl.c2
-rw-r--r--arch/mips/kernel/irixsig.c50
-rw-r--r--arch/mips/kernel/irq.c8
-rw-r--r--arch/mips/kernel/pci.c7
-rw-r--r--arch/mips/kernel/process.c11
-rw-r--r--arch/mips/kernel/ptrace.c28
-rw-r--r--arch/mips/kernel/r2300_switch.S5
-rw-r--r--arch/mips/kernel/r4k_misc.S4
-rw-r--r--arch/mips/kernel/r4k_switch.S7
-rw-r--r--arch/mips/kernel/setup.c9
-rw-r--r--arch/mips/kernel/signal.c11
-rw-r--r--arch/mips/kernel/syscalls.h1
-rw-r--r--arch/mips/kernel/sysirix.c223
-rw-r--r--arch/mips/kernel/time.c3
-rw-r--r--arch/mips/kernel/traps.c9
-rw-r--r--arch/mips/mips/Makefile39
-rwxr-xr-xarch/mips/mips/mkprom25
-rw-r--r--arch/mips/mm/Makefile2
-rw-r--r--arch/mips/mm/fault.c2
-rw-r--r--arch/mips/mm/r4xx0.c40
-rw-r--r--arch/mips/mm/stack.c27
-rw-r--r--arch/mips/sgi/kernel/indy_int.c15
-rw-r--r--arch/mips/sgi/kernel/setup.c1
-rw-r--r--arch/mips/sgi/prom/misc.c14
-rw-r--r--arch/mips/sni/.cvsignore1
-rw-r--r--arch/mips/sni/Makefile2
-rw-r--r--arch/mips/sni/int-handler.S23
-rw-r--r--arch/mips/sni/io.c172
-rw-r--r--arch/mips/sni/pci.c23
-rw-r--r--arch/mips/sni/setup.c25
-rw-r--r--arch/mips/tools/.cvsignore1
-rw-r--r--arch/mips/tools/offset.c3
-rw-r--r--arch/mips/tools/offset.h89
-rw-r--r--arch/ppc/kernel/misc.S3
-rw-r--r--arch/ppc/kernel/process.c18
-rw-r--r--arch/ppc/kernel/ptrace.c14
-rw-r--r--arch/ppc/mm/init.c109
-rw-r--r--arch/sparc/Makefile4
-rw-r--r--arch/sparc/ap1000/bnet.c14
-rw-r--r--arch/sparc/ap1000/hw.c29
-rw-r--r--arch/sparc/ap1000/mpp.c1
-rw-r--r--arch/sparc/kernel/Makefile4
-rw-r--r--arch/sparc/kernel/etrap.S14
-rw-r--r--arch/sparc/kernel/head.S15
-rw-r--r--arch/sparc/kernel/init_task.c18
-rw-r--r--arch/sparc/kernel/irq.c180
-rw-r--r--arch/sparc/kernel/process.c46
-rw-r--r--arch/sparc/kernel/ptrace.c28
-rw-r--r--arch/sparc/kernel/setup.c5
-rw-r--r--arch/sparc/kernel/signal.c4
-rw-r--r--arch/sparc/kernel/smp.c234
-rw-r--r--arch/sparc/kernel/sparc_ksyms.c37
-rw-r--r--arch/sparc/kernel/sys_sunos.c46
-rw-r--r--arch/sparc/kernel/systbls.S29
-rw-r--r--arch/sparc/kernel/tadpole.c2
-rw-r--r--arch/sparc/kernel/trampoline.S34
-rw-r--r--arch/sparc/kernel/wof.S15
-rw-r--r--arch/sparc/kernel/wuf.S16
-rw-r--r--arch/sparc/lib/Makefile6
-rw-r--r--arch/sparc/lib/blockops.S33
-rw-r--r--arch/sparc/lib/debuglocks.c463
-rw-r--r--arch/sparc/lib/irqlock.S2
-rw-r--r--arch/sparc/mm/Makefile22
-rw-r--r--arch/sparc/mm/asyncd.c7
-rw-r--r--arch/sparc/mm/fault.c6
-rw-r--r--arch/sparc/mm/hypersparc.S74
-rw-r--r--arch/sparc/mm/srmmu.c284
-rw-r--r--arch/sparc/mm/sun4c.c120
-rw-r--r--arch/sparc/mm/tsunami.S90
-rw-r--r--arch/sparc/mm/viking.S85
-rw-r--r--arch/sparc/prom/console.c18
-rw-r--r--arch/sparc/prom/devmap.c9
-rw-r--r--arch/sparc/prom/devops.c13
-rw-r--r--arch/sparc/prom/misc.c13
-rw-r--r--arch/sparc/prom/mp.c13
-rw-r--r--arch/sparc/prom/segment.c7
-rw-r--r--arch/sparc/prom/tree.c6
-rw-r--r--arch/sparc64/Makefile4
-rw-r--r--arch/sparc64/defconfig9
-rw-r--r--arch/sparc64/kernel/Makefile13
-rw-r--r--arch/sparc64/kernel/binfmt_elf32.c34
-rw-r--r--arch/sparc64/kernel/dtlb_prot.S28
-rw-r--r--arch/sparc64/kernel/entry.S124
-rw-r--r--arch/sparc64/kernel/etrap.S109
-rw-r--r--arch/sparc64/kernel/hack.S16
-rw-r--r--arch/sparc64/kernel/head.S31
-rw-r--r--arch/sparc64/kernel/init_task.c18
-rw-r--r--arch/sparc64/kernel/process.c81
-rw-r--r--arch/sparc64/kernel/rtrap.S15
-rw-r--r--arch/sparc64/kernel/setup.c4
-rw-r--r--arch/sparc64/kernel/signal.c438
-rw-r--r--arch/sparc64/kernel/signal32.c19
-rw-r--r--arch/sparc64/kernel/sparcelf32.c1281
-rw-r--r--arch/sparc64/kernel/sys_sparc32.c334
-rw-r--r--arch/sparc64/kernel/traps.c35
-rw-r--r--arch/sparc64/kernel/ttable.S28
-rw-r--r--arch/sparc64/kernel/winfixup.S101
-rw-r--r--arch/sparc64/lib/blockops.S66
-rw-r--r--arch/sparc64/lib/checksum.S25
-rw-r--r--arch/sparc64/lib/copy_from_user.S15
-rw-r--r--arch/sparc64/lib/copy_to_user.S15
-rw-r--r--arch/sparc64/lib/strlen_user.S12
-rw-r--r--arch/sparc64/lib/strncpy_from_user.S4
-rw-r--r--arch/sparc64/mm/asyncd.c7
-rw-r--r--arch/sparc64/mm/fault.c23
-rw-r--r--arch/sparc64/mm/init.c44
-rw-r--r--drivers/block/Makefile16
-rw-r--r--drivers/block/amiflop.c5
-rw-r--r--drivers/block/ataflop.c11
-rw-r--r--drivers/block/ez.c19
-rw-r--r--drivers/block/floppy.c17
-rw-r--r--drivers/block/genhd.c40
-rw-r--r--drivers/block/hd.c5
-rw-r--r--drivers/block/ide-disk.c2
-rw-r--r--drivers/block/ide-floppy.c6
-rw-r--r--drivers/block/ide-probe.c2
-rw-r--r--drivers/block/ide-tape.c10
-rw-r--r--drivers/block/ide.c19
-rw-r--r--drivers/block/linear.c3
-rw-r--r--drivers/block/loop.c5
-rw-r--r--drivers/block/md.c3
-rw-r--r--drivers/block/ps2esdi.c12
-rw-r--r--drivers/block/rd.c32
-rw-r--r--drivers/block/xd.c31
-rw-r--r--drivers/block/z2ram.c5
-rw-r--r--drivers/cdrom/aztcd.c5
-rw-r--r--drivers/cdrom/bpcd.c21
-rw-r--r--drivers/cdrom/cdi.c5
-rw-r--r--drivers/cdrom/cdu31a.c17
-rw-r--r--drivers/cdrom/cm206.c11
-rw-r--r--drivers/cdrom/gscd.c11
-rw-r--r--drivers/cdrom/isp16.c25
-rw-r--r--drivers/cdrom/mcd.c5
-rw-r--r--drivers/cdrom/mcdx.c9
-rw-r--r--drivers/cdrom/optcd.c7
-rw-r--r--drivers/cdrom/sbpcd.c20
-rw-r--r--drivers/cdrom/sjcd.c5
-rw-r--r--drivers/cdrom/sonycd535.c9
-rw-r--r--drivers/char/Config.in5
-rw-r--r--drivers/char/Makefile13
-rw-r--r--drivers/char/README.epca506
-rw-r--r--drivers/char/busmouse.c2
-rw-r--r--drivers/char/console.c3
-rw-r--r--drivers/char/consolemap.c5
-rw-r--r--drivers/char/cyclades.c5029
-rw-r--r--drivers/char/dsp56k.c578
-rw-r--r--drivers/char/epca.c4313
-rw-r--r--drivers/char/esp.c2
-rw-r--r--drivers/char/fbmem.c5
-rw-r--r--drivers/char/ftape/kernel-interface.c3
-rw-r--r--drivers/char/istallion.c2
-rw-r--r--drivers/char/keyb_m68k.c876
-rw-r--r--drivers/char/keyboard.c397
-rw-r--r--drivers/char/lp.c2
-rw-r--r--drivers/char/lp_intern.c20
-rw-r--r--drivers/char/lp_m68k.c5
-rw-r--r--drivers/char/mem.c83
-rw-r--r--drivers/char/misc.c4
-rw-r--r--drivers/char/msbusmouse.c2
-rw-r--r--drivers/char/n_tty.c10
-rw-r--r--drivers/char/pc_keyb.c647
-rw-r--r--drivers/char/pcxx.c4
-rw-r--r--drivers/char/random.c102
-rw-r--r--drivers/char/riscom8.c4
-rw-r--r--drivers/char/serial.c2
-rw-r--r--drivers/char/tga.c37
-rw-r--r--drivers/char/tpqic02.c6
-rw-r--r--drivers/char/tty_io.c97
-rw-r--r--drivers/char/vga.c9
-rw-r--r--drivers/char/vt.c2
-rw-r--r--drivers/char/wdt.c2
-rw-r--r--drivers/isdn/Config.in1
-rw-r--r--drivers/isdn/Makefile12
-rw-r--r--drivers/isdn/hisax/.cvsignore1
-rw-r--r--drivers/isdn/hisax/isdnl1.c10
-rw-r--r--drivers/isdn/isdn_net.c2
-rw-r--r--drivers/isdn/sc/Makefile2
-rw-r--r--drivers/isdn/teles/Makefile17
-rw-r--r--drivers/isdn/teles/buffers.c329
-rw-r--r--drivers/isdn/teles/callc.c1453
-rw-r--r--drivers/isdn/teles/card.c1900
-rw-r--r--drivers/isdn/teles/config.c48
-rw-r--r--drivers/isdn/teles/fsm.c156
-rw-r--r--drivers/isdn/teles/isdnl2.c1320
-rw-r--r--drivers/isdn/teles/isdnl3.c673
-rw-r--r--drivers/isdn/teles/l3_1TR6.c538
-rw-r--r--drivers/isdn/teles/l3_1TR6.h160
-rw-r--r--drivers/isdn/teles/llglue.c151
-rw-r--r--drivers/isdn/teles/mod.c160
-rw-r--r--drivers/isdn/teles/proto.h18
-rw-r--r--drivers/isdn/teles/q931.c1155
-rw-r--r--drivers/isdn/teles/tei.c248
-rw-r--r--drivers/isdn/teles/teles.h486
-rw-r--r--drivers/net/3c501.c2
-rw-r--r--drivers/net/3c505.c12
-rw-r--r--drivers/net/3c507.c2
-rw-r--r--drivers/net/3c509.c2
-rw-r--r--drivers/net/3c523.c2
-rw-r--r--drivers/net/3c59x.c2
-rw-r--r--drivers/net/a2065.c2
-rw-r--r--drivers/net/apricot.c2
-rw-r--r--drivers/net/arcnet.c2
-rw-r--r--drivers/net/ariadne.c4
-rw-r--r--drivers/net/at1700.c2
-rw-r--r--drivers/net/atarilance.c4
-rw-r--r--drivers/net/atp.c2
-rw-r--r--drivers/net/cs89x0.c2
-rw-r--r--drivers/net/de4x5.c445
-rw-r--r--drivers/net/de4x5.h160
-rw-r--r--drivers/net/defxx.c86
-rw-r--r--drivers/net/depca.c2
-rw-r--r--drivers/net/dlci.c2
-rw-r--r--drivers/net/dummy.c2
-rw-r--r--drivers/net/eepro.c2
-rw-r--r--drivers/net/eepro100.c2
-rw-r--r--drivers/net/eexpress.c11
-rw-r--r--drivers/net/eth16i.c2
-rw-r--r--drivers/net/ewrk3.c10
-rw-r--r--drivers/net/fmv18x.c2
-rw-r--r--drivers/net/hdlcdrv.c4
-rw-r--r--drivers/net/hp100.c2913
-rw-r--r--drivers/net/hp100.h494
-rw-r--r--drivers/net/ibmtr.c41
-rw-r--r--drivers/net/lance.c4
-rw-r--r--drivers/net/ltpc.c2
-rw-r--r--drivers/net/mkiss.c16
-rw-r--r--drivers/net/myri_sbus.c2
-rw-r--r--drivers/net/ni52.c4
-rw-r--r--drivers/net/ni65.c6
-rw-r--r--drivers/net/pcnet32.c4
-rw-r--r--drivers/net/plip.c2
-rw-r--r--drivers/net/ppp.c10
-rw-r--r--drivers/net/sdla.c2
-rw-r--r--drivers/net/sdla_fr.c8
-rw-r--r--drivers/net/sdla_ppp.c8
-rw-r--r--drivers/net/sdla_x25.c8
-rw-r--r--drivers/net/sdlamain.c6
-rw-r--r--drivers/net/seeq8005.c2
-rw-r--r--drivers/net/sgiseeq.c2
-rw-r--r--drivers/net/sk_g16.c9
-rw-r--r--drivers/net/skeleton.c11
-rw-r--r--drivers/net/slip.c18
-rw-r--r--drivers/net/smc9194.c2
-rw-r--r--drivers/net/sonic.c12
-rw-r--r--drivers/net/soundmodem/sm.c8
-rw-r--r--drivers/net/strip.c4
-rw-r--r--drivers/net/sunhme.c6
-rw-r--r--drivers/net/sunlance.c10
-rw-r--r--drivers/net/sunqe.c4
-rw-r--r--drivers/net/tulip.c2
-rw-r--r--drivers/net/wavelan.c18
-rw-r--r--drivers/net/wavelan.p.h1
-rw-r--r--drivers/net/x25_asy.c14
-rw-r--r--drivers/net/znet.c2
-rw-r--r--drivers/pci/pci.c16
-rw-r--r--drivers/pnp/.cvsignore1
-rw-r--r--drivers/sbus/audio/amd7930.c1
-rw-r--r--drivers/sbus/audio/cs4231.c1
-rw-r--r--drivers/sbus/char/creator.c49
-rw-r--r--drivers/sbus/char/suncons.c6
-rw-r--r--drivers/sbus/char/sunkbd.c2
-rw-r--r--drivers/sbus/char/sunserial.c45
-rw-r--r--drivers/sbus/char/vfc.h12
-rw-r--r--drivers/sbus/char/vfc_dev.c111
-rw-r--r--drivers/sbus/char/vfc_i2c.c24
-rw-r--r--drivers/scsi/53c7,8xx.c71
-rw-r--r--drivers/scsi/53c7,8xx.h2
-rw-r--r--drivers/scsi/53c7xx.c6107
-rw-r--r--drivers/scsi/53c7xx.h1675
-rw-r--r--drivers/scsi/53c7xx.scr1591
-rw-r--r--drivers/scsi/ChangeLog.ncr53c8xx72
-rw-r--r--drivers/scsi/Config.in3
-rw-r--r--drivers/scsi/Makefile42
-rw-r--r--drivers/scsi/README.ncr53c8xx61
-rw-r--r--drivers/scsi/a2091.c17
-rw-r--r--drivers/scsi/a3000.c3
-rw-r--r--drivers/scsi/amiga7xx.c107
-rw-r--r--drivers/scsi/amiga7xx.h52
-rw-r--r--drivers/scsi/atari_NCR5380.c8
-rw-r--r--drivers/scsi/atari_scsi.c9
-rw-r--r--drivers/scsi/dc390.h147
-rw-r--r--drivers/scsi/eata.c94
-rw-r--r--drivers/scsi/eata.h2
-rw-r--r--drivers/scsi/gvp11.c3
-rw-r--r--drivers/scsi/hosts.c14
-rw-r--r--drivers/scsi/ide-scsi.c2
-rw-r--r--drivers/scsi/ncr53c8xx.c1916
-rw-r--r--drivers/scsi/ncr53c8xx.h382
-rw-r--r--drivers/scsi/qlogicpti.c67
-rw-r--r--drivers/scsi/scsi.h6
-rw-r--r--drivers/scsi/scsi_proc.c20
-rw-r--r--drivers/scsi/scsiiom.c1540
-rw-r--r--drivers/scsi/sd.c3
-rw-r--r--drivers/scsi/seagate.c30
-rw-r--r--drivers/scsi/seagate.h3
-rw-r--r--drivers/scsi/tmscsim.c1928
-rw-r--r--drivers/scsi/tmscsim.h680
-rw-r--r--drivers/scsi/u14-34f.c78
-rw-r--r--drivers/scsi/u14-34f.h2
-rw-r--r--drivers/scsi/wd33c93.c218
-rw-r--r--drivers/scsi/wd33c93.h6
-rw-r--r--drivers/sgi/char/sgicons.c9
-rw-r--r--drivers/sgi/char/sgiserial.c10
-rw-r--r--drivers/sound/Config.in284
-rw-r--r--drivers/sound/lowlevel/.cvsignore1
-rw-r--r--fs/affs/Changes95
-rw-r--r--fs/affs/amigaffs.c96
-rw-r--r--fs/affs/bitmap.c52
-rw-r--r--fs/affs/dir.c25
-rw-r--r--fs/affs/file.c99
-rw-r--r--fs/affs/inode.c201
-rw-r--r--fs/affs/namei.c37
-rw-r--r--fs/affs/symlink.c4
-rw-r--r--fs/autofs/.cvsignore1
-rw-r--r--fs/autofs/Makefile29
-rw-r--r--fs/autofs/autofs_i.h175
-rw-r--r--fs/autofs/dir.c2
-rw-r--r--fs/autofs/dirhash.c49
-rw-r--r--fs/autofs/init.c27
-rw-r--r--fs/autofs/inode.c11
-rw-r--r--fs/autofs/root.c106
-rw-r--r--fs/autofs/symlink.c2
-rw-r--r--fs/autofs/waitq.c18
-rw-r--r--fs/binfmt_elf.c104
-rw-r--r--fs/buffer.c28
-rw-r--r--fs/dcache.c15
-rw-r--r--fs/dquot.c3
-rw-r--r--fs/exec.c10
-rw-r--r--fs/ext2/balloc.c55
-rw-r--r--fs/ext2/inode.c77
-rw-r--r--fs/ext2/ioctl.c8
-rw-r--r--fs/ext2/namei.c2
-rw-r--r--fs/ext2/super.c3
-rw-r--r--fs/fcntl.c6
-rw-r--r--fs/file_table.c179
-rw-r--r--fs/inode.c12
-rw-r--r--fs/isofs/dir.c5
-rw-r--r--fs/isofs/inode.c8
-rw-r--r--fs/isofs/namei.c26
-rw-r--r--fs/isofs/rock.c43
-rw-r--r--fs/lockd/.cvsignore1
-rw-r--r--fs/lockd/svcsubs.c8
-rw-r--r--fs/locks.c108
-rw-r--r--fs/msdos/msdosfs_syms.c2
-rw-r--r--fs/namei.c22
-rw-r--r--fs/ncpfs/inode.c5
-rw-r--r--fs/nfs/nfsroot.c25
-rw-r--r--fs/nfs/write.c8
-rw-r--r--fs/nfsd/.cvsignore1
-rw-r--r--fs/nfsd/vfs.c4
-rw-r--r--fs/open.c2
-rw-r--r--fs/pipe.c11
-rw-r--r--fs/proc/array.c87
-rw-r--r--fs/proc/base.c13
-rw-r--r--fs/proc/fd.c30
-rw-r--r--fs/proc/inode.c21
-rw-r--r--fs/proc/link.c9
-rw-r--r--fs/proc/mem.c18
-rw-r--r--fs/proc/root.c54
-rw-r--r--fs/romfs/.cvsignore1
-rw-r--r--fs/smbfs/inode.c5
-rw-r--r--fs/super.c11
-rw-r--r--fs/umsdos/namei.c3
-rw-r--r--fs/vfat/namei.c2
-rw-r--r--include/asm-alpha/atomic.h16
-rw-r--r--include/asm-alpha/bitops.h85
-rw-r--r--include/asm-alpha/current.h6
-rw-r--r--include/asm-alpha/io.h2
-rw-r--r--include/asm-alpha/keyboard.h200
-rw-r--r--include/asm-alpha/processor.h14
-rw-r--r--include/asm-alpha/semaphore.h4
-rw-r--r--include/asm-alpha/softirq.h4
-rw-r--r--include/asm-alpha/spinlock.h27
-rw-r--r--include/asm-alpha/system.h106
-rw-r--r--include/asm-i386/bitops.h38
-rw-r--r--include/asm-i386/current.h16
-rw-r--r--include/asm-i386/delay.h17
-rw-r--r--include/asm-i386/hardirq.h1
-rw-r--r--include/asm-i386/keyboard.h40
-rw-r--r--include/asm-i386/processor.h22
-rw-r--r--include/asm-i386/semaphore.h46
-rw-r--r--include/asm-i386/smp.h8
-rw-r--r--include/asm-i386/smp_lock.h17
-rw-r--r--include/asm-i386/spinlock.h66
-rw-r--r--include/asm-i386/system.h4
-rw-r--r--include/asm-m68k/atomic.h2
-rw-r--r--include/asm-m68k/bitops.h24
-rw-r--r--include/asm-m68k/current.h8
-rw-r--r--include/asm-m68k/dsp56k.h35
-rw-r--r--include/asm-m68k/elf.h2
-rw-r--r--include/asm-m68k/fpu.h20
-rw-r--r--include/asm-m68k/hardirq.h17
-rw-r--r--include/asm-m68k/init.h16
-rw-r--r--include/asm-m68k/keyboard.h38
-rw-r--r--include/asm-m68k/namei.h21
-rw-r--r--include/asm-m68k/pgtable.h4
-rw-r--r--include/asm-m68k/poll.h21
-rw-r--r--include/asm-m68k/processor.h14
-rw-r--r--include/asm-m68k/ptrace.h2
-rw-r--r--include/asm-m68k/semaphore.h72
-rw-r--r--include/asm-m68k/sigcontext.h4
-rw-r--r--include/asm-m68k/smp_lock.h14
-rw-r--r--include/asm-m68k/softirq.h63
-rw-r--r--include/asm-m68k/spinlock.h31
-rw-r--r--include/asm-m68k/system.h1
-rw-r--r--include/asm-m68k/unistd.h8
-rw-r--r--include/asm-mips/bitops.h155
-rw-r--r--include/asm-mips/bootinfo.h2
-rw-r--r--include/asm-mips/current.h33
-rw-r--r--include/asm-mips/delay.h12
-rw-r--r--include/asm-mips/io.h30
-rw-r--r--include/asm-mips/jazz.h2
-rw-r--r--include/asm-mips/keyboard.h198
-rw-r--r--include/asm-mips/mipsprom.h74
-rw-r--r--include/asm-mips/offset.h9
-rw-r--r--include/asm-mips/poll.h2
-rw-r--r--include/asm-mips/processor.h9
-rw-r--r--include/asm-mips/sgidefs.h24
-rw-r--r--include/asm-mips/sni.h5
-rw-r--r--include/asm-mips/spinlock.h2
-rw-r--r--include/asm-mips/system.h19
-rw-r--r--include/asm-ppc/keyboard.h49
-rw-r--r--include/asm-ppc/processor.h2
-rw-r--r--include/asm-sparc/asm_offsets.h186
-rw-r--r--include/asm-sparc/asmmacro.h14
-rw-r--r--include/asm-sparc/auxio.h47
-rw-r--r--include/asm-sparc/bitops.h27
-rw-r--r--include/asm-sparc/cache.h3
-rw-r--r--include/asm-sparc/current.h6
-rw-r--r--include/asm-sparc/hardirq.h2
-rw-r--r--include/asm-sparc/irq.h12
-rw-r--r--include/asm-sparc/linux_logo.h1045
-rw-r--r--include/asm-sparc/processor.h11
-rw-r--r--include/asm-sparc/semaphore.h26
-rw-r--r--include/asm-sparc/smp.h4
-rw-r--r--include/asm-sparc/spinlock.h106
-rw-r--r--include/asm-sparc/string.h6
-rw-r--r--include/asm-sparc/system.h71
-rw-r--r--include/asm-sparc/termbits.h8
-rw-r--r--include/asm-sparc/winmacro.h9
-rw-r--r--include/asm-sparc64/a.out.h4
-rw-r--r--include/asm-sparc64/asm_offsets.h188
-rw-r--r--include/asm-sparc64/bitops.h27
-rw-r--r--include/asm-sparc64/checksum.h12
-rw-r--r--include/asm-sparc64/current.h6
-rw-r--r--include/asm-sparc64/elf.h26
-rw-r--r--include/asm-sparc64/fs_mount.h44
-rw-r--r--include/asm-sparc64/head.h47
-rw-r--r--include/asm-sparc64/linux_logo.h1042
-rw-r--r--include/asm-sparc64/mmu_context.h12
-rw-r--r--include/asm-sparc64/pgtable.h109
-rw-r--r--include/asm-sparc64/processor.h24
-rw-r--r--include/asm-sparc64/spitfire.h10
-rw-r--r--include/asm-sparc64/string.h8
-rw-r--r--include/asm-sparc64/system.h40
-rw-r--r--include/asm-sparc64/termbits.h6
-rw-r--r--include/linux/affs_fs.h88
-rw-r--r--include/linux/affs_fs_i.h36
-rw-r--r--include/linux/affs_fs_sb.h10
-rw-r--r--include/linux/affs_hardblocks.h84
-rw-r--r--include/linux/amigaffs.h166
-rw-r--r--include/linux/auto_fs.h151
-rw-r--r--include/linux/console.h27
-rw-r--r--include/linux/cyclades.h374
-rw-r--r--include/linux/digi1.h100
-rw-r--r--include/linux/digiFep1.h136
-rw-r--r--include/linux/digiPCI.h42
-rw-r--r--include/linux/elf.h115
-rw-r--r--include/linux/epca.h170
-rw-r--r--include/linux/epcaconfig.h8
-rw-r--r--include/linux/ext2_fs.h23
-rw-r--r--include/linux/ext2_fs_sb.h3
-rw-r--r--include/linux/fb.h2
-rw-r--r--include/linux/file.h25
-rw-r--r--include/linux/fs.h57
-rw-r--r--include/linux/in6.h4
-rw-r--r--include/linux/inet.h4
-rw-r--r--include/linux/keyboard.h6
-rw-r--r--include/linux/locks.h2
-rw-r--r--include/linux/lp_m68k.h11
-rw-r--r--include/linux/major.h1
-rw-r--r--include/linux/malloc.h8
-rw-r--r--include/linux/mm.h60
-rw-r--r--include/linux/pci.h7
-rw-r--r--include/linux/proc_fs.h2
-rw-r--r--include/linux/sched.h160
-rw-r--r--include/linux/serial.h3
-rw-r--r--include/linux/skbuff.h8
-rw-r--r--include/linux/slab.h41
-rw-r--r--include/linux/smp.h1
-rw-r--r--include/linux/socket.h13
-rw-r--r--include/linux/sunrpc/clnt.h2
-rw-r--r--include/linux/sysctl.h10
-rw-r--r--include/linux/tqueue.h2
-rw-r--r--include/linux/tty.h7
-rw-r--r--include/linux/zorro.h642
-rw-r--r--include/net/ip.h30
-rw-r--r--include/net/sock.h1
-rw-r--r--include/net/tcp.h68
-rw-r--r--init/main.c83
-rw-r--r--ipc/msg.c3
-rw-r--r--ipc/sem.c3
-rw-r--r--ipc/shm.c48
-rw-r--r--ipc/util.c3
-rw-r--r--kernel/exit.c161
-rw-r--r--kernel/fork.c242
-rw-r--r--kernel/ksyms.c20
-rw-r--r--kernel/panic.c3
-rw-r--r--kernel/printk.c3
-rw-r--r--kernel/resource.c3
-rw-r--r--kernel/sched.c459
-rw-r--r--kernel/softirq.c11
-rw-r--r--kernel/sys.c135
-rw-r--r--kernel/sysctl.c3
-rw-r--r--mm/Makefile2
-rw-r--r--mm/filemap.c4
-rw-r--r--mm/kmalloc.c453
-rw-r--r--mm/memory.c81
-rw-r--r--mm/mmap.c690
-rw-r--r--mm/page_alloc.c33
-rw-r--r--mm/page_io.c8
-rw-r--r--mm/slab.c2338
-rw-r--r--mm/swap.c5
-rw-r--r--mm/swap_state.c5
-rw-r--r--mm/swapfile.c25
-rw-r--r--mm/vmscan.c76
-rw-r--r--net/.cvsignore8
-rw-r--r--net/802/llc_macinit.c3
-rw-r--r--net/802/p8022.c3
-rw-r--r--net/802/p8022tr.c3
-rw-r--r--net/802/psnap.c3
-rw-r--r--net/802/tr.c3
-rw-r--r--net/TUNABLE7
-rw-r--r--net/appletalk/aarp.c3
-rw-r--r--net/appletalk/ddp.c3
-rw-r--r--net/ax25/af_ax25.c3
-rw-r--r--net/core/dev.c5
-rw-r--r--net/core/firewall.c3
-rw-r--r--net/core/scm.c30
-rw-r--r--net/core/skbuff.c5
-rw-r--r--net/core/sock.c70
-rw-r--r--net/core/sysctl_net_core.c19
-rw-r--r--net/ethernet/eth.c9
-rw-r--r--net/ipv4/af_inet.c3
-rw-r--r--net/ipv4/arp.c5
-rw-r--r--net/ipv4/fib.c8
-rw-r--r--net/ipv4/icmp.c9
-rw-r--r--net/ipv4/ip_alias.c3
-rw-r--r--net/ipv4/ip_fragment.c451
-rw-r--r--net/ipv4/ip_fw.c3
-rw-r--r--net/ipv4/ip_masq.c3
-rw-r--r--net/ipv4/ip_masq_app.c3
-rw-r--r--net/ipv4/ip_masq_ftp.c3
-rw-r--r--net/ipv4/ip_masq_irc.c3
-rw-r--r--net/ipv4/ip_masq_quake.c3
-rw-r--r--net/ipv4/ip_masq_raudio.c5
-rw-r--r--net/ipv4/ip_options.c2
-rw-r--r--net/ipv4/ip_output.c18
-rw-r--r--net/ipv4/ip_sockglue.c18
-rw-r--r--net/ipv4/ipmr.c3
-rw-r--r--net/ipv4/rarp.c5
-rw-r--r--net/ipv4/route.c3
-rw-r--r--net/ipv4/sysctl_net_ipv4.c15
-rw-r--r--net/ipv4/tcp.c16
-rw-r--r--net/ipv4/tcp_input.c41
-rw-r--r--net/ipv4/tcp_ipv4.c111
-rw-r--r--net/ipv4/tcp_output.c146
-rw-r--r--net/ipv4/tcp_timer.c4
-rw-r--r--net/ipv4/udp.c52
-rw-r--r--net/ipv4/utils.c4
-rw-r--r--net/ipv6/.cvsignore1
-rw-r--r--net/ipv6/addrconf.c6
-rw-r--r--net/ipv6/af_inet6.c19
-rw-r--r--net/ipv6/datagram.c39
-rw-r--r--net/ipv6/icmp.c5
-rw-r--r--net/ipv6/ip6_fw.c5
-rw-r--r--net/ipv6/ip6_input.c12
-rw-r--r--net/ipv6/ipv6_sockglue.c9
-rw-r--r--net/ipv6/mcast.c8
-rw-r--r--net/ipv6/ndisc.c5
-rw-r--r--net/ipv6/route.c5
-rw-r--r--net/ipv6/sit.c5
-rw-r--r--net/ipv6/tcp_ipv6.c88
-rw-r--r--net/ipv6/udp.c5
-rw-r--r--net/ipx/af_ipx.c3
-rw-r--r--net/lapb/.cvsignore1
-rw-r--r--net/lapb/lapb_iface.c3
-rw-r--r--net/netbeui/af_netbeui.c3
-rw-r--r--net/netlink.c3
-rw-r--r--net/netrom/af_netrom.c3
-rw-r--r--net/netrom/sysctl_net_netrom.c3
-rw-r--r--net/netsyms.c7
-rw-r--r--net/rose/.cvsignore1
-rw-r--r--net/rose/af_rose.c3
-rw-r--r--net/rose/sysctl_net_rose.c3
-rw-r--r--net/socket.c83
-rw-r--r--net/sunrpc/.cvsignore1
-rw-r--r--net/sunrpc/pmap_clnt.c2
-rw-r--r--net/unix/af_unix.c3
-rw-r--r--net/wanrouter/.cvsignore1
-rw-r--r--net/wanrouter/wanmain.c3
-rw-r--r--net/wanrouter/wanproc.c3
-rw-r--r--net/x25/.cvsignore1
-rw-r--r--net/x25/af_x25.c3
-rw-r--r--net/x25/sysctl_net_x25.c3
-rw-r--r--scripts/mkdep.c3
713 files changed, 41535 insertions, 30675 deletions
diff --git a/CREDITS b/CREDITS
index d94810c40..76fed44b1 100644
--- a/CREDITS
+++ b/CREDITS
@@ -149,12 +149,8 @@ S: 91452 Wilhermsdorf
S: Germany
N: Bill Bogstad
-E: bogstad@cs.jhu.edu
-D: Wrote /proc/self patch
-S: Johns Hopkins University
-S: Computer Science Department
-S: Baltimore, Maryland 21218
-S: USA
+E: bogstad@pobox.com
+D: wrote /proc/self hack, minor samba & dosemu patches
N: Axel Boldt
E: boldt@math.ucsb.edu
@@ -468,7 +464,7 @@ S: Carnegie, Pennsylvania 15106-4304
S: USA
N: Philip Gladstone
-E: philipg@onsett.com
+E: philip@raptor.com
D: Kernel / timekeeping stuff
N: Michael A. Griffith
@@ -737,8 +733,8 @@ S: USA
N: Alain L. Knaff
E: Alain.Knaff@poboxes.com
D: floppy driver
-S: 2a, rue de l'Acier
-S: L-4505 Differdange
+S: 19, rue Jean l'Aveugle
+S: L-1148 Luxembourg-City
S: Luxembourg
N: Gerd Knorr
@@ -1246,14 +1242,14 @@ S: 00980 Helsinki
S: Finland
N: Eric Schenk
-E: schenk@cs.toronto.edu
+E: Eric.Schenk@dna.lth.se
D: Random kernel debugging.
D: SYSV Semaphore code rewrite.
D: Network layer debugging.
D: Dial on demand facility (diald).
-S: 7 Borden Street
-S: Toronto, Ontario
-S: Canada M5S 2M8
+S: Dag Hammerskjolds v. 3E
+S: S-226 64 LUND
+S: Sweden
N: Peter De Schrijver
E: stud11@cc4.kuleuven.ac.be
diff --git a/Documentation/00-INDEX b/Documentation/00-INDEX
index 09d482dac..63466ffd5 100644
--- a/Documentation/00-INDEX
+++ b/Documentation/00-INDEX
@@ -26,6 +26,8 @@ devices.txt
- plain ASCII listing of all the nodes in /dev/ with major minor #'s
digiboard.txt
- info on the Digiboard PC/X{i,e,eve} multiport boards.
+digiepca.txt
+ - info on Digi Intl. {PC,PCI,EISA}Xx and Xem series cards.
exception.txt
- how linux v2.1 handles exceptions without verify_area etc.
ez.txt
diff --git a/Documentation/Changes b/Documentation/Changes
index 3b1fed283..0b840fee6 100644
--- a/Documentation/Changes
+++ b/Documentation/Changes
@@ -29,7 +29,7 @@ English-language HTML version.
Also, don't forget http://www.linuxhq.com/ for all your Linux kernel
needs.
-Last updated: April 17, 1997.
+Last updated: May 12, 1997.
Current Author: Chris Ricker (gt1355b@prism.gatech.edu).
Current Minimal Requirements
@@ -40,16 +40,16 @@ encountered a bug!
- Kernel modules modutils-2.1.34
- Gnu C 2.7.2.1
-- Binutils 2.7.0.9
+- Binutils 2.8.0.3
- Linux C Library 5.4.23
- Dynamic Linker (ld.so) 1.8.5
- Linux C++ Library 2.7.2.1
- Procps 1.01
-- Mount 2.6e
-- Net-tools 1.32-alpha
+- Mount 2.6g
+- Net-tools 1.41
- Loadlin 1.6a
- Sh-utils 1.16
-- Autofs 970409
+- Autofs 0.3.0
- NFS 0.4.21
Upgrade notes
@@ -131,6 +131,9 @@ presence.
To run bootpd, you'll need to issue the following command: echo 1
>/proc/sys/net/ipv4/ip_boot_agent
+ For support for new features like IPv6, upgrade to the latest
+net-tools.
+
Mount and network file systems
==============================
@@ -179,8 +182,7 @@ How to know the version of the installed programs
*************************************************
There are some simple methods useful to know the version of the
-installed programs and libraries. The SysVinit version display
-requires that you be logged in as root.
+installed programs and libraries.
Binutils: ld -v
Gnu C: gcc -v or gcc --version
@@ -190,6 +192,7 @@ Libc: ls -l /lib/libc.so.*
Libc++: ls -l /usr/lib/libg++.so.*
Modutils: insmod -V
Mount: mount --version
+Net-tools: hostname -V
Procps: ps --version
RPM: rpm --version
Sh-utils: expr --v
@@ -200,12 +203,12 @@ Where to get the files
Binutils
========
-The 2.7.0.9 release:
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/binutils-2.7.0.9.bin.tar.gz
-ftp://sunsite.unc.edu/pub/Linux/GCC/binutils-2.7.0.9.bin.tar.gz
+The 2.8.0.3 release:
+ftp://tsx-11.mit.edu/pub/linux/packages/GCC/binutils-2.8.0.3.bin.tar.gz
+ftp://sunsite.unc.edu/pub/Linux/GCC/binutils-2.8.0.3.bin.tar.gz
Installation notes:
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.binutils-2.7.0.9
-ftp://sunsite.unc.edu/pub/Linux/GCC/release.binutils-2.7.0.9
+ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.binutils-2.8.0.3
+ftp://sunsite.unc.edu/pub/Linux/GCC/release.binutils-2.8.0.3
Gnu C
=====
@@ -295,14 +298,14 @@ ftp://prep.ai.mit.edu/pub/gnu/sh-utils-1.16.tar.gz
Mount
=====
-The 2.6e release:
-ftp://ftp.win.tue.nl/pub/linux/util/mount-2.6e.tar.gz
+The 2.6g release:
+ftp://ftp.win.tue.nl/pub/linux/util/mount-2.6g.tar.gz
Autofs
======
-The 970409 release:
-ftp://ftp.kernel.org/pub/linux/daemons/autofs/autofs-970409.tar.gz
+The 0.3.0 release:
+ftp://ftp.kernel.org/pub/linux/daemons/autofs/autofs-0.3.0.tar.gz
NFS
===
@@ -311,6 +314,13 @@ The 0.4.21 release:
ftp://ftp.mathematik.th-darmstadt.de/pub/linux/okir/linux-nfs-0.4.21.tar.gz
ftp://linux.nrao.edu/pub/people/okir/linux-nfs-0.4.21.tar.gz
+Net-tools
+=========
+
+The 0.41 release:
+ftp://ftp.london.uk.eu.org/pub/ipv6/net-tools-1.41.tar.gz
+ftp://ftp.cs-ipv6.lancs.ac.uk/pub/Code/Linux/Net_Tools/net-tools-1.41.tar.gz
+
Other Info
==========
diff --git a/Documentation/Configure.help b/Documentation/Configure.help
index 469fb2e02..746b2c534 100644
--- a/Documentation/Configure.help
+++ b/Documentation/Configure.help
@@ -2072,6 +2072,20 @@ CONFIG_SCSI_NCR53C406A
and read Documentation/modules.txt. The module will be called
NCR53c406.o.
+Tekram DC390W/U/F (T) SCSI support
+CONFIG_SCSI_DC390W
+ This driver supports the Tekram DC390W/U/F (T) PCI SCSI host adapters with
+ the NCR/Symbios 53c825/875 chips. If you have a DC390 (T) adaptor with the
+ Am53C974A chip use the DC390(T) driver.
+
+Tekram DC390(T) (AMD PCscsi) SCSI support
+CONFIG_SCSI_DC390T
+ This driver supports the Tekram DC390(T) PCI SCSI Hostadapter with
+ the Am53C974A chip, and perhaps other cards using the same chip.
+
+ This driver does _not_ support the DC390W/U/F adaptor with the
+ NCR/Symbios chips.
+
AM53/79C974 PCI SCSI support
CONFIG_SCSI_AM53C974
This is support for the AM53/79C974 SCSI host adapters. Please read
@@ -4036,6 +4050,16 @@ CONFIG_SERIAL_CONSOLE
N here so that they can use the serial port for modem, mouse or some
other device.
+Digi Intl. epca support
+CONFIG_DIGIEPCA
+ This is a driver for Digi Internationals Xx, Xeve, and Xem
+ series of cards. This driver supports the original PC (ISA) boards as
+ well as PCI, and EISA. If you have a card like this, say Y here and read
+ the file Documentation/digiepca.txt. NOTE: This driver is seperate from
+ the driver written and copyrighted by Troy De Jongh. Because they both
+ attempt (In some cases) to access the same hardware only one of these
+ drivers (CONFIG_DIGIEPCA or CONFIG_DIGI) should be selected.
+
Digiboard PC/Xx Support
CONFIG_DIGI
This is a driver for the Digiboard PC/Xe, PC/Xi, and PC/Xeve cards
@@ -4626,6 +4650,40 @@ CONFIG_ACI_MIXER
also controls the radio tuner on this card, however this is not
yet supported in this software.
+Gallant's Audio Excel DSP 16 support (SC-6000 and SC-6600)
+CONFIG_AEDSP16
+ Answer Y if you have a Gallant's Audio Excel DSP 16 card. This card
+ emulate an SBPro or a Microsoft Sound System card.
+ You must select one of the Sound Blaster or Microsoft Sound System
+ drivers before select this menu item.
+ Read the drivers/sound/lowlevel/README.aedsp16 file and the head of
+ drivers/sound/lowlevel/aedsp16.c to have more informations about
+ this driver and its configuration.
+
+ If you are changing the card configuration, please, undefine all
+ the old Audio Excel parameters because leaving it defined while
+ selecting the alternate emulation, may screw up your .config file.
+
+ !!!NOTE!!!
+ The driver supports Audio Excel DSP 16 but not the III version of
+ this card. Read drivers/sound/lowlevel/Readme.aedsp16 if you want
+ to know something more on how to use the III version with this sound
+ driver.
+
+SC-6600 based audio cards (new Audio Excel DSP 16)
+CONFIG_SC6600
+ The SC6600 is the new version of DSP mounted on the Audio Excel DSP 16
+ cards. Check the FCC ID of your audio card and answer Y if you have an
+ SC6600 DSP.
+
+Audio Excel DSP 16 (MSS emulation)
+CONFIG_AEDSP16_MSS
+ Answer Y if you want your audio card emulate Microsoft Sound System.
+
+Audio Excel DSP 16 (SBPro emulation)
+CONFIG_AEDSP16_SBPRO
+ Answer Y if you want your audio card emulate Sound Blaster Pro.
+
Kernel profiling support
CONFIG_PROFILE
This is for kernel hackers who want to know how much time the kernel
@@ -4918,9 +4976,13 @@ CONFIG_RMW_INSNS
Amiga AutoConfig Identification
CONFIG_ZORRO
This enables support for automatic identification of Amiga expansion
- cards that obey the AutoConfig(tm) specification. You should say Y
- to this question unless you have no expansion cards and no intention
- of getting any.
+ cards that obey the AutoConfig(tm) specification.
+ Say Y if you want your expansion cards to be identified on bootup;
+ it will enlarge your kernel by about 10KB. The identification
+ information is also available through /proc/zorro (say Y to
+ "/proc filesystem support"!).
+ Note that even if you say N here, you can still use your expansion
+ cards. If in doubt, say Y.
Amiga OCS chipset support
CONFIG_AMIFB_OCS
@@ -4948,6 +5010,8 @@ CONFIG_FB_CYBER
Please note that its use is not all that intuitive (i.e. if you have
any questions, be sure to ask!). Say N unless you have a Cybervision
64 or plan to get one before you next recompile the kernel.
+ Please note that this driver DOES NOT support the Cybervision 64 3D
+ card at present, as they use incompatible video chips.
Amiga GSP (TMS340x0) support
CONFIG_AMIGA_GSP
@@ -5188,6 +5252,16 @@ CONFIG_ATARI_MIDI
want). If you want to compile it as a module, say M here and read
Documentation/modules.txt.
+Atari DSP56k Digital Signal Processor support
+CONFIG_ATARI_DSP56K
+ If you want to be able to use the DSP56001 in Falcons, say Y.
+ This driver is still experimental, and if you don't know what it is,
+ or if you don't have this processor, just say N.
+ This driver is also available as a module ( = code 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.
+
Amiga builtin serial support
CONFIG_AMIGA_BUILTIN_SERIAL
If you want to use your Amiga's built-in serial port in Linux, say
@@ -5317,7 +5391,7 @@ CONFIG_MSDOS_PARTITION
# LocalWords: mgetty sendfax gert greenie muc lowlevel Lasermate LanManager io
# LocalWords: OOPSes trackball binghamton mobileip ncr IOMAPPED settags ns ser
# LocalWords: setsync NEGO MPARITY autotuning prefetch PIIX cdwrite utils rc
-# LocalWords: PCWATCHDOG berkprod bitgate boldt ucsb jf kyoto jp euc Tetsuyasu
+# LocalWords: PCWATCHDOG berkprod bitgate boldt ucsb jf kyoto jp euc Tetsuyasu
# LocalWords: YAMADA tetsu cauchy nslab ntt nevod perm su doc kaf kheops wsc
# LocalWords: traduc Bourgin dbourgin helptext menuconfig kfill READMEs HOWTOs
# LocalWords: IDEDISK IDEFLOPPY EIDE firewalls QMAGIC ZMAGIC LocalWords opti
diff --git a/Documentation/devices.tex b/Documentation/devices.tex
index 80dc0f9de..f20ca8c39 100644
--- a/Documentation/devices.tex
+++ b/Documentation/devices.tex
@@ -15,6 +15,7 @@
%
\begin{document}
\newcommand{\file}{\tt} % Style to use for a filename
+\newcommand{\url}{\it} % Style to use for an URL
\newcommand{\hex}{\tt} % Style to use for a hex number
\newcommand{\ud}{(Under development)} % Abbreviation
\newcommand{\1}{\({}^1\)}
@@ -46,7 +47,7 @@ foo \kill}%
%
\title{{\bf Linux Allocated Devices}}
\author{Maintained by H. Peter Anvin $<$hpa@zytor.com$>$}
-\date{Last revised: April 7, 1997}
+\date{Last revised: May 20, 1997}
\maketitle
%
\noindent
@@ -60,17 +61,19 @@ sources in \LaTeX\ and ASCII form. In case of discrepancy, the
\LaTeX\ version is authoritative.
This document is included by reference into the Linux Filesystem
-Standard (FSSTND). The FSSTND is available via FTP from
-tsx-11.mit.edu in the directory {\file
-/pub/linux/docs/linux-standards/fsstnd}.
+Standard (FSSTND). The FSSTND is available from
+{\url ftp://tsx-11.mit.edu/pub/linux/docs/linux-standards/fsstnd/}.
To have a major number allocated, or a minor number in situations
where that applies (e.g.\ busmice), please contact me with the
-appropriate device information. Also, if you have additional
-information regarding any of the devices listed below, or if I have
-made a mistake, I would greatly appreciate a note. When sending me
-mail, {\em please\/} include the word ``device'' in the subject so
-your mail won't accidentally get buried!
+appropriate device information. I *very* much appreciate if you send
+me a device description in the same format as the ones already in this
+file. Also, if you have additional information regarding any of the
+devices listed below, or if I have made a mistake, I would greatly
+appreciate a note.
+
+NOTE: When sending me mail, {\em please\/} include the word ``device''
+in the subject so your mail won't accidentally get buried!
Allocations marked (68k/Amiga) apply to Linux/68k on the Amiga
platform only. Allocations marked (68k/Atari) apply to Linux/68k on
@@ -207,7 +210,10 @@ reply.
\major{79}{}{char }{PAM Software's multimodem boards -- alternate devices}
\major{80}{}{char }{Photometrics AT200 CCD camera}
\major{81}{}{char }{Brooktree Bt848 frame grabbers}
-\major{82}{--119}{}{Unallocated}
+\major{82}{}{char }{WiNRADiO communications receiver card}
+\major{83}{}{char }{Teletext/videotext interfaces}
+\major{84}{}{char }{Ikon 1011[57] Versatec Greensheet Interface}
+\major{85}{--119}{}{Unallocated}
\major{120}{--127}{}{Local/experimental use}
\major{128}{--239}{}{Unallocated}
\major{240}{--254}{}{Local/experimental use}
@@ -487,6 +493,7 @@ physical disks.
\minor{6}{/dev/sunmouse}{Sun mouse}
\minor{7}{/dev/amigamouse1}{Second Amiga mouse}
\minor{8}{/dev/smouse}{Simple serial mouse driver}
+ \minor{9}{/dev/pc110pad}{IBM PC-110 digitizer pad}
\minor{128}{/dev/beep}{Fancy beep device}
\minor{129}{/dev/modreq}{Kernel module load request}
\minor{130}{/dev/watchdog}{Watchdog timer port}
@@ -1243,7 +1250,7 @@ $<$jth@prosig.demon.co.uk$>$ for information.
\end{devicelist}
\noindent
-See {\em http://www.coda.cs.cmu.edu\/} for information about Coda.
+See {\url http://www.coda.cs.cmu.edu\/} for information about Coda.
\begin{devicelist}
\major{68}{}{char }{CAPI 2.0 interface}
@@ -1392,7 +1399,34 @@ Currently for Dolphin Interconnect Solutions' PCI-SCI bridge.
\end{devicelist}
\begin{devicelist}
-\major{82}{--119}{}{Unallocated}
+\major{82}{}{char }{WiNRADiO communications receiver card}
+ \major{0}{/dev/winradio0}{First WiNRADiO card}
+ \major{1}{/dev/winradio1}{Second WiNRADiO card}
+ \minordots
+\end{devicelist}
+
+\noindent
+The driver and documentation may be obtained from
+{\url http://www.proximity.com.au/~brian/winradio/\/}.
+
+\begin{devicelist}
+\major{83}{}{char }{Teletext/videotext interfaces}
+ \minor{0}{/dev/vtx}{Teletext decoder}
+ \minor{16}{/dev/vttuner}{TV tuner on teletext interface}
+\end{devicelist}
+
+\noindent
+Devices for the driver contained in the VideoteXt package. More information
+on {\url http://home.pages.de/~videotext/\/}.
+
+\begin{devicelist}
+\major{84}{}{char }{Ikon 1011[57] Versatec Greensheet Interface}
+ \minor{0}{/dev/ihcp0}{First Greensheet port}
+ \minor{1}{/dev/ihcp1}{Second Greensheet port}
+\end{devicelist}
+
+\begin{devicelist}
+\major{85}{--119}{}{Unallocated}
\end{devicelist}
\begin{devicelist}
diff --git a/Documentation/devices.txt b/Documentation/devices.txt
index 17a99de95..cff94ac65 100644
--- a/Documentation/devices.txt
+++ b/Documentation/devices.txt
@@ -1,7 +1,7 @@
LINUX ALLOCATED DEVICES
Maintained by H. Peter Anvin <hpa@zytor.com>
- Last revised: April 7, 1997
+ Last revised: May 20, 1997
This list is the successor to Rick Miller's Linux Device List, which
he stopped maintaining when he got busy with other things in 1993. It
@@ -18,11 +18,14 @@ tsx-11.mit.edu in the directory /pub/linux/docs/linux-standards/fsstnd.
To have a major number allocated, or a minor number in situations
where that applies (e.g. busmice), please contact me with the
-appropriate device information. Also, if you have additional
-information regarding any of the devices listed below, or if I have
-made a mistake, I would greatly appreciate a note. When sending me
-mail, *please* include the word "device" in the subject so your mail
-won't accidentally get buried!
+appropriate device information. I *very* much appreciate if you send
+me a device description in the same format as the ones already in this
+file. Also, if you have additional information regarding any of the
+devices listed below, or if I have made a mistake, I would greatly
+appreciate a note.
+
+NOTE: When sending me mail, *please* include the word "device" in the
+subject so your mail won't accidentally get buried!
Allocations marked (68k/Amiga) apply to Linux/68k on the Amiga
platform only. Allocations marked (68k/Atari) apply to Linux/68k on
@@ -270,6 +273,7 @@ reply.
6 = /dev/sunmouse Sun mouse
7 = /dev/amigamouse1 Second Amiga mouse
8 = /dev/smouse Simple serial mouse driver
+ 9 = /dev/pc110pad IBM PC-110 digitizer pad
128 = /dev/beep Fancy beep device
129 = /dev/modreq Kernel module load request
130 = /dev/watchdog Watchdog timer port
@@ -979,7 +983,26 @@ reply.
33 = /dev/bttv-vbi1 VBI data of second Bt848 card
...
- 82-119 UNALLOCATED
+ 82 char WiNRADiO communications receiver card
+ 0 = /dev/winradio0 First WiNRADiO card
+ 1 = /dev/winradio1 Second WiNRADiO card
+ ...
+
+ The driver and documentation may be obtained from
+ http://www.proximity.com.au/~brian/winradio/
+
+ 83 char Teletext/videotext interfaces
+ 0 = /dev/vtx Teletext decoder
+ 16 = /dev/vttuner TV tuner on teletext interface
+
+ Devices for the driver contained in the VideoteXt package.
+ More information on http://home.pages.de/~videotext/
+
+ 84 char Ikon 1011[57] Versatec Greensheet Interface
+ 0 = /dev/ihcp0 First Greensheet port
+ 1 = /dev/ihcp1 Second Greensheet port
+
+ 85-119 UNALLOCATED
120-127 LOCAL/EXPERIMENTAL USE
diff --git a/Documentation/digiepca.txt b/Documentation/digiepca.txt
new file mode 100644
index 000000000..9904afb39
--- /dev/null
+++ b/Documentation/digiepca.txt
@@ -0,0 +1,96 @@
+The Digi Intl. epca driver.
+----------------------------
+The Digi Intl. epca driver for Linux supports the following boards:
+
+Digi PC/Xem, PC/Xr, PC/Xe, PC/Xi, PC/Xeve
+Digi EISA/Xem, PCI/Xem, PCI/Xr
+
+Limitations:
+------------
+Currently the driver only autoprobes for supported PCI boards.
+
+The Linux MAKEDEV command does not support generating the Digiboard
+Devices. Users executing digiConfig to setup EISA and PC series cards
+will have their device nodes automaticly constructed (cud?? for ~CLOCAL,
+and ttyD?? for CLOCAL). Users wishing to boot their board from the LILO
+prompt, or those users booting PCI cards may use buildDIGI to construct
+the necessary nodes.
+
+Notes:
+------
+This driver may be configured via LILO. For users who have already configured
+their driver using digiConfig, configuring from lilo will override previous
+settings. Multiple boards may be configured by issuing multiple LILO command
+lines. For examples see the bottom of this document.
+
+Device names start at 0 and continue up. Beware of this as previous Digi
+drivers started device names with 1.
+
+PCI boards are auto-detected and configured by the driver. PCI boards will
+be allocated device numbers (internally) begining with the lowest PCI slot
+first. In other words a PCI card in slot 3 will always have higher device
+nodes than a PCI card in slot 1.
+
+LILO config examples:
+---------------------
+Using LILO's APPEND command, a string of comma separated identifiers or
+integers can be used to configure supported boards. The six values in order
+are:
+
+ Enable/Disable this card or Override,
+ Type of card: PC/Xe (AccelePort) (0), PC/Xeve (1), PC/Xem or PC/Xr (2),
+ EISA/Xem (3), PC/64Xe (4), PC/Xi (5),
+ Enable/Disable alternate pin arrangement,
+ Number of ports on this card,
+ I/O Port where card is configured (in HEX if using string identifiers),
+ Base of memory window (in HEX if using string identifiers),
+
+NOTE : PCI boards are auto-detected and configured. Do not attempt to
+configure PCI boards with the LILO append comand. If you wish to override
+previous configuration data (As set by digiConfig), but you do not wish to
+configure any specific card (Example if there are PCI cards in the system)
+the following override command will accomplish this:
+-> append="digi=2"
+
+Samples:
+ append="digiepca=E,PC/Xe,D,16,200,D0000"
+ or
+ append="digi=1,0,0,16,512,851968"
+
+Supporting Tools:
+-----------------
+Supporting tools include digiDload, digiConfig, buildPCI, and ditty. See
+/usr/src/linux/Documentation/README.epca.dir/user.doc for more details. Note,
+this driver REQUIRES that digiDload be executed prior to it being used.
+Failure to do this will result in an ENODEV error.
+
+The latest version of the tool package is available at:
+ftp://ftp.dgii.com/drivers/linux/released/async/
+
+Documentation:
+--------------
+Complete documentation for this product may be found in the tool package.
+
+Sources of information and support:
+-----------------------------------
+Digi Intl. support site for this product:
+-> digilnux@dgii.com
+
+Related information and information concerning other drivers supporting
+Digi Intl. products:
+
+-> FTP: ftp://dgii.com
+-> Webpage: http://www.dgii.com
+-> Webpage: http://private.fuller.edu/clameter/digi.html
+-> Mailing List: digiboard@list.fuller.edu Note write e-mail to subscribe
+ common ListServ commands will not work.
+
+Acknowledgments:
+----------------
+Much of this work (And even text) was derived from a similar document
+supporting the original public domain DigiBoard driver Copyright (C)
+1994,1995 Troy De Jongh. Many thanks to Christoph Lameter
+(clameter@fuller.edu) and Mike McLagan (mike.mclagan@linux.org) who authored
+and contributed to the original document.
+
+
diff --git a/Documentation/ioctl-number.txt b/Documentation/ioctl-number.txt
index 4e1eba41e..7d86d3168 100644
--- a/Documentation/ioctl-number.txt
+++ b/Documentation/ioctl-number.txt
@@ -1,5 +1,5 @@
Ioctl Numbers
-5 Apr 1997
+10 Apr 1997
Michael Chastain
<mec@shout.net>
@@ -87,6 +87,8 @@ Code Seq# Include File Comments
'W' 28-2F linux/iso16-relay.h in development
'Y' all linux/cyclades.h
'a' all various, see http://lrcwww.epfl.ch/linux-atm/magic.html
+'b' 00-3F bit3 vme host bridge in development:
+ <mailto:natalia@nikhefk.nikhef.nl>
'c' all linux/comstats.h
'f' all linux/ext2_fs.h
'l' 00-3F linux/tcfs_fs.h in development:
@@ -94,7 +96,8 @@ Code Seq# Include File Comments
'm' all linux/mtio.h conflict!
'm' all linux/soundcard.h conflict!
'n' all linux/ncp_fs.h
-'p' all linux/mc146818rtc.h
+'p' 00-3F linux/mc146818rtc.h
+'p' 40-7F linux/nvram.h
'r' all linux/msdos_fs.h
's' all linux/cdk.h
't' 00-7F linux/if_ppp.h
@@ -108,8 +111,9 @@ Code Seq# Include File Comments
0x89 F0-FF linux/sockios.h SIOCDEVPRIVATE range
0x8B all linux/wireless.h
0x8C 00-3F WiNRADiO driver in development:
- <mailto:brian@proximity.com.au>
+ <http://www.proximity.com.au/~brian/winradio/>
0x90 00 linux/sbpcd.h
+0x93 60-7F linux/auto_fs.h
0x99 00-0F 537-Addinboard driver in development:
<mailto:b.kohl@ipn-b.comlink.apc.org>
0xA0 all Small Device Project in development:
diff --git a/Documentation/locks.txt b/Documentation/locks.txt
index ea91be8a2..3911417b2 100644
--- a/Documentation/locks.txt
+++ b/Documentation/locks.txt
@@ -2,42 +2,30 @@
Andy Walker <andy@lysaker.kvaerner.no>
- 21 Sep 1996
+ 12 May 1997
1. What's New?
--------------
-1.1 Flock Emulation Warnings
-----------------------------
-Many people will have noticed the ugly messages that the file locking
-code started generating with the release of kernel version 1.3.95. The
-messages look something like this:
+1.1 Broken Flock Emulation
+--------------------------
- fcntl_setlk() called by process XX with broken flock() emulation
+The old flock(2) emulation in the kernel was swapped for proper BSD
+compatible flock(2) support in the 1.3.x series of kernels. With the
+release of the 2.1.x kernel series, support for the old emulation has
+been totally removed, so that we don't need to carry this baggage
+forever.
-This is a warning for people using older C libraries that those libraries
-are still calling the pre 1.3.x flock() emulation routines, instead of
-the real flock() system call. The old routines are quite badly broken,
-especially with respect to parent-child lock sharing, and can give bad
-results if, for example, sendmail attempts to use them.
+This should not cause problems for anybody, since everybody using a
+2.1.x kernel should have updated their C library to a suitable version
+anyway (see the file "linux/Documentation/Changes".)
-Fixed versions of the C libraries have been on public release for many
-months. The latest versions at the time of writing are 5.3.12 (released)
-or 5.4.6 (testing) for ELF. There is also a 4.7.6 release for people
-using a.out systems.
+1.2 Allow Mixed Locks Again
+---------------------------
-With the release of Linux 2.0 Linus decided to be lenient on the
-stragglers and changed the warning message so that the kernel will only
-complain once and then shut up. That should make life more bearable even
-for people who, for some reason, don't want to upgrade their libraries.
-
-
-1.2 Disallow Mixed Locks
-------------------------
-
-1.2.1 Sendmail Problems
----------------------
+1.2.1 Typical Problems - Sendmail
+---------------------------------
Because sendmail was unable to use the old flock() emulation, many sendmail
installations use fcntl() instead of flock(). This is true of Slackware 3.0
for example. This gave rise to some other subtle problems if sendmail was
@@ -50,23 +38,17 @@ to lock solid with deadlocked processes.
1.2.2 The Solution
------------------
-I have chosen the rather cruel solution of disallowing mixed locking styles
-on a given file at a given time. Attempts to lock a file with flock() when
-fcntl() locks exist, or vice versa, return with an error status of EBUSY.
-This seemed to be the only way to avoid all possible deadlock conditions,
-as flock() locks do not strictly have one owner process and so can't be
-checked for deadlocking in the usual manner.
-
-The process that created a lock with flock() might have forked multiple
-children and exited. Previously the parent process would have been marked
-as the owner of the lock, but deadlocks could just have easily occurred in
-one or more of the children, which we would not have been able to identify
-and avoid.
-
-Some programs may break (again, groan). In particular the aforementioned
-sendmail may have problems running in 'newaliases' mode. It will no longer
-deadlock though. Recompile sendmail to use flock() and your troubles will
-be over.
+The solution I have chosen, after much experimentation and discussion,
+is to make flock() and fcntl() locks oblivious to each other. Both can
+exists, and neither will have any effect on the other.
+
+I wanted the two lock styles to be cooperative, but there were so many
+race and deadlock conditions that the current solution was the only
+practical one. It puts us in the same position as, for example, SunOS
+4.1.x and serveral other commercial Unices. The only OS's that support
+cooperative flock()/fcntl() are those that emulate flock() using
+fcntl(), with all the problems that implies.
+
1.3 Mandatory Locking As A Mount Option
---------------------------------------
diff --git a/Documentation/m68k/00-INDEX b/Documentation/m68k/00-INDEX
new file mode 100644
index 000000000..ae5b93488
--- /dev/null
+++ b/Documentation/m68k/00-INDEX
@@ -0,0 +1,9 @@
+00-INDEX
+ - this file
+amiboot.txt
+ - info and options for the Linux/m68k Amiga bootstrap (Amiboot)
+framebuffer.txt
+ - info about the Linux/m68k frame buffer device
+kernel-options.txt
+ - command line options for Linux/m68k
+
diff --git a/Documentation/m68k/amiboot.README b/Documentation/m68k/amiboot.txt
index 1e25e1d37..c119c6357 100644
--- a/Documentation/m68k/amiboot.README
+++ b/Documentation/m68k/amiboot.txt
@@ -1,7 +1,10 @@
- Linux/m68k Amiga Bootstrap version 5.1
+ Linux/m68k Amiga Bootstrap version 5.5
--------------------------------------
+Maintained by Geert Uytterhoeven (Geert.Uytterhoeven@cs.kuleuven.ac.be)
+Last revised: March 27, 1997
+
0. Introduction
---------------
@@ -10,7 +13,7 @@ Amiboot is used to boot Linux/m68k on Amiga from the CLI/Shell.
Before you try to boot Linux/m68k for the first time, please read the FAQ
- http://www-agrw.informatik.uni-kl.de/~jmayer/linux68k/linux68k-faq
+ http://www.clark.net/pub/lawrencc/linux/faq/faq.html
and the Installation Guide
@@ -19,7 +22,7 @@ and the Installation Guide
first. Although the Installation Guide is getting a bit outdated, it's still a
good starting point.
-Amiboot 5.1 is meant for Linux/m68k 2.0.x, 2.1.x or higher (kernel bootinfo
+Amiboot 5.5 is meant for Linux/m68k 2.0.x, 2.1.x or higher (kernel bootinfo
interface versions 1.x and 2.x). Please use an older version for older kernels.
@@ -30,23 +33,27 @@ The Amiboot invocation syntax looks like
amiboot [options] [kernel command line]
-Valid options are:
+Basic options:
--help Display the usage information
--kernel file Use kernel image `file' (default is `vmlinux')
- --ramdisk file Use ramdisk image `file'.
+ --ramdisk file Use ramdisk image `file'
+
+Advanced options:
--debug Enable debug mode
- --baud Set the serial port speed (default is 9600)
+ --baud speed Set the serial port speed (default is 9600 bps)
--memfile file Use memory file `file'
--keep-video Don't reset the video mode
- --model id Set the Amiga model to `id'.
+ --model id Set the Amiga model to `id'
+
+ --processor cfm Set the processor type to `cfm'
The kernel command line contains the options you want to pass to the kernel and
to init, the process that's started first by Linux. Please read
@@ -57,6 +64,10 @@ Linux/m68k kernel image, and --ramdisk if you want to boot from a ramdisk file,
i.e. a file containing a complete file system, instead of from a hard disk
partition.
+Note that both the kernel image and the ramdisk image can be compressed with
+gzip. Amiboot knows how to deal with gzipped kernel images, and the kernel
+recognizes gzipped ramdisk images.
+
Example:
amiboot -k vmlinux-2.1.13 root=/dev/hda3 video=font:PEARL8x8
@@ -65,8 +76,8 @@ Amiboot will boot the kernel image `vmlinux-2.1.13' and will pass
`root=/dev/hda3 video=font:PEARL8x8' to the kernel.
-The other options are more specialized. Don't use them unless you really have
-to and you know what you're doing.
+The other options are more advanced. Don't use them unless you really have to
+and you know what you're doing.
The --baud option allows you to specify the serial port speed for initial boot
information and initial kernel messages. Note: this option does not work with
@@ -79,8 +90,9 @@ The --keep-video option is necessary if you want to retain the current graphics
mode (on a graphics board) under Linux. Currently this is only useful if you
have a CyberVision 64 graphics board.
-Finally, --model allows you to specify your Amiga model, and --debug is for
-debugging purposes.
+Finally, --model and --processor allow you to specify your Amiga model and
+processor type if they are detected incorrectly, and --debug dumps some
+information which simplifies debugging.
2. The memory file
@@ -98,7 +110,7 @@ format for the file is:
...
For example, if you don't want Linux to use your 2nd meg of chipram, you would
-create a file that looks contains only:
+create a file that contains only:
1048576
@@ -149,7 +161,33 @@ Please send me the output of amiboot used with the --debug option if your Amiga
model is detected incorrectly.
-4. Abbreviations
+4. Processor types
+------------------
+
+If your processor is detected incorrectly, you can override this using the
+`--processor cfm' option. `cfm' must be a three-digit number with
+
+ - `c' the CPU (Central Processing Unit) type,
+ - 'f' the FPU (Floating Point Unit) type,
+ - 'm' the MMU (Memory Management Unit) type,
+
+from the table below:
+
+ value | CPU | FPU | MMU
+ -------+-------+-------+-------
+ 0 | - | - | -
+ 1 | 68020 | 68881 | 68851
+ 2 | 68030 | 68882 | 68030
+ 3 | 68040 | 68040 | 68040
+ 4 | 68060 | 68060 | 68060
+
+e.g. `444' if you have a 68060 and `303' if you have a 68LC040.
+
+Note that normally you don't have to use this option. It's only needed for some
+combinations of an old Kickstart ROM and a new processor (e.g. a 68060).
+
+
+5. Abbreviations
----------------
All options also have a shorthand:
@@ -162,9 +200,10 @@ All options also have a shorthand:
--memfile -m
--keep-video -v
--model -t
+ --processor -p
-5. Miscellaneous
+6. Miscellaneous
----------------
Some expansion boards keep on generating interrupts once they were initialized
@@ -186,7 +225,7 @@ routine for them yet:
If you write a routine to disable an expansion board, please let me know.
-6. Troubleshooting
+7. Troubleshooting
------------------
- Amiboot says
@@ -222,11 +261,13 @@ If you write a routine to disable an expansion board, please let me know.
o If that doesn't work, remove any expansion devices and retry.
+ o Check the detected Amiga model and processor type.
+
o Look at the characters that are dumped to the serial port during
booting.
-7. Amiga-Lilo
+8. Amiga-Lilo
-------------
Once you have a stable Linux/m68k installation, you may want to try Amiga-Lilo.
@@ -234,7 +275,7 @@ Amiga-Lilo allows you to boot Linux/m68k without the overhead of booting
AmigaOS first, and it provides you with a boot menu.
-8. Credits
+9. Credits
----------
This readme was written by Geert Uytterhoeven. A lot of information was taken
diff --git a/Documentation/m68k/framebuffer.txt b/Documentation/m68k/framebuffer.txt
new file mode 100644
index 000000000..490a33793
--- /dev/null
+++ b/Documentation/m68k/framebuffer.txt
@@ -0,0 +1,370 @@
+
+ The Linux/m68k Frame Buffer Device
+ ----------------------------------
+
+Maintained by Geert Uytterhoeven (Geert.Uytterhoeven@cs.kuleuven.ac.be)
+Last revised: March 23, 1997
+
+
+0. Introduction
+---------------
+
+The frame buffer device provides an abstraction for the graphics hardware. It
+represents the frame buffer of some video hardware and allows application
+software to access the graphics hardware through a well-defined interface, so
+the software doesn't need to know anything about the low-level (hardware
+register) stuff.
+
+The device is accessed through special device nodes, usually located in the
+/dev directory, i.e. /dev/fb*.
+
+
+1. User's View of /dev/fb*
+--------------------------
+
+From the user's point of view, the frame buffer device looks just like any
+other device in /dev. It's a character device using major 29, the minor is
+divided into a frame buffer number in the upper 3 bits (allowing max. 8 frame
+buffers simultaneously) and a resolution code in the lower 5 bits of the minor.
+
+By convention, the following device nodes are used (numbers indicate the device
+minor numbers):
+
+ First frame buffer
+ 0 = /dev/fb0current Current resolution
+ 1 = /dev/fb0autodetect Default resolution
+ 2 = /dev/fb0predefined0 Predefined resolutions (22)
+ ...
+ 23 = /dev/fb0predefined21
+ 24 = /dev/fb0user0 User defined resolutions (8)
+ ...
+ 31 = /dev/fb0user7
+
+ Second frame buffer
+ 32 = /dev/fb1current Current resolution
+ 33 = /dev/fb1autodetect Default resolution
+ 34 = /dev/fb1predefined0 Predefined resolutions (22)
+ ...
+ 55 = /dev/fb1predefined21
+ 56 = /dev/fb1user0 User defined resolutions (8)
+ ...
+ 63 = /dev/fb1user7
+
+and so on...
+
+The device with (minor & 31) == 0 (/dev/fb?current) stands for the frame buffer
+together with the currently set video parameters; (minor & 31) == 1
+(/dev/fb?autodetect) is the video mode detected at boot time. Any other minor
+stands for some predefined or user defined video mode.
+
+The predefined entries (/dev/fb?predefined*) usually have a device dependent
+name, e.g. for major 29, minor 5, we have /dev/fb0multiscan on Amiga and
+/dev/fb0ttmid on Atari. These are meant to contain hardware dependent
+resolutions.
+
+The user defined resolutions (/dev/fb?user?) are meant to be filled in by the
+user. This way the user can store his favorite 8 resolutions during boot up.
+
+Note: if you need more than 8 user defined resolutions, you can always override
+the predefined resolutions by storing them in one of the predefined entries.
+But this is not recommended. Similarly, if there are more than 22 predefined
+resolutions, the device writer can decide to store them in the user defined
+entries.
+
+If the device is opened (for writing), the frame buffer driver switches to the
+selected video mode. Thus, you can switch video modes by writing to a frame
+buffer device, e.g.
+
+ > /dev/fb0ttlow
+
+will switch your video to TT low mode. Note: if you specify a resolution which
+contains a value that's not possible on your hardware, the frame buffer device
+will round it up (if possible) or return an error condition.
+
+The frame buffer devices are also `normal' memory devices, this means, you can
+read and write their contents. You can, for example, make a screen snapshot by
+
+ cp /dev/fb0current myfile
+
+There also can be more than one frame buffer at a time, e.g. if you have a
+graphics card in addition to the built-in hardware. The corresponding frame
+buffer devices (/dev/fb0* and /dev/fb1* etc.) work independently.
+
+Application software that uses the frame buffer device (e.g. the X server) will
+use /dev/fb0current by default. You can specify an alternative resolution by
+setting the environment variable $FRAMEBUFFER to the path name of a frame
+buffer device, e.g. (for sh/bash users):
+
+ export FRAMEBUFFER=/dev/fb0multiscan
+
+or (for csh users):
+
+ setenv FRAMEBUFFER /dev/fb0multiscan
+
+After this the X server will use the multiscan video mode.
+
+
+2. Programmer's View of /dev/fb*
+--------------------------------
+
+As you already know, a frame buffer device is a memory device like /dev/mem and
+it has the same features. You can read it, write it, seek to some location in
+it and mmap() it (the main usage). The difference is just that the memory that
+appears in the special file is not the whole memory, but the frame buffer of
+some video hardware.
+
+/dev/fb* also allows several ioctls on it, by which lots of information about
+the hardware can be queried and set. The color map handling works via ioctls,
+too. Look into <linux/fb.h> for more information on what ioctls exist and on
+which data structures they work. Here's just a brief overview:
+
+ - You can request unchangeable information about the hardware, like name,
+ organization of the screen memory (planes, packed pixels, ...) and address
+ and length of the screen memory.
+
+ - You can request and change variable information about the hardware, like
+ visible and virtual geometry, depth, color map format, timing, and so on.
+ If you try to change that informations, the driver maybe will round up some
+ values to meet the hardware's capabilities (or return EINVAL if that isn't
+ possible).
+
+ - You can get and set parts of the color map. Communication is done with 16
+ bit per color part (red, green, blue, transparency) to support all existing
+ hardware. The driver does all the computations needed to bring it into the
+ hardware (round it down to less bits, maybe throw away transparency).
+
+All this hardware abstraction makes the implementation of application programs
+easier and more portable. E.g. the X server works completely on /dev/fb* and
+thus doesn't need to know, for example, how the color registers of the concrete
+hardware are organized. XF68_FBDev is a general X server for bitmapped,
+unaccelerated video hardware. The only thing that has to be built into
+application programs is the screen organization (bitplanes or chunky pixels
+etc.), because it works on the frame buffer image data directly.
+
+For the future it is planned that frame buffer drivers for graphics cards and
+the like can be implemented as kernel modules that are loaded at runtime. Such
+a driver just has to call register_framebuffer() and supply some functions.
+Writing and distributing such drivers independently from the kernel will save
+much trouble...
+
+
+3. Frame Buffer Resolution Maintenance
+--------------------------------------
+
+Frame buffer resolutions are maintained using the utility `fbset'. It allows to
+change the video mode properties of the current or a user defined resolution.
+It's main usage is to tune video modes and to store custom resolutions into one
+of the /dev/fb?user? entries, e.g. during boot up in one of your /etc/rc.* or
+/etc/init.d/* files, after which those resolutions can be used by applications.
+
+Fbset uses a video mode database stored in a configuration file, so you can
+easily add your own modes and refer to them with a simple identifier. The fbset
+install script also creates the special device nodes for the device dependent
+predefined resolutions.
+
+
+4. The X Server
+---------------
+
+The X server (XF68_FBDev) is the most notable application program for the frame
+buffer device. The current X server is part of the XFree86/XFree68 release 3.2
+package and has 2 modes:
+
+ - If the `Display' subsection for the `fbdev' driver in the /etc/XF86Config
+ file contains a
+
+ Modes "default"
+
+ line, the X server will use the scheme discussed above, i.e. it will start
+ up in the resolution determined by /dev/fb0current (or $FRAMEBUFFER, if
+ set). This is the default for the configuration file supplied with XFree68
+ 3.2. It's the most simple configuration (and the only possible one if you
+ want to have a broadcast compatible display, e.g. PAL or NTSC), but it has
+ some limitations.
+
+ - Therefore it's also possible to specify resolutions in the /etc/XF86Config
+ file. This allows for on-the-fly resolution switching while retaining the
+ same virtual desktop size. The frame buffer device that's used is still
+ /dev/fb0current (or $FRAMEBUFFER), but the available resolutions are
+ defined by /etc/XF86Config now. The disadvantage is that you have to
+ specify the timings in a different format (but `fbset -x' may help) and
+ that you can't have a broadcast compatible display (e.g. no PAL or NTSC).
+
+To tune a video mode, you can use fbset or xvidtune. Note that xvidtune doesn't
+work 100% with XF68_FBDev: the reported clock values are always incorrect.
+
+There exists also an accelerated X server for the Cybervision 64 graphics
+board, but that's not discussed here.
+
+
+5. Video Mode Timings
+---------------------
+
+A monitor draws an image on the screen by using an electron beam (3 electron
+beams for most color models, 1 electron beam for Trinitron color monitors and
+monochrone monitors). The front of the screen is covered by a pattern of
+colored phospors (pixels). If a phospor is hit by an electron, it emits a
+photon and thus becomes visible.
+
+The electron beam draws horizontal lines (scanlines) from left to right, and
+from the top to the bottom of the screen. By modifying the intensity of the
+electron beam, pixels with various colors and intensities can be shown.
+
+After each scanline the electron beam has to move back to the left side of the
+screen and to the next line: this is called the horizontal retrace. After the
+whole screen (frame) was painted, the beam moves back to the upper left corner:
+this is called the vertical retrace. During both the horizontal and vertical
+retrace, the electron beam is turned off (blanked).
+
+The speed at which the electron beam paints the pixels is determined by the
+dotclock in the graphics board. For a dotclock of e.g. 28.37516 MHz (millions
+of cycles per second), each pixel is 35242 ps (picoseconds) long:
+
+ 1/(28.37516E6 Hz) = 35.242E-9 s
+
+If the screen resolution is 640x480, it will take
+
+ 640*35.242E-9 s = 22.555E-6 s
+
+to paint the 640 (xres) pixels on one scanline. But the horizontal retrace
+also takes time (e.g. 272 `pixels'), so a full scanline takes
+
+ (640+272)*35.242E-9 s = 32.141E-6 s
+
+We'll say that the horizontal scanrate is about 31 kHz:
+
+ 1/(32.141E-6 s) = 31.113E3 Hz
+
+A full screen counts 480 (yres) lines, but we have to consider the vertical
+retrace too (e.g. 49 `pixels'). So a full screen will take
+
+ (480+49)*32.141E-6 s = 17.002E-3 s
+
+The vertical scanrate is about 59 Hz:
+
+ 1/(17.002E-3 s) = 58.815 Hz
+
+This means the screen data is refreshed about 59 times per second. To have a
+stable picture without visible flicker, VESA recommends a vertical scanrate of
+at least 72 Hz. But the perceived flicker is very human dependent: some people
+can use 50 Hz without any trouble, while I'll notice if it's less than 80 Hz.
+
+Since the monitor doesn't know when a new scanline starts, the graphics board
+will supply a synchronization pulse (horizontal sync or hsync) for each
+scanline. Similarly it supplies a synchronization pulse (vertical sync or
+vsync) for each new frame. The position of the image on the screen is
+influenced by the moments at which the synchronization pulses occur.
+
+The following picture summarizes all timings. The horizontal retrace time is
+the sum of the left margin, the right margin and the hsync length, while the
+vertical retrace time is the sum of the upper margin, the lower margin and the
+vsync length.
+
+ +----------+---------------------------------------------+----------+-------+
+ | | ^ | | |
+ | | |upper_margin | | |
+ | | ¥ | | |
+ +----------###############################################----------+-------+
+ | # ^ # | |
+ | # | # | |
+ | # | # | |
+ | # | # | |
+ | left # | # right | hsync |
+ | margin # | xres # margin | len |
+ |<-------->#<---------------+--------------------------->#<-------->|<----->|
+ | # | # | |
+ | # | # | |
+ | # | # | |
+ | # |yres # | |
+ | # | # | |
+ | # | # | |
+ | # | # | |
+ | # | # | |
+ | # | # | |
+ | # | # | |
+ | # | # | |
+ | # | # | |
+ | # ¥ # | |
+ +----------###############################################----------+-------+
+ | | ^ | | |
+ | | |lower_margin | | |
+ | | ¥ | | |
+ +----------+---------------------------------------------+----------+-------+
+ | | ^ | | |
+ | | |vsync_len | | |
+ | | ¥ | | |
+ +----------+---------------------------------------------+----------+-------+
+
+The frame buffer device expects all horizontal timings in number of dotclocks
+(in picoseconds, 1E-12 s), and vertical timings in number of scanlines.
+
+
+6. Converting XFree86 timing values info frame buffer device timings
+--------------------------------------------------------------------
+
+An XFree86 mode line consists of the following fields:
+ "800x600" 50 800 856 976 1040 600 637 643 666
+ < name > DCF HR SH1 SH2 HFL VR SV1 SV2 VFL
+
+The frame buffer device uses the following fields:
+
+ - pixclock: pixel clock in ps (pico seconds)
+ - left_margin: time from sync to picture
+ - right_margin: time from picture to sync
+ - upper_margin: time from sync to picture
+ - lower_margin: time from picture to sync
+ - hsync_len: length of horizontal sync
+ - vsync_len: length of vertical sync
+
+1) Pixelclock:
+ xfree: in MHz
+ fb: In Picoseconds (ps)
+
+ pixclock = 1000000 / DCF
+
+2) horizontal timings:
+ left_margin = HFL - SH2
+ right_margin = SH1 - HR
+ hsync_len = SH2 - SH1
+
+3) vertical timings:
+ upper_margin = VFL - SV2
+ lower_margin = SV1 - VR
+ vsync_len = SV2 - SV1
+
+Good examples for VESA timings can be found in the XFree86 source tree,
+under "xc/programs/Xserver/hw/xfree86/doc/modeDB.txt".
+
+
+7. References
+-------------
+
+For more specific information about the frame buffer device and its
+applications, please refer to the following documentation:
+
+ - The manual pages for fbset: fbset(8), fb.modes(5)
+ - The manual pages for XFree68: XF68_FBDev(1), XF86Config(4/5)
+ - The mighty kernel sources:
+ o linux/include/linux/fb.h
+ o linux/drivers/char/fbmem.c
+ o linux/arch/m68k/*/*fb.c
+
+
+8. Downloading
+--------------
+
+All necessary files can be found at
+
+ ftp://ftp.uni-erlangen.de/pub/Linux/LOCAL/680x0/
+
+and on its mirrors.
+
+
+9. Credits
+----------
+
+This readme was written by Geert Uytterhoeven, partly based on the original
+`X-framebuffer.README' by Roman Hodek and Martin Schaller. Section 6 was
+provided by Frank Neumann.
+
+The frame buffer device abstraction was designed by Martin Schaller.
diff --git a/Documentation/m68k/kernel-options.txt b/Documentation/m68k/kernel-options.txt
index b5878662d..ed0c203d0 100644
--- a/Documentation/m68k/kernel-options.txt
+++ b/Documentation/m68k/kernel-options.txt
@@ -800,6 +800,18 @@ hostadapters.
No argument. Used to separate blocks of keywords when there's more
than one host adapter in the system.
+5.3.7) nodma
+------------
+
+Syntax: nodma:x
+
+ If x is 1 (or if the option is just written as "nodma"), the WD33c93
+controller will not use DMA (= direct memory access) to access the
+Amiga's memory. This is useful for some systems (like A3000's and
+A4000's with the A3640 accelerator, revision 3.0) that have problems
+using DMA to chip memory. The default is 0, i.e. to use DMA if
+possible.
+
5.4) gvp11=
-----------
diff --git a/Documentation/networking/net-modules.txt b/Documentation/networking/net-modules.txt
index b83d2bd9f..bdf5a34a1 100644
--- a/Documentation/networking/net-modules.txt
+++ b/Documentation/networking/net-modules.txt
@@ -109,6 +109,10 @@ Card/Module List - Configurable Parameters and Default Values
8390.c:
(No public options, several other modules need this one)
+a2065.c:
+ Since this is a Zorro board, it supports full autoprobing, even for
+ multiple boards. (m68k/Amiga)
+
ac3200.c:
io = 0 (Checks 0x1000 to 0x8fff in 0x1000 intervals)
irq = 0 (Read from config register)
@@ -133,11 +137,24 @@ arcnet.c:
0x310, 0x320, 0x330, 0x340, 0x350, 0x360, 0x370,
0x380, 0x390, 0x3A0, 0x3E0, 0x3F0 )
+ariadne.c:
+ Since this is a Zorro board, it supports full autoprobing, even for
+ multiple boards. (m68k/Amiga)
+
at1700.c:
io = 0x260
irq = 0
(Probes ports: 0x260, 0x280, 0x2A0, 0x240, 0x340, 0x320, 0x380, 0x300)
+atari_bionet.c:
+ Supports full autoprobing. (m68k/Atari)
+
+atari_pamsnet.c:
+ Supports full autoprobing. (m68k/Atari)
+
+atarilance.c:
+ Supports full autoprobing. (m68k/Atari)
+
atp.c: *Not modularized*
(Probes ports: 0x378, 0x278, 0x3BC;
fixed IRQs: 5 and 7 )
@@ -212,6 +229,10 @@ hp100.c:
On ISA-bus probes all ports from 0x100 thru to 0x3E0
in increments of 0x020)
+hydra.c:
+ Since this is a Zorro board, it supports full autoprobing, even for
+ multiple boards. (m68k/Amiga)
+
ibmtr.c:
io = 0xa20, 0xa24 (autoprobed by default)
irq = 0 (driver cannot select irq - read from hardware)
diff --git a/Documentation/serial-console.txt b/Documentation/serial-console.txt
index 22f02e2b7..4d81e4c98 100644
--- a/Documentation/serial-console.txt
+++ b/Documentation/serial-console.txt
@@ -47,7 +47,7 @@ as the serial console. Replace as needed.
Sysvinit remembers its stty settings in a file in /etc, called
`/etc/ioctl.save'. REMOVE THIS FILE before using the serial
console for the first time, because otherwise init will probably
- set the baudrate to 38400 (bausdrate of the virtual console).
+ set the baudrate to 38400 (baudrate of the virtual console).
5. /dev/console and X
Programs that want to do something with the virtual console usually
diff --git a/Documentation/svga.txt b/Documentation/svga.txt
index 049f952ef..8239708f3 100644
--- a/Documentation/svga.txt
+++ b/Documentation/svga.txt
@@ -1,5 +1,5 @@
- Video Mode Selection Support 2.10
- (c) 1995, 1996 Martin Mares, <mj@k332.feld.cvut.cz>
+ Video Mode Selection Support 2.11
+ (c) 1995--1997 Martin Mares, <mj@k332.feld.cvut.cz>
--------------------------------------------------------------------------------
1. Intro
@@ -14,8 +14,9 @@ DESCRIBING YOUR EXPERIENCE WITH IT. BUG REPORTS ARE ALSO WELCOME.
The video mode to be used is selected by a kernel parameter which can be
specified in the kernel Makefile (the SVGA_MODE=... line) or by the "vga=..."
-option of LILO or by the "vidmode" utility (present in standard Linux utility
-packages). You can use the following settings of this parameter:
+option of LILO (or some other boot loader you use) or by the "vidmode" utility
+(present in standard Linux utility packages). You can use the following values
+of this parameter:
NORMAL_VGA - Standard 80x25 mode available on all display adapters.
@@ -39,8 +40,8 @@ packages). You can use the following settings of this parameter:
The ASK_VGA mode causes the kernel to offer a video mode menu upon
bootup. It displays a "Press <RETURN> to see video modes available, <SPACE>
to continue or wait 30 secs" message. If you press <RETURN>, you enter the
-menu, if you press <SPACE> or wait 30 seconds, the kernel will boot up with
-the standard 80x25 mode set.
+menu, if you press <SPACE> or wait 30 seconds, the kernel will boot up in
+the standard 80x25 mode.
The menu looks like:
@@ -51,62 +52,70 @@ Mode: COLSxROWS:
2 0F02 80x43
3 0F03 80x26
....
-Enter mode number: <flashing-cursor-here>
+Enter mode number or `scan': <flashing-cursor-here>
- <name-of-detected-video-adapter> should contain a name of your video adapter
-or the chip in it or at least whether it's an EGA or VGA or VESA VGA (VGA with
-a VESA-compliant BIOS in it). If it doesn't match your configuration, tell me
-and I'll try to fix it somehow (you know, hardware detection is a real pain
-on PC's).
+ <name-of-detected-video-adapter> tells what video adapter did Linux detect
+-- it's either a generic adapter name (MDA, CGA, HGC, EGA, VGA, VESA VGA [a VGA
+with VESA-compliant BIOS]) or a chipset name (e.g., Trident). Direct detection
+of chipsets is turned off by default (see CONFIG_VIDEO_SVGA in chapter 4 to see
+how to enable it if you really want) as it's inherently unreliable due to
+absolutely insane PC design.
"0 0F00 80x25" tells that the first menu item (the menu items are numbered
from "0" to "9" and from "a" to "z") is a 80x25 mode with ID=0x0f00 (see the
-next section for a description of the mode ID's).
+next section for a description of mode ID's).
<flashing-cursor-here> encourages you to write the item number or mode ID
you wish to set and press <RETURN>. If the computer complains something about
"Unknown mode ID", it tries to explain you that it isn't possible to set such
-a mode. It's also possible to press only <RETURN> which forces the current
-mode to be used.
+a mode. It's also possible to press only <RETURN> which leaves the current mode.
- The mode list may be a bit inaccurate on your machine (it isn't possible
-to autodetect all existing video cards and their mutations). Some of the
-modes may be unsettable, some of them might work incorrectly with Linux
-(the common case is mirroring of first few lines at the bottom of the screen
-because of BIOS bugs) or there can exist modes which are not displayed. If
-you think the list doesn't match your configuration, let me know and I'll try
-to add your configuration to the next version of the mode selector.
+ The mode list usually contains only few basic modes and some VESA modes. In
+case your chipset has been detected, some chipset-specific modes are shown as
+well (some of these might be missing or unusable on your machine as different
+BIOSes are often shipped with the same card and the mode numbers depend purely
+on the VGA BIOS).
The modes displayed on the menu are partially sorted: The list starts with
the standard modes (80x25 and 80x50) followed by "special" modes (80x28 and
80x43), local modes (if the local modes feature is enabled), VESA modes and
finally SVGA modes for the auto-detected adapter.
- If you enter "scan" instead of item number / mode ID, the program will try
-to scan your video modes in a slightly aggressive, but much more accurate way.
-This should reveal all video modes supported by your BIOS. During this process,
-the screen will flash wildly and strange things will appear. If you are afraid
-this could damage your monitor, don't use this functions. After scanning, the
-mode ordering is a bit different: the auto-detected SVGA modes are not listed
-at all and the modes revealed by the scan are shown before the VESA modes.
+ If you are not happy with the mode list offered (e.g., if you think your card
+is able to do more), you can enter "scan" instead of item number / mode ID. The
+program will try to ask the BIOS for all possible video mode numbers and test
+what happens then. The screen will be probably flashing wildly for some time and
+strange noises will be heard from inside the monitor and so on and then, really
+all consistent video modes supported by your BIOS will appear (plus maybe some
+`ghost modes'). If you are afraid this could damage your monitor, don't use this
+function.
+
+ After scanning, the mode ordering is a bit different: the auto-detected SVGA
+modes are not listed at all and the modes revealed by `scan' are shown before
+all VESA modes.
3. Mode ID's
~~~~~~~~~~~~
Because of the complexity of all the video stuff, the video mode ID's
used here are also a bit complex. A video mode ID is a 16-bit number usually
-expressed in a hexadecimal notation (starting with "0x"). The ID numbers
-can be divided to three regions:
+expressed in a hexadecimal notation (starting with "0x"). You can set a mode
+by entering its mode directly if you know it even if it isn't shown on the menu.
+
+The ID numbers can be divided to three regions:
- 0x0000 to 0x00ff - menu item references. 0x0000 is the first item.
+ 0x0000 to 0x00ff - menu item references. 0x0000 is the first item. Don't use
+ outside the menu as this can change from boot to boot (especially if you
+ have used the `scan' feature).
0x0100 to 0x017f - standard BIOS modes. The ID is a BIOS video mode number
- (as presented to INT 10, function 00) increased by 0x0100. You can
- use any mode numbers even if not shown on the menu.
+ (as presented to INT 10, function 00) increased by 0x0100.
0x0200 to 0x08ff - VESA BIOS modes. The ID is a VESA mode ID increased by
0x0100. All VESA modes should be autodetected and shown on the menu.
0x0900 to 0x09ff - Video7 special modes. Set by calling INT 0x10, AX=0x6f05.
+ (Usually 940=80x43, 941=132x25, 942=132x44, 943=80x60, 944=100x60,
+ 945=132x28 for the standard Video7 BIOS)
0x0f00 to 0x0fff - special modes (they are set by various tricks -- usually
by modifying one of the standard modes). Currently available:
@@ -123,7 +132,9 @@ can be divided to three regions:
0x1000 to 0x7fff - modes specified by resolution. The code has a "0xRRCC"
form where RR is a number of rows and CC is a number of columns.
E.g., 0x1950 corresponds to a 80x25 mode, 0x2b84 to 132x43 etc.
- This is the only fully portable way to refer to a non-standard mode.
+ This is the only fully portable way to refer to a non-standard mode,
+ but it relies on the mode being found and displayed on the menu
+ (remember that mode scanning is not done automatically).
0xff00 to 0xffff - aliases for backward compatibility:
0xffff equivalent to 0x0f00 (standard 80x25)
@@ -131,8 +142,9 @@ can be divided to three regions:
If you add 0x8000 to the mode ID, the program will try to recalculate
vertical display timing according to mode parameters, which can be used to
-eliminate some annoying bugs of certain VGA BIOS'es -- mainly extra lines at
-the end of the display.
+eliminate some annoying bugs of certain VGA BIOS'es (usually those used for
+cards with S3 chipsets and old Cirrus Logic BIOSes) -- mainly extra lines at the
+end of the display.
4. Options
~~~~~~~~~~
@@ -140,22 +152,27 @@ the end of the display.
All of them are simple #define's -- change them to #undef's when you want to
switch them off. Currently supported:
- CONFIG_VIDEO_SVGA - enables autodetection of SVGA cards. If your card is
-detected incorrectly, you can switch this off.
+ CONFIG_VIDEO_SVGA - enables autodetection of SVGA cards. This is switched
+off by default as it's a bit unreliable due to terribly bad PC design. If you
+really want to have the adapter autodetected (maybe in case the `scan' feature
+doesn't work on your machine), switch this on and don't cry if the results
+are not completely sane. In case you really need this feature, please drop me
+a mail as I think of removing it some day.
CONFIG_VIDEO_VESA - enables autodetection of VESA modes. If it doesn't work
on your machine (or displays a "Error: Scanning of VESA modes failed" message),
you can switch it off and report as a bug.
- CONFIG_VIDEO_COMPACT - enables compacting of the video mode list. Duplicate
-entries (those with the same screen size) are deleted except for the first one
-(see the previous section for more information on mode ordering). However,
-it's possible that the first variant doesn't work, while some of the others do
--- in this case turn this switch off to see the rest.
+ CONFIG_VIDEO_COMPACT - enables compacting of the video mode list. If there
+are more modes with the same screen size, only the first one is kept (see above
+for more info on mode ordering). However, in very strange cases it's possible
+that the first "version" of the mode doesn't work although some of the others
+do -- in this case turn this switch off to see the rest.
CONFIG_VIDEO_RETAIN - enables retaining of screen contents when switching
video modes. Works only with some boot loaders which leave enough room for the
-buffer.
+buffer. (If you have old LILO, you can adjust heap_end_ptr and loadflags
+in setup.S, but it's better to upgrade the boot loader...)
CONFIG_VIDEO_LOCAL - enables inclusion of "local modes" in the list. The
local modes are added automatically to the beginning of the list not depending
@@ -177,25 +194,7 @@ text screen resolution instead of peeking it from BIOS variables. Don't use
unless you think you know what you're doing. To activate this setup, use
mode number 0x0f08 (see section 3).
-5. Adding more cards
-~~~~~~~~~~~~~~~~~~~~
- If you have a card not detected by the driver and you are a good programmer,
-feel free to add it to the source and send me a diff. It's very simple: You
-have to add a new entry to the svga_table consisting of a pointer to your mode
-table and a pointer to your detection routine. The order of entries in the
-svga_table defines the order of probing. Please use only reliable detection
-routines which are known to identify _only_ the card in question.
-
- The detection routine is called with BP pointing to your mode table and
-ES containing 0xc000. If you want, you may alter BP allowing to select an
-appropriate mode table according to model ID detected. If the detection fails,
-return BP=0.
-
- The mode table consists of lines containing a (BIOS mode number, rows,
-columns) triple and is finished by single zero byte followed by NUL-terminated
-adapter name.
-
-6. Still doesn't work?
+5. Still doesn't work?
~~~~~~~~~~~~~~~~~~~~~~
When the mode detection doesn't work (e.g., the mode list is incorrect or
the machine hangs instead of displaying the menu), try to switch off some of
@@ -207,11 +206,11 @@ happens and how do the configuration switches affect the behaviour of the bug.
If you start Linux from the M$-DOS, you might also use some DOS tools for
video mode setting. In this case, you must specify the 0x0f04 mode ("leave
-current settings") to Linux, because if you use anything other, the 80x25
-mode will be used automatically.
+current settings") to Linux, because if you don't and you use any non-standard
+mode, Linux will switch to 80x25 automatically.
- If you set some SVGA mode and there's one or more extra lines on the
-bottom of the display containing already scrolled-out lines, your VGA BIOS
+ If you set some extended mode and there's one or more extra lines on the
+bottom of the display containing already scrolled-out text, your VGA BIOS
contains the most common video BIOS bug called "incorrect vertical display
end setting". Adding 0x8000 to the mode ID might fix the problem. Unfortunately,
this must be done manually -- no autodetection mechanisms are available.
@@ -220,7 +219,7 @@ this must be done manually -- no autodetection mechanisms are available.
is probably broken and you need to set the CONFIG_VIDEO_400_HACK switch to
force setting of the correct mode.
-7. History
+6. History
~~~~~~~~~~
1.0 (??-Nov-95) First version supporting all adapters supported by the old
setup.S + Cirrus Logic 54XX. Present in some 1.3.4? kernels
@@ -266,3 +265,8 @@ force setting of the correct mode.
- Added the CONFIG_VIDEO_400_HACK switch.
- Added the CONFIG_VIDEO_GFX_HACK switch.
- Code cleanup.
+2.11 (03-May-97)- Yet another cleanup, now including also the documentation.
+ - Direct testing of SVGA adapters turned off by default, `scan'
+ offered explicitly on the prompt line.
+ - Removed the doc section describing adding of new probing
+ functions as I try to get rid of _all_ hardware probing here.
diff --git a/MAINTAINERS b/MAINTAINERS
index 4325f02c6..7ff7cefac 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -234,6 +234,13 @@ M: fritz@wuemaus.franken.de
L: isdn4linux@hub-wue.franken.de
S: Maintained
+M68K:
+P: Jes Sorensen
+M: Jes.Sorensen@cern.ch
+W: http://www.clark.net/pub/lawrencc/linux/index.html
+L: linux-m68k@phil.uni-sb.de
+S: Maintained
+
MODULE SUPPORT [GENERAL], KERNELD
P: Bjorn Ekwall
M: bj0rn@blox.se
@@ -343,11 +350,12 @@ L: linux-kernel@vger.rutgers.edu
W: http://www-plateau.cs.berkeley.edu/people/chaffee
S: Maintained
-DIGIBOARD DRIVER:
-P: Christoph Lameter
-M: clameter@fuller.edu
-L: digiboard@list.fuller.edu
-S: Maintained
+DIGI INTL. EPCA DRIVER:
+P: Daniel Taylor
+M: support@dgii.com
+M: digilnux@dgii.com
+L: digiboard@list.fuller.edu
+S: Maintained
RISCOM8 DRIVER:
P: Dmitry Gorodchanin
diff --git a/Makefile b/Makefile
index e4ff784ae..b4a619f7f 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
VERSION = 2
PATCHLEVEL = 1
-SUBLEVEL = 36
+SUBLEVEL = 40
ARCH = mips
@@ -25,8 +25,8 @@ TOPDIR := $(shell if [ "$$PWD" != "" ]; then echo $$PWD; else pwd; fi)
HPATH = $(TOPDIR)/include
-HOSTCC = gcc
-HOSTCFLAGS = -O2 -fomit-frame-pointer
+HOSTCC = cc
+HOSTCFLAGS = -O2
CROSS_COMPILE =
@@ -186,7 +186,7 @@ vmlinux: $(CONFIGURATION) init/main.o init/version.o linuxsubdirs
$(DRIVERS) \
$(LIBS) \
-o vmlinux
- $(NM) vmlinux | grep -v '\(compiled\)\|\(\.o$$\)\|\( a \)\|\(\.\.ng$$\)' | sort > System.map
+ $(NM) vmlinux | grep -v '\(compiled\)\|\(\.o$$\)\|\( [aU] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | sort > System.map
symlinks:
rm -f include/asm
@@ -357,6 +357,8 @@ distclean: mrproper
rm -f core `find . \( -name '*.orig' -o -name '*.rej' -o -name '*~' \
-o -name '*.bak' -o -name '#*#' -o -name '.*.orig' \
-o -name '.*.rej' -o -name '.SUMS' -o -size 0 \) -print` TAGS
+ rm -f drivers/sound/Config.in
+ cp drivers/sound/Config.std drivers/sound/Config.in
backup: mrproper
cd .. && tar cf - linux/ | gzip -9 > backup.gz
@@ -367,7 +369,7 @@ sums:
dep-files: scripts/mkdep archdep include/linux/version.h
scripts/mkdep init/*.c > .tmpdepend
- scripts/mkdep `find $(FINDHPATH) -follow -name \*.h ! -name modversions.h -print` > .hdepend
+ find $(FINDHPATH) -follow -name \*.h ! -name modversions.h -print | xargs scripts/mkdep > .hdepend
set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i fastdep; done
mv .tmpdepend .depend
diff --git a/arch/alpha/defconfig b/arch/alpha/defconfig
index a6ee5a17c..0c3c65d28 100644
--- a/arch/alpha/defconfig
+++ b/arch/alpha/defconfig
@@ -42,6 +42,13 @@ CONFIG_SYSVIPC=y
CONFIG_SYSCTL=y
CONFIG_BINFMT_AOUT=y
CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_EM86=y
+# CONFIG_PNP_PARPORT is not set
+
+#
+# Plug and Play support
+#
+# CONFIG_PNP is not set
#
# Floppy, IDE, and other block devices
@@ -72,9 +79,10 @@ CONFIG_BLK_DEV_RAM=y
# CONFIG_FIREWALL is not set
# CONFIG_NET_ALIAS is not set
CONFIG_INET=y
-# CONFIG_IP_FORWARD is not set
# CONFIG_IP_MULTICAST is not set
# CONFIG_IP_ACCT is not set
+# CONFIG_IP_ROUTER is not set
+# CONFIG_NET_IPIP is not set
#
# (it is safe to leave these untouched)
@@ -133,11 +141,11 @@ CONFIG_SCSI_CONSTANTS=y
# CONFIG_SCSI_NCR53C406A is not set
# CONFIG_SCSI_NCR53C7xx is not set
# CONFIG_SCSI_NCR53C8XX is not set
-# CONFIG_SCSI_PPA is not set
# CONFIG_SCSI_PAS16 is not set
# CONFIG_SCSI_QLOGIC_FAS is not set
CONFIG_SCSI_QLOGIC_ISP=y
# CONFIG_SCSI_SEAGATE is not set
+# CONFIG_SCSI_DC390T is not set
# CONFIG_SCSI_T128 is not set
# CONFIG_SCSI_U14_34F is not set
# CONFIG_SCSI_ULTRASTOR is not set
@@ -155,19 +163,22 @@ CONFIG_NET_ETHERNET=y
# CONFIG_NET_VENDOR_SMC is not set
# CONFIG_NET_ISA is not set
CONFIG_NET_EISA=y
+# CONFIG_PCNET32 is not set
# CONFIG_APRICOT is not set
+# CONFIG_CS89x0 is not set
CONFIG_DE4X5=y
# CONFIG_DEC_ELCP is not set
# CONFIG_DGRS is not set
+# CONFIG_EEXPRESS_PRO100 is not set
# CONFIG_NET_POCKET is not set
# CONFIG_FDDI is not set
# CONFIG_DLCI is not set
-# CONFIG_PLIP is not set
# CONFIG_PPP is not set
# CONFIG_NET_RADIO is not set
-# CONFIG_LAPBETHER is not set
# CONFIG_SLIP is not set
# CONFIG_TR is not set
+# CONFIG_LAPBETHER is not set
+# CONFIG_X25_ASY is not set
#
# ISDN subsystem
@@ -192,12 +203,16 @@ CONFIG_MSDOS_FS=y
CONFIG_PROC_FS=y
CONFIG_NFS_FS=y
# CONFIG_ROOT_NFS is not set
+# CONFIG_NFSD is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
# CONFIG_SMB_FS is not set
CONFIG_ISO9660_FS=y
# CONFIG_HPFS_FS is not set
# CONFIG_SYSV_FS is not set
# CONFIG_AFFS_FS is not set
# CONFIG_ROMFS_FS is not set
+# CONFIG_AUTOFS_FS is not set
# CONFIG_UFS_FS is not set
#
@@ -206,12 +221,8 @@ CONFIG_ISO9660_FS=y
CONFIG_VT=y
CONFIG_VT_CONSOLE=y
CONFIG_SERIAL=y
-# CONFIG_DIGI is not set
-# CONFIG_CYCLADES is not set
-# CONFIG_STALDRV is not set
-# CONFIG_RISCOM8 is not set
-# CONFIG_ESPSERIAL is not set
-# CONFIG_PRINTER is not set
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
CONFIG_MOUSE=y
# CONFIG_ATIXL_BUSMOUSE is not set
# CONFIG_BUSMOUSE is not set
@@ -224,7 +235,6 @@ CONFIG_PSMOUSE=y
# CONFIG_APM is not set
# CONFIG_WATCHDOG is not set
# CONFIG_RTC is not set
-CONFIG_RTC_ARC=y
#
# Sound
diff --git a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S
index ef582b80e..af26f8996 100644
--- a/arch/alpha/kernel/entry.S
+++ b/arch/alpha/kernel/entry.S
@@ -126,7 +126,8 @@
.ent entInt
entInt:
SAVE_ALL
- ldq $8,current_set
+ lda $8,0x3fff
+ bic $30,$8,$8
jsr $26,do_entInt
br $31,ret_from_sys_call
.end entInt
@@ -147,7 +148,8 @@ entMM:
stq $15,48($30)
addq $30,56,$19
/* handle the fault */
- ldq $8,current_set
+ lda $8,0x3fff
+ bic $30,$8,$8
jsr $26,do_page_fault
/* reload the registers after the exception code played. */
ldq $9,0($30)
@@ -167,7 +169,8 @@ entMM:
.ent entArith
entArith:
SAVE_ALL
- ldq $8,current_set
+ lda $8,0x3fff
+ bic $30,$8,$8
/* How much of a win is this clockwise? We are, after all, messing
up the call/return prefetch stack. -- rth */
lda $27,do_entArith
@@ -180,7 +183,8 @@ entArith:
.ent entIF
entIF:
SAVE_ALL
- ldq $8,current_set
+ lda $8,0x3fff
+ bic $30,$8,$8
lda $27,do_entIF
lda $26,ret_from_sys_call
jsr $31,($27),do_entIF
@@ -221,12 +225,13 @@ kernel_clone:
.globl __kernel_thread
.ent __kernel_thread
__kernel_thread:
+ ldgp $29,0($27) /* we can be called from a module */
.frame $30, 4*8, $26
subq $30,4*8,$30
stq $10,16($30)
stq $9,8($30)
stq $26,0($30)
- .prologue 0
+ .prologue 1
bis $17,$17,$9 /* save fn */
bis $18,$18,$10 /* save arg */
bsr $26,kernel_clone
@@ -238,10 +243,9 @@ __kernel_thread:
ret $31,($26),1
/* this is in child: look out as we don't have any stack here.. */
1: bis $9,$9,$27 /* get fn */
- br $29,2f
-2: ldgp $29,0($29)
+ lda $8,0x3fff
bis $10,$10,$16 /* get arg */
- ldq $8,current_set
+ bic $30,$8,$8 /* get current */
jsr $26,($27)
bis $0,$0,$16
jsr $26,sys_exit
@@ -382,7 +386,8 @@ entUna:
stq $29,232($30)
stq $30,240($30)
stq $31,248($30)
- ldq $8,current_set
+ lda $8,0x3fff
+ bic $30,$8,$8
jsr $26,do_entUna
ldq $0,0($30)
ldq $1,8($30)
@@ -432,7 +437,8 @@ entUnaUser:
stq $14,40($30)
stq $15,48($30)
bis $31,$30,$19
- ldq $8,current_set
+ lda $8,0x3fff
+ bic $30,$8,$8
jsr $26,do_entUnaUser
ldq $9,0($30)
ldq $10,8($30)
@@ -497,7 +503,8 @@ alpha_switch_to:
.ent entSys
entSys:
SAVE_ALL
- ldq $8,current_set
+ lda $8,0x3fff
+ bic $30,$8,$8
lda $4,NR_SYSCALLS($31)
stq $16,SP_OFF+24($30)
lda $5,sys_call_table
@@ -532,7 +539,7 @@ ret_from_handle_bh:
ret_from_reschedule:
lda $0,need_resched
ldl $2,0($0)
- lda $4,init_task
+ lda $4,init_task_union
bne $2,reschedule
xor $4,$8,$4
beq $4,restore_all
diff --git a/arch/alpha/kernel/head.S b/arch/alpha/kernel/head.S
index 17ca4581a..f76213624 100644
--- a/arch/alpha/kernel/head.S
+++ b/arch/alpha/kernel/head.S
@@ -23,9 +23,11 @@ _stext:
__start:
br $27,1f
1: ldgp $29,0($27)
- /* We need to get current loaded up with our first task. */
- ldq $8,current_set
- /* And then we can start the kernel. */
+ /* We need to get current loaded up with our first task... */
+ lda $8,init_task_union
+ /* ... and find our stack ... */
+ lda $30,0x4000($8)
+ /* ... and then we can start the kernel. */
jsr $26,start_kernel
halt
.end __start
@@ -63,22 +65,6 @@ rdusp:
.end rdusp
.align 3
- .globl tbi
- .ent tbi
-tbi:
- call_pal PAL_tbi
- ret ($26)
- .end tbi
-
- .align 3
- .globl imb
- .ent imb
-imb:
- call_pal PAL_imb
- ret ($26)
- .end imb
-
- .align 3
.globl rdmces
.ent rdmces
rdmces:
diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c
index 2eb2d51b7..b6c97e726 100644
--- a/arch/alpha/kernel/process.c
+++ b/arch/alpha/kernel/process.c
@@ -37,6 +37,24 @@
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/io.h>
+#include <asm/pgtable.h>
+
+/*
+ * Initial task structure. Make this a per-architecture thing,
+ * because different architectures tend to have different
+ * alignment requirements and potentially different initial
+ * setup.
+ */
+
+unsigned long init_user_stack[1024] = { STACK_MAGIC, };
+static struct vm_area_struct init_mmap = INIT_MMAP;
+static struct fs_struct init_fs = INIT_FS;
+static struct files_struct init_files = INIT_FILES;
+static struct signal_struct init_signals = INIT_SIGNALS;
+struct mm_struct init_mm = INIT_MM;
+
+union task_union init_task_union __attribute__((section("init_task")))
+ = { task: INIT_TASK };
/*
* No need to acquire the kernel lock, we're entirely local..
@@ -186,7 +204,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
stack_offset = PAGE_SIZE - sizeof(struct pt_regs);
if (!(regs->ps & 8))
stack_offset = (PAGE_SIZE-1) & (unsigned long) regs;
- childregs = (struct pt_regs *) (p->kernel_stack_page + stack_offset);
+ childregs = (struct pt_regs *) (stack_offset + PAGE_SIZE + (unsigned long)p);
*childregs = *regs;
childregs->r0 = 0;
diff --git a/arch/alpha/kernel/ptrace.c b/arch/alpha/kernel/ptrace.c
index 019fb6b95..c388f0b51 100644
--- a/arch/alpha/kernel/ptrace.c
+++ b/arch/alpha/kernel/ptrace.c
@@ -67,7 +67,7 @@
* | | |
* | | v
* +================================+ <-------------------------
- * task->kernel_stack_page
+ * task + PAGE_SIZE
*/
#define PT_REG(reg) (PAGE_SIZE - sizeof(struct pt_regs) \
+ (long)&((struct pt_regs *)0)->reg)
@@ -107,19 +107,6 @@ static unsigned short regoff[] = {
static long zero;
-
-/* change a pid into a task struct. */
-static inline struct task_struct * get_task(int pid)
-{
- int i;
-
- for (i = 1; i < NR_TASKS; i++) {
- if (task[i] != NULL && (task[i]->pid == pid))
- return task[i];
- }
- return NULL;
-}
-
/*
* Get contents of register REGNO in task TASK.
*/
@@ -133,7 +120,7 @@ static inline long get_reg(struct task_struct * task, long regno)
zero = 0;
addr = &zero;
} else {
- addr = (long *) (task->kernel_stack_page + regoff[regno]);
+ addr = (long *) (regoff[regno] + PAGE_SIZE + (long)task);
}
return *addr;
}
@@ -150,7 +137,7 @@ static inline int put_reg(struct task_struct *task, long regno, long data)
} else if (regno == 31) {
addr = &zero;
} else {
- addr = (long *) (task->kernel_stack_page + regoff[regno]);
+ addr = (long *) (regoff[regno] + PAGE_SIZE + (long)task);
}
*addr = data;
return 0;
@@ -174,7 +161,7 @@ static unsigned long get_long(struct task_struct * tsk,
repeat:
pgdir = pgd_offset(vma->vm_mm, addr);
if (pgd_none(*pgdir)) {
- do_no_page(tsk, vma, addr, 0);
+ handle_mm_fault(tsk, vma, addr, 0);
goto repeat;
}
if (pgd_bad(*pgdir)) {
@@ -184,7 +171,7 @@ repeat:
}
pgmiddle = pmd_offset(pgdir, addr);
if (pmd_none(*pgmiddle)) {
- do_no_page(tsk, vma, addr, 0);
+ handle_mm_fault(tsk, vma, addr, 0);
goto repeat;
}
if (pmd_bad(*pgmiddle)) {
@@ -194,7 +181,7 @@ repeat:
}
pgtable = pte_offset(pgmiddle, addr);
if (!pte_present(*pgtable)) {
- do_no_page(tsk, vma, addr, 0);
+ handle_mm_fault(tsk, vma, addr, 0);
goto repeat;
}
page = pte_page(*pgtable);
@@ -225,7 +212,7 @@ static void put_long(struct task_struct * tsk, struct vm_area_struct * vma,
repeat:
pgdir = pgd_offset(vma->vm_mm, addr);
if (!pgd_present(*pgdir)) {
- do_no_page(tsk, vma, addr, 1);
+ handle_mm_fault(tsk, vma, addr, 1);
goto repeat;
}
if (pgd_bad(*pgdir)) {
@@ -235,7 +222,7 @@ repeat:
}
pgmiddle = pmd_offset(pgdir, addr);
if (pmd_none(*pgmiddle)) {
- do_no_page(tsk, vma, addr, 1);
+ handle_mm_fault(tsk, vma, addr, 1);
goto repeat;
}
if (pmd_bad(*pgmiddle)) {
@@ -245,12 +232,12 @@ repeat:
}
pgtable = pte_offset(pgmiddle, addr);
if (!pte_present(*pgtable)) {
- do_no_page(tsk, vma, addr, 1);
+ handle_mm_fault(tsk, vma, addr, 1);
goto repeat;
}
page = pte_page(*pgtable);
if (!pte_write(*pgtable)) {
- do_wp_page(tsk, vma, addr, 1);
+ handle_mm_fault(tsk, vma, addr, 1);
goto repeat;
}
/* this is a hack for non-kernel-mapped video buffers and similar */
@@ -507,7 +494,7 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data,
if (pid == 1) /* you may not mess with init */
goto out;
ret = -ESRCH;
- if (!(child = get_task(pid)))
+ if (!(child = find_task_by_pid(pid)))
goto out;
if (request == PTRACE_ATTACH) {
ret = -EPERM;
diff --git a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c
index 0fa1129ee..31a1f21fc 100644
--- a/arch/alpha/kernel/setup.c
+++ b/arch/alpha/kernel/setup.c
@@ -21,9 +21,9 @@
#include <linux/tty.h>
#include <linux/delay.h>
#include <linux/config.h> /* CONFIG_ALPHA_LCA etc */
+#include <linux/ioport.h>
#ifdef CONFIG_RTC
-#include <linux/ioport.h>
#include <linux/timex.h>
#endif
diff --git a/arch/alpha/mm/fault.c b/arch/alpha/mm/fault.c
index a7b1e6f2c..a8bc34108 100644
--- a/arch/alpha/mm/fault.c
+++ b/arch/alpha/mm/fault.c
@@ -97,7 +97,7 @@ good_area:
if (!(vma->vm_flags & VM_WRITE))
goto bad_area;
}
- handle_mm_fault(vma, address, cause > 0);
+ handle_mm_fault(tsk, vma, address, cause > 0);
up(&mm->mmap_sem);
return;
diff --git a/arch/alpha/mm/init.c b/arch/alpha/mm/init.c
index 13e8e4ce4..67faa97d4 100644
--- a/arch/alpha/mm/init.c
+++ b/arch/alpha/mm/init.c
@@ -133,7 +133,6 @@ unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)
init_task.tss.ptbr = newptbr;
init_task.tss.pal_flags = 1; /* set FEN, clear everything else */
init_task.tss.flags = 0;
- init_task.kernel_stack_page = INIT_STACK;
load_PCB(&init_task.tss);
flush_tlb_all();
@@ -182,7 +181,7 @@ void free_initmem (void)
atomic_set(&mem_map[MAP_NR(addr)].count, 1);
free_page(addr);
}
- printk ("Freeing unused kernel memory: %dk freed\n",
+ printk ("Freeing unused kernel memory: %ldk freed\n",
(&__init_end - &__init_begin) >> 10);
}
diff --git a/arch/alpha/vmlinux.lds b/arch/alpha/vmlinux.lds
index 2a5f00989..0fb2276ea 100644
--- a/arch/alpha/vmlinux.lds
+++ b/arch/alpha/vmlinux.lds
@@ -5,6 +5,7 @@ SECTIONS
. = 0xfffffc0000310000;
_text = .;
.text : { *(.text) }
+ .text2 : { *(.text2) }
_etext = .;
/* Exception table */
@@ -25,9 +26,12 @@ SECTIONS
__init_begin = .;
.text.init : { *(.text.init) }
.data.init : { *(.data.init) }
- . = ALIGN(8192);
+ . = ALIGN(2*8192); /* Align double page for init_task_union */
__init_end = .;
+ /* The initial task and kernel stack */
+ init_task : { *(init_task) }
+
/* Global data */
_data = .;
.rodata : { *(.rodata) }
diff --git a/arch/i386/Makefile b/arch/i386/Makefile
index c67b8671a..bc4e03029 100644
--- a/arch/i386/Makefile
+++ b/arch/i386/Makefile
@@ -45,7 +45,7 @@ ifdef SMP
CFLAGS := $(CFLAGS) -D__SMP__
endif
-HEAD := arch/i386/kernel/head.o
+HEAD := arch/i386/kernel/head.o arch/i386/kernel/init_task.o
SUBDIRS := $(SUBDIRS) arch/i386/kernel arch/i386/mm arch/i386/lib
CORE_FILES := arch/i386/kernel/kernel.o arch/i386/mm/mm.o $(CORE_FILES)
@@ -85,7 +85,7 @@ bzdisk: vmlinux
@$(MAKEBOOT) BOOTIMAGE=bzImage zdisk
install: vmlinux
- @$(MAKEBOOT) install
+ @$(MAKEBOOT) BOOTIMAGE=bzImage install
archclean:
@$(MAKEBOOT) clean
diff --git a/arch/i386/boot/video.S b/arch/i386/boot/video.S
index 8507b7081..d09f11283 100644
--- a/arch/i386/boot/video.S
+++ b/arch/i386/boot/video.S
@@ -1,12 +1,13 @@
!
-! Display adapter & video mode setup, version 2.10 (11-Nov-96)
+! Display adapter & video mode setup, version 2.11 (03-May-97)
!
-! Copyright (C) 1995, 1996 Martin Mares <mj@k332.feld.cvut.cz>
+! Copyright (C) 1995 -- 1997 Martin Mares <mj@k332.feld.cvut.cz>
! Based on the original setup.S code (C) Linus Torvalds and Mats Anderson
!
-! Enable autodetection of SVGA adapters and modes
-#define CONFIG_VIDEO_SVGA
+! Enable autodetection of SVGA adapters and modes. If you really need this
+! feature, drop me a mail as I think of removing it some day...
+#undef CONFIG_VIDEO_SVGA
! Enable autodetection of VESA modes
#define CONFIG_VIDEO_VESA
@@ -1807,11 +1808,11 @@ listhdr: db 0x0d, 0x0a
.ascii "Mode: COLSxROWS:"
crlft: db 0x0d, 0x0a, 0
prompt: db 0x0d, 0x0a
- .ascii "Enter mode number: "
+ .ascii "Enter mode number or `scan': "
db 0
unknt: .ascii "Unknown mode ID. Try again."
db 0
-badmdt: .ascii "You passed an undefined mode number to setup."
+badmdt: .ascii "You passed an undefined mode number."
db 0x0d, 0x0a, 0
vesaer: .ascii "Error: Scanning of VESA modes failed. Please "
.ascii "report to <mj@k332.feld.cvut.cz>."
diff --git a/arch/i386/defconfig b/arch/i386/defconfig
index e5b5d9f84..a27b6ebce 100644
--- a/arch/i386/defconfig
+++ b/arch/i386/defconfig
@@ -141,6 +141,7 @@ CONFIG_SCSI_OMIT_FLASHPOINT=y
# CONFIG_SCSI_QLOGIC_FAS is not set
# CONFIG_SCSI_QLOGIC_ISP is not set
# CONFIG_SCSI_SEAGATE is not set
+# CONFIG_SCSI_DC390T is not set
# CONFIG_SCSI_T128 is not set
# CONFIG_SCSI_U14_34F is not set
# CONFIG_SCSI_ULTRASTOR is not set
diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile
index e04fb5efb..9491ef562 100644
--- a/arch/i386/kernel/Makefile
+++ b/arch/i386/kernel/Makefile
@@ -15,7 +15,7 @@ else
$(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o
endif
-all: kernel.o head.o
+all: kernel.o head.o init_task.o
O_TARGET := kernel.o
O_OBJS := process.o signal.o entry.o traps.o irq.o vm86.o bios32.o \
diff --git a/arch/i386/kernel/bios32.c b/arch/i386/kernel/bios32.c
index e128000c3..157e62b2d 100644
--- a/arch/i386/kernel/bios32.c
+++ b/arch/i386/kernel/bios32.c
@@ -1,6 +1,8 @@
/*
* bios32.c - BIOS32, PCI BIOS functions.
*
+ * $Id: bios32.c,v 1.11 1997/05/07 13:35:21 mj Exp $
+ *
* Sponsored by
* iX Multiuser Multitasking Magazine
* Hannover, Germany
@@ -52,6 +54,11 @@
* Feb 3, 1997 : Set internal functions to static, save/restore flags
* avoid dead locks reading broken PCI BIOS, werner@suse.de
*
+ * Apr 26, 1997 : Fixed case when there is BIOS32, but not PCI BIOS
+ * (mj@atrey.karlin.mff.cuni.cz)
+ *
+ * May 7, 1997 : Added some missing cli()'s. [mj]
+ *
*/
#include <linux/config.h>
@@ -158,7 +165,7 @@ static unsigned long bios32_service(unsigned long service)
unsigned long entry; /* %edx */
unsigned long flags;
- save_flags(flags);
+ save_flags(flags); cli();
__asm__("lcall (%%edi)"
: "=a" (return_code),
"=b" (address),
@@ -173,10 +180,10 @@ static unsigned long bios32_service(unsigned long service)
case 0:
return address + entry;
case 0x80: /* Not present */
- printk("bios32_service(%ld) : not present\n", service);
+ printk("bios32_service(0x%lx) : not present\n", service);
return 0;
default: /* Shouldn't happen */
- printk("bios32_service(%ld) : returned 0x%x, mail drew@colorado.edu\n",
+ printk("bios32_service(0x%lx) : returned 0x%x, mail drew@colorado.edu\n",
service, return_code);
return 0;
}
@@ -189,7 +196,7 @@ static struct {
} pci_indirect = { 0, KERNEL_CS };
-__initfunc(static unsigned long check_pcibios(unsigned long memory_start, unsigned long memory_end))
+__initfunc(static int check_pcibios(void))
{
unsigned long signature;
unsigned char present_status;
@@ -201,7 +208,7 @@ __initfunc(static unsigned long check_pcibios(unsigned long memory_start, unsign
if ((pcibios_entry = bios32_service(PCI_SERVICE))) {
pci_indirect.address = pcibios_entry | PAGE_OFFSET;
- save_flags(flags);
+ save_flags(flags); cli();
__asm__("lcall (%%edi)\n\t"
"jc 1f\n\t"
"xor %%ah, %%ah\n"
@@ -212,7 +219,7 @@ __initfunc(static unsigned long check_pcibios(unsigned long memory_start, unsign
: "1" (PCIBIOS_PCI_BIOS_PRESENT),
"D" (&pci_indirect)
: "bx", "cx");
- restore_flags(flags);
+ restore_flags(flags);
present_status = (pack >> 16) & 0xff;
major_revision = (pack >> 8) & 0xff;
@@ -232,9 +239,10 @@ __initfunc(static unsigned long check_pcibios(unsigned long memory_start, unsign
if (pcibios_entry) {
printk ("pcibios_init : PCI BIOS revision %x.%02x entry at 0x%lx\n",
major_revision, minor_revision, pcibios_entry);
+ return 1;
}
}
- return memory_start;
+ return 0;
}
@@ -245,7 +253,7 @@ static int pci_bios_find_class (unsigned int class_code, unsigned short index,
unsigned long ret;
unsigned long flags;
- save_flags(flags);
+ save_flags(flags); cli();
__asm__ ("lcall (%%edi)\n\t"
"jc 1f\n\t"
"xor %%ah, %%ah\n"
@@ -270,7 +278,7 @@ static int pci_bios_find_device (unsigned short vendor, unsigned short device_id
unsigned short ret;
unsigned long flags;
- save_flags(flags);
+ save_flags(flags); cli();
__asm__("lcall (%%edi)\n\t"
"jc 1f\n\t"
"xor %%ah, %%ah\n"
@@ -295,7 +303,7 @@ static int pci_bios_read_config_byte(unsigned char bus,
unsigned long bx = (bus << 8) | device_fn;
unsigned long flags;
- save_flags(flags);
+ save_flags(flags); cli();
__asm__("lcall (%%esi)\n\t"
"jc 1f\n\t"
"xor %%ah, %%ah\n"
@@ -317,7 +325,7 @@ static int pci_bios_read_config_word (unsigned char bus,
unsigned long bx = (bus << 8) | device_fn;
unsigned long flags;
- save_flags(flags);
+ save_flags(flags); cli();
__asm__("lcall (%%esi)\n\t"
"jc 1f\n\t"
"xor %%ah, %%ah\n"
@@ -339,7 +347,7 @@ static int pci_bios_read_config_dword (unsigned char bus,
unsigned long bx = (bus << 8) | device_fn;
unsigned long flags;
- save_flags(flags);
+ save_flags(flags); cli();
__asm__("lcall (%%esi)\n\t"
"jc 1f\n\t"
"xor %%ah, %%ah\n"
@@ -361,7 +369,7 @@ static int pci_bios_write_config_byte (unsigned char bus,
unsigned long bx = (bus << 8) | device_fn;
unsigned long flags;
- save_flags(flags);
+ save_flags(flags); cli();
__asm__("lcall (%%esi)\n\t"
"jc 1f\n\t"
"xor %%ah, %%ah\n"
@@ -383,7 +391,7 @@ static int pci_bios_write_config_word (unsigned char bus,
unsigned long bx = (bus << 8) | device_fn;
unsigned long flags;
- save_flags(flags);
+ save_flags(flags); cli();
__asm__("lcall (%%esi)\n\t"
"jc 1f\n\t"
"xor %%ah, %%ah\n"
@@ -405,7 +413,7 @@ static int pci_bios_write_config_dword (unsigned char bus,
unsigned long bx = (bus << 8) | device_fn;
unsigned long flags;
- save_flags(flags);
+ save_flags(flags); cli();
__asm__("lcall (%%esi)\n\t"
"jc 1f\n\t"
"xor %%ah, %%ah\n"
@@ -476,7 +484,7 @@ static int pci_direct_find_class (unsigned int class_code, unsigned short index,
struct pci_dev *dev;
unsigned long flags;
- save_flags(flags);
+ save_flags(flags); cli();
for (dev = pci_devices; dev; dev = dev->next) {
if (dev->class == class_code) {
if (curr == index) {
@@ -502,7 +510,7 @@ static int pci_conf1_read_config_byte(unsigned char bus, unsigned char device_fn
{
unsigned long flags;
- save_flags(flags);
+ save_flags(flags); cli();
outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
switch (where & 3) {
case 0: *value = inb(0xCFC);
@@ -523,7 +531,7 @@ static int pci_conf1_read_config_word (unsigned char bus,
{
unsigned long flags;
- save_flags(flags);
+ save_flags(flags); cli();
outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
if (where & 2)
*value = inw(0xCFE);
@@ -538,7 +546,7 @@ static int pci_conf1_read_config_dword (unsigned char bus, unsigned char device_
{
unsigned long flags;
- save_flags(flags);
+ save_flags(flags); cli();
outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
*value = inl(0xCFC);
restore_flags(flags);
@@ -550,7 +558,7 @@ static int pci_conf1_write_config_byte (unsigned char bus, unsigned char device_
{
unsigned long flags;
- save_flags(flags);
+ save_flags(flags); cli();
outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
outb(value, 0xCFC);
restore_flags(flags);
@@ -562,7 +570,7 @@ static int pci_conf1_write_config_word (unsigned char bus, unsigned char device_
{
unsigned long flags;
- save_flags(flags);
+ save_flags(flags); cli();
outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
outw(value, 0xCFC);
restore_flags(flags);
@@ -574,7 +582,7 @@ static int pci_conf1_write_config_dword (unsigned char bus, unsigned char device
{
unsigned long flags;
- save_flags(flags);
+ save_flags(flags); cli();
outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
outl(value, 0xCFC);
restore_flags(flags);
@@ -610,7 +618,7 @@ static int pci_conf2_read_config_byte(unsigned char bus, unsigned char device_fn
if (device_fn & 0x80)
return PCIBIOS_DEVICE_NOT_FOUND;
- save_flags(flags);
+ save_flags(flags); cli();
outb (FUNC(device_fn), 0xCF8);
outb (bus, 0xCFA);
*value = inb(IOADDR(device_fn,where));
@@ -626,7 +634,7 @@ static int pci_conf2_read_config_word (unsigned char bus, unsigned char device_f
if (device_fn & 0x80)
return PCIBIOS_DEVICE_NOT_FOUND;
- save_flags(flags);
+ save_flags(flags); cli();
outb (FUNC(device_fn), 0xCF8);
outb (bus, 0xCFA);
*value = inw(IOADDR(device_fn,where));
@@ -642,7 +650,7 @@ static int pci_conf2_read_config_dword (unsigned char bus, unsigned char device_
if (device_fn & 0x80)
return PCIBIOS_DEVICE_NOT_FOUND;
- save_flags(flags);
+ save_flags(flags); cli();
outb (FUNC(device_fn), 0xCF8);
outb (bus, 0xCFA);
*value = inl (IOADDR(device_fn,where));
@@ -656,7 +664,7 @@ static int pci_conf2_write_config_byte (unsigned char bus, unsigned char device_
{
unsigned long flags;
- save_flags(flags);
+ save_flags(flags); cli();
outb (FUNC(device_fn), 0xCF8);
outb (bus, 0xCFA);
outb (value, IOADDR(device_fn,where));
@@ -670,7 +678,7 @@ static int pci_conf2_write_config_word (unsigned char bus, unsigned char device_
{
unsigned long flags;
- save_flags(flags);
+ save_flags(flags); cli();
outb (FUNC(device_fn), 0xCF8);
outb (bus, 0xCFA);
outw (value, IOADDR(device_fn,where));
@@ -684,7 +692,7 @@ static int pci_conf2_write_config_dword (unsigned char bus, unsigned char device
{
unsigned long flags;
- save_flags(flags);
+ save_flags(flags); cli();
outb (FUNC(device_fn), 0xCF8);
outb (bus, 0xCFA);
outl (value, IOADDR(device_fn,where));
@@ -716,7 +724,7 @@ __initfunc(static struct pci_access *check_direct_pci(void))
unsigned int tmp;
unsigned long flags;
- save_flags(flags);
+ save_flags(flags); cli();
/*
* check if configuration type 1 works
@@ -912,13 +920,11 @@ __initfunc(unsigned long pcibios_init(unsigned long memory_start, unsigned long
bios32_entry = check->fields.entry;
printk ("pcibios_init : BIOS32 Service Directory entry at 0x%lx\n", bios32_entry);
bios32_indirect.address = bios32_entry + PAGE_OFFSET;
- access_pci = &pci_bios_access;
}
}
}
- if (bios32_entry) {
- memory_start = check_pcibios (memory_start, memory_end);
- }
+ if (bios32_entry && check_pcibios())
+ access_pci = &pci_bios_access;
#endif
return memory_start;
}
diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S
index 84fe0c7fd..ac67da797 100644
--- a/arch/i386/kernel/entry.S
+++ b/arch/i386/kernel/entry.S
@@ -110,62 +110,45 @@ ENOSYS = 38
addl $4,%esp; \
iret
-#ifdef __SMP__
-/* Get the processor ID multiplied by 4 */
-#define GET_PROCESSOR_OFFSET(reg) \
- movl SYMBOL_NAME(apic_reg), reg; \
- movl 32(reg), reg; \
- shrl $22, reg; \
- andl $0x3C, reg;
-
-#define GET_CURRENT(reg) \
- GET_PROCESSOR_OFFSET(reg) \
- movl SYMBOL_NAME(current_set)(reg),reg
-
-#else
-
#define GET_CURRENT(reg) \
- movl SYMBOL_NAME(current_set),reg
-
-#endif
+ movl %esp, reg; \
+ andl $-8192, reg;
ENTRY(lcall7)
pushfl # We get a different stack layout with call gates,
pushl %eax # which has to be cleaned up later..
SAVE_ALL
- GET_CURRENT(%ebx)
movl EIP(%esp),%eax # due to call gates, this is eflags, not eip..
movl CS(%esp),%edx # this is eip..
movl EFLAGS(%esp),%ecx # and this is cs..
movl %eax,EFLAGS(%esp) #
movl %edx,EIP(%esp) # Now we move them to their "normal" places
movl %ecx,CS(%esp) #
- movl %esp,%eax
- GET_CURRENT(%edx)
- pushl %eax
- movl exec_domain(%edx),%edx # Get the execution domain
+ movl %esp,%ebx
+ pushl %ebx
+ andl $-8192,%ebx # GET_CURRENT
+ movl exec_domain(%ebx),%edx # Get the execution domain
movl 4(%edx),%edx # Get the lcall7 handler for the domain
call *%edx
popl %eax
jmp ret_from_sys_call
+
#ifdef __SMP__
ALIGN
.globl ret_from_smpfork
ret_from_smpfork:
+ GET_CURRENT(%ebx)
btrl $0, SYMBOL_NAME(scheduler_lock)
jmp ret_from_sys_call
#endif /* __SMP__ */
- ALIGN
-handle_bottom_half:
- pushl $2f
- jmp SYMBOL_NAME(do_bottom_half)
-
- ALIGN
-reschedule:
- pushl $ret_from_sys_call
- jmp SYMBOL_NAME(schedule) # test
+/*
+ * Return to user mode is not as complex as all this looks,
+ * but we want the default path for a system call return to
+ * go as quickly as possible which is why some of this is
+ * less clear than it otherwise should be.
+ */
ENTRY(system_call)
pushl %eax # save orig_eax
@@ -180,16 +163,11 @@ ENTRY(system_call)
ALIGN
.globl ret_from_sys_call
.globl ret_from_intr
-ret_from_intr:
ret_from_sys_call:
- GET_CURRENT(%ebx)
movl SYMBOL_NAME(bh_mask),%eax
andl SYMBOL_NAME(bh_active),%eax
jne handle_bottom_half
-2: movl EFLAGS(%esp),%eax # mix EFLAGS and CS
- movb CS(%esp),%al
- testl $(VM_MASK | 3),%eax # return to VM86 mode or non-supervisor?
- je 1f
+ret_with_reschedule:
cmpl $0,SYMBOL_NAME(need_resched)
jne reschedule
movl blocked(%ebx),%eax
@@ -197,7 +175,6 @@ ret_from_sys_call:
notl %eax
andl signal(%ebx),%eax
jne signal_return
-1:
RESTORE_ALL
ALIGN
signal_return:
@@ -230,6 +207,30 @@ badsys:
movl $-ENOSYS,EAX(%esp)
jmp ret_from_sys_call
+ ALIGN
+ret_from_exception:
+ movl SYMBOL_NAME(bh_mask),%eax
+ andl SYMBOL_NAME(bh_active),%eax
+ jne handle_bottom_half
+ ALIGN
+ret_from_intr:
+ GET_CURRENT(%ebx)
+ movl EFLAGS(%esp),%eax # mix EFLAGS and CS
+ movb CS(%esp),%al
+ testl $(VM_MASK | 3),%eax # return to VM86 mode or non-supervisor?
+ jne ret_with_reschedule
+ RESTORE_ALL
+
+ ALIGN
+handle_bottom_half:
+ pushl $ret_from_intr
+ jmp SYMBOL_NAME(do_bottom_half)
+
+ ALIGN
+reschedule:
+ pushl $ret_from_sys_call
+ jmp SYMBOL_NAME(schedule) # test
+
ENTRY(divide_error)
pushl $0 # no error code
@@ -260,7 +261,7 @@ error_code:
GET_CURRENT(%ebx)
call *%ecx
addl $8,%esp
- jmp ret_from_sys_call
+ jmp ret_from_exception
ENTRY(coprocessor_error)
pushl $0
@@ -271,7 +272,7 @@ ENTRY(device_not_available)
pushl $-1 # mark this as an int
SAVE_ALL
GET_CURRENT(%ebx)
- pushl $ret_from_sys_call
+ pushl $ret_from_exception
movl %cr0,%eax
testl $0x4,%eax # EM (math emulation bit)
je SYMBOL_NAME(math_state_restore)
diff --git a/arch/i386/kernel/head.S b/arch/i386/kernel/head.S
index 2bd095997..a42b87b1b 100644
--- a/arch/i386/kernel/head.S
+++ b/arch/i386/kernel/head.S
@@ -39,19 +39,21 @@ startup_32:
jz 1f
/*
* New page tables may be in 4Mbyte page mode and may
- * be using the global pages.
+ * be using the global pages.
+ *
+ * NOTE! We have to correct for the fact that we're
+ * not yet offset 0xC0000000..
*/
+#define cr4_bits mmu_cr4_features-0xC0000000
#ifdef GAS_KNOWS_CR4
movl %cr4,%eax # Turn on 4Mb pages
- orl $16+128,%eax
+ orl cr4_bits,%eax
movl %eax,%cr4
#else
.byte 0x0f,0x20,0xe0
- orl $16+128,%eax
+ orl cr4_bits,%eax
.byte 0x0f,0x22,0xe0
#endif
- movl %eax,%cr3 /* flush TLB as per app note */
- movl %cr0,%eax
#endif
/*
* Setup paging (the tables are already set up, just switch them on)
@@ -67,24 +69,16 @@ startup_32:
movl $1f,%eax
jmp *%eax /* make sure eip is relocated */
1:
+ /* Set up the stack pointer */
+ lss stack_start,%esp
#ifdef __SMP__
orw %bx,%bx
jz 1f /* Initial CPU cleans BSS */
-/*
- * Set up the stack
- */
- movl $(KERNEL_DS),%eax /* walken modif */
- mov %ax,%ss
- xorl %eax,%eax
- movw %cx, %ax
- movl %eax,%esp
- addl $0xC0000000, %esp /* shift it to the upper mapping */
pushl $0
popfl
jmp checkCPUtype
1:
- lss stack_start,%esp
#endif __SMP__
/*
* Clear BSS first so that there are no surprises...
@@ -305,15 +299,53 @@ rp_sidt:
jne rp_sidt
ret
+ENTRY(stack_start)
+ .long SYMBOL_NAME(init_task_union)+8192
+ .long KERNEL_DS
+
+/* This is the default interrupt "handler" :-) */
+int_msg:
+ .asciz "Unknown interrupt\n"
+ ALIGN
+ignore_int:
+ cld
+ pushl %eax
+ pushl %ecx
+ pushl %edx
+ push %ds
+ movl $(KERNEL_DS),%eax
+ mov %ax,%ds
+ mov %ax,%es
+ mov %ax,%fs
+ pushl $int_msg
+ call SYMBOL_NAME(printk)
+ popl %eax
+ pop %ds
+ popl %edx
+ popl %ecx
+ popl %eax
+ iret
+
+/*
+ * The interrupt descriptor table has room for 256 idt's
+ */
+ ALIGN
+.word 0
+idt_descr:
+ .word 256*8-1 # idt contains 256 entries
+ .long SYMBOL_NAME(idt)
+
+ ALIGN
+.word 0
+gdt_descr:
+#ifdef CONFIG_APM
+ .word (11+2*NR_TASKS)*8-1
+#else
+ .word (8+2*NR_TASKS)*8-1
+#endif
+ .long SYMBOL_NAME(gdt)
/*
- * page 0 is made non-existent, so that kernel NULL pointer references get
- * caught. Thus the swapper page directory has been moved to 0x101000
- * with the introduction of the compressed boot code. Theoretically,
- * the original design of overlaying the startup code with the swapper
- * page directory is still possible --- it would reduce the size of the kernel
- * by 2-3k. This would be a good thing to do at some point.....
- *
* This is initialized to create a identity-mapping at 0-4M (for bootup
* purposes) and another mapping of the 0-4M area at virtual address
* 0xC0000000.
@@ -471,63 +503,29 @@ ENTRY(empty_bad_page_table)
ENTRY(empty_zero_page)
.org 0x6000
-
-stack_start:
- .long SYMBOL_NAME(init_user_stack)+4096
- .long KERNEL_DS
-
-/* This is the default interrupt "handler" :-) */
-int_msg:
- .asciz "Unknown interrupt\n"
- ALIGN
-ignore_int:
- cld
- pushl %eax
- pushl %ecx
- pushl %edx
- push %ds
- push %es
- push %fs
- movl $(KERNEL_DS),%eax
- mov %ax,%ds
- mov %ax,%es
- mov %ax,%fs
- pushl $int_msg
- call SYMBOL_NAME(printk)
- popl %eax
- pop %fs
- pop %es
- pop %ds
- popl %edx
- popl %ecx
- popl %eax
- iret
+ENTRY(this_must_match_init_task)
/*
- * The interrupt descriptor table has room for 256 idt's
+ * This starts the data section. Note that the above is all
+ * in the text section because it has alignment requirements
+ * that we cannot fulfill any other way.
*/
- ALIGN
-.word 0
-idt_descr:
- .word 256*8-1 # idt contains 256 entries
- .long SYMBOL_NAME(idt)
+.data
+ALIGN
+/* 256 quadwords - 2048 bytes of idt */
ENTRY(idt)
.fill 256,8,0 # idt is uninitialized
- ALIGN
-.word 0
-gdt_descr:
-#ifdef CONFIG_APM
- .word (11+2*NR_TASKS)*8-1
-#else
- .word (8+2*NR_TASKS)*8-1
-#endif
- .long SYMBOL_NAME(gdt)
-
/*
* This gdt setup gives the kernel a 1GB address space at virtual
* address 0xC0000000 - space enough for expansion, I hope.
+ *
+ * This contains up to 8192 quadwords depending on NR_TASKS - 64kB of
+ * gdt entries. Ugh.
+ *
+ * NOTE! Make sure the gdt descriptor in head.S matches this if you
+ * change anything.
*/
ENTRY(gdt)
.quad 0x0000000000000000 /* NULL descriptor */
diff --git a/arch/i386/kernel/i386_ksyms.c b/arch/i386/kernel/i386_ksyms.c
index 8c16f0204..daa6baf42 100644
--- a/arch/i386/kernel/i386_ksyms.c
+++ b/arch/i386/kernel/i386_ksyms.c
@@ -19,6 +19,11 @@ extern void dump_thread(struct pt_regs *, struct user *);
extern int dump_fpu(elf_fpregset_t *);
extern void __lock_kernel(void);
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_HD) || defined(CONFIG_BLK_DEV_IDE_MODULE) || defined(CONFIG_BLK_DEV_HD_MODULE)
+extern struct drive_info_struct drive_info;
+EXPORT_SYMBOL(drive_info);
+#endif
+
/* platform dependent support */
EXPORT_SYMBOL(EISA_bus);
EXPORT_SYMBOL(MCA_bus);
@@ -39,12 +44,13 @@ EXPORT_SYMBOL(csum_partial_copy);
#ifdef __SMP__
EXPORT_SYMBOL(apic_reg); /* Needed internally for the I386 inlines */
EXPORT_SYMBOL(cpu_data);
-EXPORT_SYMBOL(kernel_flag);
-EXPORT_SYMBOL(active_kernel_processor);
+EXPORT_SYMBOL_NOVERS(kernel_flag);
+EXPORT_SYMBOL_NOVERS(active_kernel_processor);
EXPORT_SYMBOL(smp_invalidate_needed);
EXPORT_SYMBOL_NOVERS(__lock_kernel);
/* Global SMP irq stuff */
+EXPORT_SYMBOL(synchronize_irq);
EXPORT_SYMBOL(global_irq_holder);
EXPORT_SYMBOL(__global_cli);
EXPORT_SYMBOL(__global_sti);
diff --git a/arch/i386/kernel/init_task.c b/arch/i386/kernel/init_task.c
new file mode 100644
index 000000000..cc0a19231
--- /dev/null
+++ b/arch/i386/kernel/init_task.c
@@ -0,0 +1,22 @@
+#include <linux/mm.h>
+#include <linux/sched.h>
+
+#include <asm/pgtable.h>
+
+static struct vm_area_struct init_mmap = INIT_MMAP;
+static struct fs_struct init_fs = INIT_FS;
+static struct files_struct init_files = INIT_FILES;
+static struct signal_struct init_signals = INIT_SIGNALS;
+struct mm_struct init_mm = INIT_MM;
+
+/*
+ * Initial task structure.
+ *
+ * We need to make sure that this is 8192-byte aligned due to the
+ * way process stacks are handled. This is done by making sure
+ * the linker maps this in the .text segment right after head.S,
+ * and making head.S ensure the proper alignment.
+ *
+ * The things we do for performance..
+ */
+union task_union init_task_union __attribute__((__section__(".text"))) = { INIT_TASK };
diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c
index 95a7b525f..e5fb5acb1 100644
--- a/arch/i386/kernel/irq.c
+++ b/arch/i386/kernel/irq.c
@@ -44,9 +44,6 @@ extern volatile unsigned long smp_local_timer_ticks[1+NR_CPUS];
#define CR0_NE 32
-static unsigned char cache_21 = 0xff;
-static unsigned char cache_A1 = 0xff;
-
unsigned int local_irq_count[NR_CPUS];
#ifdef __SMP__
atomic_t __intel_bh_counter;
@@ -58,51 +55,84 @@ int __intel_bh_counter;
static unsigned int int_count[NR_CPUS][NR_IRQS] = {{0},};
#endif
-static inline void mask_irq(unsigned int irq_nr)
-{
- unsigned char mask;
+/*
+ * This contains the irq mask for both irq controllers
+ */
+static unsigned int cached_irq_mask = 0xffff;
+
+#define cached_21 (((char *)(&cached_irq_mask))[0])
+#define cached_A1 (((char *)(&cached_irq_mask))[1])
- mask = 1 << (irq_nr & 7);
- if (irq_nr < 8) {
- cache_21 |= mask;
- outb(cache_21,0x21);
+spinlock_t irq_controller_lock;
+
+/*
+ * This is always called from an interrupt context
+ * with local interrupts disabled. Don't worry about
+ * irq-safe locks.
+ *
+ * Note that we always ack the primary irq controller,
+ * even if the interrupt came from the secondary, as
+ * the primary will still have routed it. Oh, the joys
+ * of PC hardware.
+ */
+static inline void mask_and_ack_irq(int irq_nr)
+{
+ spin_lock(&irq_controller_lock);
+ cached_irq_mask |= 1 << irq_nr;
+ if (irq_nr & 8) {
+ inb(0xA1); /* DUMMY */
+ outb(cached_A1,0xA1);
+ outb(0x20,0xA0);
} else {
- cache_A1 |= mask;
- outb(cache_A1,0xA1);
+ inb(0x21); /* DUMMY */
+ outb(cached_21,0x21);
}
+ outb(0x20,0x20);
+ spin_unlock(&irq_controller_lock);
}
-static inline void unmask_irq(unsigned int irq_nr)
+static inline void set_irq_mask(int irq_nr)
{
- unsigned char mask;
-
- mask = ~(1 << (irq_nr & 7));
- if (irq_nr < 8) {
- cache_21 &= mask;
- outb(cache_21,0x21);
+ if (irq_nr & 8) {
+ outb(cached_A1,0xA1);
} else {
- cache_A1 &= mask;
- outb(cache_A1,0xA1);
+ outb(cached_21,0x21);
}
}
+/*
+ * These have to be protected by the spinlock
+ * before being called.
+ */
+static inline void mask_irq(unsigned int irq_nr)
+{
+ cached_irq_mask |= 1 << irq_nr;
+ set_irq_mask(irq_nr);
+}
+
+static inline void unmask_irq(unsigned int irq_nr)
+{
+ cached_irq_mask &= ~(1 << irq_nr);
+ set_irq_mask(irq_nr);
+}
+
void disable_irq(unsigned int irq_nr)
{
unsigned long flags;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&irq_controller_lock, flags);
mask_irq(irq_nr);
- restore_flags(flags);
+ spin_unlock_irqrestore(&irq_controller_lock, flags);
+ synchronize_irq();
}
void enable_irq(unsigned int irq_nr)
{
unsigned long flags;
- save_flags(flags);
- cli();
+
+ spin_lock_irqsave(&irq_controller_lock, flags);
unmask_irq(irq_nr);
- restore_flags(flags);
+ spin_unlock_irqrestore(&irq_controller_lock, flags);
}
/*
@@ -133,7 +163,8 @@ void enable_irq(unsigned int irq_nr)
#error make irq stub building NR_IRQS dependent and remove me.
#endif
-BUILD_TIMER_IRQ(FIRST,0,0x01)
+BUILD_COMMON_IRQ()
+BUILD_IRQ(FIRST,0,0x01)
BUILD_IRQ(FIRST,1,0x02)
BUILD_IRQ(FIRST,2,0x04)
BUILD_IRQ(FIRST,3,0x08)
@@ -157,10 +188,6 @@ BUILD_SMP_INTERRUPT(stop_cpu_interrupt)
BUILD_SMP_TIMER_INTERRUPT(apic_timer_interrupt)
#endif
-/*
- * Pointers to the low-level handlers: first the general ones, then the
- * fast ones, then the bad ones.
- */
static void (*interrupt[17])(void) = {
IRQ0_interrupt, IRQ1_interrupt, IRQ2_interrupt, IRQ3_interrupt,
IRQ4_interrupt, IRQ5_interrupt, IRQ6_interrupt, IRQ7_interrupt,
@@ -168,28 +195,6 @@ static void (*interrupt[17])(void) = {
IRQ12_interrupt, IRQ13_interrupt, IRQ14_interrupt, IRQ15_interrupt
};
-static void (*fast_interrupt[16])(void) = {
- fast_IRQ0_interrupt, fast_IRQ1_interrupt,
- fast_IRQ2_interrupt, fast_IRQ3_interrupt,
- fast_IRQ4_interrupt, fast_IRQ5_interrupt,
- fast_IRQ6_interrupt, fast_IRQ7_interrupt,
- fast_IRQ8_interrupt, fast_IRQ9_interrupt,
- fast_IRQ10_interrupt, fast_IRQ11_interrupt,
- fast_IRQ12_interrupt, fast_IRQ13_interrupt,
- fast_IRQ14_interrupt, fast_IRQ15_interrupt
-};
-
-static void (*bad_interrupt[16])(void) = {
- bad_IRQ0_interrupt, bad_IRQ1_interrupt,
- bad_IRQ2_interrupt, bad_IRQ3_interrupt,
- bad_IRQ4_interrupt, bad_IRQ5_interrupt,
- bad_IRQ6_interrupt, bad_IRQ7_interrupt,
- bad_IRQ8_interrupt, bad_IRQ9_interrupt,
- bad_IRQ10_interrupt, bad_IRQ11_interrupt,
- bad_IRQ12_interrupt, bad_IRQ13_interrupt,
- bad_IRQ14_interrupt, bad_IRQ15_interrupt
-};
-
/*
* Initial irq handlers.
*/
@@ -240,14 +245,10 @@ int get_irq_list(char *buf)
action = irq_action[i];
if (!action)
continue;
- len += sprintf(buf+len, "%2d: %10u %c %s",
- i, kstat.interrupts[i],
- (action->flags & SA_INTERRUPT) ? '+' : ' ',
- action->name);
+ len += sprintf(buf+len, "%2d: %10u %s",
+ i, kstat.interrupts[i], action->name);
for (action=action->next; action; action = action->next) {
- len += sprintf(buf+len, ",%s %s",
- (action->flags & SA_INTERRUPT) ? " +" : "",
- action->name);
+ len += sprintf(buf+len, ", %s", action->name);
}
len += sprintf(buf+len, "\n");
}
@@ -298,13 +299,9 @@ int get_smp_prof_list(char *buf) {
for (j=0;j<smp_num_cpus;j++)
len+=sprintf(buf+len, "%10d ",
int_count[cpu_logical_map[j]][i]);
- len += sprintf(buf+len, "%c %s",
- (action->flags & SA_INTERRUPT) ? '+' : ' ',
- action->name);
+ len += sprintf(buf+len, " %s", action->name);
for (action=action->next; action; action = action->next) {
- len += sprintf(buf+len, ",%s %s",
- (action->flags & SA_INTERRUPT) ? " +" : "",
- action->name);
+ len += sprintf(buf+len, ", %s", action->name);
}
len += sprintf(buf+len, "\n");
}
@@ -393,16 +390,8 @@ static inline void check_smp_invalidate(int cpu)
static unsigned long previous_irqholder;
-#undef INIT_STUCK
-#define INIT_STUCK 100000000
-
-#undef STUCK
-#define STUCK \
-if (!--stuck) {printk("wait_on_irq CPU#%d stuck at %08lx, waiting for %08lx (local=%d, global=%d)\n", cpu, where, previous_irqholder, local_count, atomic_read(&global_irq_count)); stuck = INIT_STUCK; }
-
static inline void wait_on_irq(int cpu, unsigned long where)
{
- int stuck = INIT_STUCK;
int local_count = local_irq_count[cpu];
/* Are we the only one in an interrupt context? */
@@ -421,13 +410,12 @@ static inline void wait_on_irq(int cpu, unsigned long where)
* their things before trying to get the lock again.
*/
for (;;) {
- STUCK;
check_smp_invalidate(cpu);
if (atomic_read(&global_irq_count))
continue;
if (global_irq_lock)
continue;
- if (!set_bit(0,&global_irq_lock))
+ if (!test_and_set_bit(0,&global_irq_lock))
break;
}
atomic_add(local_count, &global_irq_count);
@@ -456,28 +444,18 @@ void synchronize_irq(void)
}
}
-#undef INIT_STUCK
-#define INIT_STUCK 10000000
-
-#undef STUCK
-#define STUCK \
-if (!--stuck) {printk("get_irqlock stuck at %08lx, waiting for %08lx\n", where, previous_irqholder); stuck = INIT_STUCK;}
-
static inline void get_irqlock(int cpu, unsigned long where)
{
- int stuck = INIT_STUCK;
-
- if (set_bit(0,&global_irq_lock)) {
+ if (test_and_set_bit(0,&global_irq_lock)) {
/* do we already hold the lock? */
if ((unsigned char) cpu == global_irq_holder)
return;
/* Uhhuh.. Somebody else got it. Wait.. */
do {
do {
- STUCK;
check_smp_invalidate(cpu);
} while (test_bit(0,&global_irq_lock));
- } while (set_bit(0,&global_irq_lock));
+ } while (test_and_set_bit(0,&global_irq_lock));
}
/*
* Ok, we got the lock bit.
@@ -519,7 +497,8 @@ void __global_restore_flags(unsigned long flags)
{
switch (flags) {
case 0:
- __global_sti();
+ release_irqlock(smp_processor_id());
+ __sti();
break;
case 1:
__global_cli();
@@ -533,56 +512,58 @@ void __global_restore_flags(unsigned long flags)
#endif
/*
- * do_IRQ handles IRQ's that have been installed without the
- * SA_INTERRUPT flag: it uses the full signal-handling return
- * and runs with other interrupts enabled. All relatively slow
- * IRQ's should use this format: notably the keyboard/timer
- * routines.
+ * do_IRQ handles all normal device IRQ's (the special
+ * SMP cross-CPU interrupts have their own specific
+ * handlers).
*/
-asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
+asmlinkage void do_IRQ(struct pt_regs regs)
{
+ int irq = regs.orig_eax & 0xff;
struct irqaction * action;
- int do_random, cpu = smp_processor_id();
+ int status, cpu;
+
+ /*
+ * mask and ack quickly, we don't want the irq controller
+ * thinking we're snobs just because some other CPU has
+ * disabled global interrupts (we have already done the
+ * INT_ACK cycles, it's too late to try to pretend to the
+ * controller that we aren't taking the interrupt).
+ */
+ mask_and_ack_irq(irq);
+ cpu = smp_processor_id();
irq_enter(cpu, irq);
kstat.interrupts[irq]++;
- /* slow interrupts run with interrupts enabled */
- __sti();
+ /* Return with this interrupt masked if no action */
+ status = 0;
action = *(irq + irq_action);
- do_random = 0;
- while (action) {
- do_random |= action->flags;
- action->handler(irq, action->dev_id, regs);
- action = action->next;
+ if (action) {
+ do {
+ status |= action->flags;
+ action->handler(irq, action->dev_id, &regs);
+ action = action->next;
+ } while (action);
+ if (status & SA_SAMPLE_RANDOM)
+ add_interrupt_randomness(irq);
+
+ __cli();
+ spin_lock(&irq_controller_lock);
+ unmask_irq(irq);
+ spin_unlock(&irq_controller_lock);
}
- if (do_random & SA_SAMPLE_RANDOM)
- add_interrupt_randomness(irq);
- irq_exit(cpu, irq);
-}
-/*
- * do_fast_IRQ handles IRQ's that don't need the fancy interrupt return
- * stuff - the handler is also running with interrupts disabled unless
- * it explicitly enables them later.
- */
-asmlinkage void do_fast_IRQ(int irq)
-{
- struct irqaction * action;
- int do_random, cpu = smp_processor_id();
-
- irq_enter(cpu, irq);
- kstat.interrupts[irq]++;
- action = *(irq + irq_action);
- do_random = 0;
- while (action) {
- do_random |= action->flags;
- action->handler(irq, action->dev_id, NULL);
- action = action->next;
- }
- if (do_random & SA_SAMPLE_RANDOM)
- add_interrupt_randomness(irq);
irq_exit(cpu, irq);
+ /*
+ * This should be conditional: we should really get
+ * a return code from the irq handler to tell us
+ * whether the handler wants us to do software bottom
+ * half handling or not..
+ */
+ if (1) {
+ if (bh_active & bh_mask)
+ do_bottom_half();
+ }
}
int setup_x86_irq(int irq, struct irqaction * new)
@@ -597,10 +578,6 @@ int setup_x86_irq(int irq, struct irqaction * new)
if (!(old->flags & new->flags & SA_SHIRQ))
return -EBUSY;
- /* Can't share interrupts unless both are same type */
- if ((old->flags ^ new->flags) & SA_INTERRUPT)
- return -EBUSY;
-
/* add new interrupt at end of irq queue */
do {
p = &old->next;
@@ -617,11 +594,9 @@ int setup_x86_irq(int irq, struct irqaction * new)
*p = new;
if (!shared) {
- if (new->flags & SA_INTERRUPT)
- set_intr_gate(0x20+irq,fast_interrupt[irq]);
- else
- set_intr_gate(0x20+irq,interrupt[irq]);
+ spin_lock(&irq_controller_lock);
unmask_irq(irq);
+ spin_unlock(&irq_controller_lock);
}
restore_flags(flags);
return 0;
@@ -676,10 +651,6 @@ void free_irq(unsigned int irq, void *dev_id)
save_flags(flags);
cli();
*p = action->next;
- if (!irq[irq_action]) {
- mask_irq(irq);
- set_intr_gate(0x20+irq,bad_interrupt[irq]);
- }
restore_flags(flags);
kfree(action);
return;
@@ -689,7 +660,7 @@ void free_irq(unsigned int irq, void *dev_id)
unsigned long probe_irq_on (void)
{
- unsigned int i, irqs = 0, irqmask;
+ unsigned int i, irqs = 0;
unsigned long delay;
/* first, enable any unassigned irqs */
@@ -705,19 +676,17 @@ unsigned long probe_irq_on (void)
/* about 100ms delay */;
/* now filter out any obviously spurious interrupts */
- irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int)cache_21;
- return irqs & ~irqmask;
+ return irqs & ~cached_irq_mask;
}
int probe_irq_off (unsigned long irqs)
{
- unsigned int i, irqmask;
+ unsigned int i;
- irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int)cache_21;
#ifdef DEBUG
- printk("probe_irq_off: irqs=0x%04lx irqmask=0x%04x\n", irqs, irqmask);
+ printk("probe_irq_off: irqs=0x%04lx irqmask=0x%04x\n", irqs, cached_irq_mask);
#endif
- irqs &= irqmask;
+ irqs &= cached_irq_mask;
if (!irqs)
return 0;
i = ffz(~irqs);
@@ -729,10 +698,6 @@ int probe_irq_off (unsigned long irqs)
__initfunc(void init_IRQ(void))
{
int i;
- static unsigned char smptrap=0;
- if(smptrap)
- return;
- smptrap=1;
/* set the clock to 100 Hz */
outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */
@@ -740,7 +705,7 @@ __initfunc(void init_IRQ(void))
outb(LATCH >> 8 , 0x40); /* MSB */
for (i = 0; i < NR_IRQS ; i++)
- set_intr_gate(0x20+i,bad_interrupt[i]);
+ set_intr_gate(0x20+i,interrupt[i]);
#ifdef __SMP__
/*
diff --git a/arch/i386/kernel/irq.h b/arch/i386/kernel/irq.h
index 3a349f20a..1f9e89399 100644
--- a/arch/i386/kernel/irq.h
+++ b/arch/i386/kernel/irq.h
@@ -33,7 +33,6 @@ static inline void irq_enter(int cpu, int irq)
static inline void irq_exit(int cpu, int irq)
{
- __cli();
hardirq_exit(cpu);
release_irqlock(cpu);
}
@@ -63,125 +62,12 @@ static inline void irq_exit(int cpu, int irq)
"mov %dx,%ds\n\t" \
"mov %dx,%es\n\t"
-/*
- * SAVE_MOST/RESTORE_MOST is used for the faster version of IRQ handlers,
- * installed by using the SA_INTERRUPT flag. These kinds of IRQ's don't
- * call the routines that do signal handling etc on return, and can have
- * more relaxed register-saving etc. They are also atomic, and are thus
- * suited for small, fast interrupts like the serial lines or the harddisk
- * drivers, which don't actually need signal handling etc.
- *
- * Also note that we actually save only those registers that are used in
- * C subroutines (%eax, %edx and %ecx), so if you do something weird,
- * you're on your own. The only segments that are saved (not counting the
- * automatic stack and code segment handling) are %ds and %es, and they
- * point to kernel space. No messing around with %fs here.
- */
-#define SAVE_MOST \
- "cld\n\t" \
- "push %es\n\t" \
- "push %ds\n\t" \
- "pushl %eax\n\t" \
- "pushl %edx\n\t" \
- "pushl %ecx\n\t" \
- "movl $" STR(KERNEL_DS) ",%edx\n\t" \
- "mov %dx,%ds\n\t" \
- "mov %dx,%es\n\t"
-
-#define RESTORE_MOST \
- "popl %ecx\n\t" \
- "popl %edx\n\t" \
- "popl %eax\n\t" \
- "pop %ds\n\t" \
- "pop %es\n\t" \
- "iret"
-
-/*
- * Some fast irq handlers might want to access saved registers (mostly
- * cs or flags)
- */
-
-struct fast_irq_regs {
- long ecx;
- long edx;
- long eax;
- int xds;
- int xes;
- long eip;
- int xcs;
- long eflags;
- long esp;
- int xss;
-};
-
-/*
- * The "inb" instructions are not needed, but seem to change the timings
- * a bit - without them it seems that the harddisk driver won't work on
- * all hardware. Arghh.
- */
-#define ACK_FIRST(mask,nr) \
- "inb $0x21,%al\n\t" \
- "jmp 1f\n" \
- "1:\tjmp 1f\n" \
- "1:\torb $" #mask ","SYMBOL_NAME_STR(cache_21)"\n\t" \
- "movb "SYMBOL_NAME_STR(cache_21)",%al\n\t" \
- "outb %al,$0x21\n\t" \
- "jmp 1f\n" \
- "1:\tjmp 1f\n" \
- "1:\tmovb $0x20,%al\n\t" \
- "outb %al,$0x20\n\t"
-
-#define ACK_SECOND(mask,nr) \
- "inb $0xA1,%al\n\t" \
- "jmp 1f\n" \
- "1:\tjmp 1f\n" \
- "1:\torb $" #mask ","SYMBOL_NAME_STR(cache_A1)"\n\t" \
- "movb "SYMBOL_NAME_STR(cache_A1)",%al\n\t" \
- "outb %al,$0xA1\n\t" \
- "jmp 1f\n" \
- "1:\tjmp 1f\n" \
- "1:\tmovb $0x20,%al\n\t" \
- "outb %al,$0xA0\n\t" \
- "jmp 1f\n" \
- "1:\tjmp 1f\n" \
- "1:\toutb %al,$0x20\n\t"
-
-#define UNBLK_FIRST(mask) \
- "inb $0x21,%al\n\t" \
- "jmp 1f\n" \
- "1:\tjmp 1f\n" \
- "1:\tandb $~(" #mask "),"SYMBOL_NAME_STR(cache_21)"\n\t" \
- "movb "SYMBOL_NAME_STR(cache_21)",%al\n\t" \
- "outb %al,$0x21\n\t"
-
-#define UNBLK_SECOND(mask) \
- "inb $0xA1,%al\n\t" \
- "jmp 1f\n" \
- "1:\tjmp 1f\n" \
- "1:\tandb $~(" #mask "),"SYMBOL_NAME_STR(cache_A1)"\n\t" \
- "movb "SYMBOL_NAME_STR(cache_A1)",%al\n\t" \
- "outb %al,$0xA1\n\t"
-
#define IRQ_NAME2(nr) nr##_interrupt(void)
#define IRQ_NAME(nr) IRQ_NAME2(IRQ##nr)
-#define FAST_IRQ_NAME(nr) IRQ_NAME2(fast_IRQ##nr)
-#define BAD_IRQ_NAME(nr) IRQ_NAME2(bad_IRQ##nr)
-
-#ifdef __SMP__
-
-#define GET_CURRENT \
- "movl "SYMBOL_NAME_STR(apic_reg)", %ebx\n\t" \
- "movl 32(%ebx), %ebx\n\t" \
- "shrl $22,%ebx\n\t" \
- "andl $0x3C,%ebx\n\t" \
- "movl " SYMBOL_NAME_STR(current_set) "(,%ebx),%ebx\n\t"
-
-#else
#define GET_CURRENT \
- "movl " SYMBOL_NAME_STR(current_set) ",%ebx\n\t"
-
-#endif
+ "movl %esp, %ebx\n\t" \
+ "andl $-8192, %ebx\n\t"
#ifdef __SMP__
@@ -205,66 +91,30 @@ __asm__( \
"\n"__ALIGN_STR"\n" \
SYMBOL_NAME_STR(x) ":\n\t" \
"pushl $-1\n\t" \
- SAVE_ALL \
- "movl %esp,%eax\n\t" \
- "pushl %eax\n\t" \
+ SAVE_ALL \
+ "movl %esp,%eax\n\t" \
+ "pushl %eax\n\t" \
"call "SYMBOL_NAME_STR(smp_##x)"\n\t" \
- "addl $4,%esp\n\t" \
+ "addl $4,%esp\n\t" \
"jmp ret_from_intr\n");
#endif /* __SMP__ */
-#define BUILD_IRQ(chip,nr,mask) \
-asmlinkage void IRQ_NAME(nr); \
-asmlinkage void FAST_IRQ_NAME(nr); \
-asmlinkage void BAD_IRQ_NAME(nr); \
+#define BUILD_COMMON_IRQ() \
__asm__( \
-"\n"__ALIGN_STR"\n" \
-SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \
- "pushl $-"#nr"-2\n\t" \
+ "\n" __ALIGN_STR"\n" \
+ "common_interrupt:\n\t" \
SAVE_ALL \
- ACK_##chip(mask,(nr&7)) \
- "movl %esp,%eax\n\t" \
- "pushl %eax\n\t" \
- "pushl $" #nr "\n\t" \
- "call "SYMBOL_NAME_STR(do_IRQ)"\n\t" \
- "addl $8,%esp\n\t" \
- UNBLK_##chip(mask) \
- "jmp ret_from_intr\n" \
-"\n"__ALIGN_STR"\n" \
-SYMBOL_NAME_STR(fast_IRQ) #nr "_interrupt:\n\t" \
- SAVE_MOST \
- ACK_##chip(mask,(nr&7)) \
- "pushl $" #nr "\n\t" \
- "call "SYMBOL_NAME_STR(do_fast_IRQ)"\n\t" \
- "addl $4,%esp\n\t" \
- UNBLK_##chip(mask) \
- RESTORE_MOST \
-"\n"__ALIGN_STR"\n" \
-SYMBOL_NAME_STR(bad_IRQ) #nr "_interrupt:\n\t" \
- SAVE_MOST \
- ACK_##chip(mask,(nr&7)) \
- RESTORE_MOST);
-
-#define BUILD_TIMER_IRQ(chip,nr,mask) \
+ "pushl $ret_from_intr\n\t" \
+ "jmp "SYMBOL_NAME_STR(do_IRQ));
+
+#define BUILD_IRQ(chip,nr,mask) \
asmlinkage void IRQ_NAME(nr); \
-asmlinkage void FAST_IRQ_NAME(nr); \
-asmlinkage void BAD_IRQ_NAME(nr); \
__asm__( \
"\n"__ALIGN_STR"\n" \
-SYMBOL_NAME_STR(fast_IRQ) #nr "_interrupt:\n\t" \
-SYMBOL_NAME_STR(bad_IRQ) #nr "_interrupt:\n\t" \
SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \
- "pushl $-"#nr"-2\n\t" \
- SAVE_ALL \
- ACK_##chip(mask,(nr&7)) \
- "movl %esp,%eax\n\t" \
- "pushl %eax\n\t" \
- "pushl $" #nr "\n\t" \
- "call "SYMBOL_NAME_STR(do_IRQ)"\n\t" \
- "addl $8,%esp\n\t" \
- UNBLK_##chip(mask) \
- "jmp ret_from_intr\n");
+ "pushl $"#nr"-256\n\t" \
+ "jmp common_interrupt");
/*
* x86 profiling function, SMP safe. We might want to do this in
@@ -276,15 +126,14 @@ static inline void x86_do_profile (unsigned long eip)
extern int _stext;
eip -= (unsigned long) &_stext;
eip >>= prof_shift;
- if (eip < prof_len)
- atomic_inc((atomic_t *)&prof_buffer[eip]);
- else
/*
* Dont ignore out-of-bounds EIP values silently,
* put them into the last histogram slot, so if
* present, they will show up as a sharp peak.
*/
- atomic_inc((atomic_t *)&prof_buffer[prof_len-1]);
+ if (eip > prof_len-1)
+ eip = prof_len-1;
+ atomic_inc((atomic_t *)&prof_buffer[eip]);
}
}
diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c
index fe4723951..33842a21f 100644
--- a/arch/i386/kernel/process.c
+++ b/arch/i386/kernel/process.c
@@ -30,6 +30,7 @@
#include <linux/delay.h>
#include <linux/smp.h>
#include <linux/reboot.h>
+#include <linux/init.h>
#if defined(CONFIG_APM) && defined(CONFIG_APM_POWER_OFF)
#include <linux/apm_bios.h>
#endif
@@ -149,7 +150,8 @@ int cpu_idle(void *unused)
current->priority = -100;
while(1)
{
- if(cpu_data[smp_processor_id()].hlt_works_ok && !hlt_counter && !need_resched)
+ if(cpu_data[smp_processor_id()].hlt_works_ok &&
+ !hlt_counter && !need_resched)
__asm("hlt");
/*
* tq_scheduler currently assumes we're running in a process
@@ -183,7 +185,7 @@ static long no_idt[2] = {0, 0};
static int reboot_mode = 0;
static int reboot_thru_bios = 0;
-void reboot_setup(char *str, int *ints)
+__initfunc(void reboot_setup(char *str, int *ints))
{
while(1) {
switch (*str) {
@@ -324,11 +326,14 @@ void machine_restart(char * __unused)
pg0 [0] = 7;
- /* Use `swapper_pg_dir' as our page directory. Don't bother with
- `SET_PAGE_DIR' because interrupts are disabled and we're rebooting.
- This instruction flushes the TLB. */
+ /*
+ * Use `swapper_pg_dir' as our page directory. We bother with
+ * `SET_PAGE_DIR' because although might be rebooting, but if we change
+ * the way we set root page dir in the future, then we wont break a
+ * seldom used feature ;)
+ */
- __asm__ __volatile__ ("movl %0,%%cr3" : : "a" (swapper_pg_dir) : "memory");
+ SET_PAGE_DIR(current,swapper_pg_dir);
/* Write 0x1234 to absolute memory location 0x472. The BIOS reads
this on booting to tell it to "Bypass memory test (also warm
@@ -473,6 +478,8 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long esp,
int i;
struct pt_regs * childregs;
+ p->tss.tr = _TSS(nr);
+ p->tss.ldt = _LDT(nr);
p->tss.es = KERNEL_DS;
p->tss.cs = KERNEL_CS;
p->tss.ss = KERNEL_DS;
@@ -480,9 +487,8 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long esp,
p->tss.fs = USER_DS;
p->tss.gs = USER_DS;
p->tss.ss0 = KERNEL_DS;
- p->tss.esp0 = p->kernel_stack_page + PAGE_SIZE;
- p->tss.tr = _TSS(nr);
- childregs = ((struct pt_regs *) (p->kernel_stack_page + PAGE_SIZE)) - 1;
+ p->tss.esp0 = 2*PAGE_SIZE + (unsigned long) p;
+ childregs = ((struct pt_regs *) (p->tss.esp0)) - 1;
p->tss.esp = (unsigned long) childregs;
#ifdef __SMP__
p->tss.eip = (unsigned long) ret_from_smpfork;
@@ -496,7 +502,6 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long esp,
childregs->eax = 0;
childregs->esp = esp;
p->tss.back_link = 0;
- p->tss.ldt = _LDT(nr);
if (p->ldt) {
p->ldt = (struct desc_struct*) vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE);
if (p->ldt != NULL)
@@ -512,6 +517,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long esp,
p->tss.io_bitmap[i] = ~0;
if (last_task_used_math == current)
__asm__("clts ; fnsave %0 ; frstor %0":"=m" (p->tss.i387));
+
return 0;
}
diff --git a/arch/i386/kernel/ptrace.c b/arch/i386/kernel/ptrace.c
index 920d1bc1c..0dfffd672 100644
--- a/arch/i386/kernel/ptrace.c
+++ b/arch/i386/kernel/ptrace.c
@@ -34,18 +34,6 @@
*/
#define EFL_OFFSET ((EFL-2)*4-sizeof(struct pt_regs))
-/* change a pid into a task struct. */
-static inline struct task_struct * get_task(int pid)
-{
- int i;
-
- for (i = 1; i < NR_TASKS; i++) {
- if (task[i] != NULL && (task[i]->pid == pid))
- return task[i];
- }
- return NULL;
-}
-
/*
* this routine will get a word off of the processes privileged stack.
* the offset is how far from the base addr as stored in the TSS.
@@ -95,7 +83,7 @@ static unsigned long get_long(struct task_struct * tsk,
repeat:
pgdir = pgd_offset(vma->vm_mm, addr);
if (pgd_none(*pgdir)) {
- do_no_page(tsk, vma, addr, 0);
+ handle_mm_fault(tsk, vma, addr, 0);
goto repeat;
}
if (pgd_bad(*pgdir)) {
@@ -105,7 +93,7 @@ repeat:
}
pgmiddle = pmd_offset(pgdir, addr);
if (pmd_none(*pgmiddle)) {
- do_no_page(tsk, vma, addr, 0);
+ handle_mm_fault(tsk, vma, addr, 0);
goto repeat;
}
if (pmd_bad(*pgmiddle)) {
@@ -115,7 +103,7 @@ repeat:
}
pgtable = pte_offset(pgmiddle, addr);
if (!pte_present(*pgtable)) {
- do_no_page(tsk, vma, addr, 0);
+ handle_mm_fault(tsk, vma, addr, 0);
goto repeat;
}
page = pte_page(*pgtable);
@@ -146,7 +134,7 @@ static void put_long(struct task_struct * tsk, struct vm_area_struct * vma, unsi
repeat:
pgdir = pgd_offset(vma->vm_mm, addr);
if (!pgd_present(*pgdir)) {
- do_no_page(tsk, vma, addr, 1);
+ handle_mm_fault(tsk, vma, addr, 1);
goto repeat;
}
if (pgd_bad(*pgdir)) {
@@ -156,7 +144,7 @@ repeat:
}
pgmiddle = pmd_offset(pgdir, addr);
if (pmd_none(*pgmiddle)) {
- do_no_page(tsk, vma, addr, 1);
+ handle_mm_fault(tsk, vma, addr, 1);
goto repeat;
}
if (pmd_bad(*pgmiddle)) {
@@ -166,12 +154,12 @@ repeat:
}
pgtable = pte_offset(pgmiddle, addr);
if (!pte_present(*pgtable)) {
- do_no_page(tsk, vma, addr, 1);
+ handle_mm_fault(tsk, vma, addr, 1);
goto repeat;
}
page = pte_page(*pgtable);
if (!pte_write(*pgtable)) {
- do_wp_page(tsk, vma, addr, 1);
+ handle_mm_fault(tsk, vma, addr, 1);
goto repeat;
}
/* this is a hack for non-kernel-mapped video buffers and similar */
@@ -381,7 +369,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
if (pid == 1) /* you may not mess with init */
goto out;
ret = -ESRCH;
- if (!(child = get_task(pid)))
+ if (!(child = find_task_by_pid(pid)))
goto out;
ret = -EPERM;
if (request == PTRACE_ATTACH) {
diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c
index ec5954771..f62744d11 100644
--- a/arch/i386/kernel/setup.c
+++ b/arch/i386/kernel/setup.c
@@ -247,7 +247,7 @@ static const char * i586model(unsigned int nr)
static const char * i686model(unsigned int nr)
{
static const char *model[] = {
- "PPro A-step", "Pentium Pro"
+ "PPro A-step", "Pentium Pro", "2", "Pentium II"
};
if (nr < sizeof(model)/sizeof(char *))
return model[nr];
@@ -279,9 +279,10 @@ static const char * getmodel(int x86, int model)
int get_cpuinfo(char * buffer)
{
int i, len = 0;
+ int sep_bug;
static const char *x86_cap_flags[] = {
"fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
- "cx8", "apic", "10", "11", "mtrr", "pge", "mca", "cmov",
+ "cx8", "apic", "10", "sep", "mtrr", "pge", "mca", "cmov",
"16", "17", "18", "19", "20", "21", "22", "mmx",
"24", "25", "26", "27", "28", "29", "30", "31"
};
@@ -321,10 +322,18 @@ int get_cpuinfo(char * buffer)
else
len += sprintf(buffer+len,
"stepping\t: unknown\n");
+
+ sep_bug = CD(have_cpuid) &&
+ (CD(x86_capability) & 0x800) &&
+ !memcmp(x86_vendor_id, "GenuineIntel", 12) &&
+ CD(x86) == 6 &&
+ CD(x86_model) < 3 &&
+ CD(x86_mask) < 3;
len += sprintf(buffer+len,
"fdiv_bug\t: %s\n"
"hlt_bug\t\t: %s\n"
+ "sep_bug\t\t: %s\n"
"fpu\t\t: %s\n"
"fpu_exception\t: %s\n"
"cpuid\t\t: %s\n"
@@ -332,6 +341,7 @@ int get_cpuinfo(char * buffer)
"flags\t\t:",
CD(fdiv_bug) ? "yes" : "no",
CD(hlt_works_ok) ? "no" : "yes",
+ sep_bug ? "yes" : "no",
CD(hard_math) ? "yes" : "no",
(CD(hard_math) && ignore_irq13)
? "yes" : "no",
diff --git a/arch/i386/kernel/signal.c b/arch/i386/kernel/signal.c
index 970c8c5d7..3141c5318 100644
--- a/arch/i386/kernel/signal.c
+++ b/arch/i386/kernel/signal.c
@@ -318,6 +318,14 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
unsigned long signr;
struct sigaction * sa;
+ /*
+ * We want the common case to go fast, which
+ * is why we may in certain cases get here from
+ * kernel mode. Just return without doing anything
+ * if so.
+ */
+ if ((regs->xcs & 3) != 3)
+ return 1;
mask = ~current->blocked;
while ((signr = current->signal & mask)) {
/*
@@ -384,10 +392,12 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
case SIGQUIT: case SIGILL: case SIGTRAP:
case SIGABRT: case SIGFPE: case SIGSEGV:
+ lock_kernel();
if (current->binfmt && current->binfmt->core_dump) {
if (current->binfmt->core_dump(signr, regs))
signr |= 0x80;
}
+ unlock_kernel();
/* fall through */
default:
spin_lock_irq(&current->sigmask_lock);
diff --git a/arch/i386/kernel/smp.c b/arch/i386/kernel/smp.c
index a1590f500..1dc615501 100644
--- a/arch/i386/kernel/smp.c
+++ b/arch/i386/kernel/smp.c
@@ -1,5 +1,5 @@
/*
- * Intel MP v1.1/v1.4 specification support routines for multi-pentium
+ * Intel MP v1.1/v1.4 specification support routines for multi-pentium
* hosts.
*
* (c) 1995 Alan Cox, CymruNET Ltd <alan@cymru.net>
@@ -46,14 +46,15 @@
#include <asm/smp.h>
#include <asm/io.h>
+#define __KERNEL_SYSCALLS__
+#include <linux/unistd.h>
+
#include "irq.h"
extern unsigned long start_kernel, _etext;
extern void update_one_process( struct task_struct *p,
- unsigned long ticks, unsigned long user,
- unsigned long system);
-void setup_APIC_clock (void);
-
+ unsigned long ticks, unsigned long user,
+ unsigned long system);
/*
* Some notes on processor bugs:
*
@@ -67,7 +68,7 @@ void setup_APIC_clock (void);
* Pentium
* There is a marginal case where REP MOVS on 100MHz SMP
* machines with B stepping processors can fail. XXX should provide
- * an L1cache=Writethrough or L1cache=off option.
+ * an L1cache=Writethrough or L1cache=off option.
*
* B stepping CPU's may hang. There are hardware work arounds
* for this. We warn about it in case your board doesnt have the work
@@ -91,12 +92,12 @@ void setup_APIC_clock (void);
* If this sounds worrying believe me these bugs are ___RARE___ and
* there's about nothing of note with C stepping upwards.
*/
-
-
+
+
/*
* Why isn't this somewhere standard ??
*/
-
+
extern __inline int max(int a,int b)
{
if(a>b)
@@ -121,7 +122,6 @@ struct cpuinfo_x86 cpu_data[NR_CPUS]; /* Per cpu bogomips and other parameters
static unsigned int num_processors = 1; /* Internal processor count */
static unsigned long io_apic_addr = 0xFEC00000; /* Address of the I/O apic (not yet used) */
unsigned char boot_cpu_id = 0; /* Processor that is doing the boot up */
-static unsigned char *kstack_base,*kstack_end; /* Kernel stack list pointers */
static int smp_activated = 0; /* Tripped once we need to start cross invalidating */
int apic_version[NR_CPUS]; /* APIC version number */
static volatile int smp_commenced=0; /* Tripped when we start scheduling */
@@ -129,7 +129,6 @@ unsigned long apic_addr = 0xFEE00000; /* Address of APIC (defaults to 0xFEE000
unsigned long nlong = 0; /* dummy used for apic_reg address + 0x20 */
unsigned char *apic_reg=((unsigned char *)(&nlong))-0x20;/* Later set to the ioremap() of the APIC */
unsigned long apic_retval; /* Just debugging the assembler.. */
-unsigned char *kernel_stacks[NR_CPUS]; /* Kernel stack pointers for CPU's (debugging) */
static volatile unsigned char smp_cpu_in_msg[NR_CPUS]; /* True if this processor is sending an IPI */
@@ -195,10 +194,10 @@ static inline void ack_APIC_irq (void)
apic_write(APIC_EOI, 0);
}
-/*
+/*
* Checksum an MP configuration block.
*/
-
+
static int mpf_checksum(unsigned char *mp, int len)
{
int sum=0;
@@ -210,7 +209,7 @@ static int mpf_checksum(unsigned char *mp, int len)
/*
* Processor encoding in an MP configuration block
*/
-
+
static char *mpc_family(int family,int model)
{
static char n[32];
@@ -274,11 +273,11 @@ __initfunc(static int smp_read_mpc(struct mp_config_table *mpc))
/* set the local APIC address */
apic_addr = (unsigned long)phys_to_virt((unsigned long)mpc->mpc_lapic);
-
+
/*
* Now process the configuration blocks.
*/
-
+
while(count<mpc->mpc_length)
{
switch(*mpt)
@@ -290,13 +289,13 @@ __initfunc(static int smp_read_mpc(struct mp_config_table *mpc))
if(m->mpc_cpuflag&CPU_ENABLED)
{
printk("Processor #%d %s APIC version %d\n",
- m->mpc_apicid,
+ m->mpc_apicid,
mpc_family((m->mpc_cpufeature&
CPU_FAMILY_MASK)>>8,
(m->mpc_cpufeature&
CPU_MODEL_MASK)>>4),
m->mpc_apicver);
-#ifdef SMP_DEBUG
+#ifdef SMP_DEBUG
if(m->mpc_featureflag&(1<<0))
printk(" Floating point unit present.\n");
if(m->mpc_featureflag&(1<<7))
@@ -305,7 +304,7 @@ __initfunc(static int smp_read_mpc(struct mp_config_table *mpc))
printk(" 64 bit compare & exchange supported.\n");
if(m->mpc_featureflag&(1<<9))
printk(" Internal APIC present.\n");
-#endif
+#endif
if(m->mpc_cpuflag&CPU_BOOTPROCESSOR)
{
SMP_PRINTK((" Bootup CPU\n"));
@@ -313,10 +312,10 @@ __initfunc(static int smp_read_mpc(struct mp_config_table *mpc))
}
else /* Boot CPU already counted */
num_processors++;
-
+
if(m->mpc_apicid>NR_CPUS)
printk("Processor #%d unused. (Max %d processors).\n",m->mpc_apicid, NR_CPUS);
- else
+ else
{
cpu_present_map|=(1<<m->mpc_apicid);
apic_version[m->mpc_apicid]=m->mpc_apicver;
@@ -337,7 +336,7 @@ __initfunc(static int smp_read_mpc(struct mp_config_table *mpc))
str));
mpt+=sizeof(*m);
count+=sizeof(*m);
- break;
+ break;
}
case MP_IOAPIC:
{
@@ -346,20 +345,20 @@ __initfunc(static int smp_read_mpc(struct mp_config_table *mpc))
if(m->mpc_flags&MPC_APIC_USABLE)
{
apics++;
- printk("I/O APIC #%d Version %d at 0x%lX.\n",
- m->mpc_apicid,m->mpc_apicver,
- m->mpc_apicaddr);
- io_apic_addr = (unsigned long)phys_to_virt(m->mpc_apicaddr);
- }
- mpt+=sizeof(*m);
- count+=sizeof(*m);
- break;
+ printk("I/O APIC #%d Version %d at 0x%lX.\n",
+ m->mpc_apicid,m->mpc_apicver,
+ m->mpc_apicaddr);
+ io_apic_addr = (unsigned long)phys_to_virt(m->mpc_apicaddr);
+ }
+ mpt+=sizeof(*m);
+ count+=sizeof(*m);
+ break;
}
case MP_INTSRC:
{
struct mpc_config_intsrc *m=
(struct mpc_config_intsrc *)mpt;
-
+
mpt+=sizeof(*m);
count+=sizeof(*m);
break;
@@ -376,29 +375,29 @@ __initfunc(static int smp_read_mpc(struct mp_config_table *mpc))
}
if(apics>1)
printk("Warning: Multiple APIC's not supported.\n");
- return num_processors;
+ return num_processors;
}
/*
* Scan the memory blocks for an SMP configuration block.
*/
-
+
__initfunc(int smp_scan_config(unsigned long base, unsigned long length))
{
unsigned long *bp=phys_to_virt(base);
struct intel_mp_floating *mpf;
-
+
SMP_PRINTK(("Scan SMP from %p for %ld bytes.\n",
bp,length));
if(sizeof(*mpf)!=16)
printk("Error: MPF size\n");
-
+
while(length>0)
{
if(*bp==SMP_MAGIC_IDENT)
{
mpf=(struct intel_mp_floating *)bp;
- if(mpf->mpf_length==1 &&
+ if(mpf->mpf_length==1 &&
!mpf_checksum((unsigned char *)bp,16) &&
(mpf->mpf_specification == 1
|| mpf->mpf_specification == 4) )
@@ -433,7 +432,7 @@ __initfunc(int smp_scan_config(unsigned long base, unsigned long length))
* We know that page 0 is not
* used. Steal it for now!
*/
-
+
cfg=pg0[0];
pg0[0] = (apic_addr | 7);
local_flush_tlb();
@@ -451,7 +450,7 @@ __initfunc(int smp_scan_config(unsigned long base, unsigned long length))
*
* END OF HACK END OF HACK END OF HACK END OF HACK END OF HACK
*
- */
+ */
/*
* 2 CPUs, numbered 0 & 1.
*/
@@ -513,6 +512,7 @@ __initfunc(int smp_scan_config(unsigned long base, unsigned long length))
nlong = boot_cpu_id<<24; /* Dummy 'self' for bootup */
cpu_logical_map[0] = boot_cpu_id;
global_irq_holder = boot_cpu_id;
+ current->processor = boot_cpu_id;
printk("Processors: %d\n", num_processors);
/*
@@ -534,61 +534,37 @@ __initfunc(int smp_scan_config(unsigned long base, unsigned long length))
extern unsigned char trampoline_data [];
extern unsigned char trampoline_end [];
+static unsigned char *trampoline_base;
/*
* Currently trivial. Write the real->protected mode
* bootstrap into the page concerned. The caller
* has made sure it's suitably aligned.
*/
-
-__initfunc(static void install_trampoline(unsigned char *mp))
+
+__initfunc(static unsigned long setup_trampoline(void))
{
- memcpy(mp, trampoline_data, trampoline_end - trampoline_data);
+ memcpy(trampoline_base, trampoline_data, trampoline_end - trampoline_data);
+ return virt_to_phys(trampoline_base);
}
/*
- * We are called very early to get the low memory for the trampoline/kernel stacks
- * This has to be done by mm/init.c to parcel us out nice low memory. We allocate
- * the kernel stacks at 4K, 8K, 12K... currently (0-03FF is preserved for SMM and
- * other things).
+ * We are called very early to get the low memory for the
+ * SMP bootup trampoline page.
*/
-
__initfunc(unsigned long smp_alloc_memory(unsigned long mem_base))
{
- int size=(num_processors-1)*PAGE_SIZE; /* Number of stacks needed */
-
- /*
- * Our stacks have to be below the 1Mb line, and mem_base on entry
- * is 4K aligned.
- */
-
- if(virt_to_phys((void *)(mem_base+size))>=0x9F000)
- panic("smp_alloc_memory: Insufficient low memory for kernel stacks 0x%lx.\n", mem_base);
- kstack_base=(void *)mem_base;
- mem_base+=size;
- kstack_end=(void *)mem_base;
- return mem_base;
-}
-
-/*
- * Hand out stacks one at a time.
- */
-
-__initfunc(static void *get_kernel_stack(void))
-{
- void *stack=kstack_base;
- if(kstack_base>=kstack_end)
- return NULL;
- kstack_base+=PAGE_SIZE;
- return stack;
+ if (virt_to_phys((void *)mem_base) >= 0x9F000)
+ panic("smp_alloc_memory: Insufficient low memory for kernel trampoline 0x%lx.\n", mem_base);
+ trampoline_base = (void *)mem_base;
+ return mem_base + PAGE_SIZE;
}
-
/*
* The bootstrap kernel entry code has set these up. Save them for
* a given CPU
*/
-
+
__initfunc(void smp_store_cpu_info(int id))
{
struct cpuinfo_x86 *c=&cpu_data[id];
@@ -615,7 +591,7 @@ __initfunc(void smp_store_cpu_info(int id))
* fired off. This allows the BP to have everything in order [we hope].
* At the end of this all the AP's will hit the system scheduling and off
* we go. Each AP will load the system gdt's and jump through the kernel
- * init into idle(). At this point the scheduler will one day take over
+ * init into idle(). At this point the scheduler will one day take over
* and give them jobs to do. smp_callin is a standard routine
* we use to track CPU's as they power up.
*/
@@ -634,74 +610,276 @@ __initfunc(void smp_callin(void))
extern void calibrate_delay(void);
int cpuid=GET_APIC_ID(apic_read(APIC_ID));
unsigned long l;
-
+
/*
* Activate our APIC
*/
-
- SMP_PRINTK(("CALLIN %d\n",smp_processor_id()));
+
+ SMP_PRINTK(("CALLIN %d %d\n",hard_smp_processor_id(), smp_processor_id()));
l=apic_read(APIC_SPIV);
l|=(1<<8); /* Enable */
apic_write(APIC_SPIV,l);
/*
- * Set up our APIC timer.
+ * Set up our APIC timer.
*/
setup_APIC_clock ();
sti();
/*
* Get our bogomips.
- */
+ */
calibrate_delay();
SMP_PRINTK(("Stack at about %p\n",&cpuid));
-
+
/*
* Save our processor parameters
*/
smp_store_cpu_info(cpuid);
+
/*
* Allow the master to continue.
- */
+ */
set_bit(cpuid, (unsigned long *)&cpu_callin_map[0]);
+}
+
+static int cpucount = 0;
+
+extern int cpu_idle(void * unused);
+
+/*
+ * Activate a secondary processor.
+ */
+__initfunc(int start_secondary(void *unused))
+{
+ smp_callin();
+ while (!smp_commenced)
+ barrier();
+ return cpu_idle(NULL);
+}
+
+/*
+ * Everything has been set up for the secondary
+ * CPU's - they just need to reload everything
+ * from the task structure
+ */
+__initfunc(void initialize_secondary(void))
+{
+ struct thread_struct * p = &current->tss;
+
/*
- * Until we are ready for SMP scheduling
+ * We don't actually need to load the full TSS,
+ * basically just the stack pointer and the eip.
*/
- load_ldt(0);
- local_flush_tlb();
-
- while (cpu_number_map[cpuid] == -1)
- barrier();
+ asm volatile("lldt %%ax": :"a" (p->ldt));
+ asm volatile("ltr %%ax": :"a" (p->tr));
+ asm volatile(
+ "movl %0,%%esp\n\t"
+ "jmp *%1"
+ :
+ :"r" (p->esp),"r" (p->eip));
+}
- while(!task[cpuid] || current_set[cpuid] != task[cpu_number_map[cpuid]])
- barrier();
+extern struct {
+ void * esp;
+ unsigned short ss;
+} stack_start;
- local_flush_tlb();
- load_TR(cpu_number_map[cpuid]);
+__initfunc(static void do_boot_cpu(int i))
+{
+ unsigned long cfg;
+ pgd_t maincfg;
+ struct task_struct *idle;
+ unsigned long send_status, accept_status;
+ int timeout, num_starts, j;
+ unsigned long start_eip;
- while(!smp_commenced)
- barrier();
-
+ /*
+ * We need an idle process for each processor.
+ */
+
+ kernel_thread(start_secondary, NULL, CLONE_PID);
+ cpucount++;
+
+ idle = task[cpucount];
+ if (!idle)
+ panic("No idle process for CPU %d\n", i);
+
+ idle->processor = i;
+ cpu_logical_map[cpucount] = i;
+ cpu_number_map[i] = cpucount;
+
+ /* start_eip had better be page-aligned! */
+ start_eip = setup_trampoline();
+
+ printk("Booting processor %d eip %lx: ", i, start_eip); /* So we see what's up */
+ stack_start.esp = (void *) (1024 + PAGE_SIZE + (char *)idle);
+
+ /*
+ * This grunge runs the startup process for
+ * the targeted processor.
+ */
+
+ SMP_PRINTK(("Setting warm reset code and vector.\n"));
+
+ CMOS_WRITE(0xa, 0xf);
local_flush_tlb();
+ SMP_PRINTK(("1.\n"));
+ *((volatile unsigned short *) phys_to_virt(0x469)) = start_eip >> 4;
+ SMP_PRINTK(("2.\n"));
+ *((volatile unsigned short *) phys_to_virt(0x467)) = start_eip & 0xf;
+ SMP_PRINTK(("3.\n"));
+
+ maincfg=swapper_pg_dir[0];
+ ((unsigned long *)swapper_pg_dir)[0]=0x102007;
+
+ /*
+ * Be paranoid about clearing APIC errors.
+ */
+
+ if ( apic_version[i] & 0xF0 )
+ {
+ apic_write(APIC_ESR, 0);
+ accept_status = (apic_read(APIC_ESR) & 0xEF);
+ }
+
+ /*
+ * Status is now clean
+ */
- SMP_PRINTK(("Commenced..\n"));
+ send_status = 0;
+ accept_status = 0;
+
+ /*
+ * Starting actual IPI sequence...
+ */
+
+ SMP_PRINTK(("Asserting INIT.\n"));
+
+ /*
+ * Turn INIT on
+ */
+
+ cfg=apic_read(APIC_ICR2);
+ cfg&=0x00FFFFFF;
+ apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(i)); /* Target chip */
+ cfg=apic_read(APIC_ICR);
+ cfg&=~0xCDFFF; /* Clear bits */
+ cfg |= (APIC_DEST_FIELD | APIC_DEST_LEVELTRIG
+ | APIC_DEST_ASSERT | APIC_DEST_DM_INIT);
+ apic_write(APIC_ICR, cfg); /* Send IPI */
+
+ udelay(200);
+ SMP_PRINTK(("Deasserting INIT.\n"));
+
+ cfg=apic_read(APIC_ICR2);
+ cfg&=0x00FFFFFF;
+ apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(i)); /* Target chip */
+ cfg=apic_read(APIC_ICR);
+ cfg&=~0xCDFFF; /* Clear bits */
+ cfg |= (APIC_DEST_FIELD | APIC_DEST_LEVELTRIG
+ | APIC_DEST_DM_INIT);
+ apic_write(APIC_ICR, cfg); /* Send IPI */
+
+ /*
+ * Should we send STARTUP IPIs ?
+ *
+ * Determine this based on the APIC version.
+ * If we don't have an integrated APIC, don't
+ * send the STARTUP IPIs.
+ */
+
+ if ( apic_version[i] & 0xF0 )
+ num_starts = 2;
+ else
+ num_starts = 0;
+
+ /*
+ * Run STARTUP IPI loop.
+ */
+
+ for (j = 1; !(send_status || accept_status)
+ && (j <= num_starts) ; j++)
+ {
+ SMP_PRINTK(("Sending STARTUP #%d.\n",j));
+ apic_write(APIC_ESR, 0);
+ SMP_PRINTK(("After apic_write.\n"));
+
+ /*
+ * STARTUP IPI
+ */
+
+ cfg=apic_read(APIC_ICR2);
+ cfg&=0x00FFFFFF;
+ apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(i)); /* Target chip */
+ cfg=apic_read(APIC_ICR);
+ cfg&=~0xCDFFF; /* Clear bits */
+ cfg |= (APIC_DEST_FIELD
+ | APIC_DEST_DM_STARTUP
+ | (start_eip >> 12)); /* Boot on the stack */
+ SMP_PRINTK(("Before start apic_write.\n"));
+ apic_write(APIC_ICR, cfg); /* Kick the second */
+
+ SMP_PRINTK(("Startup point 1.\n"));
+ timeout = 0;
+ do {
+ SMP_PRINTK(("Sleeping.\n")); udelay(1000000);
+ udelay(10);
+ } while ( (send_status = (apic_read(APIC_ICR) & 0x1000))
+ && (timeout++ < 1000));
+ udelay(200);
+ accept_status = (apic_read(APIC_ESR) & 0xEF);
+ }
+ SMP_PRINTK(("After Startup.\n"));
+
+ if (send_status) /* APIC never delivered?? */
+ printk("APIC never delivered???\n");
+ if (accept_status) /* Send accept error */
+ printk("APIC delivery error (%lx).\n", accept_status);
+
+ if( !(send_status || accept_status) )
+ {
+ for(timeout=0;timeout<50000;timeout++)
+ {
+ if(cpu_callin_map[0]&(1<<i))
+ break; /* It has booted */
+ udelay(100); /* Wait 5s total for a response */
+ }
+ if(cpu_callin_map[0]&(1<<i))
+ {
+ /* number CPUs logically, starting from 1 (BSP is 0) */
+#if 0
+ cpu_number_map[i] = cpucount;
+ cpu_logical_map[cpucount] = i;
+#endif
+ }
+ else
+ {
+ if(*((volatile unsigned char *)phys_to_virt(8192))==0xA5)
+ printk("Stuck ??\n");
+ else
+ printk("Not responding.\n");
+ }
+ }
+ SMP_PRINTK(("CPU has booted.\n"));
+
+ swapper_pg_dir[0]=maincfg;
local_flush_tlb();
- sti();
+
+ /* mark "stuck" area as not stuck */
+ *((volatile unsigned long *)phys_to_virt(8192)) = 0;
}
+
/*
* Cycle through the processors sending APIC IPI's to boot each.
*/
-
+
__initfunc(void smp_boot_cpus(void))
{
int i;
- int cpucount=0;
unsigned long cfg;
- pgd_t maincfg;
- void *stack;
- extern unsigned long init_user_stack[];
-
+
/*
* Initialize the logical to physical cpu number mapping
*/
@@ -712,12 +890,10 @@ __initfunc(void smp_boot_cpus(void))
/*
* Setup boot CPU information
*/
-
- kernel_stacks[boot_cpu_id]=(void *)init_user_stack; /* Set up for boot processor first */
smp_store_cpu_info(boot_cpu_id); /* Final full version of the data */
- cpu_present_map |= (1 << smp_processor_id());
+ cpu_present_map |= (1 << hard_smp_processor_id());
cpu_number_map[boot_cpu_id] = 0;
active_kernel_processor=boot_cpu_id;
@@ -744,11 +920,11 @@ __initfunc(void smp_boot_cpus(void))
*/
apic_reg = ioremap(apic_addr,4096);
-
+
if(apic_reg == NULL)
panic("Unable to map local apic.\n");
-
-#ifdef SMP_DEBUG
+
+#ifdef SMP_DEBUG
{
int reg;
@@ -785,11 +961,11 @@ __initfunc(void smp_boot_cpus(void))
SMP_PRINTK(("Getting LVT1: %x\n", reg));
}
#endif
-
+
/*
* Enable the local APIC
*/
-
+
cfg=apic_read(APIC_SPIV);
cfg|=(1<<8); /* Enable APIC */
apic_write(APIC_SPIV,cfg);
@@ -798,15 +974,15 @@ __initfunc(void smp_boot_cpus(void))
/*
* Set up our local APIC timer:
- */
+ */
setup_APIC_clock ();
/*
* Now scan the cpu present map and fire up the other CPUs.
*/
-
+
SMP_PRINTK(("CPU map: %lx\n", cpu_present_map));
-
+
for(i=0;i<NR_CPUS;i++)
{
/*
@@ -814,213 +990,17 @@ __initfunc(void smp_boot_cpus(void))
*/
if (i == boot_cpu_id)
continue;
-
+
if ((cpu_present_map & (1 << i))
&& (max_cpus < 0 || max_cpus > cpucount+1))
{
- unsigned long send_status, accept_status;
- int timeout, num_starts, j;
-
- /*
- * We need a kernel stack for each processor.
- */
-
- stack=get_kernel_stack(); /* We allocated these earlier */
- if(stack==NULL)
- panic("No memory for processor stacks.\n");
-
- kernel_stacks[i]=(void *)phys_to_virt((unsigned long)stack);
- install_trampoline(stack);
-
- printk("Booting processor %d stack %p: ",i,stack); /* So we set what's up */
-
- /*
- * This grunge runs the startup process for
- * the targeted processor.
- */
-
- SMP_PRINTK(("Setting warm reset code and vector.\n"));
-
- /*
- * Install a writable page 0 entry.
- */
-
- cfg=pg0[0];
-
- CMOS_WRITE(0xa, 0xf);
- pg0[0]=7;
- local_flush_tlb();
- SMP_PRINTK(("1.\n"));
- *((volatile unsigned short *) phys_to_virt(0x469)) = ((unsigned long)stack)>>4;
- SMP_PRINTK(("2.\n"));
- *((volatile unsigned short *) phys_to_virt(0x467)) = 0;
- SMP_PRINTK(("3.\n"));
-
- /*
- * Protect it again
- */
-
- pg0[0]= cfg;
- local_flush_tlb();
-
- /* walken modif
- * enable mapping of the first 4M at virtual
- * address zero
- */
-
- maincfg=swapper_pg_dir[0];
- ((unsigned long *)swapper_pg_dir)[0]=0x102007;
-
- /* no need to local_flush_tlb :
- we are setting this up for the slave processor ! */
-
- /*
- * Be paranoid about clearing APIC errors.
- */
-
- if ( apic_version[i] & 0xF0 )
- {
- apic_write(APIC_ESR, 0);
- accept_status = (apic_read(APIC_ESR) & 0xEF);
- }
-
- /*
- * Status is now clean
- */
-
- send_status = 0;
- accept_status = 0;
-
- /*
- * Starting actual IPI sequence...
- */
-
- SMP_PRINTK(("Asserting INIT.\n"));
-
- /*
- * Turn INIT on
- */
-
- cfg=apic_read(APIC_ICR2);
- cfg&=0x00FFFFFF;
- apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(i)); /* Target chip */
- cfg=apic_read(APIC_ICR);
- cfg&=~0xCDFFF; /* Clear bits */
- cfg |= (APIC_DEST_FIELD | APIC_DEST_LEVELTRIG
- | APIC_DEST_ASSERT | APIC_DEST_DM_INIT);
- apic_write(APIC_ICR, cfg); /* Send IPI */
-
- udelay(200);
- SMP_PRINTK(("Deasserting INIT.\n"));
-
- cfg=apic_read(APIC_ICR2);
- cfg&=0x00FFFFFF;
- apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(i)); /* Target chip */
- cfg=apic_read(APIC_ICR);
- cfg&=~0xCDFFF; /* Clear bits */
- cfg |= (APIC_DEST_FIELD | APIC_DEST_LEVELTRIG
- | APIC_DEST_DM_INIT);
- apic_write(APIC_ICR, cfg); /* Send IPI */
-
- /*
- * Should we send STARTUP IPIs ?
- *
- * Determine this based on the APIC version.
- * If we don't have an integrated APIC, don't
- * send the STARTUP IPIs.
- */
-
- if ( apic_version[i] & 0xF0 )
- num_starts = 2;
- else
- num_starts = 0;
-
- /*
- * Run STARTUP IPI loop.
- */
-
- for (j = 1; !(send_status || accept_status)
- && (j <= num_starts) ; j++)
- {
- SMP_PRINTK(("Sending STARTUP #%d.\n",j));
-
- apic_write(APIC_ESR, 0);
- SMP_PRINTK(("After apic_write.\n"));
-
- /*
- * STARTUP IPI
- */
-
- cfg=apic_read(APIC_ICR2);
- cfg&=0x00FFFFFF;
- apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(i)); /* Target chip */
- cfg=apic_read(APIC_ICR);
- cfg&=~0xCDFFF; /* Clear bits */
- cfg |= (APIC_DEST_FIELD
- | APIC_DEST_DM_STARTUP
- | (((int)virt_to_phys(stack)) >> 12)); /* Boot on the stack */
- SMP_PRINTK(("Before start apic_write.\n"));
- apic_write(APIC_ICR, cfg); /* Kick the second */
-
- SMP_PRINTK(("Startup point 1.\n"));
- timeout = 0;
- do {
- SMP_PRINTK(("Sleeping.\n")); udelay(1000000);
- udelay(10);
- } while ( (send_status = (apic_read(APIC_ICR) & 0x1000))
- && (timeout++ < 1000));
- udelay(200);
-
- accept_status = (apic_read(APIC_ESR) & 0xEF);
- }
- SMP_PRINTK(("After Startup.\n"));
-
- if (send_status) /* APIC never delivered?? */
- printk("APIC never delivered???\n");
- if (accept_status) /* Send accept error */
- printk("APIC delivery error (%lx).\n", accept_status);
-
- if( !(send_status || accept_status) )
- {
- for(timeout=0;timeout<50000;timeout++)
- {
- if(cpu_callin_map[0]&(1<<i))
- break; /* It has booted */
- udelay(100); /* Wait 5s total for a response */
- }
- if(cpu_callin_map[0]&(1<<i))
- {
- cpucount++;
- /* number CPUs logically, starting from 1 (BSP is 0) */
- cpu_number_map[i] = cpucount;
- cpu_logical_map[cpucount] = i;
- }
- else
- {
- if(*((volatile unsigned char *)phys_to_virt(8192))==0xA5)
- printk("Stuck ??\n");
- else
- printk("Not responding.\n");
- }
- }
- SMP_PRINTK(("CPU has booted.\n"));
-
- /* walken modif
- * restore mapping of the first 4M
- */
-
- swapper_pg_dir[0]=maincfg;
-
- local_flush_tlb();
-
- /* mark "stuck" area as not stuck */
- *((volatile unsigned long *)phys_to_virt(8192)) = 0;
+ do_boot_cpu(i);
}
-
- /*
+
+ /*
* Make sure we unmap all failed CPUs
*/
-
+
if (cpu_number_map[i] == -1)
cpu_present_map &= ~(1 << i);
}
@@ -1056,12 +1036,12 @@ __initfunc(void smp_boot_cpus(void))
/*
* Allow the user to impress friends.
*/
-
+
SMP_PRINTK(("Before bogomips.\n"));
if(cpucount==0)
{
printk("Error: only one processor found.\n");
- cpu_present_map=(1<<smp_processor_id());
+ cpu_present_map=(1<<hard_smp_processor_id());
}
else
{
@@ -1071,8 +1051,8 @@ __initfunc(void smp_boot_cpus(void))
if(cpu_present_map&(1<<i))
bogosum+=cpu_data[i].udelay_val;
}
- printk("Total of %d processors activated (%lu.%02lu BogoMIPS).\n",
- cpucount+1,
+ printk("Total of %d processors activated (%lu.%02lu BogoMIPS).\n",
+ cpucount+1,
(bogosum+2500)/500000,
((bogosum+2500)/5000)%100);
SMP_PRINTK(("Before bogocount - setting activated=1.\n"));
@@ -1096,7 +1076,7 @@ __initfunc(void smp_boot_cpus(void))
* IDE disk problems), and other messages sent with IRQ's enabled in a civilised fashion. That
* will also boost performance.
*/
-
+
void smp_message_pass(int target, int msg, unsigned long data, int wait)
{
unsigned long flags;
@@ -1109,11 +1089,11 @@ void smp_message_pass(int target, int msg, unsigned long data, int wait)
/*
* During boot up send no messages
*/
-
+
if(!smp_activated || !smp_commenced)
return;
-
-
+
+
/*
* Skip the reschedule if we are waiting to clear a
* message at this time. The reschedule cannot wait
@@ -1121,7 +1101,7 @@ void smp_message_pass(int target, int msg, unsigned long data, int wait)
*/
switch (msg) {
- case MSG_RESCHEDULE:
+ case MSG_RESCHEDULE:
irq = 0x30;
if (smp_cpu_in_msg[p])
return;
@@ -1148,21 +1128,21 @@ void smp_message_pass(int target, int msg, unsigned long data, int wait)
* no data and can occur during a flush.. guess what panic
* I got to notice this bug...
*/
-
+
/*
* We are busy
*/
-
- smp_cpu_in_msg[p]++;
+ smp_cpu_in_msg[p]++;
+
/* printk("SMP message pass #%d to %d of %d\n",
p, msg, target);*/
-
+
/*
* Wait for the APIC to become ready - this should never occur. Its
* a debugging check really.
*/
-
+
while(ct<1000)
{
cfg=apic_read(APIC_ICR);
@@ -1171,14 +1151,14 @@ void smp_message_pass(int target, int msg, unsigned long data, int wait)
ct++;
udelay(10);
}
-
+
/*
* Just pray... there is nothing more we can do
*/
-
+
if(ct==1000)
printk("CPU #%d: previous IPI still not cleared after 10mS\n", p);
-
+
/*
* Program the APIC to deliver the IPI
*/
@@ -1190,12 +1170,12 @@ void smp_message_pass(int target, int msg, unsigned long data, int wait)
apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(target)); /* Target chip */
cfg=apic_read(APIC_ICR);
cfg&=~0xFDFFF; /* Clear bits */
- cfg|=APIC_DEST_FIELD|APIC_DEST_DM_FIXED|irq; /* Send an IRQ 13 */
+ cfg|=APIC_DEST_FIELD|APIC_DEST_DM_FIXED|irq; /* Send an IRQ 13 */
/*
* Set the target requirement
*/
-
+
if(target==MSG_ALL_BUT_SELF)
{
cfg|=APIC_DEST_ALLBUT;
@@ -1213,18 +1193,18 @@ void smp_message_pass(int target, int msg, unsigned long data, int wait)
target_map=(1<<target);
cpu_callin_map[0]=0;
}
-
+
/*
* Send the IPI. The write to APIC_ICR fires this off.
*/
-
+
apic_write(APIC_ICR, cfg);
__restore_flags(flags);
-
+
/*
* Spin waiting for completion
*/
-
+
switch(wait)
{
int stuck;
@@ -1247,17 +1227,17 @@ void smp_message_pass(int target, int msg, unsigned long data, int wait)
clear_bit(p, &smp_invalidate_needed);
--stuck;
if (!stuck) {
- printk("stuck on smp_invalidate_needed IPI wait\n");
+ printk("stuck on smp_invalidate_needed IPI wait (CPU#%d)\n",p);
break;
}
}
break;
}
-
+
/*
* Record our completion
*/
-
+
smp_cpu_in_msg[p]--;
}
@@ -1266,14 +1246,17 @@ void smp_message_pass(int target, int msg, unsigned long data, int wait)
* even with IRQ's off. We have to avoid a pair of crossing flushes
* or we are doomed. See the notes about smp_message_pass.
*/
-
+
void smp_flush_tlb(void)
{
unsigned long flags;
+
+#if 0
if(smp_activated && smp_processor_id()!=active_kernel_processor) {
printk("CPU #%d:Attempted flush tlb IPI when not AKP(=%d)\n",smp_processor_id(),active_kernel_processor);
*(char *)0=0;
}
+#endif
/* printk("SMI-");*/
/*
@@ -1282,30 +1265,30 @@ void smp_flush_tlb(void)
* may issue a tlb flush. If you break any one of those three change this to an atomic
* bus locked or.
*/
-
+
smp_invalidate_needed=cpu_present_map;
-
+
/*
* Processors spinning on the lock will see this IRQ late. The smp_invalidate_needed map will
* ensure they don't do a spurious flush tlb or miss one.
*/
-
+
__save_flags(flags);
__cli();
smp_message_pass(MSG_ALL_BUT_SELF, MSG_INVALIDATE_TLB, 0L, 2);
-
+
/*
* Flush the local TLB
*/
-
- local_flush_tlb();
+ local_flush_tlb();
+
__restore_flags(flags);
-
+
/*
* Completed.
*/
-
+
/* printk("SMID\n");*/
}
@@ -1315,14 +1298,14 @@ void smp_flush_tlb(void)
*
* We do profiling in every local tick, statistics/rescheduling
* happen only every 'profiling multiplier' ticks. The default
- * multiplier is 1 and it can be changed by writing a 4 bytes multiplier
+ * multiplier is 1 and it can be changed by writing the new multiplier
* value into /proc/profile.
*/
unsigned int prof_multiplier[NR_CPUS];
unsigned int prof_counter[NR_CPUS];
-static inline void smp_local_timer_interrupt(struct pt_regs * regs)
+void smp_local_timer_interrupt(struct pt_regs * regs)
{
int cpu = smp_processor_id();
@@ -1367,7 +1350,7 @@ static inline void smp_local_timer_interrupt(struct pt_regs * regs)
kstat.cpu_user += user;
kstat.cpu_system += system;
-
+
} else {
#ifdef __SMP_PROF__
if (test_bit(cpu,&smp_idle_map))
@@ -1386,14 +1369,11 @@ static inline void smp_local_timer_interrupt(struct pt_regs * regs)
* We take the 'long' return path, and there every subsystem
* grabs the apropriate locks (kernel lock/ irq lock).
*
- * FIXME: we want to decouple profiling from the 'long path'.
+ * we might want to decouple profiling from the 'long path',
+ * and do the profiling totally in assembly.
*
* Currently this isnt too much of an issue (performancewise),
* we can take more than 100K local irqs per second on a 100 MHz P5.
- * [ although we notice need_resched too early, thus the way we
- * schedule (deliver signals and handle bhs) changes. ]
- *
- * Possibly we could solve these problems with 'smart irqs'.
*/
}
@@ -1401,6 +1381,9 @@ static inline void smp_local_timer_interrupt(struct pt_regs * regs)
* Local APIC timer interrupt. This is the most natural way for doing
* local interrupts, but local timer interrupts can be emulated by
* broadcast interrupts too. [in case the hw doesnt support APIC timers]
+ *
+ * [ if a single-CPU system runs an SMP kernel then we call the local
+ * interrupt as well. Thus we cannot inline the local irq ... ]
*/
void smp_apic_timer_interrupt(struct pt_regs * regs)
{
@@ -1415,7 +1398,7 @@ void smp_apic_timer_interrupt(struct pt_regs * regs)
smp_local_timer_interrupt(regs);
}
-/*
+/*
* Reschedule call back
*/
asmlinkage void smp_reschedule_interrupt(void)
@@ -1437,11 +1420,11 @@ asmlinkage void smp_reschedule_interrupt(void)
*/
asmlinkage void smp_invalidate_interrupt(void)
{
- if (clear_bit(smp_processor_id(), &smp_invalidate_needed))
+ if (test_and_clear_bit(smp_processor_id(), &smp_invalidate_needed))
local_flush_tlb();
ack_APIC_irq ();
-}
+}
/*
* CPU halt call-back
@@ -1471,11 +1454,11 @@ asmlinkage void smp_stop_cpu_interrupt(void)
* but we do not accept timer interrupts yet. We only allow the BP
* to calibrate.
*/
-static unsigned int get_8254_timer_count (void)
+__initfunc(static unsigned int get_8254_timer_count (void))
{
unsigned int count;
- outb_p(0x00, 0x43);
+ outb_p(0x00, 0x43);
count = inb_p(0x40);
count |= inb_p(0x40) << 8;
@@ -1500,7 +1483,7 @@ static unsigned int get_8254_timer_count (void)
void setup_APIC_timer (unsigned int clocks)
{
- unsigned long lvtt1_value;
+ unsigned long lvtt1_value;
unsigned int tmp_value;
/*
@@ -1508,8 +1491,8 @@ void setup_APIC_timer (unsigned int clocks)
* mode. With the IO APIC we can re-route the external timer
* interrupt and broadcast it as an NMI to all CPUs, so no pain.
*
- * NOTE: this trap vector (0x41) and the gate in BUILD_SMP_TIMER_INTERRUPT
- * should be the same ;)
+ * NOTE: this trap vector (0x41) and the gate in
+ * BUILD_SMP_TIMER_INTERRUPT should be the same ;)
*/
tmp_value = apic_read(APIC_LVTT);
lvtt1_value = APIC_LVT_TIMER_PERIODIC | 0x41;
@@ -1526,7 +1509,7 @@ void setup_APIC_timer (unsigned int clocks)
apic_write(APIC_TMICT, clocks/APIC_DIVISOR);
}
-void wait_8254_wraparound (void)
+__initfunc(void wait_8254_wraparound (void))
{
unsigned int curr_count, prev_count=~0;
int delta;
@@ -1560,11 +1543,12 @@ void wait_8254_wraparound (void)
* APIC irq that way.
*/
-int calibrate_APIC_clock (void)
+__initfunc(int calibrate_APIC_clock (void))
{
unsigned long long t1,t2;
long tt1,tt2;
long calibration_result;
+ int i;
printk("calibrating APIC timer ... ");
@@ -1589,10 +1573,12 @@ int calibrate_APIC_clock (void)
RTDSC(t1);
tt1=apic_read(APIC_TMCCT);
+#define LOOPS (HZ/10)
/*
- * lets wait until we get to the next wrapround:
+ * lets wait LOOPS wraprounds:
*/
- wait_8254_wraparound ();
+ for (i=0; i<LOOPS; i++)
+ wait_8254_wraparound ();
tt2=apic_read(APIC_TMCCT);
RTDSC(t2);
@@ -1605,46 +1591,47 @@ int calibrate_APIC_clock (void)
* underflown to be exact, as the timer counts down ;)
*/
- calibration_result = (tt1-tt2)*APIC_DIVISOR;
+ calibration_result = (tt1-tt2)*APIC_DIVISOR/LOOPS;
- printk("\n..... %ld CPU clocks in 1 timer chip tick.\n",
- (unsigned long)(t2-t1));
+ SMP_PRINTK(("\n..... %ld CPU clocks in 1 timer chip tick.",
+ (unsigned long)(t2-t1)/LOOPS));
- printk("..... %ld APIC bus clocks in 1 timer chip tick.\n",
- calibration_result);
+ SMP_PRINTK(("\n..... %ld APIC bus clocks in 1 timer chip tick.",
+ calibration_result));
- printk("..... CPU clock speed is %ld.%ld MHz.\n",
- ((long)(t2-t1))/(1000000/HZ),
- ((long)(t2-t1))%(1000000/HZ) );
+ printk("\n..... CPU clock speed is %ld.%04ld MHz.\n",
+ ((long)(t2-t1)/LOOPS)/(1000000/HZ),
+ ((long)(t2-t1)/LOOPS)%(1000000/HZ) );
- printk("..... APIC bus clock speed is %ld.%ld MHz.\n",
+ printk("..... APIC bus clock speed is %ld.%04ld MHz.\n",
calibration_result/(1000000/HZ),
calibration_result%(1000000/HZ) );
+#undef LOOPS
return calibration_result;
}
static unsigned int calibration_result;
-void setup_APIC_clock (void)
+__initfunc(void setup_APIC_clock (void))
{
int cpu = smp_processor_id();
- unsigned long flags;
+ unsigned long flags;
static volatile int calibration_lock;
save_flags(flags);
cli();
- printk("setup_APIC_clock() called.\n");
+ SMP_PRINTK(("setup_APIC_clock() called.\n"));
/*
* [ setup_APIC_clock() is called from all CPUs, but we want
* to do this part of the setup only once ... and it fits
* here best ]
*/
- if (!set_bit(0,&calibration_lock)) {
+ if (!test_and_set_bit(0,&calibration_lock)) {
calibration_result=calibrate_APIC_clock();
/*
@@ -1656,9 +1643,9 @@ void setup_APIC_clock (void)
/*
* Other CPU is calibrating, wait for finish:
*/
- printk("waiting for other CPU calibrating APIC timer ... ");
+ SMP_PRINTK(("waiting for other CPU calibrating APIC ... "));
while (calibration_lock == 1);
- printk("done, continuing.\n");
+ SMP_PRINTK(("done, continuing.\n"));
}
/*
@@ -1669,16 +1656,8 @@ void setup_APIC_clock (void)
prof_counter[cpu] = prof_multiplier[cpu] = 1;
/*
- * FIXME: i sporadically see booting problems (keyboard irq is
- * lost, looks like the timer irq isnt working or some irq
- * lock is messed up). Once we reboot the bug doesnt showu
- * up anymore.
- *
- * i'm quite certain it's a timing problem/race condition in
- * the bootup logic, not a hw bug. It might have been gone
- * meanwhile, tell me if you see it.
+ * We ACK the APIC, just in case there is something pending.
*/
-
ack_APIC_irq ();
restore_flags(flags);
@@ -1686,7 +1665,7 @@ void setup_APIC_clock (void)
/*
* the frequency of the profiling timer can be changed
- * by writing 4 bytes into /proc/profile.
+ * by writing a multiplier value into /proc/profile.
*
* usually you want to run this on all CPUs ;)
*/
@@ -1697,8 +1676,8 @@ int setup_profiling_timer (unsigned int multiplier)
/*
* Sanity check. [at least 500 APIC cycles should be
- * between APIC interrupts as a rule of thumb, rather be
- * careful as irq flooding renders the system unusable]
+ * between APIC interrupts as a rule of thumb, to avoid
+ * irqs flooding us]
*/
if ( (!multiplier) || (calibration_result/multiplier < 500))
return -EINVAL;
diff --git a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c
index 6a7d6b461..e45cc7279 100644
--- a/arch/i386/kernel/time.c
+++ b/arch/i386/kernel/time.c
@@ -23,6 +23,7 @@
#include <linux/time.h>
#include <linux/delay.h>
#include <linux/init.h>
+#include <linux/smp.h>
#include <asm/uaccess.h>
#include <asm/io.h>
@@ -379,11 +380,15 @@ static inline void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
do_timer(regs);
/*
* In the SMP case we use the local APIC timer interrupt to do the
- * profiling.
+ * profiling, except when we simulate SMP mode on a uniprocessor
+ * system, in that case we have to call the local interrupt handler.
*/
#ifndef __SMP__
if (!user_mode(regs))
x86_do_profile(regs->eip);
+#else
+ if (!smp_found_config)
+ smp_local_timer_interrupt(regs);
#endif
/*
diff --git a/arch/i386/kernel/trampoline.S b/arch/i386/kernel/trampoline.S
index 63bc51c5e..d0a726f6b 100644
--- a/arch/i386/kernel/trampoline.S
+++ b/arch/i386/kernel/trampoline.S
@@ -21,13 +21,9 @@
* and IP is zero. Thus, data addresses need to be absolute
* (no relocation) and are taken with regard to r_base.
*
- * On the transition to protected mode, this page appears at
- * address 8192, so protected mode addresses are with regard
- * to p_base.
- *
* If you work on this file, check the object module with objdump
* --full-contents --reloc to make sure there are no relocation
- * entries.
+ * entries except for the gdt one..
*/
#include <linux/linkage.h>
@@ -39,15 +35,10 @@
ENTRY(trampoline_data)
r_base = .
-p_base = . - 8192
mov %cs, %ax # Code and data in the same place
mov %ax, %ds
- mov %ax, %cx # Pass stack info to the 32bit boot
- shl $4, %cx # Segment -> Offset
- add $4096, %cx # End of page is wanted
-
mov $1, %bx # Flag an SMP trampoline
cli # We should be safe anyway
@@ -71,37 +62,7 @@ idt_48:
gdt_48:
.word 0x0800 # gdt limit = 2048, 256 GDT entries
- .word gdt - p_base, 0x0 # gdt base = gdt (first SMP CPU)
- # we load the others with first table
- # saves rewriting gdt_48 for each
-gdt:
- .word 0, 0, 0, 0 # dummy
-
- .word 0, 0, 0, 0 # unused
-
-# walken modif
-
- .word 0xFFFF # 4 Gb - (0x100000*0x1000 = 4Gb)
- .word 0x0000 # base address = 0
- .word 0x9A00 # code read / exec
- .word 0x00CF # granularity = 4096, 386 (+5th nibble of limit)
-
- .word 0xFFFF # 4 Gb - (0x100000*0x1000 = 4Gb)
- .word 0x0000 # base address = 0
- .word 0x9200 # data read / write
- .word 0x00CF # granularity = 4096, 386 (+5th nibble of limit)
-
-# walken modif
-
-# .word 0x07FF # 8 Mb - limit = 2047 (2048 * 4096 = 8 Mb)
-# .word 0x0000 # base address = 0
-# .word 0x9A00 # code read / exec
-# .word 0x00C0 # granularity = 4096, 386
-
-# .word 0x07FF # 8 Mb - limit = 2047 (2048 * 4096 = 8 Mb)
-# .word 0x0000 # base address = 0
-# .word 0x9200 # data read / write
-# .word 0x00C0 # granularity = 4096, 386
+ .long gdt-0xc0000000 # gdt base = gdt (first SMP CPU)
.globl SYMBOL_NAME(trampoline_end)
SYMBOL_NAME_LABEL(trampoline_end)
diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c
index 905cf5b13..696e37004 100644
--- a/arch/i386/kernel/traps.c
+++ b/arch/i386/kernel/traps.c
@@ -23,10 +23,12 @@
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/init.h>
+#include <linux/delay.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/io.h>
+#include <asm/spinlock.h>
asmlinkage int system_call(void);
asmlinkage void lcall7(void);
@@ -121,7 +123,7 @@ static void show_registers(struct pt_regs *regs)
unsigned long esp;
unsigned short ss;
unsigned long *stack, addr, module_start, module_end;
- extern char start_kernel, _etext;
+ extern char _stext, _etext;
esp = (unsigned long) &regs->esp;
ss = KERNEL_DS;
@@ -129,8 +131,8 @@ static void show_registers(struct pt_regs *regs)
esp = regs->esp;
ss = regs->xss & 0xffff;
}
- printk("CPU: %d\n", smp_processor_id());
- printk("EIP: %04x:[<%08lx>]\nEFLAGS: %08lx\n", 0xffff & regs->xcs,regs->eip,regs->eflags);
+ printk("CPU: %d\nEIP: %04x:[<%08lx>]\nEFLAGS: %08lx\n",
+ smp_processor_id(), 0xffff & regs->xcs, regs->eip, regs->eflags);
printk("eax: %08lx ebx: %08lx ecx: %08lx edx: %08lx\n",
regs->eax, regs->ebx, regs->ecx, regs->edx);
printk("esi: %08lx edi: %08lx ebp: %08lx esp: %08lx\n",
@@ -138,10 +140,8 @@ static void show_registers(struct pt_regs *regs)
printk("ds: %04x es: %04x ss: %04x\n",
regs->xds & 0xffff, regs->xes & 0xffff, ss);
store_TR(i);
- if (STACK_MAGIC != *(unsigned long *)current->kernel_stack_page)
- printk("Corrupted stack page\n");
printk("Process %s (pid: %d, process nr: %d, stackpage=%08lx)\nStack: ",
- current->comm, current->pid, 0xffff & i, current->kernel_stack_page);
+ current->comm, current->pid, 0xffff & i, 4096+(unsigned long)current);
stack = (unsigned long *) esp;
for(i=0; i < kstack_depth_to_print; i++) {
if (((long) stack & 4095) == 0)
@@ -166,7 +166,7 @@ static void show_registers(struct pt_regs *regs)
* down the cause of the crash will be able to figure
* out the call path that was taken.
*/
- if (((addr >= (unsigned long) &start_kernel) &&
+ if (((addr >= (unsigned long) &_stext) &&
(addr <= (unsigned long) &_etext)) ||
((addr >= module_start) && (addr <= module_end))) {
if (i && ((i % 8) == 0))
@@ -181,13 +181,19 @@ static void show_registers(struct pt_regs *regs)
printk("\n");
}
+spinlock_t die_lock;
+
/*static*/ void die_if_kernel(const char * str, struct pt_regs * regs, long err)
{
if ((regs->eflags & VM_MASK) || (3 & regs->xcs) == 3)
return;
console_verbose();
+ spin_lock_irq(&die_lock);
printk("%s: %04lx\n", str, err & 0xffff);
show_registers(regs);
+do { int i=2000000000; while (i) i--; } while (0);
+do { int i=2000000000; while (i) i--; } while (0);
+ spin_unlock_irq(&die_lock);
do_exit(SIGSEGV);
}
@@ -235,18 +241,45 @@ out:
unlock_kernel();
}
-asmlinkage void do_nmi(struct pt_regs * regs, long error_code)
+static void mem_parity_error(unsigned char reason, struct pt_regs * regs)
{
- printk("NMI\n"); show_registers(regs);
-#ifdef CONFIG_SMP_NMI_INVAL
- smp_flush_tlb_rcv();
-#else
-#ifndef CONFIG_IGNORE_NMI
printk("Uhhuh. NMI received. Dazed and confused, but trying to continue\n");
- printk("You probably have a hardware problem with your RAM chips or a\n");
- printk("power saving mode enabled.\n");
-#endif
-#endif
+ printk("You probably have a hardware problem with your RAM chips\n");
+}
+
+static void io_check_error(unsigned char reason, struct pt_regs * regs)
+{
+ unsigned long i;
+
+ printk("NMI: IOCK error (debug interrupt?)\n");
+ show_registers(regs);
+
+ /* Re-enable the IOCK line, wait for a few seconds */
+ reason |= 8;
+ outb(reason, 0x61);
+ i = 2000;
+ while (--i) udelay(1000);
+ reason &= ~8;
+ outb(reason, 0x61);
+}
+
+static void unknown_nmi_error(unsigned char reason, struct pt_regs * regs)
+{
+ printk("Uhhuh. NMI received for unknown reason %02x.\n", reason);
+ printk("Dazed and confused, but trying to continue\n");
+ printk("Do you have a strange power saving mode enabled?\n");
+}
+
+asmlinkage void do_nmi(struct pt_regs * regs, long error_code)
+{
+ unsigned char reason = inb(0x61);
+
+ if (reason & 0x80)
+ mem_parity_error(reason, regs);
+ if (reason & 0x40)
+ io_check_error(reason, regs);
+ if (!(reason & 0xc0))
+ unknown_nmi_error(reason, regs);
}
asmlinkage void do_debug(struct pt_regs * regs, long error_code)
@@ -380,15 +413,7 @@ __initfunc(void trap_init(void))
{
int i;
struct desc_struct * p;
- static int smptrap=0;
-
- if(smptrap)
- {
- __asm__("pushfl ; andl $0xffffbfff,(%esp) ; popfl");
- load_ldt(0);
- return;
- }
- smptrap++;
+
if (readl(0x0FFFD9) == 'E' + ('I'<<8) + ('S'<<16) + ('A'<<24))
EISA_bus = 1;
set_call_gate(&default_ldt,lcall7);
diff --git a/arch/i386/kernel/vm86.c b/arch/i386/kernel/vm86.c
index bfba24327..a09fa6419 100644
--- a/arch/i386/kernel/vm86.c
+++ b/arch/i386/kernel/vm86.c
@@ -81,8 +81,8 @@ asmlinkage struct pt_regs * save_v86_state(struct kernel_vm86_regs * regs)
printk("vm86: could not access userspace vm86_info\n");
do_exit(SIGSEGV);
}
- current->tss.esp0 = current->saved_kernel_stack;
- current->saved_kernel_stack = 0;
+ current->tss.esp0 = current->tss.saved_esp0;
+ current->tss.saved_esp0 = 0;
ret = KVM86->regs32;
unlock_kernel();
return ret;
@@ -137,7 +137,7 @@ asmlinkage int sys_vm86old(struct vm86_struct * v86)
lock_kernel();
tsk = current;
- if (tsk->saved_kernel_stack)
+ if (tsk->tss.saved_esp0)
goto out;
tmp = copy_from_user(&info, v86, VM86_REGS_SIZE1);
tmp += copy_from_user(&info.regs.VM86_REGS_PART2, &v86->regs.VM86_REGS_PART2,
@@ -187,7 +187,7 @@ asmlinkage int sys_vm86(unsigned long subfunction, struct vm86plus_struct * v86)
/* we come here only for functions VM86_ENTER, VM86_ENTER_NO_BYPASS */
ret = -EPERM;
- if (tsk->saved_kernel_stack)
+ if (tsk->tss.saved_esp0)
goto out;
tmp = copy_from_user(&info, v86, VM86_REGS_SIZE1);
tmp += copy_from_user(&info.regs.VM86_REGS_PART2, &v86->regs.VM86_REGS_PART2,
@@ -247,7 +247,7 @@ static void do_sys_vm86(struct kernel_vm86_struct *info, struct task_struct *tsk
* Save old state, set default return value (%eax) to 0
*/
info->regs32->eax = 0;
- tsk->saved_kernel_stack = tsk->tss.esp0;
+ tsk->tss.saved_esp0 = tsk->tss.esp0;
tsk->tss.esp0 = (unsigned long) &info->VM86_TSS_ESP0;
tsk->tss.screen_bitmap = info->screen_bitmap;
@@ -601,11 +601,17 @@ static inline void free_vm86_irq(int irqnumber)
static inline int task_valid(struct task_struct *tsk)
{
struct task_struct *p;
+ int ret = 0;
+ read_lock(&tasklist_lock);
for_each_task(p) {
- if ((p == tsk) && (p->sig)) return 1;
+ if ((p == tsk) && (p->sig)) {
+ ret = 1;
+ break;
+ }
}
- return 0;
+ read_unlock(&tasklist_lock);
+ return ret;
}
static inline void handle_irq_zombies(void)
diff --git a/arch/i386/lib/locks.S b/arch/i386/lib/locks.S
index b9d8b0a9c..30a5bc432 100644
--- a/arch/i386/lib/locks.S
+++ b/arch/i386/lib/locks.S
@@ -10,22 +10,25 @@
* %eax contains callers PC and %edx holds this cpu ID.
*/
ENTRY(__lock_kernel)
- pushl %eax ! return address
1:
lock
btsl $0, SYMBOL_NAME(kernel_flag)
jnc 3f
+ sti
2:
btl %dl, SYMBOL_NAME(smp_invalidate_needed)
jnc 0f
lock
btrl %dl, SYMBOL_NAME(smp_invalidate_needed)
jnc 0f
+ pushl %eax
movl %cr3, %eax
movl %eax, %cr3
+ popl %eax
0:
btl $0, SYMBOL_NAME(kernel_flag)
jc 2b
+ cli
jmp 1b
3:
diff --git a/arch/i386/lib/semaphore.S b/arch/i386/lib/semaphore.S
index ff2443c40..faddbf4ec 100644
--- a/arch/i386/lib/semaphore.S
+++ b/arch/i386/lib/semaphore.S
@@ -13,16 +13,17 @@
* there is contention on the semaphore.
*/
ENTRY(__down_failed)
- pushl %eax /* return address */
+ pushl %eax /* save %eax */
pushl %edx /* save %edx */
pushl %ecx /* save %ecx (and argument) */
call SYMBOL_NAME(__down)
popl %ecx /* restore %ecx (count on __down not changing it) */
popl %edx /* restore %edx */
+ popl %eax /* restore %eax */
ret
+/* Don't save/restore %eax, because that will be our return value */
ENTRY(__down_failed_interruptible)
- pushl %eax /* return address */
pushl %edx /* save %edx */
pushl %ecx /* save %ecx (and argument) */
call SYMBOL_NAME(__down_interruptible)
@@ -31,10 +32,11 @@ ENTRY(__down_failed_interruptible)
ret
ENTRY(__up_wakeup)
- pushl %eax /* return address */
+ pushl %eax /* save %eax */
pushl %edx /* save %edx */
pushl %ecx /* save %ecx (and argument) */
call SYMBOL_NAME(__up)
popl %ecx /* restore %ecx (count on __up not changing it) */
popl %edx /* restore %edx */
+ popl %eax /* restore %eax */
ret
diff --git a/arch/i386/mm/fault.c b/arch/i386/mm/fault.c
index 65a4a67d3..b0404a6a9 100644
--- a/arch/i386/mm/fault.c
+++ b/arch/i386/mm/fault.c
@@ -49,7 +49,7 @@ good_area:
start &= PAGE_MASK;
for (;;) {
- do_wp_page(current, vma, start, 1);
+ handle_mm_fault(current,vma, start, 1);
if (!size)
break;
size--;
@@ -86,10 +86,6 @@ bad_area:
*/
asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
{
- void (*handler)(struct task_struct *,
- struct vm_area_struct *,
- unsigned long,
- int);
struct task_struct *tsk = current;
struct mm_struct *mm = tsk->mm;
struct vm_area_struct * vma;
@@ -128,10 +124,8 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
*/
good_area:
write = 0;
- handler = do_no_page;
switch (error_code & 3) {
default: /* 3: write, present */
- handler = do_wp_page;
#ifdef TEST_VERIFY_AREA
if (regs->cs == KERNEL_CS)
printk("WP fault at %08lx\n", regs->eip);
@@ -148,7 +142,7 @@ good_area:
if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
goto bad_area;
}
- handler(tsk, vma, address, write);
+ handle_mm_fault(tsk, vma, address, write);
up(&mm->mmap_sem);
/*
* Did it hit the DOS screen memory VA from vm86 mode?
@@ -169,7 +163,10 @@ bad_area:
/* Are we prepared to handle this fault? */
if ((fixup = search_exception_table(regs->eip)) != 0) {
- printk(KERN_DEBUG "Exception at [<%lx>] (%lx)\n", regs->eip, fixup);
+ printk(KERN_DEBUG "%s: Exception at [<%lx>] (%lx)\n",
+ current->comm,
+ regs->eip,
+ fixup);
regs->eip = fixup;
goto out;
}
diff --git a/arch/i386/mm/init.c b/arch/i386/mm/init.c
index 173649338..c8371aa81 100644
--- a/arch/i386/mm/init.c
+++ b/arch/i386/mm/init.c
@@ -139,12 +139,23 @@ extern char __init_begin, __init_end;
#define write_cr4 ".byte 0x0f,0x22,0xe0"
#endif
-#define set_in_cr4(x) \
-__asm__(read_cr4 "\n\t" \
- "orl %0,%%eax\n\t" \
- write_cr4 \
- : : "i" (x) \
- :"ax");
+/*
+ * Save the cr4 feature set we're using (ie
+ * Pentium 4MB enable and PPro Global page
+ * enable), so that any CPU's that boot up
+ * after us can get the correct flags.
+ */
+unsigned long mmu_cr4_features __initdata = 0;
+
+static inline void set_in_cr4(unsigned long mask)
+{
+ mmu_cr4_features |= mask;
+ __asm__(read_cr4 "\n\t"
+ "orl %0,%%eax\n\t"
+ write_cr4
+ : : "irg" (mask)
+ :"ax");
+}
/*
* paging_init() sets up the page tables - note that the first 4MB are
diff --git a/arch/i386/vmlinux.lds b/arch/i386/vmlinux.lds
index 6d1195013..7a1fd3d08 100644
--- a/arch/i386/vmlinux.lds
+++ b/arch/i386/vmlinux.lds
@@ -13,6 +13,7 @@ SECTIONS
*(.fixup)
*(.gnu.warning)
} = 0x9090
+ .text.lock : { *(.text.lock) } /* out-of-line lock text */
.rodata : { *(.rodata) }
.kstrtab : { *(.kstrtab) }
diff --git a/arch/m68k/Makefile b/arch/m68k/Makefile
index 939a80387..7548a8dc8 100644
--- a/arch/m68k/Makefile
+++ b/arch/m68k/Makefile
@@ -24,19 +24,9 @@ ifneq ($(COMPILE_ARCH),$(ARCH))
CROSS_COMPILE = m68k-linux-
endif
-#
-# Set these to indicate how to link it..
-#
-# -zmagic:
-#
-# LINKFLAGS = -Ttext 0x100000
-#
-# -qmagic (we need to remove the 32 byte header for bootup purposes)
-#
-
-LINKFLAGS = -Ttext 0x1000
+LINKFLAGS = -T $(TOPDIR)/arch/m68k/vmlinux.lds
-CFLAGS := $(CFLAGS) -pipe -fno-strength-reduce
+CFLAGS += -pipe -fno-strength-reduce -ffixed-a2
ifdef CONFIG_OPTIMIZE_040
CFLAGS := $(CFLAGS) -m68040
diff --git a/arch/m68k/amiga/amifb.c b/arch/m68k/amiga/amifb.c
index c97609611..eb72970d7 100644
--- a/arch/m68k/amiga/amifb.c
+++ b/arch/m68k/amiga/amifb.c
@@ -50,12 +50,14 @@
#include <linux/delay.h>
#include <linux/config.h>
#include <linux/interrupt.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/irq.h>
#include <asm/amigahw.h>
#include <asm/amigaints.h>
-#include <linux/fb.h>
#define DEBUG
@@ -1802,7 +1804,7 @@ static int amiga_fb_set_cursorstate(struct fb_cursorstate *state, int con)
* Initialisation
*/
-struct fb_info *amiga_fb_init(long *mem_start)
+__initfunc(struct fb_info *amiga_fb_init(long *mem_start))
{
int err, tag, i;
u_long chipptr;
diff --git a/arch/m68k/amiga/amiints.c b/arch/m68k/amiga/amiints.c
index b527a8c6c..9df5083c1 100644
--- a/arch/m68k/amiga/amiints.c
+++ b/arch/m68k/amiga/amiints.c
@@ -25,6 +25,7 @@
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/kernel_stat.h>
+#include <linux/init.h>
#include <asm/system.h>
#include <asm/irq.h>
@@ -68,7 +69,7 @@ static void ami_badint(int irq, void *dev_id, struct pt_regs *fp)
* the amiga IRQ handling routines.
*/
-void amiga_init_IRQ(void)
+__initfunc(void amiga_init_IRQ(void))
{
int i;
diff --git a/arch/m68k/amiga/amikeyb.c b/arch/m68k/amiga/amikeyb.c
index f2e826023..1058270dd 100644
--- a/arch/m68k/amiga/amikeyb.c
+++ b/arch/m68k/amiga/amikeyb.c
@@ -22,6 +22,7 @@
#include <linux/kd.h>
#include <linux/random.h>
#include <linux/kernel.h>
+#include <linux/init.h>
#include <asm/amigaints.h>
#include <asm/amigahw.h>
@@ -295,7 +296,7 @@ static void keyboard_interrupt(int irq, void *dummy, struct pt_regs *fp)
}
}
-int amiga_keyb_init(void)
+__initfunc(int amiga_keyb_init(void))
{
if (!AMIGAHW_PRESENT(AMI_KEYBOARD))
return -EIO;
diff --git a/arch/m68k/amiga/amisound.c b/arch/m68k/amiga/amisound.c
index b2b2e3055..d5656d170 100644
--- a/arch/m68k/amiga/amisound.c
+++ b/arch/m68k/amiga/amisound.c
@@ -10,6 +10,7 @@
#include <linux/sched.h>
#include <linux/timer.h>
+#include <linux/init.h>
#include <asm/system.h>
#include <asm/amigahw.h>
@@ -39,7 +40,7 @@ u_short amiga_audio_period = MAX_PERIOD;
static u_long clock_constant;
-static void init_sound(void)
+__initfunc(static void init_sound(void))
{
snd_data = amiga_chip_alloc(sizeof(sine_data));
if (!snd_data) {
@@ -84,7 +85,7 @@ void amiga_mksound( unsigned int hz, unsigned int ticks )
custom.aud[2].audlc = snd_data;
custom.aud[2].audlen = sizeof(sine_data)/2;
custom.aud[2].audper = (u_short)period;
- custom.aud[2].audvol = 64; /* maxvol */
+ custom.aud[2].audvol = 32; /* 50% of maxvol */
if (ticks) {
sound_timer.expires = jiffies + ticks;
diff --git a/arch/m68k/amiga/chipram.c b/arch/m68k/amiga/chipram.c
index 237662c93..50d5a0de0 100644
--- a/arch/m68k/amiga/chipram.c
+++ b/arch/m68k/amiga/chipram.c
@@ -8,6 +8,7 @@
#include <linux/types.h>
#include <linux/kernel.h>
+#include <linux/init.h>
#include <asm/amigahw.h>
struct chip_desc {
@@ -21,19 +22,18 @@ struct chip_desc {
#define DP(ptr) ((struct chip_desc *)(ptr))
u_long amiga_chip_size;
-static unsigned long chipavail; /*MILAN*/
+static unsigned long chipavail;
-/*MILAN*/
unsigned long amiga_chip_avail( void )
{
#ifdef DEBUG
- printk("chip_avail : %ld bytes\n",chipavail);
+ printk("chip_avail : %ld bytes\n",chipavail);
#endif
- return chipavail;
+ return chipavail;
}
-void amiga_chip_init (void)
+__initfunc(void amiga_chip_init (void))
{
struct chip_desc *dp;
diff --git a/arch/m68k/amiga/cia.c b/arch/m68k/amiga/cia.c
index 02b1ad564..408dcbf5a 100644
--- a/arch/m68k/amiga/cia.c
+++ b/arch/m68k/amiga/cia.c
@@ -15,6 +15,7 @@
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/kernel_stat.h>
+#include <linux/init.h>
#include <asm/irq.h>
#include <asm/amigahw.h>
@@ -152,7 +153,7 @@ static void cia_handler(int irq, void *dev_id, struct pt_regs *fp)
amiga_do_irq_list(base->server_irq, fp, &base->server);
}
-void cia_init_IRQ(struct ciabase *base)
+__initfunc(void cia_init_IRQ(struct ciabase *base))
{
int i;
diff --git a/arch/m68k/amiga/config.c b/arch/m68k/amiga/config.c
index 8e6ae531c..08396a5bc 100644
--- a/arch/m68k/amiga/config.c
+++ b/arch/m68k/amiga/config.c
@@ -20,6 +20,7 @@
#include <linux/kd.h>
#include <linux/tty.h>
#include <linux/console.h>
+#include <linux/init.h>
#include <asm/bootinfo.h>
#include <asm/setup.h>
@@ -148,7 +149,7 @@ int amiga_parse_bootinfo(const struct bi_record *record)
* Setup the Amiga configuration info
*/
-void config_amiga(void)
+__initfunc(void config_amiga(void))
{
/* Fill in some default values, if necessary */
if (amiga_eclock == 0)
@@ -376,8 +377,8 @@ void config_amiga(void)
static unsigned short jiffy_ticks;
-static void amiga_sched_init(void (*timer_routine)(int, void *,
- struct pt_regs *))
+__initfunc(static void amiga_sched_init(void (*timer_routine)(int, void *,
+ struct pt_regs *)))
{
jiffy_ticks = (amiga_eclock+HZ/2)/HZ;
@@ -796,7 +797,7 @@ void amiga_serial_gets(char *s, int len)
}
#endif
-static void amiga_debug_init(void)
+__initfunc(static void amiga_debug_init(void))
{
if (!strcmp( m68k_debug_device, "ser" )) {
/* no initialization required (?) */
diff --git a/arch/m68k/amiga/cyberfb.c b/arch/m68k/amiga/cyberfb.c
index d74d52c4f..31e2a4608 100644
--- a/arch/m68k/amiga/cyberfb.c
+++ b/arch/m68k/amiga/cyberfb.c
@@ -29,12 +29,13 @@
#include <linux/tty.h>
#include <linux/malloc.h>
#include <linux/delay.h>
+#include <linux/zorro.h>
+#include <linux/fb.h>
+#include <linux/init.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/irq.h>
-#include <linux/zorro.h>
#include <asm/pgtable.h>
-#include <linux/fb.h>
#include "s3blit.h"
@@ -1157,7 +1158,7 @@ void Cyber_video_setup(char *options, int *ints)
* Initialization
*/
-struct fb_info *Cyber_fb_init(long *mem_start)
+__initfunc(struct fb_info *Cyber_fb_init(long *mem_start))
{
int err;
struct Cyber_fb_par par;
diff --git a/arch/m68k/amiga/retz3fb.c b/arch/m68k/amiga/retz3fb.c
index 4885e48f7..49a0853bc 100644
--- a/arch/m68k/amiga/retz3fb.c
+++ b/arch/m68k/amiga/retz3fb.c
@@ -30,1762 +30,12 @@
#include <linux/malloc.h>
#include <linux/delay.h>
#include <linux/fb.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <asm/irq.h>
#include <linux/zorro.h>
-#include <asm/pgtable.h>
-
-#include "retz3fb.h"
-
-/* #define DEBUG if(1) */
-#define DEBUG if(0)
-
-/*
- * Reserve space for one pattern line.
- *
- * For the time being we only support 4MB boards!
- */
-
-#define PAT_MEM_SIZE 16*3
-#define PAT_MEM_OFF (4*1024*1024 - PAT_MEM_SIZE)
-
-#define arraysize(x) (sizeof(x)/sizeof(*(x)))
-
-struct retz3_fb_par {
- int xres;
- int yres;
- int xres_vir;
- int yres_vir;
- int xoffset;
- int yoffset;
- int bpp;
-
- struct fb_bitfield red;
- struct fb_bitfield green;
- struct fb_bitfield blue;
- struct fb_bitfield transp;
-
- int pixclock;
- int left_margin; /* time from sync to picture */
- int right_margin; /* time from picture to sync */
- int upper_margin; /* time from sync to picture */
- int lower_margin;
- int hsync_len; /* length of horizontal sync */
- int vsync_len; /* length of vertical sync */
- int vmode;
-};
-
-struct display_data {
- long h_total; /* Horizontal Total */
- long h_sstart; /* Horizontal Sync Start */
- long h_sstop; /* Horizontal Sync Stop */
- long h_bstart; /* Horizontal Blank Start */
- long h_bstop; /* Horizontal Blank Stop */
- long h_dispend; /* Horizontal Display End */
- long v_total; /* Vertical Total */
- long v_sstart; /* Vertical Sync Start */
- long v_sstop; /* Vertical Sync Stop */
- long v_bstart; /* Vertical Blank Start */
- long v_bstop; /* Vertical Blank Stop */
- long v_dispend; /* Horizontal Display End */
-};
-
-static struct retz3_fb_par current_par;
-
-static int current_par_valid = 0;
-static int currcon = 0;
-
-static struct display disp[MAX_NR_CONSOLES];
-static struct fb_info fb_info;
-
-static int node; /* node of the /dev/fb?current file */
-
-
-/*
- * Switch for Chipset Independency
- */
-
-static struct fb_hwswitch {
-
- /* Initialisation */
-
- int (*init)(void);
-
- /* Display Control */
-
- int (*encode_fix)(struct fb_fix_screeninfo *fix, struct retz3_fb_par *par);
- int (*decode_var)(struct fb_var_screeninfo *var, struct retz3_fb_par *par);
- int (*encode_var)(struct fb_var_screeninfo *var, struct retz3_fb_par *par);
- int (*getcolreg)(unsigned int regno, unsigned int *red, unsigned
- int *green, unsigned int *blue, unsigned int *transp);
- int (*setcolreg)(unsigned int regno, unsigned int red, unsigned int
- green, unsigned int blue, unsigned int transp);
- void (*blank)(int blank);
-} *fbhw;
-
-
-/*
- * Frame Buffer Name
- */
-
-static char retz3_fb_name[16] = "RetinaZ3";
-
-
-static int z3_key = 0;
-static unsigned char retz3_color_table [256][4];
-static unsigned long z3_mem;
-static unsigned long z3_fbmem;
-static unsigned long z3_size;
-static volatile unsigned char *z3_regs;
-
-static long *memstart;
-
-
-/*
- * Predefined Video Mode Names
- */
-
-static char *retz3_fb_modenames[] = {
-
- /*
- * Autodetect (Default) Video Mode
- */
-
- "default",
-
- /*
- * Predefined Video Modes
- */
-
- "640x480", /* RetinaZ3 8 bpp */
- "800x600", /* RetinaZ3 8 bpp */
- "1024x768i",
- "640x480-16", /* RetinaZ3 16 bpp */
- "640x480-24", /* RetinaZ3 24 bpp */
-
- /*
- * Dummy Video Modes
- */
-
- "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", "dummy",
- "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", "dummy",
- "dummy", "dummy", "dummy", "dummy", "dummy", "dummy",
-
- /*
- * User Defined Video Modes
- *
- * This doesn't work yet!!
- */
-
- "user0", "user1", "user2", "user3",
- "user4", "user5", "user6", "user7"
-};
-
-/*
- * A small info on how to convert XFree86 timing values into fb
- * timings - by Frank Neumann:
- *
-An XFree86 mode line consists of the following fields:
- "800x600" 50 800 856 976 1040 600 637 643 666
- < name > DCF HR SH1 SH2 HFL VR SV1 SV2 VFL
-
-The fields in the fb_var_screeninfo structure are:
- unsigned long pixclock; * pixel clock in ps (pico seconds) *
- unsigned long left_margin; * time from sync to picture *
- unsigned long right_margin; * time from picture to sync *
- unsigned long upper_margin; * time from sync to picture *
- unsigned long lower_margin;
- unsigned long hsync_len; * length of horizontal sync *
- unsigned long vsync_len; * length of vertical sync *
-
-1) Pixelclock:
- xfree: in MHz
- fb: In Picoseconds (ps)
-
- pixclock = 1000000 / DCF
-
-2) horizontal timings:
- left_margin = HFL - SH2
- right_margin = SH1 - HR
- hsync_len = SH2 - SH1
-
-3) vertical timings:
- upper_margin = VFL - SV2
- lower_margin = SV1 - VR
- vsync_len = SV2 - SV1
-
-Good examples for VESA timings can be found in the XFree86 source tree,
-under "programs/Xserver/hw/xfree86/doc/modeDB.txt".
-*/
-
-/*
- * Predefined Video Mode Definitions
- */
-
-static struct fb_var_screeninfo retz3_fb_predefined[] = {
-
- /*
- * Autodetect (Default) Video Mode
- */
-
- { 0, },
-
- /*
- * Predefined Video Modes
- */
-
- /*
- * NB: it is very important to adjust the pixel-clock to the color-depth.
- */
-
- {
- 640, 480, 640, 480, 0, 0, 8, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_RETINAZ3, 38461, 28, 32, 12, 10, 96, 2,
- FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
- },
- /*
- ModeLine "800x600" 36 800 824 896 1024 600 601 603 625
- < name > DCF HR SH1 SH2 HFL VR SV1 SV2 VFL
- */
- {
- /* 800 x 600, 8 bpp */
- 800, 600, 800, 600, 0, 0, 8, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_RETINAZ3, 27778, 64, 24, 22, 1, 120, 2,
- FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
- },
- /*
- ModeLine "1024x768i" 45 1024 1064 1224 1264 768 777 785 817 interlace
- < name > DCF HR SH1 SH2 HFL VR SV1 SV2 VFL
- */
- {
- /* 1024 x 768, 8 bpp, interlaced */
- 1024, 768, 1024, 768, 0, 0, 8, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_RETINAZ3, 22222, 40, 40, 32, 9, 160, 8,
- FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_INTERLACED
- },
- {
- 640, 480, 640, 480, 0, 0, 16, 0,
- {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_RETINAZ3, 38461/2, 28, 32, 12, 10, 96, 2,
- FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
- },
- {
- 640, 480, 640, 480, 0, 0, 24, 0,
- {8, 8, 8}, {8, 8, 8}, {8, 8, 8}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_RETINAZ3, 38461/3, 28, 32, 12, 10, 96, 2,
- FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
- },
-
- /*
- * Dummy Video Modes
- */
-
- { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, },
- { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, },
- { 0, }, { 0, },
-
- /*
- * User Defined Video Modes
- */
-
- { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }
-};
-
-
-#define NUM_TOTAL_MODES arraysize(retz3_fb_predefined)
-#define NUM_PREDEF_MODES (5)
-
-
-static int z3fb_inverse = 0;
-static int z3fb_mode = 0;
-
-
-/*
- * Interface used by the world
- */
-
-int retz3_probe(void);
-void retz3_video_setup(char *options, int *ints);
-
-static int retz3_fb_get_fix(struct fb_fix_screeninfo *fix, int con);
-static int retz3_fb_get_var(struct fb_var_screeninfo *var, int con);
-static int retz3_fb_set_var(struct fb_var_screeninfo *var, int con);
-static int retz3_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con);
-static int retz3_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con);
-static int retz3_fb_pan_display(struct fb_var_screeninfo *var, int con);
-static int retz3_fb_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg, int con);
-
-
-/*
- * Interface to the low level console driver
- */
-
-struct fb_info *retz3_fb_init(long *mem_start); /* Through amiga_fb_init() */
-static int z3fb_switch(int con);
-static int z3fb_updatevar(int con);
-static void z3fb_blank(int blank);
-static int z3fb_setcmap(struct fb_cmap *cmap, int con);
-
-
-/*
- * Accelerated Functions used by the low level console driver
- */
-
-void retz3_bitblt(struct fb_var_screeninfo *scr,
- unsigned short curx, unsigned short cury, unsigned
- short destx, unsigned short desty, unsigned short
- width, unsigned short height, unsigned short cmd,
- unsigned short mask);
-void retz3_fill(unsigned short x, unsigned short y, unsigned short
- width, unsigned short height, unsigned short mode,
- unsigned short color);
-
-/*
- * Hardware Specific Routines
- */
-
-static int retz3_init(void);
-static int retz3_encode_fix(struct fb_fix_screeninfo *fix,
- struct retz3_fb_par *par);
-static int retz3_decode_var(struct fb_var_screeninfo *var,
- struct retz3_fb_par *par);
-static int retz3_encode_var(struct fb_var_screeninfo *var,
- struct retz3_fb_par *par);
-static int retz3_getcolreg(unsigned int regno, unsigned int *red,
- unsigned int *green, unsigned int *blue,
- unsigned int *transp);
-static int retz3_setcolreg(unsigned int regno, unsigned int red,
- unsigned int green, unsigned int blue,
- unsigned int transp);
-static void retz3_blank(int blank);
-
-
-/*
- * Internal routines
- */
-
-static void retz3_fb_get_par(struct retz3_fb_par *par);
-static void retz3_fb_set_par(struct retz3_fb_par *par);
-static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive);
-static struct fb_cmap *get_default_colormap(int bpp);
-static int do_fb_get_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var,
- int kspc);
-static int do_fb_set_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var,
- int kspc);
-static void do_install_cmap(int con);
-static void memcpy_fs(int fsfromto, void *to, void *from, int len);
-static void copy_cmap(struct fb_cmap *from, struct fb_cmap *to, int fsfromto);
-static int alloc_cmap(struct fb_cmap *cmap, int len, int transp);
-static void retz3_fb_set_disp(int con);
-static int get_video_mode(const char *name);
-
-
-/* -------------------- Hardware specific routines -------------------------- */
-
-static unsigned short find_fq(unsigned int freq)
-{
- unsigned long f;
- long tmp;
- long prev = 0x7fffffff;
- long n2, n1 = 3;
- unsigned long m;
- unsigned short res = 0;
-
- if (freq <= 31250000)
- n2 = 3;
- else if (freq <= 62500000)
- n2 = 2;
- else if (freq <= 125000000)
- n2 = 1;
- else if (freq <= 250000000)
- n2 = 0;
- else
- return(0);
-
-
- do {
- f = freq >> (10 - n2);
-
- m = (f * n1) / (14318180/1024);
-
- if (m > 129)
- break;
-
- tmp = (((m * 14318180) >> n2) / n1) - freq;
- if (tmp < 0)
- tmp = -tmp;
-
- if (tmp < prev) {
- prev = tmp;
- res = (((n2 << 5) | (n1-2)) << 8) | (m-2);
- }
-
- } while ( (++n1) <= 21);
-
- return res;
-}
-
-
-static int retz3_set_video(struct fb_var_screeninfo *var,
- struct retz3_fb_par *par)
-{
- float freq_f;
- long freq;
-
- int xres, hfront, hsync, hback;
- int yres, vfront, vsync, vback;
- unsigned char tmp;
- unsigned short best_freq;
- struct display_data data;
-
- short clocksel = 0; /* Apparantly this is always zero */
-
- int bpp = var->bits_per_pixel;
-
- /*
- * XXX
- */
- if (bpp == 24)
- return 0;
-
- if ((bpp != 8) && (bpp != 16) && (bpp != 24))
- return -EFAULT;
-
- par->xoffset = 0;
- par->yoffset = 0;
-
- xres = var->xres * bpp / 4;
- hfront = var->right_margin * bpp / 4;
- hsync = var->hsync_len * bpp / 4;
- hback = var->left_margin * bpp / 4;
-
- if (var->vmode & FB_VMODE_DOUBLE)
- {
- yres = var->yres * 2;
- vfront = var->lower_margin * 2;
- vsync = var->vsync_len * 2;
- vback = var->upper_margin * 2;
- }
- else if (var->vmode & FB_VMODE_INTERLACED)
- {
- yres = (var->yres + 1) / 2;
- vfront = (var->lower_margin + 1) / 2;
- vsync = (var->vsync_len + 1) / 2;
- vback = (var->upper_margin + 1) / 2;
- }
- else
- {
- yres = var->yres; /* -1 ? */
- vfront = var->lower_margin;
- vsync = var->vsync_len;
- vback = var->upper_margin;
- }
-
- data.h_total = (hback / 8) + (xres / 8)
- + (hfront / 8) + (hsync / 8) - 1 /* + 1 */;
- data.h_dispend = ((xres + bpp - 1)/ 8) - 1;
- data.h_bstart = xres / 8 /* + 1 */;
-
- data.h_bstop = data.h_total+1 + 2 + 1;
- data.h_sstart = (xres / 8) + (hfront / 8) + 1;
- data.h_sstop = (xres / 8) + (hfront / 8) + (hsync / 8) + 1;
-
- data.v_total = yres + vfront + vsync + vback - 1;
-
- data.v_dispend = yres - 1;
- data.v_bstart = yres;
-
- data.v_bstop = data.v_total;
- data.v_sstart = yres + vfront - 1 - 2;
- data.v_sstop = yres + vfront + vsync - 1;
-
-#if 0 /* testing */
-
- printk("HBS: %i\n", data.h_bstart);
- printk("HSS: %i\n", data.h_sstart);
- printk("HSE: %i\n", data.h_sstop);
- printk("HBE: %i\n", data.h_bstop);
- printk("HT: %i\n", data.h_total);
-
- printk("hsync: %i\n", hsync);
- printk("hfront: %i\n", hfront);
- printk("hback: %i\n", hback);
-
- printk("VBS: %i\n", data.v_bstart);
- printk("VSS: %i\n", data.v_sstart);
- printk("VSE: %i\n", data.v_sstop);
- printk("VBE: %i\n", data.v_bstop);
- printk("VT: %i\n", data.v_total);
-
- printk("vsync: %i\n", vsync);
- printk("vfront: %i\n", vfront);
- printk("vback: %i\n", vback);
-#endif
-
- if (data.v_total >= 1024)
- printk("MAYDAY: v_total >= 1024; bailing out!\n");
-
- reg_w(GREG_MISC_OUTPUT_W, 0xe3 | ((clocksel & 3) * 0x04));
- reg_w(GREG_FEATURE_CONTROL_W, 0x00);
-
- seq_w(SEQ_RESET, 0x00);
- seq_w(SEQ_RESET, 0x03); /* reset sequencer logic */
-
- /*
- * CLOCKING_MODE bits:
- * 2: This one is only set for certain text-modes, wonder if
- * it may be for EGA-lines? (it was referred to as CLKDIV2)
- * (The CL drivers sets it to 0x21 with the comment:
- * FullBandwidth (video off) and 8/9 dot clock)
- */
- seq_w(SEQ_CLOCKING_MODE, 0x01 | 0x00 /* 0x08 */);
-
- seq_w(SEQ_MAP_MASK, 0x0f); /* enable writing to plane 0-3 */
- seq_w(SEQ_CHAR_MAP_SELECT, 0x00); /* doesn't matter in gfx-mode */
- seq_w(SEQ_MEMORY_MODE, 0x06); /* CL driver says 0x0e for 256 col mode*/
- seq_w(SEQ_RESET, 0x01);
- seq_w(SEQ_RESET, 0x03);
-
- seq_w(SEQ_EXTENDED_ENABLE, 0x05);
-
- seq_w(SEQ_CURSOR_CONTROL, 0x00); /* disable cursor */
- seq_w(SEQ_PRIM_HOST_OFF_HI, 0x00);
- seq_w(SEQ_PRIM_HOST_OFF_HI, 0x00);
- seq_w(SEQ_LINEAR_0, 0x4a);
- seq_w(SEQ_LINEAR_1, 0x00);
-
- seq_w(SEQ_SEC_HOST_OFF_HI, 0x00);
- seq_w(SEQ_SEC_HOST_OFF_LO, 0x00);
- seq_w(SEQ_EXTENDED_MEM_ENA, 0x3 | 0x4 | 0x10 | 0x40);
-
- /*
- * The lower 4 bits (0-3) are used to set the font-width for
- * text-mode - DON'T try to set this for gfx-mode.
- */
- seq_w(SEQ_EXT_CLOCK_MODE, 0x10);
- seq_w(SEQ_EXT_VIDEO_ADDR, 0x03);
-
- /*
- * Extended Pixel Control:
- * bit 0: text-mode=0, gfx-mode=1 (Graphics Byte ?)
- * bit 1: (Packed/Nibble Pixel Format ?)
- * bit 4-5: depth, 0=1-8bpp, 1=9-16bpp, 2=17-24bpp
- */
- seq_w(SEQ_EXT_PIXEL_CNTL, 0x01 | (((bpp / 8) - 1) << 4));
-
- seq_w(SEQ_BUS_WIDTH_FEEDB, 0x04);
- seq_w(SEQ_COLOR_EXP_WFG, 0x01);
- seq_w(SEQ_COLOR_EXP_WBG, 0x00);
- seq_w(SEQ_EXT_RW_CONTROL, 0x00);
- seq_w(SEQ_MISC_FEATURE_SEL, (0x51 | (clocksel & 8)));
- seq_w(SEQ_COLOR_KEY_CNTL, 0x40);
- seq_w(SEQ_COLOR_KEY_MATCH0, 0x00);
- seq_w(SEQ_COLOR_KEY_MATCH1, 0x00);
- seq_w(SEQ_COLOR_KEY_MATCH2, 0x00);
- seq_w(SEQ_CRC_CONTROL, 0x00);
- seq_w(SEQ_PERF_SELECT, 0x10);
- seq_w(SEQ_ACM_APERTURE_1, 0x00);
- seq_w(SEQ_ACM_APERTURE_2, 0x30);
- seq_w(SEQ_ACM_APERTURE_3, 0x00);
- seq_w(SEQ_MEMORY_MAP_CNTL, 0x03);
-
-
- /* unlock register CRT0..CRT7 */
- crt_w(CRT_END_VER_RETR, (data.v_sstop & 0x0f) | 0x20);
-
- /* Zuerst zu schreibende Werte nur per printk ausgeben */
- DEBUG printk("CRT_HOR_TOTAL: %ld\n", data.h_total);
- crt_w(CRT_HOR_TOTAL, data.h_total & 0xff);
-
- DEBUG printk("CRT_HOR_DISP_ENA_END: %ld\n", data.h_dispend);
- crt_w(CRT_HOR_DISP_ENA_END, (data.h_dispend) & 0xff);
-
- DEBUG printk("CRT_START_HOR_BLANK: %ld\n", data.h_bstart);
- crt_w(CRT_START_HOR_BLANK, data.h_bstart & 0xff);
-
- DEBUG printk("CRT_END_HOR_BLANK: 128+%ld\n", data.h_bstop % 32);
- crt_w(CRT_END_HOR_BLANK, 0x80 | (data.h_bstop & 0x1f));
-
- DEBUG printk("CRT_START_HOR_RETR: %ld\n", data.h_sstart);
- crt_w(CRT_START_HOR_RETR, data.h_sstart & 0xff);
-
- tmp = (data.h_sstop & 0x1f);
- if (data.h_bstop & 0x20)
- tmp |= 0x80;
- DEBUG printk("CRT_END_HOR_RETR: %d\n", tmp);
- crt_w(CRT_END_HOR_RETR, tmp);
-
- DEBUG printk("CRT_VER_TOTAL: %ld\n", data.v_total & 0xff);
- crt_w(CRT_VER_TOTAL, (data.v_total & 0xff));
-
- tmp = 0x10; /* LineCompare bit #9 */
- if (data.v_total & 256)
- tmp |= 0x01;
- if (data.v_dispend & 256)
- tmp |= 0x02;
- if (data.v_sstart & 256)
- tmp |= 0x04;
- if (data.v_bstart & 256)
- tmp |= 0x08;
- if (data.v_total & 512)
- tmp |= 0x20;
- if (data.v_dispend & 512)
- tmp |= 0x40;
- if (data.v_sstart & 512)
- tmp |= 0x80;
- DEBUG printk("CRT_OVERFLOW: %d\n", tmp);
- crt_w(CRT_OVERFLOW, tmp);
-
- crt_w(CRT_PRESET_ROW_SCAN, 0x00); /* not CL !!! */
-
- tmp = 0x40; /* LineCompare bit #8 */
- if (data.v_bstart & 512)
- tmp |= 0x20;
- if (var->vmode & FB_VMODE_DOUBLE)
- tmp |= 0x80;
- DEBUG printk("CRT_MAX_SCAN_LINE: %d\n", tmp);
- crt_w(CRT_MAX_SCAN_LINE, tmp);
-
- crt_w(CRT_CURSOR_START, 0x00);
- crt_w(CRT_CURSOR_END, 8 & 0x1f); /* font height */
-
- crt_w(CRT_START_ADDR_HIGH, 0x00);
- crt_w(CRT_START_ADDR_LOW, 0x00);
-
- crt_w(CRT_CURSOR_LOC_HIGH, 0x00);
- crt_w(CRT_CURSOR_LOC_LOW, 0x00);
-
- DEBUG printk("CRT_START_VER_RETR: %ld\n", data.v_sstart & 0xff);
- crt_w(CRT_START_VER_RETR, (data.v_sstart & 0xff));
-
-#if 1
- /* 5 refresh cycles per scanline */
- DEBUG printk("CRT_END_VER_RETR: 64+32+%ld\n", data.v_sstop % 16);
- crt_w(CRT_END_VER_RETR, ((data.v_sstop & 0x0f) | 0x40 | 0x20));
-#else
- DEBUG printk("CRT_END_VER_RETR: 128+32+%ld\n", data.v_sstop % 16);
- crt_w(CRT_END_VER_RETR, ((data.v_sstop & 0x0f) | 128 | 32));
-#endif
- DEBUG printk("CRT_VER_DISP_ENA_END: %ld\n", data.v_dispend & 0xff);
- crt_w(CRT_VER_DISP_ENA_END, (data.v_dispend & 0xff));
-
- DEBUG printk("CRT_START_VER_BLANK: %ld\n", data.v_bstart & 0xff);
- crt_w(CRT_START_VER_BLANK, (data.v_bstart & 0xff));
-
- DEBUG printk("CRT_END_VER_BLANK: %ld\n", data.v_bstop & 0xff);
- crt_w(CRT_END_VER_BLANK, (data.v_bstop & 0xff));
-
- DEBUG printk("CRT_MODE_CONTROL: 0xe3\n");
- crt_w(CRT_MODE_CONTROL, 0xe3);
-
- DEBUG printk("CRT_LINE_COMPARE: 0xff\n");
- crt_w(CRT_LINE_COMPARE, 0xff);
-
- tmp = (var->xres_virtual / 8) * (bpp / 8);
- crt_w(CRT_OFFSET, tmp);
-
- crt_w(CRT_UNDERLINE_LOC, 0x07); /* probably font-height - 1 */
-
- tmp = 0x20; /* Enable extended end bits */
- if (data.h_total & 0x100)
- tmp |= 0x01;
- if ((data.h_dispend) & 0x100)
- tmp |= 0x02;
- if (data.h_bstart & 0x100)
- tmp |= 0x04;
- if (data.h_sstart & 0x100)
- tmp |= 0x08;
- if (var->vmode & FB_VMODE_INTERLACED)
- tmp |= 0x10;
- DEBUG printk("CRT_EXT_HOR_TIMING1: %d\n", tmp);
- crt_w(CRT_EXT_HOR_TIMING1, tmp);
-
- tmp = 0x00;
- if (((var->xres_virtual / 8) * (bpp / 8)) & 0x100)
- tmp |= 0x10;
- crt_w(CRT_EXT_START_ADDR, tmp);
-
- tmp = 0x00;
- if (data.h_total & 0x200)
- tmp |= 0x01;
- if ((data.h_dispend) & 0x200)
- tmp |= 0x02;
- if (data.h_bstart & 0x200)
- tmp |= 0x04;
- if (data.h_sstart & 0x200)
- tmp |= 0x08;
- tmp |= ((data.h_bstop & 0xc0) >> 2);
- tmp |= ((data.h_sstop & 0x60) << 1);
- crt_w(CRT_EXT_HOR_TIMING2, tmp);
- DEBUG printk("CRT_EXT_HOR_TIMING2: %d\n", tmp);
-
- tmp = 0x10; /* Line compare bit 10 */
- if (data.v_total & 0x400)
- tmp |= 0x01;
- if ((data.v_dispend) & 0x400)
- tmp |= 0x02;
- if (data.v_bstart & 0x400)
- tmp |= 0x04;
- if (data.v_sstart & 0x400)
- tmp |= 0x08;
- tmp |= ((data.v_bstop & 0x300) >> 3);
- if (data.v_sstop & 0x10)
- tmp |= 0x80;
- crt_w(CRT_EXT_VER_TIMING, tmp);
- DEBUG printk("CRT_EXT_VER_TIMING: %d\n", tmp);
-
- crt_w(CRT_MONITOR_POWER, 0x00);
-
- /*
- * Convert from ps to Hz.
- */
- freq_f = (1.0/(float)var->pixclock) * 1000000000;
- freq = ((long)freq_f) * 1000;
-
- best_freq = find_fq(freq);
- pll_w(0x02, best_freq);
- best_freq = find_fq(61000000);
- pll_w(0x0a, best_freq);
- pll_w(0x0e, 0x22);
-
- gfx_w(GFX_SET_RESET, 0x00);
- gfx_w(GFX_ENABLE_SET_RESET, 0x00);
- gfx_w(GFX_COLOR_COMPARE, 0x00);
- gfx_w(GFX_DATA_ROTATE, 0x00);
- gfx_w(GFX_READ_MAP_SELECT, 0x00);
- gfx_w(GFX_GRAPHICS_MODE, 0x00);
- gfx_w(GFX_MISC, 0x05);
- gfx_w(GFX_COLOR_XCARE, 0x0f);
- gfx_w(GFX_BITMASK, 0xff);
-
- reg_r(ACT_ADDRESS_RESET);
- attr_w(ACT_PALETTE0 , 0x00);
- attr_w(ACT_PALETTE1 , 0x01);
- attr_w(ACT_PALETTE2 , 0x02);
- attr_w(ACT_PALETTE3 , 0x03);
- attr_w(ACT_PALETTE4 , 0x04);
- attr_w(ACT_PALETTE5 , 0x05);
- attr_w(ACT_PALETTE6 , 0x06);
- attr_w(ACT_PALETTE7 , 0x07);
- attr_w(ACT_PALETTE8 , 0x08);
- attr_w(ACT_PALETTE9 , 0x09);
- attr_w(ACT_PALETTE10, 0x0a);
- attr_w(ACT_PALETTE11, 0x0b);
- attr_w(ACT_PALETTE12, 0x0c);
- attr_w(ACT_PALETTE13, 0x0d);
- attr_w(ACT_PALETTE14, 0x0e);
- attr_w(ACT_PALETTE15, 0x0f);
- reg_r(ACT_ADDRESS_RESET);
-
- attr_w(ACT_ATTR_MODE_CNTL, 0x09); /* 0x01 for CL */
-
- attr_w(ACT_OVERSCAN_COLOR, 0x00);
- attr_w(ACT_COLOR_PLANE_ENA, 0x0f);
- attr_w(ACT_HOR_PEL_PANNING, 0x00);
- attr_w(ACT_COLOR_SELECT, 0x00);
-
- reg_r(ACT_ADDRESS_RESET);
- reg_w(ACT_DATA, 0x20);
-
- reg_w(VDAC_MASK, 0xff);
-
- /*
- * Extended palette adressing ???
- */
- switch (bpp){
- case 8:
- reg_w(0x83c6, 0x00);
- break;
- case 16:
- reg_w(0x83c6, 0x60);
- break;
- case 24:
- reg_w(0x83c6, 0xe0);
- break;
- default:
- printk("Illegal color-depth: %i\n", bpp);
- }
-
- reg_w(VDAC_ADDRESS, 0x00);
-
- seq_w(SEQ_MAP_MASK, 0x0f );
-
- return 0;
-}
-
-/*
- * Initialization
- *
- * Set the default video mode for this chipset. If a video mode was
- * specified on the command line, it will override the default mode.
- */
-
-static int retz3_init(void)
-{
- int i;
-#if 0
- volatile unsigned long *CursorBase;
-#endif
- unsigned long board_addr, board_size;
- struct ConfigDev *cd;
-
- cd = zorro_get_board (z3_key);
- zorro_config_board (z3_key, 0);
- board_addr = (unsigned long)cd->cd_BoardAddr;
- board_size = (unsigned long)cd->cd_BoardSize;
-
- for (i = 0; i < 256; i++){
- for (i = 0; i < 256; i++){
- retz3_color_table [i][0] = i;
- retz3_color_table [i][1] = i;
- retz3_color_table [i][2] = i;
- retz3_color_table [i][3] = 0;
- }
- }
-
- *memstart = (*memstart + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
-
- z3_mem = kernel_map (board_addr, board_size,
- KERNELMAP_NOCACHE_SER, memstart);
-
- z3_regs = (char*) z3_mem;
- z3_fbmem = z3_mem + VIDEO_MEM_OFFSET;
-
- /* Get memory size - for now we asume its a 4MB board */
-
- z3_size = 0x00400000; /* 4 MB */
-
- memset ((char*)z3_fbmem, 0, z3_size);
-
- /* Disable hardware cursor */
-
- seq_w(SEQ_CURSOR_Y_INDEX, 0x00);
-
-
-#if 0
- /* Initialize hardware cursor */
- CursorBase = (unsigned long *)((char *)(z3_mem) + z3_size - 0x400);
- for (i=0; i < 8; i++){
- *(CursorBase +(i*4)) = 0xffffff00;
- *(CursorBase+1+(i*4)) = 0xffff0000;
- *(CursorBase+2+(i*4)) = 0xffff0000;
- *(CursorBase+3+(i*4)) = 0xffff0000;
- }
- for (i=8; i < 64; i++){
- *(CursorBase +(i*4)) = 0xffff0000;
- *(CursorBase+1+(i*4)) = 0xffff0000;
- *(CursorBase+2+(i*4)) = 0xffff0000;
- *(CursorBase+3+(i*4)) = 0xffff0000;
- }
-#endif
-
- retz3_setcolreg (255, 56, 100, 160, 0);
- retz3_setcolreg (254, 0, 0, 0, 0);
-
- return 0;
-}
-
-
-/*
- * This function should fill in the `fix' structure based on the
- * values in the `par' structure.
- */
-
-static int retz3_encode_fix(struct fb_fix_screeninfo *fix,
- struct retz3_fb_par *par)
-{
- int i;
-
- strcpy(fix->id, retz3_fb_name);
- fix->smem_start = z3_fbmem;
- fix->smem_len = z3_size;
-
- fix->type = FB_TYPE_PACKED_PIXELS;
- fix->type_aux = 0;
- if (par->bpp == 8)
- fix->visual = FB_VISUAL_PSEUDOCOLOR;
- else
- fix->visual = FB_VISUAL_DIRECTCOLOR;
-
- fix->xpanstep = 0;
- fix->ypanstep = 0;
- fix->ywrapstep = 0;
- fix->line_length = 0;
-
- for (i = 0; i < arraysize(fix->reserved); i++)
- fix->reserved[i] = 0;
-
- return 0;
-}
-
-
-/*
- * Get the video params out of `var'. If a value doesn't fit, round
- * it up, if it's too big, return -EINVAL.
- */
-
-static int retz3_decode_var(struct fb_var_screeninfo *var,
- struct retz3_fb_par *par)
-{
- par->xres = var->xres;
- par->yres = var->yres;
- par->xres_vir = var->xres_virtual;
- par->yres_vir = var->yres_virtual;
- par->bpp = var->bits_per_pixel;
- par->pixclock = var->pixclock;
- par->vmode = var->vmode;
-
- par->red = var->red;
- par->green = var->green;
- par->blue = var->blue;
- par->transp = var->transp;
-
- par->left_margin = var->left_margin;
- par->right_margin = var->right_margin;
- par->upper_margin = var->upper_margin;
- par->lower_margin = var->lower_margin;
- par->hsync_len = var->hsync_len;
- par->vsync_len = var->vsync_len;
-
- return 0;
-}
-
-
-/*
- * Fill the `var' structure based on the values in `par' and maybe
- * other values read out of the hardware.
- */
-
-static int retz3_encode_var(struct fb_var_screeninfo *var,
- struct retz3_fb_par *par)
-{
- int i;
-
- var->xres = par->xres;
- var->yres = par->yres;
- var->xres_virtual = par->xres_vir;
- var->yres_virtual = par->yres_vir;
- var->xoffset = 0;
- var->yoffset = 0;
-
- var->bits_per_pixel = par->bpp;
- var->grayscale = 0;
-
- var->red = par->red;
- var->green = par->green;
- var->blue = par->blue;
- var->transp = par->transp;
-
- var->nonstd = 0;
- var->activate = 0;
-
- var->height = -1;
- var->width = -1;
-
- var->accel = FB_ACCEL_RETINAZ3;
-
- var->pixclock = par->pixclock;
-
- var->sync = 0; /* ??? */
- var->left_margin = par->left_margin;
- var->right_margin = par->right_margin;
- var->upper_margin = par->upper_margin;
- var->lower_margin = par->lower_margin;
- var->hsync_len = par->hsync_len;
- var->vsync_len = par->vsync_len;
-
- for (i = 0; i < arraysize(var->reserved); i++)
- var->reserved[i] = 0;
-
- var->vmode = par->vmode;
- return 0;
-}
-
-
-/*
- * Set a single color register. The values supplied are already
- * rounded down to the hardware's capabilities (according to the
- * entries in the var structure). Return != 0 for invalid regno.
- */
-
-static int retz3_setcolreg(unsigned int regno, unsigned int red,
- unsigned int green, unsigned int blue,
- unsigned int transp)
-{
- /* We'll get to this */
-
- if (regno > 255)
- return 1;
-
- retz3_color_table [regno][0] = red & 0xff;
- retz3_color_table [regno][1] = green & 0xff;
- retz3_color_table [regno][2] = blue & 0xff;
- retz3_color_table [regno][3] = transp;
-
- reg_w(VDAC_ADDRESS_W, regno);
- reg_w(VDAC_DATA, (red & 0xff) >> 2);
- reg_w(VDAC_DATA, (green & 0xff) >> 2);
- reg_w(VDAC_DATA, (blue & 0xff) >> 2);
-
- return 0;
-}
-
-
-/*
- * Read a single color register and split it into
- * colors/transparent. Return != 0 for invalid regno.
- */
-
-static int retz3_getcolreg(unsigned int regno, unsigned int *red,
- unsigned int *green, unsigned int *blue,
- unsigned int *transp)
-{
- if (regno > 255)
- return 1;
- *red = retz3_color_table [regno][0];
- *green = retz3_color_table [regno][1];
- *blue = retz3_color_table [regno][2];
- *transp = retz3_color_table [regno][3];
- return 0;
-}
-
-
-/*
- * (Un)Blank the screen
- */
-
-void retz3_blank(int blank)
-{
- int i;
-
- if (blank)
- for (i = 0; i < 256; i++){
- reg_w(VDAC_ADDRESS_W, i);
- reg_w(VDAC_DATA, 0);
- reg_w(VDAC_DATA, 0);
- reg_w(VDAC_DATA, 0);
- }
- else
- for (i = 0; i < 256; i++){
- reg_w(VDAC_ADDRESS_W, i);
- reg_w(VDAC_DATA, retz3_color_table [i][0] >> 2);
- reg_w(VDAC_DATA, retz3_color_table [i][1] >> 2);
- reg_w(VDAC_DATA, retz3_color_table [i][2] >> 2);
- }
-}
-
-
-void retz3_bitblt (struct fb_var_screeninfo *var,
- unsigned short srcx, unsigned short srcy, unsigned
- short destx, unsigned short desty, unsigned short
- width, unsigned short height, unsigned short cmd,
- unsigned short mask)
-{
-
- volatile unsigned long *acm = (unsigned long *) (z3_mem + ACM_OFFSET);
- unsigned long *pattern = (unsigned long *)(z3_fbmem + PAT_MEM_OFF);
-
- unsigned short mod;
- unsigned long tmp;
- unsigned long pat, src, dst;
- unsigned char blt_status;
-
- int i, xres_virtual = var->xres_virtual;
- short bpp = (var->bits_per_pixel & 0xff);
-
- if (bpp < 8)
- bpp = 8;
-
- tmp = mask | (mask << 16);
-
-#if 0
- /*
- * Check for blitter finished before we start messing with the
- * pattern.
- */
- do{
- blt_status = *(((volatile unsigned char *)acm) +
- (ACM_START_STATUS + 2));
- }while ((blt_status & 1) == 0);
-#endif
-
- i = 0;
- do{
- *pattern++ = tmp;
- }while(i++ < bpp/4);
-
- tmp = cmd << 8;
- *(acm + ACM_RASTEROP_ROTATION/4) = tmp;
-
- mod = 0xc0c2;
-
- pat = 8 * PAT_MEM_OFF;
- dst = bpp * (destx + desty * xres_virtual);
-
- /*
- * Source is not set for clear.
- */
- if ((cmd != Z3BLTclear) && (cmd != Z3BLTset)) {
- src = bpp * (srcx + srcy * xres_virtual);
-
- if (destx > srcx) {
- mod &= ~0x8000;
- src += bpp * (width - 1);
- dst += bpp * (width - 1);
- pat += bpp * 2;
- }
- if (desty > srcy) {
- mod &= ~0x4000;
- src += bpp * (height - 1) * xres_virtual;
- dst += bpp * (height - 1) * xres_virtual;
- pat += bpp * 4;
- }
-
- *(acm + ACM_SOURCE/4) = cpu_to_le32(src);
- }
-
- *(acm + ACM_PATTERN/4) = cpu_to_le32(pat);
-
- *(acm + ACM_DESTINATION/4) = cpu_to_le32(dst);
-
- tmp = mod << 16;
- *(acm + ACM_CONTROL/4) = tmp;
-
- tmp = width | (height << 16);
-
- *(acm + ACM_BITMAP_DIMENSION/4) = cpu_to_le32(tmp);
-
- *(((volatile unsigned char *)acm) + ACM_START_STATUS) = 0x00;
- *(((volatile unsigned char *)acm) + ACM_START_STATUS) = 0x01;
-
- /*
- * No reason to wait for the blitter to finish, it is better
- * just to check if it has finished before we use it again.
- */
-#if 1
-#if 0
- while ((*(((volatile unsigned char *)acm) +
- (ACM_START_STATUS + 2)) & 1) == 0);
-#else
- do{
- blt_status = *(((volatile unsigned char *)acm) +
- (ACM_START_STATUS + 2));
- }
- while ((blt_status & 1) == 0);
-#endif
-#endif
-}
+#include <linux/init.h>
-#if 0
-void retz3_fill (unsigned short x, unsigned short y, unsigned
- short width, unsigned short height,
- unsigned short mode, unsigned short color)
-{
-
-}
-#endif
-
-
-/**************************************************************
- * Move cursor to x, y
- */
-void retz3_MoveCursor (unsigned short x, unsigned short y)
-{
- /* Guess we gotta deal with the cursor at some point */
-}
-
-
-/* -------------------- Interfaces to hardware functions -------------------- */
-
-
-static struct fb_hwswitch retz3_switch = {
- retz3_init, retz3_encode_fix, retz3_decode_var, retz3_encode_var,
- retz3_getcolreg, retz3_setcolreg, retz3_blank
-};
-
-
-/* -------------------- Generic routines ------------------------------------ */
-
-
-/*
- * Fill the hardware's `par' structure.
- */
-
-static void retz3_fb_get_par(struct retz3_fb_par *par)
-{
- if (current_par_valid)
- *par = current_par;
- else
- fbhw->decode_var(&retz3_fb_predefined[z3fb_mode], par);
-}
-
-
-static void retz3_fb_set_par(struct retz3_fb_par *par)
-{
- current_par = *par;
- current_par_valid = 1;
-}
-
-
-static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive)
-{
- int err, activate;
- struct retz3_fb_par par;
-
- if ((err = fbhw->decode_var(var, &par)))
- return err;
- activate = var->activate;
- if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW && isactive)
- retz3_fb_set_par(&par);
- fbhw->encode_var(var, &par);
- var->activate = activate;
-
-#if 1
- retz3_set_video(var, &current_par);
-#endif
- return 0;
-}
-
-
-/*
- * Default Colormaps
- */
-
-static unsigned short red16[] =
- { 0x0000, 0x0000, 0x0000, 0x0000, 0xc000, 0xc000, 0xc000, 0xc000,
- 0x8000, 0x0000, 0x0000, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff };
-static unsigned short green16[] =
- { 0x0000, 0x0000, 0xc000, 0xc000, 0x0000, 0x0000, 0xc000, 0xc000,
- 0x8000, 0x0000, 0xffff, 0xffff, 0x0000, 0x0000, 0xffff, 0xffff };
-static unsigned short blue16[] =
- { 0x0000, 0xc000, 0x0000, 0xc000, 0x0000, 0xc000, 0x0000, 0xc000,
- 0x8000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff };
-
-
-static struct fb_cmap default_16_colors =
- { 0, 16, red16, green16, blue16, NULL };
-
-
-static struct fb_cmap *get_default_colormap(int bpp)
-{
- return &default_16_colors;
-}
-
-
-#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7fff-(val))>>16)
-#define CNVT_FROMHW(val,width) (((width) ? ((((val)<<16)-(val)) / \
- ((1<<(width))-1)) : 0))
-
-static int do_fb_get_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var,
- int kspc)
-{
- int i, start;
- unsigned short *red, *green, *blue, *transp;
- unsigned int hred, hgreen, hblue, htransp;
-
- red = cmap->red;
- green = cmap->green;
- blue = cmap->blue;
- transp = cmap->transp;
- start = cmap->start;
-
- if (start < 0)
- return -EINVAL;
- for (i = 0; i < cmap->len; i++) {
- if (fbhw->getcolreg(start++, &hred, &hgreen, &hblue, &htransp))
- return 0;
- hred = CNVT_FROMHW(hred, var->red.length);
- hgreen = CNVT_FROMHW(hgreen, var->green.length);
- hblue = CNVT_FROMHW(hblue, var->blue.length);
- htransp = CNVT_FROMHW(htransp, var->transp.length);
- if (kspc) {
- *red = hred;
- *green = hgreen;
- *blue = hblue;
- if (transp)
- *transp = htransp;
- } else {
- put_user(hred, red);
- put_user(hgreen, green);
- put_user(hblue, blue);
- if (transp)
- put_user(htransp, transp);
- }
- red++;
- green++;
- blue++;
- if (transp)
- transp++;
- }
- return 0;
-}
-
-
-static int do_fb_set_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var,
- int kspc)
-{
- int i, start;
- unsigned short *red, *green, *blue, *transp;
- unsigned int hred, hgreen, hblue, htransp;
-
- red = cmap->red;
- green = cmap->green;
- blue = cmap->blue;
- transp = cmap->transp;
- start = cmap->start;
-
- if (start < 0)
- return -EINVAL;
- for (i = 0; i < cmap->len; i++) {
- if (kspc) {
- hred = *red;
- hgreen = *green;
- hblue = *blue;
- htransp = transp ? *transp : 0;
- } else {
- get_user(hred, red);
- get_user(hgreen, green);
- get_user(hblue, blue);
- if (transp)
- get_user(htransp, transp);
- else
- htransp = 0;
- }
- hred = CNVT_TOHW(hred, var->red.length);
- hgreen = CNVT_TOHW(hgreen, var->green.length);
- hblue = CNVT_TOHW(hblue, var->blue.length);
- htransp = CNVT_TOHW(htransp, var->transp.length);
- red++;
- green++;
- blue++;
- if (transp)
- transp++;
- if (fbhw->setcolreg(start++, hred, hgreen, hblue, htransp))
- return 0;
- }
- return 0;
-}
-
-
-static void do_install_cmap(int con)
-{
- if (con != currcon)
- return;
- if (disp[con].cmap.len)
- do_fb_set_cmap(&disp[con].cmap, &disp[con].var, 1);
- else
- do_fb_set_cmap(get_default_colormap(disp[con].var.bits_per_pixel),
- &disp[con].var, 1);
-}
-
-
-static void memcpy_fs(int fsfromto, void *to, void *from, int len)
-{
- switch (fsfromto) {
- case 0:
- memcpy(to, from, len);
- return;
- case 1:
- copy_from_user(to, from, len);
- return;
- case 2:
- copy_to_user(to, from, len);
- return;
- }
-}
-
-
-static void copy_cmap(struct fb_cmap *from, struct fb_cmap *to, int fsfromto)
-{
- int size;
- int tooff = 0, fromoff = 0;
-
- if (to->start > from->start)
- fromoff = to->start-from->start;
- else
- tooff = from->start-to->start;
- size = to->len-tooff;
- if (size > from->len-fromoff)
- size = from->len-fromoff;
- if (size < 0)
- return;
- size *= sizeof(unsigned short);
- memcpy_fs(fsfromto, to->red+tooff, from->red+fromoff, size);
- memcpy_fs(fsfromto, to->green+tooff, from->green+fromoff, size);
- memcpy_fs(fsfromto, to->blue+tooff, from->blue+fromoff, size);
- if (from->transp && to->transp)
- memcpy_fs(fsfromto, to->transp+tooff,
- from->transp+fromoff, size);
-}
-
-
-static int alloc_cmap(struct fb_cmap *cmap, int len, int transp)
-{
- int size = len*sizeof(unsigned short);
-
- if (cmap->len != len) {
- if (cmap->red)
- kfree(cmap->red);
- if (cmap->green)
- kfree(cmap->green);
- if (cmap->blue)
- kfree(cmap->blue);
- if (cmap->transp)
- kfree(cmap->transp);
- cmap->red = cmap->green = cmap->blue = cmap->transp = NULL;
- cmap->len = 0;
- if (!len)
- return 0;
- if (!(cmap->red = kmalloc(size, GFP_ATOMIC)))
- return -1;
- if (!(cmap->green = kmalloc(size, GFP_ATOMIC)))
- return -1;
- if (!(cmap->blue = kmalloc(size, GFP_ATOMIC)))
- return -1;
- if (transp) {
- if (!(cmap->transp = kmalloc(size, GFP_ATOMIC)))
- return -1;
- } else
- cmap->transp = NULL;
- }
- cmap->start = 0;
- cmap->len = len;
- copy_cmap(get_default_colormap(len), cmap, 0);
- return 0;
-}
-
-
-/*
- * Get the Fixed Part of the Display
- */
-
-static int retz3_fb_get_fix(struct fb_fix_screeninfo *fix, int con)
-{
- struct retz3_fb_par par;
- int error = 0;
-
- if (con == -1)
- retz3_fb_get_par(&par);
- else
- error = fbhw->decode_var(&disp[con].var, &par);
- return(error ? error : fbhw->encode_fix(fix, &par));
-}
-
-
-/*
- * Get the User Defined Part of the Display
- */
-
-static int retz3_fb_get_var(struct fb_var_screeninfo *var, int con)
-{
- struct retz3_fb_par par;
- int error = 0;
-
- if (con == -1) {
- retz3_fb_get_par(&par);
- error = fbhw->encode_var(var, &par);
- } else
- *var = disp[con].var;
- return error;
-}
-
-
-static void retz3_fb_set_disp(int con)
-{
- struct fb_fix_screeninfo fix;
-
- retz3_fb_get_fix(&fix, con);
- if (con == -1)
- con = 0;
- disp[con].screen_base = (unsigned char *)fix.smem_start;
- disp[con].visual = fix.visual;
- disp[con].type = fix.type;
- disp[con].type_aux = fix.type_aux;
- disp[con].ypanstep = fix.ypanstep;
- disp[con].ywrapstep = fix.ywrapstep;
- disp[con].can_soft_blank = 1;
- disp[con].inverse = z3fb_inverse;
-}
-
-
-/*
- * Set the User Defined Part of the Display
- */
-
-static int retz3_fb_set_var(struct fb_var_screeninfo *var, int con)
-{
- int err, oldxres, oldyres, oldvxres, oldvyres, oldbpp;
-
- if ((err = do_fb_set_var(var, con == currcon)))
- return err;
- if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
- oldxres = disp[con].var.xres;
- oldyres = disp[con].var.yres;
- oldvxres = disp[con].var.xres_virtual;
- oldvyres = disp[con].var.yres_virtual;
- oldbpp = disp[con].var.bits_per_pixel;
- disp[con].var = *var;
- if (oldxres != var->xres || oldyres != var->yres ||
- oldvxres != var->xres_virtual ||
- oldvyres != var->yres_virtual ||
- oldbpp != var->bits_per_pixel) {
- retz3_fb_set_disp(con);
- (*fb_info.changevar)(con);
- alloc_cmap(&disp[con].cmap, 0, 0);
- do_install_cmap(con);
- }
- }
- var->activate = 0;
- return 0;
-}
-
-
-/*
- * Get the Colormap
- */
-
-static int retz3_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con)
-{
- if (con == currcon) /* current console? */
- return(do_fb_get_cmap(cmap, &disp[con].var, kspc));
- else if (disp[con].cmap.len) /* non default colormap? */
- copy_cmap(&disp[con].cmap, cmap, kspc ? 0 : 2);
- else
- copy_cmap(get_default_colormap(disp[con].var.bits_per_pixel),
- cmap, kspc ? 0 : 2);
- return 0;
-}
-
-
-/*
- * Set the Colormap
- */
-
-static int retz3_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con)
-{
- int err;
-
- if (!disp[con].cmap.len) { /* no colormap allocated? */
- if ((err = alloc_cmap(&disp[con].cmap,
- 1<<disp[con].var.bits_per_pixel, 0)))
- return err;
- }
- if (con == currcon) /* current console? */
- return(do_fb_set_cmap(cmap, &disp[con].var, kspc));
- else
- copy_cmap(cmap, &disp[con].cmap, kspc ? 0 : 1);
- return 0;
-}
-
-
-/*
- * Pan or Wrap the Display
- *
- * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
- */
-
-static int retz3_fb_pan_display(struct fb_var_screeninfo *var, int con)
-{
- return -EINVAL;
-}
-
-
-/*
- * RetinaZ3 Frame Buffer Specific ioctls
- */
-
-static int retz3_fb_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg, int con)
-{
- return -EINVAL;
-}
-
-
-static struct fb_ops retz3_fb_ops = {
- retz3_fb_get_fix, retz3_fb_get_var, retz3_fb_set_var, retz3_fb_get_cmap,
- retz3_fb_set_cmap, retz3_fb_pan_display, retz3_fb_ioctl
-};
-
-
-int retz3_probe(void)
-{
- z3_key = zorro_find(MANUF_MACROSYSTEMS2, PROD_RETINA_Z3, 0, 0);
- return(z3_key);
-}
-
-
-void retz3_video_setup(char *options, int *ints)
-{
- char *this_opt;
- int i;
-
- fb_info.fontname[0] = '\0';
-
- if (!options || !*options)
- return;
-
- for (this_opt = strtok(options, ","); this_opt;
- this_opt = strtok(NULL, ",")){
- if (!strcmp(this_opt, "inverse")) {
- z3fb_inverse = 1;
- for (i = 0; i < 16; i++) {
- red16[i] = ~red16[i];
- green16[i] = ~green16[i];
- blue16[i] = ~blue16[i];
- }
- } else if (!strncmp(this_opt, "font:", 5))
- strcpy(fb_info.fontname, this_opt+5);
- else
- z3fb_mode = get_video_mode(this_opt);
- }
-}
-
-
-/*
- * Initialization
- */
-
-struct fb_info *retz3_fb_init(long *mem_start)
-{
- int err;
- struct retz3_fb_par par;
-
- memstart = mem_start;
-
- fbhw = &retz3_switch;
-
- err = register_framebuffer(retz3_fb_name, &node, &retz3_fb_ops,
- NUM_TOTAL_MODES, retz3_fb_predefined);
- if (err < 0)
- panic("Cannot register frame buffer\n");
-
- fbhw->init();
-
- if (z3fb_mode == -1)
- z3fb_mode = 1;
-
- fbhw->decode_var(&retz3_fb_predefined[z3fb_mode], &par);
- fbhw->encode_var(&retz3_fb_predefined[0], &par);
-
- strcpy(fb_info.modename, retz3_fb_name);
- fb_info.disp = disp;
- fb_info.switch_con = &z3fb_switch;
- fb_info.updatevar = &z3fb_updatevar;
- fb_info.blank = &z3fb_blank;
- fb_info.setcmap = &z3fb_setcmap;
-
- do_fb_set_var(&retz3_fb_predefined[0], 0);
- retz3_fb_get_var(&disp[0].var, -1);
- retz3_fb_set_disp(-1);
- do_install_cmap(0);
-
- return &fb_info;
-}
-
-
-static int z3fb_switch(int con)
-{
- /* Do we have to save the colormap? */
- if (disp[currcon].cmap.len)
- do_fb_get_cmap(&disp[currcon].cmap, &disp[currcon].var, 1);
-
- do_fb_set_var(&disp[con].var, 1);
- currcon = con;
- /* Install new colormap */
- do_install_cmap(con);
- return 0;
-}
-
-
-/*
- * Update the `var' structure (called by fbcon.c)
- *
- * This call looks only at yoffset and the FB_VMODE_YWRAP flag in `var'.
- * Since it's called by a kernel driver, no range checking is done.
- */
-
-static int z3fb_updatevar(int con)
-{
- return 0;
-}
-
-
-/*
- * Blank the display.
- */
-
-static void z3fb_blank(int blank)
-{
- fbhw->blank(blank);
-}
-
-
-/*
- * Set the colormap
- */
-
-static int z3fb_setcmap(struct fb_cmap *cmap, int con)
-{
- return(retz3_fb_set_cmap(cmap, 1, con));
-}
-
-
-/*
- * Get a Video Mode
- */
-
-static int get_video_mode(const char *name)
-{
- int i;
-
- for (i = 1; i <= NUM_PREDEF_MODES; i++)
- if (!strcmp(name, retz3_fb_modenames[i])){
- retz3_fb_predefined[0] = retz3_fb_predefined[i];
- return i;
- }
- return -1;
-}
-/*
- * Linux/arch/m68k/amiga/retz3fb.c -- Low level implementation of the
- * RetinaZ3 frame buffer device
- *
- * Copyright (C) 1997 Jes Sorensen
- *
- * This file is based on the CyberVision64 frame buffer device and
- * the generic Cirrus Logic driver.
- *
- * cyberfb.c: Copyright (C) 1996 Martin Apel,
- * Geert Uytterhoeven
- * clgen.c: Copyright (C) 1996 Frank Neumann
- *
- * History:
- * - 22 Jan 97: Initial work
- * - 14 Feb 97: Screen initialization works somewhat, still only
- * 8-bit packed pixel is supported.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/tty.h>
-#include <linux/malloc.h>
-#include <linux/delay.h>
-#include <linux/fb.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/irq.h>
-#include <linux/zorro.h>
#include <asm/pgtable.h>
#include "retz3fb.h"
@@ -3402,7 +1652,7 @@ void retz3_video_setup(char *options, int *ints)
* Initialization
*/
-struct fb_info *retz3_fb_init(long *mem_start)
+__initfunc(struct fb_info *retz3_fb_init(long *mem_start))
{
int err;
struct retz3_fb_par par;
diff --git a/arch/m68k/amiga/retz3fb.h b/arch/m68k/amiga/retz3fb.h
index 9ff209060..0cb03c324 100644
--- a/arch/m68k/amiga/retz3fb.h
+++ b/arch/m68k/amiga/retz3fb.h
@@ -284,289 +284,3 @@
#define Z3BLTorInverted 0xb0 /* NOT src OR dst */
#define Z3BLTnand 0x70 /* NOT src OR NOT dst */
#define Z3BLTset 0xf0 /* 1 */
-/*
- * Linux/arch/m68k/amiga/retz3fb.h -- Defines and macros for the
- * RetinaZ3 frame buffer device
- *
- * Copyright (C) 1997 Jes Sorensen
- *
- * History:
- * - 22 Jan 97: Initial work
- *
- *
- * 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.
- */
-
-/*
- * Macros to read and write to registers.
- */
-#define reg_w(reg,dat) (*(z3_regs + reg) = dat)
-#define reg_r(reg) (*(z3_regs + reg))
-
-/*
- * Macro to access the sequencer.
- */
-#define seq_w(sreg,sdat) \
- do{ reg_w(SEQ_IDX, sreg); reg_w(SEQ_DATA, sdat); } while(0)
-
-/*
- * Macro to access the CRT controller.
- */
-#define crt_w(creg,cdat) \
- do{ reg_w(CRT_IDX, creg); reg_w(CRT_DATA, cdat); } while(0)
-
-/*
- * Macro to access the graphics controller.
- */
-#define gfx_w(greg,gdat) \
- do{ reg_w(GFX_IDX, greg); reg_w(GFX_DATA, gdat); } while(0)
-
-/*
- * Macro to access the attribute controller.
- */
-#define attr_w(areg,adat) \
- do{ reg_w(ACT_IDX, areg); reg_w(ACT_DATA, adat); } while(0)
-
-/*
- * Macro to access the pll.
- */
-#define pll_w(preg,pdat) \
- do{ reg_w(PLL_IDX, preg); \
- reg_w(PLL_DATA, (pdat & 0xff)); \
- reg_w(PLL_DATA, (pdat >> 8));\
- } while(0)
-
-/*
- * Offsets
- */
-#define VIDEO_MEM_OFFSET 0x00c00000
-#define ACM_OFFSET 0x00b00000
-
-/*
- * Accelerator Control Menu
- */
-#define ACM_PRIMARY_OFFSET 0x00
-#define ACM_SECONDARY_OFFSET 0x04
-#define ACM_MODE_CONTROL 0x08
-#define ACM_CURSOR_POSITION 0x0c
-#define ACM_START_STATUS 0x30
-#define ACM_CONTROL 0x34
-#define ACM_RASTEROP_ROTATION 0x38
-#define ACM_BITMAP_DIMENSION 0x3c
-#define ACM_DESTINATION 0x40
-#define ACM_SOURCE 0x44
-#define ACM_PATTERN 0x48
-#define ACM_FOREGROUND 0x4c
-#define ACM_BACKGROUND 0x50
-
-/*
- * Video DAC addresses
- */
-#define VDAC_ADDRESS 0x03c8
-#define VDAC_ADDRESS_W 0x03c8
-#define VDAC_ADDRESS_R 0x03c7
-#define VDAC_STATE 0x03c7
-#define VDAC_DATA 0x03c9
-#define VDAC_MASK 0x03c6
-
-/*
- * Sequencer
- */
-#define SEQ_IDX 0x03c4 /* Sequencer Index */
-#define SEQ_DATA 0x03c5
-#define SEQ_RESET 0x00
-#define SEQ_CLOCKING_MODE 0x01
-#define SEQ_MAP_MASK 0x02
-#define SEQ_CHAR_MAP_SELECT 0x03
-#define SEQ_MEMORY_MODE 0x04
-#define SEQ_EXTENDED_ENABLE 0x05 /* NCR extensions */
-#define SEQ_UNKNOWN1 0x06
-#define SEQ_UNKNOWN2 0x07
-#define SEQ_CHIP_ID 0x08
-#define SEQ_UNKNOWN3 0x09
-#define SEQ_CURSOR_COLOR1 0x0a
-#define SEQ_CURSOR_COLOR0 0x0b
-#define SEQ_CURSOR_CONTROL 0x0c
-#define SEQ_CURSOR_X_LOC_HI 0x0d
-#define SEQ_CURSOR_X_LOC_LO 0x0e
-#define SEQ_CURSOR_Y_LOC_HI 0x0f
-#define SEQ_CURSOR_Y_LOC_LO 0x10
-#define SEQ_CURSOR_X_INDEX 0x11
-#define SEQ_CURSOR_Y_INDEX 0x12
-#define SEQ_CURSOR_STORE_HI 0x13
-#define SEQ_CURSOR_STORE_LO 0x14
-#define SEQ_CURSOR_ST_OFF_HI 0x15
-#define SEQ_CURSOR_ST_OFF_LO 0x16
-#define SEQ_CURSOR_PIXELMASK 0x17
-#define SEQ_PRIM_HOST_OFF_HI 0x18
-#define SEQ_PRIM_HOST_OFF_LO 0x19
-#define SEQ_LINEAR_0 0x1a
-#define SEQ_LINEAR_1 0x1b
-#define SEQ_SEC_HOST_OFF_HI 0x1c
-#define SEQ_SEC_HOST_OFF_LO 0x1d
-#define SEQ_EXTENDED_MEM_ENA 0x1e
-#define SEQ_EXT_CLOCK_MODE 0x1f
-#define SEQ_EXT_VIDEO_ADDR 0x20
-#define SEQ_EXT_PIXEL_CNTL 0x21
-#define SEQ_BUS_WIDTH_FEEDB 0x22
-#define SEQ_PERF_SELECT 0x23
-#define SEQ_COLOR_EXP_WFG 0x24
-#define SEQ_COLOR_EXP_WBG 0x25
-#define SEQ_EXT_RW_CONTROL 0x26
-#define SEQ_MISC_FEATURE_SEL 0x27
-#define SEQ_COLOR_KEY_CNTL 0x28
-#define SEQ_COLOR_KEY_MATCH0 0x29
-#define SEQ_COLOR_KEY_MATCH1 0x2a
-#define SEQ_COLOR_KEY_MATCH2 0x2b
-#define SEQ_UNKNOWN6 0x2c
-#define SEQ_CRC_CONTROL 0x2d
-#define SEQ_CRC_DATA_LOW 0x2e
-#define SEQ_CRC_DATA_HIGH 0x2f
-#define SEQ_MEMORY_MAP_CNTL 0x30
-#define SEQ_ACM_APERTURE_1 0x31
-#define SEQ_ACM_APERTURE_2 0x32
-#define SEQ_ACM_APERTURE_3 0x33
-#define SEQ_BIOS_UTILITY_0 0x3e
-#define SEQ_BIOS_UTILITY_1 0x3f
-
-/*
- * Graphics Controller
- */
-#define GFX_IDX 0x03ce
-#define GFX_DATA 0x03cf
-#define GFX_SET_RESET 0x00
-#define GFX_ENABLE_SET_RESET 0x01
-#define GFX_COLOR_COMPARE 0x02
-#define GFX_DATA_ROTATE 0x03
-#define GFX_READ_MAP_SELECT 0x04
-#define GFX_GRAPHICS_MODE 0x05
-#define GFX_MISC 0x06
-#define GFX_COLOR_XCARE 0x07
-#define GFX_BITMASK 0x08
-
-/*
- * CRT Controller
- */
-#define CRT_IDX 0x03d4
-#define CRT_DATA 0x03d5
-#define CRT_HOR_TOTAL 0x00
-#define CRT_HOR_DISP_ENA_END 0x01
-#define CRT_START_HOR_BLANK 0x02
-#define CRT_END_HOR_BLANK 0x03
-#define CRT_START_HOR_RETR 0x04
-#define CRT_END_HOR_RETR 0x05
-#define CRT_VER_TOTAL 0x06
-#define CRT_OVERFLOW 0x07
-#define CRT_PRESET_ROW_SCAN 0x08
-#define CRT_MAX_SCAN_LINE 0x09
-#define CRT_CURSOR_START 0x0a
-#define CRT_CURSOR_END 0x0b
-#define CRT_START_ADDR_HIGH 0x0c
-#define CRT_START_ADDR_LOW 0x0d
-#define CRT_CURSOR_LOC_HIGH 0x0e
-#define CRT_CURSOR_LOC_LOW 0x0f
-#define CRT_START_VER_RETR 0x10
-#define CRT_END_VER_RETR 0x11
-#define CRT_VER_DISP_ENA_END 0x12
-#define CRT_OFFSET 0x13
-#define CRT_UNDERLINE_LOC 0x14
-#define CRT_START_VER_BLANK 0x15
-#define CRT_END_VER_BLANK 0x16
-#define CRT_MODE_CONTROL 0x17
-#define CRT_LINE_COMPARE 0x18
-#define CRT_UNKNOWN1 0x19
-#define CRT_UNKNOWN2 0x1a
-#define CRT_UNKNOWN3 0x1b
-#define CRT_UNKNOWN4 0x1c
-#define CRT_UNKNOWN5 0x1d
-#define CRT_UNKNOWN6 0x1e
-#define CRT_UNKNOWN7 0x1f
-#define CRT_UNKNOWN8 0x20
-#define CRT_UNKNOWN9 0x21
-#define CRT_UNKNOWN10 0x22
-#define CRT_UNKNOWN11 0x23
-#define CRT_UNKNOWN12 0x24
-#define CRT_UNKNOWN13 0x25
-#define CRT_UNKNOWN14 0x26
-#define CRT_UNKNOWN15 0x27
-#define CRT_UNKNOWN16 0x28
-#define CRT_UNKNOWN17 0x29
-#define CRT_UNKNOWN18 0x2a
-#define CRT_UNKNOWN19 0x2b
-#define CRT_UNKNOWN20 0x2c
-#define CRT_UNKNOWN21 0x2d
-#define CRT_UNKNOWN22 0x2e
-#define CRT_UNKNOWN23 0x2f
-#define CRT_EXT_HOR_TIMING1 0x30 /* NCR crt extensions */
-#define CRT_EXT_START_ADDR 0x31
-#define CRT_EXT_HOR_TIMING2 0x32
-#define CRT_EXT_VER_TIMING 0x33
-#define CRT_MONITOR_POWER 0x34
-
-/*
- * General Registers
- */
-#define GREG_STATUS0_R 0x03c2
-#define GREG_STATUS1_R 0x03da
-#define GREG_MISC_OUTPUT_R 0x03cc
-#define GREG_MISC_OUTPUT_W 0x03c2
-#define GREG_FEATURE_CONTROL_R 0x03ca
-#define GREG_FEATURE_CONTROL_W 0x03da
-#define GREG_POS 0x0102
-
-/*
- * Attribute Controller
- */
-#define ACT_IDX 0x03C0
-#define ACT_ADDRESS_R 0x03C0
-#define ACT_DATA 0x03C0
-#define ACT_ADDRESS_RESET 0x03DA
-#define ACT_PALETTE0 0x00
-#define ACT_PALETTE1 0x01
-#define ACT_PALETTE2 0x02
-#define ACT_PALETTE3 0x03
-#define ACT_PALETTE4 0x04
-#define ACT_PALETTE5 0x05
-#define ACT_PALETTE6 0x06
-#define ACT_PALETTE7 0x07
-#define ACT_PALETTE8 0x08
-#define ACT_PALETTE9 0x09
-#define ACT_PALETTE10 0x0A
-#define ACT_PALETTE11 0x0B
-#define ACT_PALETTE12 0x0C
-#define ACT_PALETTE13 0x0D
-#define ACT_PALETTE14 0x0E
-#define ACT_PALETTE15 0x0F
-#define ACT_ATTR_MODE_CNTL 0x10
-#define ACT_OVERSCAN_COLOR 0x11
-#define ACT_COLOR_PLANE_ENA 0x12
-#define ACT_HOR_PEL_PANNING 0x13
-#define ACT_COLOR_SELECT 0x14
-
-/*
- * PLL
- */
-#define PLL_IDX 0x83c8
-#define PLL_DATA 0x83c9
-
-/*
- * Blitter operations
- */
-#define Z3BLTclear 0x00 /* 0 */
-#define Z3BLTand 0x80 /* src AND dst */
-#define Z3BLTandReverse 0x40 /* src AND NOT dst */
-#define Z3BLTcopy 0xc0 /* src */
-#define Z3BLTandInverted 0x20 /* NOT src AND dst */
-#define Z3BLTnoop 0xa0 /* dst */
-#define Z3BLTxor 0x60 /* src XOR dst */
-#define Z3BLTor 0xe0 /* src OR dst */
-#define Z3BLTnor 0x10 /* NOT src AND NOT dst */
-#define Z3BLTequiv 0x90 /* NOT src XOR dst */
-#define Z3BLTinvert 0x50 /* NOT dst */
-#define Z3BLTorReverse 0xd0 /* src OR NOT dst */
-#define Z3BLTcopyInverted 0x30 /* NOT src */
-#define Z3BLTorInverted 0xb0 /* NOT src OR dst */
-#define Z3BLTnand 0x70 /* NOT src OR NOT dst */
-#define Z3BLTset 0xf0 /* 1 */
diff --git a/arch/m68k/amiga/zorro.c b/arch/m68k/amiga/zorro.c
index acca3e6bc..d64ad8ce3 100644
--- a/arch/m68k/amiga/zorro.c
+++ b/arch/m68k/amiga/zorro.c
@@ -13,10 +13,11 @@
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/zorro.h>
#include <asm/setup.h>
#include <asm/bitops.h>
#include <asm/amigahw.h>
-#include <linux/zorro.h>
#ifdef CONFIG_ZORRO
@@ -415,10 +416,6 @@ BEGIN_PROD(MASOBOSHI)
PROD("MVD 819", MVD_819)
END
-BEGIN_PROD(DELACOMP)
- PROD("RAM Expansion 2000", DELACOMP_RAM_2000)
-END
-
BEGIN_PROD(VILLAGE_TRONIC)
PROD("Domino Graphics Board (RAM)", DOMINO_RAM)
PROD("Domino Graphics Board (REG)", DOMINO_REG)
@@ -656,7 +653,6 @@ BEGIN_MANUF
MANUF("Helfrich", HELFRICH1)
MANUF("Software Result Enterprises", SW_RESULT_ENTS)
MANUF("Masoboshi", MASOBOSHI)
- MANUF("DelaComp", DELACOMP)
MANUF("Village Tronic", VILLAGE_TRONIC)
MANUF("Utilities Unlimited", UTILITIES_ULTD)
MANUF("Amitrix", AMITRIX)
@@ -992,7 +988,7 @@ static void mark_region(u_long addr, u_long size, int flag)
* Initialization
*/
-void zorro_init(void)
+__initfunc(void zorro_init(void))
{
int i;
struct ConfigDev *cd;
diff --git a/arch/m68k/atari/atafb.c b/arch/m68k/atari/atafb.c
index 64c9a62d3..efa6fc8b8 100644
--- a/arch/m68k/atari/atafb.c
+++ b/arch/m68k/atari/atafb.c
@@ -46,6 +46,7 @@
#include <linux/tty.h>
#include <linux/malloc.h>
#include <linux/delay.h>
+#include <linux/init.h>
#include <asm/setup.h>
#include <asm/uaccess.h>
@@ -2911,8 +2912,8 @@ atafb_setcmap(struct fb_cmap *cmap, int con)
return(atari_fb_set_cmap(cmap, 1, con));
}
-struct fb_info *
-atari_fb_init(long *mem_start)
+__initfunc(struct fb_info *
+atari_fb_init(long *mem_start))
{
int err;
int pad;
diff --git a/arch/m68k/atari/ataints.c b/arch/m68k/atari/ataints.c
index b65beefb1..b2887f7da 100644
--- a/arch/m68k/atari/ataints.c
+++ b/arch/m68k/atari/ataints.c
@@ -39,6 +39,7 @@
#include <linux/kernel.h>
#include <linux/ptrace.h>
#include <linux/kernel_stat.h>
+#include <linux/init.h>
#include <asm/system.h>
#include <asm/traps.h>
@@ -162,15 +163,19 @@ static int free_vme_vec_bitmap = 0;
#define MFP_MK_BASE "0xfa13"
-/* This must agree with head.S. */
-#define ORIG_DO "0x20"
-#define FORMATVEC "0x2E"
-#define SR "0x28"
+/* This must agree with entry.S. */
+#define ORIG_DO "0x24"
+#define FORMATVEC "0x32"
+#define SR "0x2C"
#define SAVE_ALL \
"clrl %%sp@-;" /* stk_adj */ \
"pea -1:w;" /* orig d0 = -1 */ \
"movel %%d0,%%sp@-;" /* d0 */ \
- "moveml %%d1-%%d5/%%a0-%%a1,%%sp@-"
+ "moveml %%d1-%%d5/%%a0-%%a2,%%sp@-"
+#define GET_CURRENT(tmp) \
+ "movel %%sp,"#tmp";" \
+ "andw #-8192,"#tmp";" \
+ "movel "#tmp",%%a2"
#define BUILD_SLOW_IRQ(n) \
asmlinkage void IRQ_NAME(n); \
@@ -180,6 +185,7 @@ __asm__ (ALIGN_STR "\n" \
SYMBOL_NAME_STR(atari_slow_irq_) #n "_handler:\t" \
" addql #1,"SYMBOL_NAME_STR(local_irq_count)"\n" \
SAVE_ALL "\n" \
+ GET_CURRENT(%%d0) "\n" \
" andb #~(1<<(" #n "&7))," /* mask this interrupt */ \
"("MFP_MK_BASE"+(((" #n "&8)^8)>>2)+((" #n "&16)<<3)):w\n" \
" bfextu %%sp@("SR"){#5,#3},%%d0\n" /* get old IPL from stack frame */ \
@@ -282,7 +288,8 @@ SYMBOL_NAME_STR(atari_fast_irq_handler) ":
orw #0x700,%%sr /* disable all interrupts */
"SYMBOL_NAME_STR(atari_prio_irq_handler) ":\t
addql #1,"SYMBOL_NAME_STR(local_irq_count)"\n"
- SAVE_ALL "
+ SAVE_ALL "\n"
+ GET_CURRENT(%%d0) "
/* get vector number from stack frame and convert to source */
bfextu %%sp@(" FORMATVEC "){#4,#10},%%d0
subw #(0x40-8),%%d0
@@ -331,7 +338,7 @@ extern void atari_microwire_cmd( int cmd );
* the atari IRQ handling routines.
*/
-void atari_init_IRQ(void)
+__initfunc(void atari_init_IRQ(void))
{
int i;
diff --git a/arch/m68k/atari/atakeyb.c b/arch/m68k/atari/atakeyb.c
index 4f57cb928..beccf9a84 100644
--- a/arch/m68k/atari/atakeyb.c
+++ b/arch/m68k/atari/atakeyb.c
@@ -22,6 +22,7 @@
#include <linux/timer.h>
#include <linux/kd.h>
#include <linux/random.h>
+#include <linux/init.h>
#include <asm/atariints.h>
#include <asm/atarihw.h>
@@ -804,7 +805,7 @@ void atari_kbd_leds (unsigned int leds)
* Martin Rogge, 20 Aug 1995
*/
-int atari_keyb_init(void)
+__initfunc(int atari_keyb_init(void))
{
/* setup key map */
key_maps[0] = ataplain_map;
diff --git a/arch/m68k/atari/config.c b/arch/m68k/atari/config.c
index 0d0607da0..3cc2a840a 100644
--- a/arch/m68k/atari/config.c
+++ b/arch/m68k/atari/config.c
@@ -32,6 +32,7 @@
#include <linux/tty.h>
#include <linux/console.h>
#include <linux/interrupt.h>
+#include <linux/init.h>
#include <asm/bootinfo.h>
#include <asm/setup.h>
@@ -106,7 +107,7 @@ extern void (*kd_mksound)(unsigned int, unsigned int);
* a temporary VBR and a vector table for the duration of the test.
*/
-static int hwreg_present( volatile void *regp )
+__initfunc(static int hwreg_present( volatile void *regp ))
{
int ret = 0;
long save_sp, save_vbr;
@@ -132,9 +133,8 @@ static int hwreg_present( volatile void *regp )
}
#if 0
-static int hwreg_present_bywrite( volatile void *regp,
- unsigned char val )
-
+__initfunc(static int
+hwreg_present_bywrite(volatile void *regp, unsigned char val))
{
int ret;
long save_sp, save_vbr;
@@ -166,7 +166,7 @@ static int hwreg_present_bywrite( volatile void *regp,
/* Basically the same, but writes a value into a word register, protected
* by a bus error handler */
-static int hwreg_write( volatile void *regp, unsigned short val )
+__initfunc(static int hwreg_write( volatile void *regp, unsigned short val ))
{
int ret;
long save_sp, save_vbr;
@@ -201,7 +201,7 @@ static int hwreg_write( volatile void *regp, unsigned short val )
* should be readable without trouble (from channel A!).
*/
-static int scc_test( volatile char *ctla )
+__initfunc(static int scc_test( volatile char *ctla ))
{
if (!hwreg_present( ctla ))
return( 0 );
@@ -228,7 +228,7 @@ static int scc_test( volatile char *ctla )
* Parse an Atari-specific record in the bootinfo
*/
-int atari_parse_bootinfo(const struct bi_record *record)
+__initfunc(int atari_parse_bootinfo(const struct bi_record *record))
{
int unknown = 0;
const u_long *data = record->data;
@@ -247,7 +247,7 @@ int atari_parse_bootinfo(const struct bi_record *record)
* Setup the Atari configuration info
*/
-void config_atari(void)
+__initfunc(void config_atari(void))
{
memset(&atari_hw_present, 0, sizeof(atari_hw_present));
@@ -493,7 +493,8 @@ void config_atari(void)
}
}
-static void atari_sched_init(void (*timer_routine)(int, void *, struct pt_regs *))
+__initfunc(static void
+atari_sched_init(void (*timer_routine)(int, void *, struct pt_regs *)))
{
/* set Timer C data Register */
mfp.tim_dt_c = INT_TICKS;
@@ -976,7 +977,7 @@ static void atari_par_console_write (const char *str, unsigned int count)
}
-static void atari_debug_init(void)
+__initfunc(static void atari_debug_init(void))
{
#ifdef CONFIG_KGDB
/* if the m68k_debug_device is used by the GDB stub, do nothing here */
diff --git a/arch/m68k/atari/joystick.c b/arch/m68k/atari/joystick.c
index de6014171..2e33b151f 100644
--- a/arch/m68k/atari/joystick.c
+++ b/arch/m68k/atari/joystick.c
@@ -11,6 +11,7 @@
#include <linux/errno.h>
#include <linux/major.h>
#include <linux/poll.h>
+#include <linux/init.h>
#include <asm/atarikb.h>
#include <asm/atari_joystick.h>
@@ -128,7 +129,7 @@ struct file_operations atari_joystick_fops = {
release_joystick
};
-int atari_joystick_init(void)
+__initfunc(int atari_joystick_init(void))
{
joystick[0].active = joystick[1].active = 0;
joystick[0].ready = joystick[1].ready = 0;
diff --git a/arch/m68k/atari/stdma.c b/arch/m68k/atari/stdma.c
index 247b9f684..9dc82de18 100644
--- a/arch/m68k/atari/stdma.c
+++ b/arch/m68k/atari/stdma.c
@@ -32,6 +32,8 @@
#include <linux/types.h>
#include <linux/genhd.h>
#include <linux/sched.h>
+#include <linux/init.h>
+
#include <asm/atari_stdma.h>
#include <asm/atariints.h>
#include <asm/atarihw.h>
@@ -171,7 +173,7 @@ int stdma_islocked(void)
*
*/
-void stdma_init(void)
+__initfunc(void stdma_init(void))
{
stdma_isr = NULL;
request_irq(IRQ_MFP_FDC, stdma_int, IRQ_TYPE_SLOW,
diff --git a/arch/m68k/atari/stram.c b/arch/m68k/atari/stram.c
index 565b20535..4e5f57bc9 100644
--- a/arch/m68k/atari/stram.c
+++ b/arch/m68k/atari/stram.c
@@ -149,6 +149,7 @@ atari_stram_free (void *ptr)
#else
#include <linux/mm.h>
+#include <linux/init.h>
/* ++roman:
*
@@ -190,7 +191,7 @@ static unsigned long stram_end;
/* Overall end of ST-Ram */
-void atari_stram_init( void )
+__initfunc(void atari_stram_init( void ))
{ int i;
diff --git a/arch/m68k/boot/amiga/linuxboot.c b/arch/m68k/boot/amiga/linuxboot.c
index d35966686..23b7fa9d0 100644
--- a/arch/m68k/boot/amiga/linuxboot.c
+++ b/arch/m68k/boot/amiga/linuxboot.c
@@ -22,6 +22,8 @@
* for more details.
*
* History:
+ * 27 Mar 1997 FPU-less machines couldn't boot kernels that use bootinfo
+ * interface version 1.0 (Geert)
* 03 Feb 1997 Implemented kernel decompression (Geert, based on Roman's
* code for ataboot)
* 30 Dec 1996 Reverted the CPU detection to the old scheme
@@ -791,6 +793,7 @@ static u_long get_chipset(void)
static void get_processor(u_long *cpu, u_long *fpu, u_long *mmu)
{
*cpu = *fpu = 0;
+
if (SysBase->AttnFlags & AFF_68060)
*cpu = CPU_68060;
else if (SysBase->AttnFlags & AFF_68040)
@@ -799,15 +802,15 @@ static void get_processor(u_long *cpu, u_long *fpu, u_long *mmu)
*cpu = CPU_68030;
else if (SysBase->AttnFlags & AFF_68020)
*cpu = CPU_68020;
+
if (*cpu == CPU_68040 || *cpu == CPU_68060) {
if (SysBase->AttnFlags & AFF_FPU40)
*fpu = *cpu;
- } else {
- if (SysBase->AttnFlags & AFF_68882)
- *fpu = FPU_68882;
- else if (SysBase->AttnFlags & AFF_68881)
- *fpu = FPU_68881;
- }
+ } else if (SysBase->AttnFlags & AFF_68882)
+ *fpu = FPU_68882;
+ else if (SysBase->AttnFlags & AFF_68881)
+ *fpu = FPU_68881;
+
*mmu = *cpu;
}
@@ -1047,7 +1050,7 @@ static int create_compat_bootinfo(void)
compat_bootinfo.cputype |= COMPAT_FPU_68040;
else if (bi.fputype & FPU_68060)
compat_bootinfo.cputype |= COMPAT_FPU_68060;
- else {
+ else if (bi.fputype) {
Printf("FPU type 0x%08lx not supported by kernel\n", bi.fputype);
return(0);
}
diff --git a/arch/m68k/boot/amiga/linuxboot.h b/arch/m68k/boot/amiga/linuxboot.h
index 8ebfe63b4..e04425a3a 100644
--- a/arch/m68k/boot/amiga/linuxboot.h
+++ b/arch/m68k/boot/amiga/linuxboot.h
@@ -31,7 +31,7 @@
* Amiboot Version
*/
-#define AMIBOOT_VERSION "5.4"
+#define AMIBOOT_VERSION "5.5"
/*
diff --git a/arch/m68k/fpsp040/skeleton.S b/arch/m68k/fpsp040/skeleton.S
index 5768516bd..466cf3fbc 100644
--- a/arch/m68k/fpsp040/skeleton.S
+++ b/arch/m68k/fpsp040/skeleton.S
@@ -51,13 +51,23 @@
.include "fpsp.h"
-LOFF_ORIG_D0 = 0x20
+/*
+ * This has to match entry.S
+ */
+LOFF_ORIG_D0 = 0x24
+
+#define curptr a2
#define SAVE_ALL \
clrl %sp@-; /* stk_adj */ \
movel %d0,%sp@-; /* orig d0 */ \
movel %d0,%sp@-; /* d0 */ \
- moveml %d1-%d5/%a0-%a1,%sp@-
+ moveml %d1-%d5/%a0-%a1/%curptr,%sp@-;
+
+#define GET_CURRENT(tmp) \
+ movel %sp,tmp; \
+ andw &-8192,tmp; \
+ movel tmp,%curptr;
|xref b1238_fix
@@ -81,6 +91,7 @@ real_dz:
movel %d0,%sp@(LOFF_ORIG_D0) | a -1 in the ORIG_D0 field
| signifies that the stack frame
| is NOT for syscall
+ GET_CURRENT(%d0)
movel %sp,%sp@- | stack frame pointer argument
bsrl SYMBOL_NAME(trap_c)
addql #4,%sp
@@ -175,6 +186,7 @@ inex_done:
movel %d0,%sp@(LOFF_ORIG_D0) | a -1 in the ORIG_D0 field
| signifies that the stack frame
| is NOT for syscall
+ GET_CURRENT(%d0)
movel %sp,%sp@- | stack frame pointer argument
bsrl SYMBOL_NAME(trap_c)
addql #4,%sp
@@ -204,6 +216,7 @@ ovfl_done:
movel %d0,%sp@(LOFF_ORIG_D0) | a -1 in the ORIG_D0 field
| signifies that the stack frame
| is NOT for syscall
+ GET_CURRENT(%d0)
movel %sp,%sp@- | stack frame pointer argument
bsrl SYMBOL_NAME(trap_c)
addql #4,%sp
@@ -233,6 +246,7 @@ unfl_done:
movel %d0,%sp@(LOFF_ORIG_D0) | a -1 in the ORIG_D0 field
| signifies that the stack frame
| is NOT for syscall
+ GET_CURRENT(%d0)
movel %sp,%sp@- | stack frame pointer argument
bsrl SYMBOL_NAME(trap_c)
addql #4,%sp
@@ -258,6 +272,7 @@ real_snan:
movel %d0,%sp@(LOFF_ORIG_D0) | a -1 in the ORIG_D0 field
| signifies that the stack frame
| is NOT for syscall
+ GET_CURRENT(%d0)
movel %sp,%sp@- | stack frame pointer argument
bsrl SYMBOL_NAME(trap_c)
addql #4,%sp
@@ -283,6 +298,7 @@ real_operr:
movel %d0,%sp@(LOFF_ORIG_D0) | a -1 in the ORIG_D0 field
| signifies that the stack frame
| is NOT for syscall
+ GET_CURRENT(%d0)
movel %sp,%sp@- | stack frame pointer argument
bsrl SYMBOL_NAME(trap_c)
addql #4,%sp
@@ -314,6 +330,7 @@ real_bsun:
movel %d0,%sp@(LOFF_ORIG_D0) | a -1 in the ORIG_D0 field
| signifies that the stack frame
| is NOT for syscall
+ GET_CURRENT(%d0)
movel %sp,%sp@- | stack frame pointer argument
bsrl SYMBOL_NAME(trap_c)
addql #4,%sp
@@ -338,6 +355,7 @@ real_fline:
movel %d0,%sp@(LOFF_ORIG_D0) | a -1 in the ORIG_D0 field
| signifies that the stack frame
| is NOT for syscall
+ GET_CURRENT(%d0)
movel %sp,%sp@- | stack frame pointer argument
bsrl SYMBOL_NAME(trap_c)
addql #4,%sp
@@ -363,6 +381,7 @@ real_unsupp:
movel %d0,%sp@(LOFF_ORIG_D0) | a -1 in the ORIG_D0 field
| signifies that the stack frame
| is NOT for syscall
+ GET_CURRENT(%d0)
movel %sp,%sp@- | stack frame pointer argument
bsrl SYMBOL_NAME(trap_c)
addql #4,%sp
@@ -419,6 +438,7 @@ Lmustsched:
SAVE_ALL
moveq #-1,%d0
movel %d0,%sp@(LOFF_ORIG_D0) | indicate stack frame not for syscall
+ GET_CURRENT(%d0)
bral SYMBOL_NAME(ret_from_exception) | deliver signals, reschedule etc..
@@ -497,7 +517,7 @@ user_read:
movel %d0,-(%sp)
movel %a1,-(%sp)
movel %a0,-(%sp)
- jsr copyin
+ jsr copyin
addw #12,%sp
movel (%sp)+,%d1
rts
diff --git a/arch/m68k/ifpsp060/iskeleton.S b/arch/m68k/ifpsp060/iskeleton.S
index 5940a374a..3c310c237 100644
--- a/arch/m68k/ifpsp060/iskeleton.S
+++ b/arch/m68k/ifpsp060/iskeleton.S
@@ -36,13 +36,23 @@
#include <linux/linkage.h>
-LOFF_ORIG_D0 = 0x20
+/*
+ * This has to match entry.S
+ */
+LOFF_ORIG_D0 = 0x24
+
+#define curptr a2
#define SAVE_ALL \
clrl %sp@-; /* stk_adj */ \
movel %d0,%sp@-; /* orig d0 */ \
movel %d0,%sp@-; /* d0 */ \
- moveml %d1-%d5/%a0-%a1,%sp@-
+ moveml %d1-%d5/%a0-%a1/%curptr,%sp@-;
+
+#define GET_CURRENT(tmp) \
+ movel %sp,tmp; \
+ andw &-8192,tmp; \
+ movel tmp,%curptr;
|################################
| (1) EXAMPLE CALL-OUTS #
@@ -85,6 +95,7 @@ Lmustsched:
SAVE_ALL
moveq #-1,%d0
movel %d0,%sp@(LOFF_ORIG_D0) | indicate stack frame not for syscall
+ GET_CURRENT(%d0)
bral SYMBOL_NAME(ret_from_exception) | deliver signals, reschedule etc..
|
diff --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S
index 2cb35e67f..ef5ef46d6 100644
--- a/arch/m68k/kernel/entry.S
+++ b/arch/m68k/kernel/entry.S
@@ -33,12 +33,13 @@
* 10(sp) - d5
* 14(sp) - a0
* 18(sp) - a1
- * 1C(sp) - d0
- * 20(sp) - orig_d0
- * 24(sp) - stack adjustment
- * 28(sp) - sr
- * 2A(sp) - pc
- * 2E(sp) - format & vector
+ * 1C(sp) - a2
+ * 20(sp) - d0
+ * 24(sp) - orig_d0
+ * 28(sp) - stack adjustment
+ * 2C(sp) - sr
+ * 2E(sp) - pc
+ * 32(sp) - format & vector
*/
/*
@@ -47,6 +48,11 @@
* number 0 in the 'current_set' list.
*/
+/*
+ * 97/05/14 Andreas: Register %a2 is now set to the current task throughout
+ * the whole kernel.
+ */
+
#include <linux/sys.h>
#include <linux/config.h>
#include <linux/linkage.h>
@@ -57,6 +63,8 @@
.globl SYMBOL_NAME(kgdb_registers)
#endif
+#define curptr a2
+
LENOSYS = 38
/*
@@ -80,15 +88,15 @@ LTASK_FLAGS = 20
#define MAX_NOINT_IPL 0
#endif /* machine compilation types */
-LD0 = 0x1C
-LORIG_D0 = 0x20
-LSR = 0x28
-LFORMATVEC = 0x2E
+LD0 = 0x20
+LORIG_D0 = 0x24
+LSR = 0x2C
+LFORMATVEC = 0x32
/*
* This defines the normal kernel pt-regs layout.
*
- * regs are a2-a6 and d6-d7 preserved by C code
+ * regs a3-a6 and d6-d7 are preserved by C code
* the kernel doesn't mess with usp unless it needs to
*/
#ifndef CONFIG_KGDB
@@ -96,7 +104,7 @@ LFORMATVEC = 0x2E
clrl %sp@-; /* stk_adj */ \
movel %d0,%sp@-; /* orig d0 */ \
movel %d0,%sp@-; /* d0 */ \
- moveml %d1-%d5/%a0-%a1,%sp@-
+ moveml %d1-%d5/%a0-%a1/%curptr,%sp@-;
#else
/* Need to save the "missing" registers for kgdb...
*/
@@ -104,25 +112,30 @@ LFORMATVEC = 0x2E
clrl %sp@-; /* stk_adj */ \
movel %d0,%sp@-; /* orig d0 */ \
movel %d0,%sp@-; /* d0 */ \
- moveml %d1-%d5/%a0-%a1,%sp@-; \
+ moveml %d1-%d5/%a0-%a1/%curptr,%sp@-; \
moveml %d6-%d7,SYMBOL_NAME(kgdb_registers)+GDBOFFA_D6; \
- moveml %a2-%a6,SYMBOL_NAME(kgdb_registers)+GDBOFFA_A2
+ moveml %a3-%a6,SYMBOL_NAME(kgdb_registers)+GDBOFFA_A3;
#endif
#define RESTORE_ALL \
- moveml %sp@+,%a0-%a1/%d1-%d5; \
+ moveml %sp@+,%a0-%a1/%curptr/%d1-%d5; \
movel %sp@+,%d0; \
addql #4,%sp; /* orig d0 */ \
addl %sp@+,%sp; /* stk adj */ \
rte
-#define SWITCH_STACK_SIZE (7*4+4) /* includes return address */
+#define SWITCH_STACK_SIZE (6*4+4) /* includes return address */
#define SAVE_SWITCH_STACK \
- moveml %a2-%a6/%d6-%d7,%sp@-
+ moveml %a3-%a6/%d6-%d7,%sp@-
#define RESTORE_SWITCH_STACK \
- moveml %sp@+,%a2-%a6/%d6-%d7
+ moveml %sp@+,%a3-%a6/%d6-%d7
+
+#define GET_CURRENT(tmp) \
+ movel %sp,tmp; \
+ andw &-8192,tmp; \
+ movel tmp,%curptr;
.globl SYMBOL_NAME(system_call), SYMBOL_NAME(buserr), SYMBOL_NAME(trap)
.globl SYMBOL_NAME(resume), SYMBOL_NAME(ret_from_exception)
@@ -139,6 +152,7 @@ ENTRY(buserr)
| signifies that the stack frame
| is NOT for syscall
+ GET_CURRENT(%d0)
movel %sp,%sp@- | stack frame pointer argument
bsrl SYMBOL_NAME(buserr_c)
addql #4,%sp
@@ -150,6 +164,7 @@ ENTRY(trap)
movel %d0,%sp@(LORIG_D0) | a -1 in the ORIG_D0 field
| signifies that the stack frame
| is NOT for syscall
+ GET_CURRENT(%d0)
movel %sp,%sp@- | stack frame pointer argument
bsrl SYMBOL_NAME(trap_c)
addql #4,%sp
@@ -190,6 +205,7 @@ ENTRY(system_call)
SAVE_ALL
movel %d0,%d2
+ GET_CURRENT(%d0)
| save top of frame
pea %sp@
jbsr SYMBOL_NAME(set_esp0)
@@ -197,8 +213,7 @@ ENTRY(system_call)
cmpl #NR_syscalls,%d2
jcc badsys
- movel SYMBOL_NAME(current_set),%a0
- btst #5,%a0@(LTASK_FLAGS+3) | PF_TRACESYS
+ btst #5,%curptr@(LTASK_FLAGS+3) | PF_TRACESYS
jne do_trace
jbsr @(SYMBOL_NAME(sys_call_table),%d2:l:4)@(0)
movel %d0,%sp@(LD0) | save the return value
@@ -208,24 +223,23 @@ SYMBOL_NAME_LABEL(ret_from_exception)
bnes 2f | if so, skip resched, signals
tstl SYMBOL_NAME(need_resched)
jne SYMBOL_NAME(reschedule)
- movel SYMBOL_NAME(current_set),%a0
- cmpl #SYMBOL_NAME(task),%a0 | task[0] cannot have signals
+ cmpl #SYMBOL_NAME(task),%curptr | task[0] cannot have signals
jeq 2f
- bclr #5,%a0@(LTASK_FLAGS+1) | check for delayed trace
+ bclr #5,%curptr@(LTASK_FLAGS+1) | check for delayed trace
jne do_delayed_trace
5:
- tstl %a0@(LTASK_STATE) | state
+ tstl %curptr@(LTASK_STATE) | state
jne SYMBOL_NAME(reschedule)
- tstl %a0@(LTASK_COUNTER) | counter
+ tstl %curptr@(LTASK_COUNTER) | counter
jeq SYMBOL_NAME(reschedule)
- movel %a0@(LTASK_BLOCKED),%d0
+ movel %curptr@(LTASK_BLOCKED),%d0
movel %d0,%d1 | save blocked in d1 for sig handling
notl %d0
- btst #4,%a0@(LTASK_FLAGS+3) | PF_PTRACED
+ btst #4,%curptr@(LTASK_FLAGS+3) | PF_PTRACED
jeq 1f
moveq #-1,%d0 | let the debugger see all signals
-1: andl %a0@(LTASK_SIGNAL),%d0
+1: andl %curptr@(LTASK_SIGNAL),%d0
jne Lsignal_return
2: RESTORE_ALL
@@ -248,7 +262,6 @@ do_delayed_trace:
jbsr SYMBOL_NAME(send_sig)
addql #8,%sp
addql #4,%sp
- movel SYMBOL_NAME(current_set),%a0
jra 5b
/*
@@ -260,6 +273,7 @@ SYMBOL_NAME_LABEL(inthandler)
movel %d0,%sp@(LORIG_D0) | a -1 in the ORIG_D0 field
| signifies that the stack frame
| is NOT for syscall
+ GET_CURRENT(%d0)
addql #1,SYMBOL_NAME(local_irq_count)
| put exception # in d0
bfextu %sp@(LFORMATVEC){#4,#10},%d0
@@ -270,28 +284,31 @@ SYMBOL_NAME_LABEL(inthandler)
addql #8,%sp | pop parameters off stack
SYMBOL_NAME_LABEL(ret_from_interrupt)
- /* check if we need to do software interrupts */
- movel SYMBOL_NAME(local_irq_count),%d1
- subql #1,%d1
- jne 4f
-#if 0
- bfextu %sp@(LSR){#5,#3},%d0 | Check for nested interrupt.
+ subql #1,SYMBOL_NAME(local_irq_count)
+ jeq 1f
+2:
+ RESTORE_ALL
+1:
+#if 1
+ bfextu %sp@(LSR){#5,#3},%d0 | Check for nested interrupt.
#if MAX_NOINT_IPL > 0
cmpiw #MAX_NOINT_IPL,%d0
#endif
- jhi 4f
+ jhi 2b
#endif
+ /* Let the rest run with interrupts allowed. This is safe since
+ the kernel never uses a non-standard ipl and this is the outer
+ level interrupt. */
+ andw #ALLOWINT,%sr
+
+ /* check if we need to do software interrupts */
+
movel SYMBOL_NAME(bh_active),%d0
andl SYMBOL_NAME(bh_mask),%d0
- jeq 3f
+ jeq SYMBOL_NAME(ret_from_exception)
- jbsr SYMBOL_NAME(do_bottom_half)
-3:
- clrl SYMBOL_NAME(local_irq_count)
- jra SYMBOL_NAME(ret_from_exception)
-4:
- movel %d1,SYMBOL_NAME(local_irq_count)
- RESTORE_ALL
+ pea SYMBOL_NAME(ret_from_exception)
+ jra SYMBOL_NAME(do_bottom_half)
/* Handler for uninitialized and spurious interrupts */
@@ -398,7 +415,7 @@ SYMBOL_NAME_LABEL(resume)
3:
/* get pointer to tss struct (a1 contains new task) */
- movel %a1,SYMBOL_NAME(current_set)
+ movel %a1,%curptr
addl %d1,%a1
/* Skip address space switching if they are the same. */
@@ -419,7 +436,7 @@ SYMBOL_NAME_LABEL(resume)
movec %cacr,%d0
oriw #LFLUSH_I_AND_D,%d0
movec %d0,%cacr
-
+
/* switch the root pointer */
pmove %a1@(LTSS_CRP),%crp
#endif
diff --git a/arch/m68k/kernel/head.S b/arch/m68k/kernel/head.S
index c2b72aa2d..36a4072ac 100644
--- a/arch/m68k/kernel/head.S
+++ b/arch/m68k/kernel/head.S
@@ -223,17 +223,9 @@ ENTRY(_start)
movel %d0,%a0@ /* save cache mode for page tables */
/*
- * raise interrupt level with MASTER bit set, copy isp to msp (if not 68060)
+ * raise interrupt level
*/
-#ifdef FROM_PL9
- movew #0x3700,%sr
- is_060(1f)
- movec %isp,%d0
- movel %d0,%sp
-1:
-#else
movew #0x2700,%sr
-#endif
/*
If running on an Atari, determine the I/O base of the
@@ -896,8 +888,10 @@ Lcache68060:
/*
* Setup initial stack pointer
+ * We need to get current loaded up with our first task...
*/
- lea SYMBOL_NAME(init_user_stack)+PAGESIZE,%sp
+ lea SYMBOL_NAME(init_task_union),%a2
+ lea 8192(%a2),%sp
/* jump to the kernel start */
putr()
diff --git a/arch/m68k/kernel/ints.c b/arch/m68k/kernel/ints.c
index f49c38cd3..39e1fbce6 100644
--- a/arch/m68k/kernel/ints.c
+++ b/arch/m68k/kernel/ints.c
@@ -29,6 +29,7 @@
#include <linux/sched.h>
#include <linux/kernel_stat.h>
#include <linux/errno.h>
+#include <linux/init.h>
#include <asm/system.h>
#include <asm/irq.h>
@@ -79,7 +80,7 @@ void (*mach_free_irq) (unsigned int, void *) = dummy_free_irq;
* the IRQ handling routines.
*/
-void init_IRQ(void)
+__initfunc(void init_IRQ(void))
{
int i;
diff --git a/arch/m68k/kernel/m68k_ksyms.c b/arch/m68k/kernel/m68k_ksyms.c
index 3138d99df..f6bb0689b 100644
--- a/arch/m68k/kernel/m68k_ksyms.c
+++ b/arch/m68k/kernel/m68k_ksyms.c
@@ -6,6 +6,8 @@
#include <linux/mm.h>
#include <linux/user.h>
#include <linux/elfcore.h>
+#include <linux/in6.h>
+#include <linux/interrupt.h>
#include <asm/setup.h>
#include <asm/machdep.h>
@@ -14,6 +16,7 @@
#include <asm/semaphore.h>
#include <asm/checksum.h>
#include <asm/hardirq.h>
+#include <asm/softirq.h>
asmlinkage long long __ashrdi3 (long long, int);
extern char m68k_debug_device[];
@@ -40,6 +43,7 @@ EXPORT_SYMBOL(strnlen);
EXPORT_SYMBOL(strrchr);
EXPORT_SYMBOL(strstr);
EXPORT_SYMBOL(local_irq_count);
+EXPORT_SYMBOL(__m68k_bh_counter);
/* Networking helper routines. */
EXPORT_SYMBOL(csum_partial_copy);
diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c
index 5422831a8..ad0662f22 100644
--- a/arch/m68k/kernel/process.c
+++ b/arch/m68k/kernel/process.c
@@ -10,6 +10,7 @@
* This file handles the architecture-dependent parts of process handling..
*/
+#include <linux/config.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
@@ -29,6 +30,23 @@
#include <asm/traps.h>
#include <asm/machdep.h>
#include <asm/setup.h>
+#include <asm/pgtable.h>
+
+/*
+ * Initial task structure. Make this a per-architecture thing,
+ * because different architectures tend to have different
+ * alignment requirements and potentially different initial
+ * setup.
+ */
+static struct vm_area_struct init_mmap = INIT_MMAP;
+static struct fs_struct init_fs = INIT_FS;
+static struct files_struct init_files = INIT_FILES;
+static struct signal_struct init_signals = INIT_SIGNALS;
+struct mm_struct init_mm = INIT_MM;
+
+union task_union init_task_union
+ __attribute__((section("init_task"), aligned(2*PAGE_SIZE)))
+ = { task: INIT_TASK };
asmlinkage void ret_from_exception(void);
@@ -46,8 +64,17 @@ asmlinkage int sys_idle(void)
/* endless idle loop with no priority at all */
current->priority = -100;
current->counter = -100;
- for (;;)
+ for (;;){
+ if (!need_resched)
+#if defined(CONFIG_ATARI) && !defined(CONFIG_AMIGA) && !defined(CONFIG_MAC)
+ /* block out HSYNC on the atari (falcon) */
+ __asm__("stop #0x2200" : : : "cc");
+#else /* portable version */
+ __asm__("stop #0x2000" : : : "cc");
+#endif /* machine compilation types */
+ run_task_queue(&tq_scheduler);
schedule();
+ }
ret = 0;
out:
unlock_kernel();
@@ -76,8 +103,8 @@ void show_regs(struct pt_regs * regs)
printk("\n");
printk("Format %02x Vector: %04x PC: %08lx Status: %04x\n",
regs->format, regs->vector, regs->pc, regs->sr);
- printk("ORIG_D0: %08lx D0: %08lx A1: %08lx\n",
- regs->orig_d0, regs->d0, regs->a1);
+ printk("ORIG_D0: %08lx D0: %08lx A2: %08lx A1: %08lx\n",
+ regs->orig_d0, regs->d0, regs->a2, regs->a1);
printk("A0: %08lx D5: %08lx D4: %08lx\n",
regs->a0, regs->d5, regs->d4);
printk("D3: %08lx D2: %08lx D1: %08lx\n",
@@ -144,8 +171,8 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
struct switch_stack * childstack, *stack;
unsigned long stack_offset, *retp;
- stack_offset = PAGE_SIZE - sizeof(struct pt_regs);
- childregs = (struct pt_regs *) (p->kernel_stack_page + stack_offset);
+ stack_offset = 2*PAGE_SIZE - sizeof(struct pt_regs);
+ childregs = (struct pt_regs *) ((unsigned long) p + stack_offset);
*childregs = *regs;
childregs->d0 = 0;
@@ -231,7 +258,7 @@ void dump_thread(struct pt_regs * regs, struct user * dump)
dump->regs.d7 = sw->d7;
dump->regs.a0 = regs->a0;
dump->regs.a1 = regs->a1;
- dump->regs.a2 = sw->a2;
+ dump->regs.a2 = regs->a2;
dump->regs.a3 = sw->a3;
dump->regs.a4 = sw->a4;
dump->regs.a5 = sw->a5;
diff --git a/arch/m68k/kernel/ptrace.c b/arch/m68k/kernel/ptrace.c
index 70e341b31..be4149cbb 100644
--- a/arch/m68k/kernel/ptrace.c
+++ b/arch/m68k/kernel/ptrace.c
@@ -47,23 +47,11 @@
static int regoff[] = {
PT_REG(d1), PT_REG(d2), PT_REG(d3), PT_REG(d4),
PT_REG(d5), SW_REG(d6), SW_REG(d7), PT_REG(a0),
- PT_REG(a1), SW_REG(a2), SW_REG(a3), SW_REG(a4),
+ PT_REG(a1), PT_REG(a2), SW_REG(a3), SW_REG(a4),
SW_REG(a5), SW_REG(a6), PT_REG(d0), -1,
PT_REG(orig_d0), PT_REG(sr), PT_REG(pc),
};
-/* change a pid into a task struct. */
-static inline struct task_struct * get_task(int pid)
-{
- int i;
-
- for (i = 1; i < NR_TASKS; i++) {
- if (task[i] != NULL && (task[i]->pid == pid))
- return task[i];
- }
- return NULL;
-}
-
/*
* Get contents of register REGNO in task TASK.
*/
@@ -116,7 +104,7 @@ static unsigned long get_long(struct task_struct * tsk,
repeat:
pgdir = pgd_offset(vma->vm_mm, addr);
if (pgd_none(*pgdir)) {
- do_no_page(tsk, vma, addr, 0);
+ handle_mm_fault(tsk, vma, addr, 0);
goto repeat;
}
if (pgd_bad(*pgdir)) {
@@ -126,7 +114,7 @@ repeat:
}
pgmiddle = pmd_offset(pgdir,addr);
if (pmd_none(*pgmiddle)) {
- do_no_page(tsk, vma, addr, 0);
+ handle_mm_fault(tsk, vma, addr, 0);
goto repeat;
}
if (pmd_bad(*pgmiddle)) {
@@ -137,7 +125,7 @@ repeat:
}
pgtable = pte_offset(pgmiddle, addr);
if (!pte_present(*pgtable)) {
- do_no_page(tsk, vma, addr, 0);
+ handle_mm_fault(tsk, vma, addr, 0);
goto repeat;
}
page = pte_page(*pgtable);
@@ -168,7 +156,7 @@ static void put_long(struct task_struct * tsk, struct vm_area_struct * vma, unsi
repeat:
pgdir = pgd_offset(vma->vm_mm, addr);
if (!pgd_present(*pgdir)) {
- do_no_page(tsk, vma, addr, 1);
+ handle_mm_fault(tsk, vma, addr, 1);
goto repeat;
}
if (pgd_bad(*pgdir)) {
@@ -178,7 +166,7 @@ repeat:
}
pgmiddle = pmd_offset(pgdir,addr);
if (pmd_none(*pgmiddle)) {
- do_no_page(tsk, vma, addr, 1);
+ handle_mm_fault(tsk, vma, addr, 1);
goto repeat;
}
if (pmd_bad(*pgmiddle)) {
@@ -189,12 +177,12 @@ repeat:
}
pgtable = pte_offset(pgmiddle, addr);
if (!pte_present(*pgtable)) {
- do_no_page(tsk, vma, addr, 1);
+ handle_mm_fault(tsk, vma, addr, 1);
goto repeat;
}
page = pte_page(*pgtable);
if (!pte_write(*pgtable)) {
- do_wp_page(tsk, vma, addr, 2);
+ handle_mm_fault(tsk, vma, addr, 1);
goto repeat;
}
/* this is a hack for non-kernel-mapped video buffers and similar */
@@ -340,7 +328,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
if (pid == 1) /* you may not mess with init */
goto out;
ret = -ESRCH;
- if (!(child = get_task(pid)))
+ if (!(child = find_task_by_pid(pid)))
goto out;
ret = -EPERM;
if (request == PTRACE_ATTACH) {
diff --git a/arch/m68k/kernel/setup.c b/arch/m68k/kernel/setup.c
index dfd91d0d4..def50a747 100644
--- a/arch/m68k/kernel/setup.c
+++ b/arch/m68k/kernel/setup.c
@@ -18,6 +18,7 @@
#include <linux/genhd.h>
#include <linux/errno.h>
#include <linux/string.h>
+#include <linux/init.h>
#include <asm/bootinfo.h>
#include <asm/setup.h>
@@ -55,13 +56,13 @@ static struct mem_info m68k_ramdisk = { 0, 0 };
static char m68k_command_line[CL_SIZE];
char saved_command_line[CL_SIZE];
-void (*mach_sched_init) (void (*handler)(int, void *, struct pt_regs *));
+void (*mach_sched_init) (void (*handler)(int, void *, struct pt_regs *)) __initdata;
/* machine dependent keyboard functions */
-int (*mach_keyb_init) (void);
+int (*mach_keyb_init) (void) __initdata;
int (*mach_kbdrate) (struct kbd_repeat *) = NULL;
void (*mach_kbd_leds) (unsigned int) = NULL;
/* machine dependent irq functions */
-void (*mach_init_IRQ) (void);
+void (*mach_init_IRQ) (void) __initdata;
void (*(*mach_default_handler)[]) (int, void *, struct pt_regs *) = NULL;
void (*mach_get_model) (char *model) = NULL;
int (*mach_get_hardware_list) (char *buffer) = NULL;
@@ -73,12 +74,12 @@ void (*mach_gettod) (int*, int*, int*, int*, int*, int*);
int (*mach_hwclk) (int, struct hwclk_time*) = NULL;
int (*mach_set_clock_mmss) (unsigned long) = NULL;
void (*mach_reset)( void );
-struct fb_info *(*mach_fb_init)(long *);
+struct fb_info *(*mach_fb_init)(long *) __initdata;
long mach_max_dma_address = 0x00ffffff; /* default set to the lower 16MB */
-void (*mach_video_setup) (char *, int *);
+void (*mach_video_setup) (char *, int *) __initdata;
#ifdef CONFIG_BLK_DEV_FD
-int (*mach_floppy_init) (void) = NULL;
-void (*mach_floppy_setup) (char *, int *) = NULL;
+int (*mach_floppy_init) (void) __initdata = NULL;
+void (*mach_floppy_setup) (char *, int *) __initdata = NULL;
void (*mach_floppy_eject) (void) = NULL;
#endif
@@ -94,7 +95,7 @@ extern void config_apollo(void);
#define MASK_256K 0xfffc0000
-static void m68k_parse_bootinfo(const struct bi_record *record)
+__initfunc(static void m68k_parse_bootinfo(const struct bi_record *record))
{
while (record->tag != BI_LAST) {
int unknown = 0;
@@ -141,8 +142,8 @@ static void m68k_parse_bootinfo(const struct bi_record *record)
}
}
-void setup_arch(char **cmdline_p, unsigned long * memory_start_p,
- unsigned long * memory_end_p)
+ __initfunc(void setup_arch(char **cmdline_p, unsigned long * memory_start_p,
+ unsigned long * memory_end_p))
{
unsigned long memory_start, memory_end;
extern int _etext, _edata, _end;
@@ -337,7 +338,7 @@ int get_hardware_list(char *buffer)
}
#ifdef CONFIG_BLK_DEV_FD
-int floppy_init(void)
+__initfunc(int floppy_init(void))
{
if (mach_floppy_init)
return mach_floppy_init();
@@ -345,7 +346,7 @@ int floppy_init(void)
return 0;
}
-void floppy_setup(char *str, int *ints)
+__initfunc(void floppy_setup(char *str, int *ints))
{
if (mach_floppy_setup)
mach_floppy_setup (str, ints);
@@ -358,7 +359,7 @@ void floppy_eject(void)
}
#endif
-unsigned long arch_kbd_init(void)
+__initfunc(unsigned long arch_kbd_init(void))
{
return mach_keyb_init();
}
@@ -372,7 +373,7 @@ void arch_gettod(int *year, int *mon, int *day, int *hour,
*year = *mon = *day = *hour = *min = *sec = 0;
}
-void video_setup (char *options, int *ints)
+__initfunc(void video_setup (char *options, int *ints))
{
if (mach_video_setup)
mach_video_setup (options, ints);
diff --git a/arch/m68k/kernel/signal.c b/arch/m68k/kernel/signal.c
index c60e82b0b..52c13445d 100644
--- a/arch/m68k/kernel/signal.c
+++ b/arch/m68k/kernel/signal.c
@@ -42,7 +42,9 @@
#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
-asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options);
+asmlinkage int sys_wait4(pid_t pid, unsigned long *stat_addr,
+ int options, unsigned long *ru);
+
asmlinkage int do_signal(unsigned long oldmask, struct pt_regs *regs);
const int frame_extra_sizes[16] = {
@@ -466,7 +468,7 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs *regs)
if (signr != SIGCHLD)
continue;
/* check for SIGCHLD: it's special */
- while (sys_waitpid(-1,NULL,WNOHANG) > 0)
+ while (sys_wait4(-1,NULL,WNOHANG, NULL) > 0)
/* nothing */;
continue;
}
diff --git a/arch/m68k/kernel/sys_m68k.c b/arch/m68k/kernel/sys_m68k.c
index 5acfd1cbd..e29509cac 100644
--- a/arch/m68k/kernel/sys_m68k.c
+++ b/arch/m68k/kernel/sys_m68k.c
@@ -532,12 +532,15 @@ sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len)
*/
vma = find_vma (current->mm, addr);
ret = -EINVAL;
+ /* Check for overflow. */
+ if (addr + len < addr)
+ goto out;
if (vma == NULL || addr < vma->vm_start || addr + len > vma->vm_end)
goto out;
}
if (CPU_IS_020_OR_030) {
- if (scope == FLUSH_SCOPE_LINE) {
+ if (scope == FLUSH_SCOPE_LINE && len < 256) {
unsigned long cacr;
__asm__ ("movec %%cacr, %0" : "=r" (cacr));
if (cache & FLUSH_CACHE_INSN)
diff --git a/arch/m68k/kernel/time.c b/arch/m68k/kernel/time.c
index dbff49276..7b3acdfa6 100644
--- a/arch/m68k/kernel/time.c
+++ b/arch/m68k/kernel/time.c
@@ -27,6 +27,24 @@ static inline int set_rtc_mmss(unsigned long nowtime)
return -1;
}
+static inline void do_profile (unsigned long pc)
+{
+ if (prof_buffer && current->pid) {
+ extern int _stext;
+ pc -= (unsigned long) &_stext;
+ pc >>= prof_shift;
+ if (pc < prof_len)
+ ++prof_buffer[pc];
+ else
+ /*
+ * Dont ignore out-of-bounds PC values silently,
+ * put them into the last histogram slot, so if
+ * present, they will show up as a sharp peak.
+ */
+ ++prof_buffer[prof_len-1];
+ }
+}
+
/*
* timer_interrupt() needs to keep up the real-time clock,
* as well as call the "do_timer()" routine every clocktick
@@ -38,6 +56,9 @@ static void timer_interrupt(int irq, void *dummy, struct pt_regs * regs)
do_timer(regs);
+ if (!user_mode(regs))
+ do_profile(regs->pc);
+
/*
* If we have an externally synchronized Linux clock, then update
* CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
diff --git a/arch/m68k/kernel/traps.c b/arch/m68k/kernel/traps.c
index 1cc547907..25be40007 100644
--- a/arch/m68k/kernel/traps.c
+++ b/arch/m68k/kernel/traps.c
@@ -27,6 +27,7 @@
#include <linux/user.h>
#include <linux/string.h>
#include <linux/linkage.h>
+#include <linux/init.h>
#include <asm/setup.h>
#include <asm/fpu.h>
@@ -63,7 +64,7 @@ asm(".text\n"
__ALIGN_STR "\n"
SYMBOL_NAME_STR(nmihandler) ": rte");
-void trap_init (void)
+__initfunc(void trap_init (void))
{
int i;
@@ -932,16 +933,15 @@ void die_if_kernel (char *str, struct pt_regs *fp, int nr)
#endif
console_verbose();
printk("%s: %08x\n",str,nr);
- printk("PC: [<%08lx>]\nSR: %04x SP: %p\n", fp->pc, fp->sr, fp);
+ printk("PC: [<%08lx>]\nSR: %04x SP: %p a2: %08lx\n",
+ fp->pc, fp->sr, fp, fp->a2);
printk("d0: %08lx d1: %08lx d2: %08lx d3: %08lx\n",
fp->d0, fp->d1, fp->d2, fp->d3);
printk("d4: %08lx d5: %08lx a0: %08lx a1: %08lx\n",
fp->d4, fp->d5, fp->a0, fp->a1);
- if (STACK_MAGIC != *(unsigned long *)current->kernel_stack_page)
- printk("Corrupted stack page\n");
printk("Process %s (pid: %d, stackpage=%08lx)\n",
- current->comm, current->pid, current->kernel_stack_page);
+ current->comm, current->pid, PAGE_SIZE+(unsigned long)current);
#ifdef CONFIG_KGDB
}
#endif
diff --git a/arch/m68k/lib/semaphore.S b/arch/m68k/lib/semaphore.S
index 76ffc3cc5..8e4141149 100644
--- a/arch/m68k/lib/semaphore.S
+++ b/arch/m68k/lib/semaphore.S
@@ -19,8 +19,7 @@ ENTRY(__down_failed)
movel %a1,-(%sp)
jbsr SYMBOL_NAME(__down)
movel (%sp)+,%a1
- movel (%sp)+,%d0
- movel (%sp)+,%d1
+ moveml (%sp)+,%a0/%d0/%d1
rts
ENTRY(__down_failed_interruptible)
@@ -30,6 +29,7 @@ ENTRY(__down_failed_interruptible)
jbsr SYMBOL_NAME(__down_interruptible)
movel (%sp)+,%a1
movel (%sp)+,%d1
+ movel (%sp)+,%a0
rts
ENTRY(__up_wakeup)
@@ -37,6 +37,5 @@ ENTRY(__up_wakeup)
movel %a1,-(%sp)
jbsr SYMBOL_NAME(__up)
movel (%sp)+,%a1
- movel (%sp)+,%d0
- movel (%sp)+,%d1
+ moveml (%sp)+,%a0/%d0/%d1
rts
diff --git a/arch/m68k/mm/fault.c b/arch/m68k/mm/fault.c
index 71b46e2d9..193c6baee 100644
--- a/arch/m68k/mm/fault.c
+++ b/arch/m68k/mm/fault.c
@@ -32,14 +32,10 @@ extern const int frame_extra_sizes[]; /* in m68k/kernel/signal.c */
asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address,
unsigned long error_code)
{
- void (*handler)(struct task_struct *,
- struct vm_area_struct *,
- unsigned long,
- int);
struct task_struct *tsk = current;
struct mm_struct *mm = tsk->mm;
struct vm_area_struct * vma;
- unsigned long fixup, fault_pc;
+ unsigned long fixup;
int write;
#ifdef DEBUG
@@ -73,10 +69,8 @@ asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address,
*/
good_area:
write = 0;
- handler = do_no_page;
switch (error_code & 3) {
default: /* 3: write, present */
- handler = do_wp_page;
/* fall through */
case 2: /* write, not present */
if (!(vma->vm_flags & VM_WRITE))
@@ -89,7 +83,7 @@ good_area:
if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
goto bad_area;
}
- handler(tsk, vma, address, write);
+ handle_mm_fault(current, vma, address, write);
up(&mm->mmap_sem);
/* There seems to be a missing invalidate somewhere in do_no_page.
@@ -108,10 +102,10 @@ bad_area:
up(&mm->mmap_sem);
/* Are we prepared to handle this fault? */
- fault_pc = regs->pc;
- if ((fixup = search_exception_table(fault_pc)) != 0) {
+ if ((fixup = search_exception_table(regs->pc)) != 0) {
struct pt_regs *tregs;
- printk(KERN_DEBUG "Exception at [<%lx>] (%lx)\n", fault_pc, fixup);
+ printk(KERN_DEBUG "%s: Exception at [<%lx>] (%lx)\n",
+ current->comm, regs->pc, fixup);
/* Create a new four word stack frame, discarding the old
one. */
regs->stkadj = frame_extra_sizes[regs->format];
diff --git a/arch/m68k/mm/init.c b/arch/m68k/mm/init.c
index 01cd315dd..b46037f80 100644
--- a/arch/m68k/mm/init.c
+++ b/arch/m68k/mm/init.c
@@ -12,6 +12,7 @@
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/types.h>
+#include <linux/init.h>
#ifdef CONFIG_BLK_DEV_RAM
#include <linux/blk.h>
#endif
@@ -116,9 +117,8 @@ pte_t *kernel_page_table (unsigned long *memavailp)
return ptablep;
}
-static unsigned long map_chunk (unsigned long addr,
- unsigned long size,
- unsigned long *memavailp)
+__initfunc(static unsigned long
+map_chunk (unsigned long addr, unsigned long size, unsigned long *memavailp))
{
#define ONEMEG (1024*1024)
#define L3TREESIZE (256*1024)
@@ -283,6 +283,11 @@ static unsigned long map_chunk (unsigned long addr,
extern unsigned long free_area_init(unsigned long, unsigned long);
+/* References to section boundaries */
+
+extern char _text, _etext, _edata, __bss_start, _end;
+extern char __init_begin, __init_end;
+
extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
/*
@@ -291,7 +296,7 @@ extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
* The parameters are pointers to where to stick the starting and ending
* addresses of available kernel virtual memory.
*/
-unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)
+__initfunc(unsigned long paging_init(unsigned long start_mem, unsigned long end_mem))
{
int chunk;
unsigned long mem_avail = 0;
@@ -395,12 +400,12 @@ unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)
return PAGE_ALIGN(free_area_init (start_mem, end_mem));
}
-void mem_init(unsigned long start_mem, unsigned long end_mem)
+__initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
{
int codepages = 0;
int datapages = 0;
+ int initpages = 0;
unsigned long tmp;
- extern int _etext;
end_mem &= PAGE_MASK;
high_memory = (void *) end_mem;
@@ -448,8 +453,15 @@ void mem_init(unsigned long start_mem, unsigned long end_mem)
if (VTOP (tmp) >= mach_max_dma_address)
clear_bit(PG_DMA, &mem_map[MAP_NR(tmp)].flags);
if (PageReserved(mem_map+MAP_NR(tmp))) {
- if (tmp < (unsigned long)&_etext)
- codepages++;
+ if (tmp >= (unsigned long)&_text
+ && tmp < (unsigned long)&_edata) {
+ if (tmp < (unsigned long) &_etext)
+ codepages++;
+ else
+ datapages++;
+ } else if (tmp >= (unsigned long) &__init_begin
+ && tmp < (unsigned long) &__init_end)
+ initpages++;
else
datapages++;
continue;
@@ -461,16 +473,24 @@ void mem_init(unsigned long start_mem, unsigned long end_mem)
#endif
free_page(tmp);
}
- printk("Memory: %luk/%luk available (%dk kernel code, %dk data)\n",
+ printk("Memory: %luk/%luk available (%dk kernel code, %dk data, %dk init)\n",
(unsigned long) nr_free_pages << (PAGE_SHIFT-10),
max_mapnr << (PAGE_SHIFT-10),
codepages << (PAGE_SHIFT-10),
- datapages << (PAGE_SHIFT-10));
+ datapages << (PAGE_SHIFT-10),
+ initpages << (PAGE_SHIFT-10));
}
void free_initmem(void)
{
- /* To be written */
+ unsigned long addr;
+
+ addr = (unsigned long)&__init_begin;
+ for (; addr < (unsigned long)&__init_end; addr += PAGE_SIZE) {
+ mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved);
+ atomic_set(&mem_map[MAP_NR(addr)].count, 1);
+ free_page(addr);
+ }
}
void si_meminfo(struct sysinfo *val)
diff --git a/arch/m68k/mm/memory.c b/arch/m68k/mm/memory.c
index 55d5e98f3..77eb2dbfe 100644
--- a/arch/m68k/mm/memory.c
+++ b/arch/m68k/mm/memory.c
@@ -280,6 +280,8 @@ static unsigned long transp_transl_matches( unsigned long regval,
return( (vaddr & mask) == (base & mask) );
}
+static unsigned long mm_vtop_fallback (unsigned long);
+
/*
* The following two routines map from a physical address to a kernel
* virtual address and vice versa.
@@ -301,7 +303,13 @@ unsigned long mm_vtop (unsigned long vaddr)
offset += m68k_memory[i].size;
i++;
}while (i < m68k_num_memory);
+ return mm_vtop_fallback(vaddr);
+}
+/* Separate function to make the common case faster (needs to save less
+ registers) */
+static unsigned long mm_vtop_fallback (unsigned long vaddr)
+{
/* not in one of the memory chunks; test for applying transparent
* translation */
diff --git a/arch/m68k/vmlinux.lds b/arch/m68k/vmlinux.lds
new file mode 100644
index 000000000..cc5b1e20e
--- /dev/null
+++ b/arch/m68k/vmlinux.lds
@@ -0,0 +1,60 @@
+/* ld script to make m68k Linux kernel */
+OUTPUT_FORMAT("elf32-m68k", "elf32-m68k", "elf32-m68k")
+OUTPUT_ARCH(m68k)
+ENTRY(_start)
+SECTIONS
+{
+ . = 0x1000;
+ _text = .; /* Text and read-only data */
+ .text : {
+ *(.text)
+ *(.fixup)
+ *(.text.lock) /* out-of-line lock text */
+ *(.gnu.warning)
+ } = 0x4e75
+ .rodata : { *(.rodata) }
+ .kstrtab : { *(.kstrtab) }
+
+ . = ALIGN(16); /* Exception table */
+ __start___ex_table = .;
+ __ex_table : { *(__ex_table) }
+ __stop___ex_table = .;
+
+ __start___ksymtab = .; /* Kernel symbol table */
+ __ksymtab : { *(__ksymtab) }
+ __stop___ksymtab = .;
+
+ _etext = .; /* End of text section */
+
+ .data : { /* Data */
+ *(.data)
+ CONSTRUCTORS
+ }
+
+ . = ALIGN(8192);
+ init_task : { *(init_task) } /* The initial task and kernel stack */
+
+ _edata = .; /* End of data section */
+
+ . = ALIGN(4096); /* Init code and data */
+ __init_begin = .;
+ .text.init : { *(.text.init) }
+ .data.init : { *(.data.init) }
+ . = ALIGN(4096);
+ __init_end = .;
+
+ __bss_start = .; /* BSS */
+ .bss : {
+ *(.bss)
+ }
+ _end = . ;
+
+ /* Stabs debugging sections. */
+ .stab 0 : { *(.stab) }
+ .stabstr 0 : { *(.stabstr) }
+ .stab.excl 0 : { *(.stab.excl) }
+ .stab.exclstr 0 : { *(.stab.exclstr) }
+ .stab.index 0 : { *(.stab.index) }
+ .stab.indexstr 0 : { *(.stab.indexstr) }
+ .comment 0 : { *(.comment) }
+}
diff --git a/arch/mips/Makefile b/arch/mips/Makefile
index 5ea699450..1aa371ae1 100644
--- a/arch/mips/Makefile
+++ b/arch/mips/Makefile
@@ -156,9 +156,9 @@ endif
# The pipe options is bad for my low-mem machine
# Uncomment this if you want this.
#
-#CFLAGS += -pipe
+CFLAGS += -pipe
-HEAD := arch/mips/kernel/head.o
+HEAD := arch/mips/kernel/head.o arch/mips/kernel/init_task.o
SUBDIRS := $(SUBDIRS) $(addprefix arch/mips/, kernel mm lib tools)
CORE_FILES := arch/mips/kernel/kernel.o arch/mips/mm/mm.o $(CORE_FILES)
diff --git a/arch/mips/boot/Makefile b/arch/mips/boot/Makefile
index fd445c865..dd834efd9 100644
--- a/arch/mips/boot/Makefile
+++ b/arch/mips/boot/Makefile
@@ -34,7 +34,11 @@ mkboot: mkboot.c
$(HOSTCC) -o $@ $^
zdisk: zImage
- mcopy -o zImage a:vmlinux
+ if [ -f /etc/remote-mcopy ]; then \
+ ssh rio mcopy -o - a:vmlinux <zImage; \
+ else \
+ mcopy -o zImage a:vmlinux; \
+ fi
dep:
$(CPP) -M *.[cS] > .depend
diff --git a/arch/mips/boot/mkboot.c b/arch/mips/boot/mkboot.c
index 48f27113e..35612d248 100644
--- a/arch/mips/boot/mkboot.c
+++ b/arch/mips/boot/mkboot.c
@@ -355,7 +355,7 @@ main(argc, argv)
char *infile, *outfile;
struct stat ifstat;
off_t ifsize;
- void *image;
+ char *image;
int ifd, ofd, i, symtabix, strtabix;
Elf32_Ehdr eh;
Elf32_Phdr *ph;
@@ -421,7 +421,7 @@ main(argc, argv)
* we're reading might have different type sizes, byteorder
* or alignment than the host.
*/
- memcpy(eh.e_ident, image, sizeof(eh.e_ident));
+ memcpy(eh.e_ident, (void *)image, sizeof(eh.e_ident));
if(memcmp(eh.e_ident, ELFMAG, SELFMAG)) {
fprintf(stderr, "Input file isn't a ELF file\n");
exit(1);
@@ -476,7 +476,7 @@ main(argc, argv)
exit(1);
}
for(i = 0;i < eh.e_phnum; i++)
- get_elfph(image + eh.e_phoff + i * 32, ph + i);
+ get_elfph((void *)(image + eh.e_phoff + i * 32), ph + i);
/*
* ... and then the section headers.
@@ -487,7 +487,7 @@ main(argc, argv)
exit(1);
}
for(i = 0;i < eh.e_shnum; i++)
- get_elfsh(image + eh.e_shoff + (i * 40), sh + i);
+ get_elfsh((void *)(image + eh.e_shoff + (i * 40)), sh + i);
/*
* Find the symboltable and the stringtable in the file.
diff --git a/arch/mips/config.in b/arch/mips/config.in
index a0e655ea1..14e9dec3f 100644
--- a/arch/mips/config.in
+++ b/arch/mips/config.in
@@ -178,23 +178,27 @@ fi
source fs/Config.in
if [ "$CONFIG_SGI" != "y" ]; then
- source drivers/char/Config.in
+ source drivers/char/Config.in
- mainmenu_option next_comment
- comment 'Sound'
+ mainmenu_option next_comment
+ comment 'Sound'
- tristate 'Sound card support' CONFIG_SOUND
- if [ "$CONFIG_SOUND" != "n" ]; then
- source drivers/sound/Config.in
- fi
- endmenu
+ tristate 'Sound card support' CONFIG_SOUND
+ if [ "$CONFIG_SOUND" != "n" ]; then
+ source drivers/sound/Config.in
+ fi
+ endmenu
else
- comment 'SGI Character Devices'
- tristate 'PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE
- bool 'SGI Zilog85C30 serial support' CONFIG_SGI_SERIAL
- if [ "$CONFIG_SGI_SERIAL" != "n" ]; then
- define_bool CONFIG_SERIAL y
- fi
+ comment 'SGI Character Devices'
+ bool 'Virtual terminal' CONFIG_VT
+ if [ "$CONFIG_VT" = "y" ]; then
+ bool 'Console on virtual terminal' CONFIG_VT_CONSOLE
+ fi
+ tristate 'PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE
+ bool 'SGI Zilog85C30 serial support' CONFIG_SGI_SERIAL
+ if [ "$CONFIG_SGI_SERIAL" != "n" ]; then
+ define_bool CONFIG_SERIAL y
+ fi
fi
mainmenu_option next_comment
diff --git a/arch/mips/defconfig b/arch/mips/defconfig
index dc28a8cd8..33f54a301 100644
--- a/arch/mips/defconfig
+++ b/arch/mips/defconfig
@@ -22,6 +22,7 @@ CONFIG_PCI=y
#
# CONFIG_CPU_R3000 is not set
# CONFIG_CPU_R6000 is not set
+# CONFIG_CPU_R4300 is not set
CONFIG_CPU_R4X00=y
# CONFIG_CPU_R5000 is not set
# CONFIG_CPU_R8000 is not set
diff --git a/arch/mips/deskstation/io.c b/arch/mips/deskstation/io.c
new file mode 100644
index 000000000..cd33e2eb6
--- /dev/null
+++ b/arch/mips/deskstation/io.c
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ *
+ * Low level I/O functions for Jazz family machine.
+ *
+ * FIXME: This implementation fits the Tyne. How does the EISA rPC44 handle
+ * the eight high address bits?
+ */
+#include <linux/string.h>
+#include <asm/mipsconfig.h>
+#include <asm/addrspace.h>
+#include <asm/sni.h>
+
+/*
+ * isa_slot_offset is the address where E(ISA) busaddress 0 is is mapped
+ * for the processor.
+ */
+extern unsigned long isa_slot_offset;
+
+static unsigned char deskstation_readb(unsigned long addr)
+{
+ return *(volatile unsigned char *) (isa_slot_offset + addr);
+}
+
+static unsigned short deskstation_readw(unsigned long addr)
+{
+ return *(volatile unsigned short *) (isa_slot_offset + addr);
+}
+
+static unsigned int deskstation_readl(unsigned long addr)
+{
+ return *(volatile unsigned int *) (isa_slot_offset + addr);
+}
+
+static void deskstation_writeb(unsigned char val, unsigned long addr)
+{
+ *(volatile unsigned char *) (isa_slot_offset + addr) = val;
+}
+
+static void deskstation_writew(unsigned short val, unsigned long addr)
+{
+ *(volatile unsigned char *) (isa_slot_offset + addr) = val;
+}
+
+static void deskstation_writel(unsigned int val, unsigned long addr)
+{
+ *(volatile unsigned char *) (isa_slot_offset + addr) = val;
+}
+
+static void deskstation_memset_io(unsigned long addr, int val, unsigned long len)
+{
+ addr += isa_slot_offset;
+ memset((void *)addr, val, len);
+}
+
+static void deskstation_memcpy_fromio(unsigned long to, unsigned long from, unsigned long len)
+{
+ from += isa_slot_offset;
+ memcpy((void *)to, (void *)from, len);
+}
+
+static void deskstation_memcpy_toio(unsigned long to, unsigned long from, unsigned long len)
+{
+ to += isa_slot_offset;
+ memcpy((void *)to, (void *)from, len);
+}
diff --git a/arch/mips/deskstation/setup.c b/arch/mips/deskstation/setup.c
index c2451e855..8b70a656c 100644
--- a/arch/mips/deskstation/setup.c
+++ b/arch/mips/deskstation/setup.c
@@ -5,10 +5,10 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 1996 by Ralf Baechle
+ * Copyright (C) 1996, 1997 by Ralf Baechle
*/
-#include <asm/ptrace.h>
#include <linux/config.h>
+#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
@@ -16,6 +16,7 @@
#include <asm/bootinfo.h>
#include <asm/io.h>
#include <asm/irq.h>
+#include <asm/ptrace.h>
#include <asm/mipsregs.h>
#include <asm/reboot.h>
#include <asm/vector.h>
@@ -43,8 +44,7 @@ extern void deskstation_machine_power_off(void);
unsigned long mips_dma_cache_size = 0;
unsigned long mips_dma_cache_base = KSEG0;
-static void
-tyne_irq_setup(void)
+__initfunc(static void tyne_irq_setup(void))
{
set_except_vector(0, deskstation_handle_int);
/* set the clock to 100 Hz */
@@ -58,8 +58,7 @@ tyne_irq_setup(void)
#endif
#ifdef CONFIG_DESKSTATION_RPC44
-static void
-rpc44_irq_setup(void)
+__initfunc(static void rpc44_irq_setup(void))
{
/*
* For the moment just steal the TYNE support. In the
@@ -77,8 +76,7 @@ rpc44_irq_setup(void)
}
#endif
-void
-deskstation_setup(void)
+__initfunc(void deskstation_setup(void))
{
switch(mips_machtype) {
#ifdef CONFIG_DESKSTATION_TYNE
diff --git a/arch/mips/jazz/.cvsignore b/arch/mips/jazz/.cvsignore
new file mode 100644
index 000000000..4671378ae
--- /dev/null
+++ b/arch/mips/jazz/.cvsignore
@@ -0,0 +1 @@
+.depend
diff --git a/arch/mips/jazz/io.c b/arch/mips/jazz/io.c
new file mode 100644
index 000000000..a151b99fe
--- /dev/null
+++ b/arch/mips/jazz/io.c
@@ -0,0 +1,136 @@
+/*
+ * 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.
+ *
+ * Low level I/O functions for Jazz family machines.
+ *
+ * Copyright (C) 1997 by Ralf Baechle.
+ */
+#include <linux/string.h>
+#include <asm/mipsconfig.h>
+#include <asm/addrspace.h>
+#include <asm/system.h>
+#include <asm/spinlock.h>
+#include <asm/jazz.h>
+
+/*
+ * Map an 16mb segment of the EISA address space to 0xe3000000;
+ */
+static inline void map_eisa_address(unsigned long address)
+{
+ /* XXX */
+ /* We've got an wired entry in the TLB. We just need to modify it.
+ fast and clean. But since we want to get rid of wired entries
+ things are a little bit more complicated ... */
+}
+
+static unsigned char jazz_readb(unsigned long addr)
+{
+ unsigned char res;
+
+ map_eisa_address(addr);
+ addr &= 0xffffff;
+ res = *(volatile unsigned char *) (JAZZ_EISA_BASE + addr);
+
+ return res;
+}
+
+static unsigned short jazz_readw(unsigned long addr)
+{
+ unsigned short res;
+
+ map_eisa_address(addr);
+ addr &= 0xffffff;
+ res = *(volatile unsigned char *) (JAZZ_EISA_BASE + addr);
+
+ return res;
+}
+
+static unsigned int jazz_readl(unsigned long addr)
+{
+ unsigned int res;
+
+ map_eisa_address(addr);
+ addr &= 0xffffff;
+ res = *(volatile unsigned char *) (JAZZ_EISA_BASE + addr);
+
+ return res;
+}
+
+static void jazz_writeb(unsigned char val, unsigned long addr)
+{
+ map_eisa_address(addr);
+ addr &= 0xffffff;
+ *(volatile unsigned char *) (JAZZ_EISA_BASE + addr) = val;
+}
+
+static void jazz_writew(unsigned short val, unsigned long addr)
+{
+ map_eisa_address(addr);
+ addr &= 0xffffff;
+ *(volatile unsigned char *) (JAZZ_EISA_BASE + addr) = val;
+}
+
+static void jazz_writel(unsigned int val, unsigned long addr)
+{
+ map_eisa_address(addr);
+ addr &= 0xffffff;
+ *(volatile unsigned char *) (JAZZ_EISA_BASE + addr) = val;
+}
+
+static void jazz_memset_io(unsigned long addr, int val, unsigned long len)
+{
+ unsigned long waddr;
+
+ waddr = JAZZ_EISA_BASE | (addr & 0xffffff);
+ while(len) {
+ unsigned long fraglen;
+
+ fraglen = (~addr + 1) & 0xffffff;
+ fraglen = (fraglen < len) ? fraglen : len;
+ map_eisa_address(addr);
+ memset((char *)waddr, val, fraglen);
+ addr += fraglen;
+ waddr = waddr + fraglen - 0x1000000;
+ len -= fraglen;
+ }
+}
+
+static void jazz_memcpy_fromio(unsigned long to, unsigned long from, unsigned long len)
+{
+ unsigned long waddr;
+
+ waddr = JAZZ_EISA_BASE | (from & 0xffffff);
+ while(len) {
+ unsigned long fraglen;
+
+ fraglen = (~from + 1) & 0xffffff;
+ fraglen = (fraglen < len) ? fraglen : len;
+ map_eisa_address(from);
+ memcpy((void *)to, (void *)waddr, fraglen);
+ to += fraglen;
+ from += fraglen;
+ waddr = waddr + fraglen - 0x1000000;
+ len -= fraglen;
+ }
+}
+
+static void jazz_memcpy_toio(unsigned long to, unsigned long from, unsigned long len)
+{
+ unsigned long waddr;
+
+ waddr = JAZZ_EISA_BASE | (to & 0xffffff);
+ while(len) {
+ unsigned long fraglen;
+
+ fraglen = (~to + 1) & 0xffffff;
+ fraglen = (fraglen < len) ? fraglen : len;
+ map_eisa_address(to);
+ memcpy((char *)to + JAZZ_EISA_BASE, (void *)from, fraglen);
+ to += fraglen;
+ from += fraglen;
+ waddr = waddr + fraglen - 0x1000000;
+ len -= fraglen;
+ }
+}
diff --git a/arch/mips/jazz/setup.c b/arch/mips/jazz/setup.c
index 1b137cf85..805efa821 100644
--- a/arch/mips/jazz/setup.c
+++ b/arch/mips/jazz/setup.c
@@ -5,14 +5,15 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 1996 by Ralf Baechle
+ * Copyright (C) 1996, 1997 by Ralf Baechle
*/
-#include <asm/ptrace.h>
+#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <asm/irq.h>
#include <asm/jazz.h>
+#include <asm/ptrace.h>
#include <asm/reboot.h>
#include <asm/vector.h>
#include <asm/io.h>
@@ -35,8 +36,7 @@ extern void jazz_machine_restart(char *command);
extern void jazz_machine_halt(void);
extern void jazz_machine_power_off(void);
-static void
-jazz_irq_setup(void)
+__initfunc(static void jazz_irq_setup(void))
{
set_except_vector(0, jazz_handle_int);
r4030_write_reg16(JAZZ_IO_IRQ_ENABLE,
@@ -55,8 +55,7 @@ jazz_irq_setup(void)
setup_x86_irq(2, &irq2);
}
-void
-jazz_setup(void)
+__initfunc(void jazz_setup(void))
{
irq_setup = jazz_irq_setup;
fd_cacheflush = jazz_fd_cacheflush;
diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile
index b251d6e1a..21dd3610b 100644
--- a/arch/mips/kernel/Makefile
+++ b/arch/mips/kernel/Makefile
@@ -9,7 +9,7 @@
.S.o:
$(CC) $(CFLAGS) -c $< -o $*.o
-all: kernel.o head.o
+all: kernel.o head.o init_task.o
EXTRA_ASFLAGS = -mips3 -mcpu=r4000
O_TARGET := kernel.o
O_OBJS := branch.o process.o signal.o entry.o traps.o ptrace.o vm86.o \
diff --git a/arch/mips/kernel/entry.S b/arch/mips/kernel/entry.S
index 8bb8fb41c..682e00cda 100644
--- a/arch/mips/kernel/entry.S
+++ b/arch/mips/kernel/entry.S
@@ -14,9 +14,11 @@
* and faults that can result in a task-switch. The ISA dependent TLB
* code is in arch/mips/<ISA-level>/<cputype>.S
*/
+#include <linux/config.h>
#include <linux/sys.h>
#include <asm/asm.h>
+#include <asm/current.h>
#include <asm/errno.h>
#include <asm/mipsregs.h>
#include <asm/mipsconfig.h>
@@ -53,7 +55,6 @@ reschedule:
nop
EXPORT(ret_from_sys_call)
-
lw t0,bh_mask
lw t1,bh_active # unused delay slot
and t0,t1
@@ -64,7 +65,7 @@ EXPORT(ret_from_sys_call)
beqz t1,return # -> yes
lw t1,need_resched
bnez t1,reschedule
- lw s0,current_set
+ GET_CURRENT(s0)
lw t0,task
lw a0,TASK_BLOCKED(s0)
diff --git a/arch/mips/kernel/head.S b/arch/mips/kernel/head.S
index a957e16bd..4c3e5bd52 100644
--- a/arch/mips/kernel/head.S
+++ b/arch/mips/kernel/head.S
@@ -22,6 +22,15 @@
#include <asm/bootinfo.h>
#include <asm/cpu.h>
+/*
+ * Get current task pointer
+ */
+#define GET_CURRENT(reg) \
+ lui reg, %hi(kernelsp); \
+ lw reg, %lo(kernelsp)(reg); \
+ ori reg, 8191; \
+ xori reg, 8191
+
.text
/*
* Reserved space for exception handlers.
@@ -43,8 +52,7 @@
LEAF(except_vec0_r4000)
.set mips3
mfc0 k0, CP0_BADVADDR # Get faulting address
- lui k1, %hi(current_set)
- lw k1, %lo(current_set)(k1) # get current task ptr
+ GET_CURRENT(k1) # get current task ptr
srl k0, k0, 22 # get pgd only bits
lw k1, THREAD_PGDIR(k1) # get task pg_dir
sll k0, k0, 2
@@ -71,8 +79,7 @@
LEAF(except_vec0_r4600)
.set mips3
mfc0 k0, CP0_BADVADDR
- lui k1, %hi(current_set)
- lw k1, %lo(current_set)(k1)
+ GET_CURRENT(k1) # get current task ptr
srl k0, k0, 22
lw k1, THREAD_PGDIR(k1)
sll k0, k0, 2
@@ -98,8 +105,7 @@
LEAF(except_vec0_r45k_bvahwbug)
.set mips3
mfc0 k0, CP0_BADVADDR
- lui k1, %hi(current_set)
- lw k1, %lo(current_set)(k1)
+ GET_CURRENT(k1) # get current task ptr
srl k0, k0, 22
lw k1, THREAD_PGDIR(k1)
sll k0, k0, 2
@@ -129,8 +135,7 @@
LEAF(except_vec0_r4k_mphwbug)
.set mips3
mfc0 k0, CP0_BADVADDR
- lui k1, %hi(current_set)
- lw k1, %lo(current_set)(k1)
+ GET_CURRENT(k1) # get current task ptr
srl k0, k0, 22
lw k1, THREAD_PGDIR(k1)
sll k0, k0, 2
@@ -160,8 +165,7 @@
LEAF(except_vec0_r4k_250MHZhwbug)
.set mips3
mfc0 k0, CP0_BADVADDR
- lui k1, %hi(current_set)
- lw k1, %lo(current_set)(k1)
+ GET_CURRENT(k1) # get current task ptr
srl k0, k0, 22
lw k1, THREAD_PGDIR(k1)
sll k0, k0, 2
@@ -191,8 +195,7 @@
LEAF(except_vec0_r4k_MP250MHZhwbug)
.set mips3
mfc0 k0, CP0_BADVADDR
- lui k1, %hi(current_set)
- lw k1, %lo(current_set)(k1)
+ GET_CURRENT(k1) # get current task ptr
srl k0, k0, 22
lw k1, THREAD_PGDIR(k1)
sll k0, k0, 2
@@ -224,8 +227,7 @@
LEAF(except_vec0_r2300)
.set mips1
mfc0 k0, CP0_BADVADDR
- lui k1, %hi(current_set)
- lw k1, %lo(current_set)(k1)
+ GET_CURRENT(k1) # get current task ptr
srl k0, k0, 22
lw k1, THREAD_PGDIR(k1)
sll k0, k0, 2
@@ -403,9 +405,11 @@ probe_done:
/*
* Stack for kernel and init
+ *
+ * Kernelsp will never be referenced for process 0.
*/
-9: la sp, init_user_stack+(KERNEL_STACK_SIZE-4*SZREG)
- la t0, init_kernel_stack+(KERNEL_STACK_SIZE)
+9: la sp, init_task_union+(KERNEL_STACK_SIZE-4*SZREG)
+ la t0, init_task_union+(KERNEL_STACK_SIZE)
sw t0, kernelsp
/* Disable coprocessors */
@@ -745,9 +749,13 @@ map0_sni_rm200_pci:
.org 0x6000
+ /*
+ * init_task_union follows here in the .text segment.
+ * Keep this aligned to a 8kb boundary!
+ */
+ .data
EXPORT(cache_error_buffer)
.fill 32*4,1,0
- .data
EXPORT(kernelsp)
PTR 0
diff --git a/arch/mips/kernel/init_task.c b/arch/mips/kernel/init_task.c
new file mode 100644
index 000000000..cc0a19231
--- /dev/null
+++ b/arch/mips/kernel/init_task.c
@@ -0,0 +1,22 @@
+#include <linux/mm.h>
+#include <linux/sched.h>
+
+#include <asm/pgtable.h>
+
+static struct vm_area_struct init_mmap = INIT_MMAP;
+static struct fs_struct init_fs = INIT_FS;
+static struct files_struct init_files = INIT_FILES;
+static struct signal_struct init_signals = INIT_SIGNALS;
+struct mm_struct init_mm = INIT_MM;
+
+/*
+ * Initial task structure.
+ *
+ * We need to make sure that this is 8192-byte aligned due to the
+ * way process stacks are handled. This is done by making sure
+ * the linker maps this in the .text segment right after head.S,
+ * and making head.S ensure the proper alignment.
+ *
+ * The things we do for performance..
+ */
+union task_union init_task_union __attribute__((__section__(".text"))) = { INIT_TASK };
diff --git a/arch/mips/kernel/irix5sys.h b/arch/mips/kernel/irix5sys.h
index a20e619e3..be57dc1f5 100644
--- a/arch/mips/kernel/irix5sys.h
+++ b/arch/mips/kernel/irix5sys.h
@@ -105,7 +105,7 @@ SYS(irix_sgikopt, 3) /* 1083 sys_sgikopt() DC*/
SYS(sys_sysfs, 3) /* 1084 sysfs() ?V*/
SYS(irix_unimp, 0) /* 1085 XXX sys_getmsg() DC*/
SYS(irix_unimp, 0) /* 1086 XXX sys_putmsg() DC*/
-SYS(irix_poll, 3) /* 1087 sys_poll() V*/
+SYS(sys_poll, 3) /* 1087 poll() V*/
SYS(irix_sigreturn, 0) /* 1088 sigreturn() ?V*/
SYS(sys_accept, 3) /* 1089 accept() V*/
SYS(sys_bind, 3) /* 1090 bind() V*/
diff --git a/arch/mips/kernel/irixelf.c b/arch/mips/kernel/irixelf.c
index 46345b308..d994155d0 100644
--- a/arch/mips/kernel/irixelf.c
+++ b/arch/mips/kernel/irixelf.c
@@ -1,4 +1,4 @@
-/* $Id: irixelf.c,v 1.8 1996/08/24 03:52:25 dm Exp $
+/*
* irixelf.c: Code to load IRIX ELF executables which conform to
* the MIPS ABI.
*
@@ -17,6 +17,7 @@
#include <linux/mman.h>
#include <linux/a.out.h>
#include <linux/errno.h>
+#include <linux/init.h>
#include <linux/signal.h>
#include <linux/binfmts.h>
#include <linux/string.h>
@@ -720,16 +721,16 @@ static inline int do_load_irix_binary(struct linux_binprm * bprm,
sys_close(elf_exec_fileno);
current->personality = PER_IRIX32;
- if (current->exec_domain && current->exec_domain->use_count)
- (*current->exec_domain->use_count)--;
- if (current->binfmt && current->binfmt->use_count)
- (*current->binfmt->use_count)--;
+ if (current->exec_domain && current->exec_domain->module)
+ __MOD_DEC_USE_COUNT(current->exec_domain->module);
+ if (current->binfmt && current->binfmt->module)
+ __MOD_DEC_USE_COUNT(current->binfmt->module);
current->exec_domain = lookup_exec_domain(current->personality);
current->binfmt = &irix_format;
- if (current->exec_domain && current->exec_domain->use_count)
- (*current->exec_domain->use_count)++;
- if (current->binfmt && current->binfmt->use_count)
- (*current->binfmt->use_count)++;
+ if (current->exec_domain && current->exec_domain->module)
+ __MOD_INC_USE_COUNT(current->exec_domain->module);
+ if (current->binfmt && current->binfmt->module)
+ __MOD_INC_USE_COUNT(current->binfmt->module);
current->suid = current->euid = current->fsuid = bprm->e_uid;
current->sgid = current->egid = current->fsgid = bprm->e_gid;
@@ -1180,20 +1181,20 @@ static int irix_core_dump(long signr, struct pt_regs * regs)
notes[0].datasz = sizeof(prstatus);
notes[0].data = &prstatus;
prstatus.pr_info.si_signo = prstatus.pr_cursig = signr;
- copy_sigbits32(&prstatus.pr_sigpend, current->signal);
- copy_sigbits32(&prstatus.pr_sighold, current->blocked);
+ prstatus.pr_sigpend = current->signal;
+ prstatus.pr_sighold = current->blocked;
psinfo.pr_pid = prstatus.pr_pid = current->pid;
psinfo.pr_ppid = prstatus.pr_ppid = current->p_pptr->pid;
psinfo.pr_pgrp = prstatus.pr_pgrp = current->pgrp;
psinfo.pr_sid = prstatus.pr_sid = current->session;
- prstatus.pr_utime.tv_sec = CT_TO_SECS(current->utime);
- prstatus.pr_utime.tv_usec = CT_TO_USECS(current->utime);
- prstatus.pr_stime.tv_sec = CT_TO_SECS(current->stime);
- prstatus.pr_stime.tv_usec = CT_TO_USECS(current->stime);
- prstatus.pr_cutime.tv_sec = CT_TO_SECS(current->cutime);
- prstatus.pr_cutime.tv_usec = CT_TO_USECS(current->cutime);
- prstatus.pr_cstime.tv_sec = CT_TO_SECS(current->cstime);
- prstatus.pr_cstime.tv_usec = CT_TO_USECS(current->cstime);
+ prstatus.pr_utime.tv_sec = CT_TO_SECS(current->times.tms_utime);
+ prstatus.pr_utime.tv_usec = CT_TO_USECS(current->times.tms_utime);
+ prstatus.pr_stime.tv_sec = CT_TO_SECS(current->times.tms_stime);
+ prstatus.pr_stime.tv_usec = CT_TO_USECS(current->times.tms_stime);
+ prstatus.pr_cutime.tv_sec = CT_TO_SECS(current->times.tms_cutime);
+ prstatus.pr_cutime.tv_usec = CT_TO_USECS(current->times.tms_cutime);
+ prstatus.pr_cstime.tv_sec = CT_TO_SECS(current->times.tms_cstime);
+ prstatus.pr_cstime.tv_usec = CT_TO_USECS(current->times.tms_cstime);
if (sizeof(elf_gregset_t) != sizeof(struct pt_regs)) {
printk("sizeof(elf_gregset_t) (%d) != sizeof(struct pt_regs) "
"(%d)\n", sizeof(elf_gregset_t), sizeof(struct pt_regs));
@@ -1339,13 +1340,15 @@ static int irix_core_dump(long signr, struct pt_regs * regs)
return has_dumped;
}
-int init_irix_binfmt(void) {
+__initfunc(int init_irix_binfmt(void))
+{
return register_binfmt(&irix_format);
}
#ifdef MODULE
-int init_module(void) {
+int init_module(void)
+{
/* Install the COFF, ELF and XOUT loaders.
* N.B. We *rely* on the table being the right size with the
* right number of free slots...
@@ -1354,7 +1357,8 @@ int init_module(void) {
}
-void cleanup_module( void) {
+void cleanup_module( void)
+{
/* Remove the IRIX ELF loaders. */
unregister_binfmt(&irix_format);
}
diff --git a/arch/mips/kernel/irixioctl.c b/arch/mips/kernel/irixioctl.c
index 3405904fa..e0230f9f0 100644
--- a/arch/mips/kernel/irixioctl.c
+++ b/arch/mips/kernel/irixioctl.c
@@ -8,6 +8,8 @@
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
#include <linux/tty.h>
#include <asm/uaccess.h>
diff --git a/arch/mips/kernel/irixsig.c b/arch/mips/kernel/irixsig.c
index 6a5636c76..b2d7cbe49 100644
--- a/arch/mips/kernel/irixsig.c
+++ b/arch/mips/kernel/irixsig.c
@@ -8,6 +8,8 @@
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/errno.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
#include <linux/time.h>
#include <asm/ptrace.h>
@@ -162,7 +164,10 @@ asmlinkage int do_irix_signal(unsigned long oldmask, struct pt_regs * regs)
case SIGCONT: case SIGCHLD: case SIGWINCH:
continue;
- case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU:
+ case SIGTSTP: case SIGTTIN: case SIGTTOU:
+ if (is_orphaned_pgrp(current->pgrp))
+ continue;
+ case SIGSTOP:
if (current->flags & PF_PTRACED)
continue;
current->state = TASK_STOPPED;
@@ -175,15 +180,19 @@ asmlinkage int do_irix_signal(unsigned long oldmask, struct pt_regs * regs)
case SIGQUIT: case SIGILL: case SIGTRAP:
case SIGIOT: case SIGFPE: case SIGSEGV: case SIGBUS:
+ lock_kernel();
if (current->binfmt && current->binfmt->core_dump) {
if (current->binfmt->core_dump(signr, regs))
signr |= 0x80;
}
+ unlock_kernel();
/* fall through */
default:
current->signal |= _S(signr & 0x7f);
current->flags |= PF_SIGNALED;
+ lock_kernel(); /* 8-( */
do_exit(signr);
+ unlock_kernel();
}
}
/*
@@ -314,7 +323,7 @@ static inline void check_pending(int signum)
spin_lock(&current->sigmask_lock);
if (p->sa_handler == SIG_IGN) {
current->signal &= ~_S(signum);
- } else if if (p->sa_handler == SIG_DFL) {
+ } else if (p->sa_handler == SIG_DFL) {
if (signum != SIGCONT && signum != SIGCHLD && signum != SIGWINCH)
return;
current->signal &= ~_S(signum);
@@ -347,11 +356,9 @@ asmlinkage int irix_sigaction(int sig, struct sigact_irix5 *new,
if(sig == SIGKILL || sig == SIGSTOP) {
return -EINVAL;
}
- new_sa.sa_flags = new->flags;
- new_sa.sa_handler = (__sighandler_t) new->handler;
- new_sa.sa_mask.__sigbits[1] = new_sa.sa_mask.__sigbits[2] =
- new_sa.sa_mask.__sigbits[3] = 0;
- new_sa.sa_mask.__sigbits[0] = new->sigset[0];
+ __get_user(new_sa.sa_flags, &new->flags);
+ __get_user(new_sa.sa_handler, &(__sighandler_t) new->handler);
+ __get_user(new_sa.sa_mask, &new->sigset[0]);
if(new_sa.sa_handler != SIG_DFL && new_sa.sa_handler != SIG_IGN) {
res = verify_area(VERIFY_READ, new_sa.sa_handler, 1);
@@ -368,19 +375,22 @@ asmlinkage int irix_sigaction(int sig, struct sigact_irix5 *new,
int res = verify_area(VERIFY_WRITE, old, sizeof(*old));
if(res)
return res;
- old->flags = p->sa_flags;
- old->handler = (void *) p->sa_handler;
- old->sigset[1] = old->sigset[2] = old->sigset[3] = 0;
- old->sigset[0] = p->sa_mask.__sigbits[0];
- old->_unused0[0] = old->_unused0[1] = 0;
+ __put_user(p->sa_flags, &old->flags);
+ __put_user(p->sa_handler, &old->handler);
+ __put_user(p->sa_mask, &old->sigset[0]);
+ __put_user(0, &old->sigset[1]);
+ __put_user(0, &old->sigset[2]);
+ __put_user(0, &old->sigset[3]);
+ __put_user(0, &old->_unused0[0]);
+ __put_user(0, &old->_unused0[1]);
}
-
if(new) {
spin_lock_irq(&current->sig->siglock);
*p = new_sa;
check_pending(sig);
spin_unlock_irq(&current->sig->siglock);
}
+
return 0;
}
@@ -640,14 +650,14 @@ repeat:
__put_user(p->pid, &info->stuff.procinfo.pid);
__put_user((p->exit_code >> 8) & 0xff,
&info->stuff.procinfo.procdata.child.status);
- __put_user(p->utime, &info->stuff.procinfo.procdata.child.utime);
- __put_user(p->stime, &info->stuff.procinfo.procdata.child.stime);
+ __put_user(p->times.tms_utime, &info->stuff.procinfo.procdata.child.utime);
+ __put_user(p->times.tms_stime, &info->stuff.procinfo.procdata.child.stime);
p->exit_code = 0;
retval = 0;
goto end_waitsys;
case TASK_ZOMBIE:
- current->cutime += p->utime + p->cutime;
- current->cstime += p->stime + p->cstime;
+ current->times.tms_cutime += p->times.tms_utime + p->times.tms_cutime;
+ current->times.tms_cstime += p->times.tms_stime + p->times.tms_cstime;
if (ru != NULL)
getrusage(p, RUSAGE_BOTH, ru);
__put_user(SIGCHLD, &info->sig);
@@ -655,9 +665,9 @@ repeat:
__put_user(p->pid, &info->stuff.procinfo.pid);
__put_user((p->exit_code >> 8) & 0xff,
&info->stuff.procinfo.procdata.child.status);
- __put_user(p->utime,
+ __put_user(p->times.tms_utime,
&info->stuff.procinfo.procdata.child.utime);
- __put_user(p->stime,
+ __put_user(p->times.tms_stime,
&info->stuff.procinfo.procdata.child.stime);
retval = 0;
if (p->p_opptr != p->p_pptr) {
@@ -855,6 +865,8 @@ asmlinkage int irix_sigaltstack(struct irix_sigaltstack *new,
out:
error = 0;
unlock_kernel();
+
+ return error;
}
struct irix_procset {
diff --git a/arch/mips/kernel/irq.c b/arch/mips/kernel/irq.c
index a78bc3417..0896ed1c7 100644
--- a/arch/mips/kernel/irq.c
+++ b/arch/mips/kernel/irq.c
@@ -13,6 +13,7 @@
*/
#include <linux/config.h>
#include <linux/errno.h>
+#include <linux/init.h>
#include <linux/kernel_stat.h>
#include <linux/signal.h>
#include <linux/sched.h>
@@ -154,11 +155,6 @@ asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
irq_enter(cpu, irq);
kstat.interrupts[irq]++;
-#ifdef CONFIG_SGI
- prom_printf("Got irq %d, press a key.", irq);
- prom_getchar();
- romvec->imode();
-#endif
/* slow interrupts run with interrupts enabled */
sti();
action = *(irq + irq_action);
@@ -344,7 +340,7 @@ int probe_irq_off (unsigned long irqs)
return i;
}
-void init_IRQ(void)
+__initfunc(void init_IRQ(void))
{
int i;
diff --git a/arch/mips/kernel/pci.c b/arch/mips/kernel/pci.c
index e521ecdd9..5e71233af 100644
--- a/arch/mips/kernel/pci.c
+++ b/arch/mips/kernel/pci.c
@@ -7,6 +7,7 @@
*/
#include <linux/bios32.h>
#include <linux/config.h>
+#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/types.h>
@@ -17,7 +18,8 @@
/*
* BIOS32 replacement.
*/
-unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end)
+__initfunc(unsigned long pcibios_init(unsigned long memory_start,
+ unsigned long memory_end))
{
return memory_start;
}
@@ -112,7 +114,8 @@ const char *pcibios_strerror (int error)
* specific implementation.
*/
unsigned long (*_pcibios_init)(unsigned long memory_start, unsigned long memory_end);
-unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end)
+__initfunc(unsigned long pcibios_init(unsigned long memory_start,
+ unsigned long memory_end))
{
return _pcibios_init ? _pcibios_init(memory_start, memory_end)
: memory_start;
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index f8b10bdea..08dd13c6c 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -64,16 +64,23 @@ void release_thread(struct task_struct *dead_task)
{
}
+#define roundup(val, rnd) ({ \
+ unsigned _v = val; \
+ unsigned long _r = rnd; \
+ _v = (_v + _r - 1) & ~(_r - 1); \
+ _v; \
+})
+
int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
struct task_struct * p, struct pt_regs * regs)
{
struct pt_regs * childregs;
long childksp;
- childksp = p->kernel_stack_page + KERNEL_STACK_SIZE - 8;
+ childksp = roundup((unsigned long)p, KERNEL_STACK_SIZE) - 8;
/* set up new TSS. */
- childregs = ((struct pt_regs *) (p->kernel_stack_page + PAGE_SIZE)) - 1;
+ childregs = ((struct pt_regs *) ((unsigned long)p + KERNEL_STACK_SIZE)) - 1;
*childregs = *regs;
childregs->regs[7] = 0; /* Clear error flag */
if(current->personality == PER_LINUX) {
diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c
index 41deb8f18..e61911549 100644
--- a/arch/mips/kernel/ptrace.c
+++ b/arch/mips/kernel/ptrace.c
@@ -18,18 +18,6 @@
#include <asm/page.h>
#include <asm/system.h>
-/* change a pid into a task struct. */
-static inline struct task_struct * get_task(int pid)
-{
- int i;
-
- for (i = 1; i < NR_TASKS; i++) {
- if (task[i] != NULL && (task[i]->pid == pid))
- return task[i];
- }
- return NULL;
-}
-
/*
* This routine gets a long from any process space by following the page
* tables. NOTE! You should check that the long isn't on a page boundary,
@@ -47,7 +35,7 @@ static unsigned long get_long(struct task_struct * tsk,
repeat:
pgdir = pgd_offset(vma->vm_mm, addr);
if (pgd_none(*pgdir)) {
- do_no_page(tsk, vma, addr, 0);
+ handle_mm_fault(tsk, vma, addr, 0);
goto repeat;
}
if (pgd_bad(*pgdir)) {
@@ -57,7 +45,7 @@ repeat:
}
pgmiddle = pmd_offset(pgdir, addr);
if (pmd_none(*pgmiddle)) {
- do_no_page(tsk, vma, addr, 0);
+ handle_mm_fault(tsk, vma, addr, 0);
goto repeat;
}
if (pmd_bad(*pgmiddle)) {
@@ -67,7 +55,7 @@ repeat:
}
pgtable = pte_offset(pgmiddle, addr);
if (!pte_present(*pgtable)) {
- do_no_page(tsk, vma, addr, 0);
+ handle_mm_fault(tsk, vma, addr, 0);
goto repeat;
}
page = pte_page(*pgtable);
@@ -101,7 +89,7 @@ static void put_long(struct task_struct *tsk,
repeat:
pgdir = pgd_offset(vma->vm_mm, addr);
if (!pgd_present(*pgdir)) {
- do_no_page(tsk, vma, addr, 1);
+ handle_mm_fault(tsk, vma, addr, 1);
goto repeat;
}
if (pgd_bad(*pgdir)) {
@@ -111,7 +99,7 @@ repeat:
}
pgmiddle = pmd_offset(pgdir, addr);
if (pmd_none(*pgmiddle)) {
- do_no_page(tsk, vma, addr, 1);
+ handle_mm_fault(tsk, vma, addr, 1);
goto repeat;
}
if (pmd_bad(*pgmiddle)) {
@@ -121,12 +109,12 @@ repeat:
}
pgtable = pte_offset(pgmiddle, addr);
if (!pte_present(*pgtable)) {
- do_no_page(tsk, vma, addr, 1);
+ handle_mm_fault(tsk, vma, addr, 1);
goto repeat;
}
page = pte_page(*pgtable);
if (!pte_write(*pgtable)) {
- do_wp_page(tsk, vma, addr, 1);
+ handle_mm_fault(tsk, vma, addr, 1);
goto repeat;
}
/* this is a hack for non-kernel-mapped video buffers and similar */
@@ -280,7 +268,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
res = -EPERM;
goto out;
}
- if (!(child = get_task(pid))) {
+ if (!(child = find_task_by_pid(pid))) {
res = -ESRCH;
goto out;
}
diff --git a/arch/mips/kernel/r2300_switch.S b/arch/mips/kernel/r2300_switch.S
index 83190514b..901871a31 100644
--- a/arch/mips/kernel/r2300_switch.S
+++ b/arch/mips/kernel/r2300_switch.S
@@ -9,6 +9,7 @@
#include <asm/asm.h>
#include <asm/bootinfo.h>
#include <asm/cachectl.h>
+#include <asm/current.h>
#include <asm/fpregdef.h>
#include <asm/mipsconfig.h>
#include <asm/mipsregs.h>
@@ -31,8 +32,7 @@ MODE_ALIAS = 0x00e0 # uncachable, dirty, valid
*/
.align 5
LEAF(r2300_resume)
- lui t5, %hi(current_set)
- lw t0, %lo(current_set)(t5)
+ GET_CURRENT(t0)
mfc0 t1,CP0_STATUS # Save status register
addu t0,a1 # Add tss offset
sw t1,THREAD_STATUS(t0)
@@ -50,7 +50,6 @@ MODE_ALIAS = 0x00e0 # uncachable, dirty, valid
1:
FPU_SAVE_16EVEN(t0, t1)
2:
- sw a0,%lo(current_set)(t5) # Switch current task
addu a0,a1 # Add tss offset
lw t0,THREAD_PGDIR(a0) # Switch the root pointer
li t1,TLB_ROOT # get PFN
diff --git a/arch/mips/kernel/r4k_misc.S b/arch/mips/kernel/r4k_misc.S
index 432c65215..5c9ad4d84 100644
--- a/arch/mips/kernel/r4k_misc.S
+++ b/arch/mips/kernel/r4k_misc.S
@@ -10,6 +10,7 @@
#include <asm/offset.h>
#include <asm/bootinfo.h>
#include <asm/cachectl.h>
+#include <asm/current.h>
#include <asm/fpregdef.h>
#include <asm/mipsconfig.h>
#include <asm/mipsregs.h>
@@ -29,9 +30,8 @@
*/
#define LOAD_PTE(pte, ptr) \
mfc0 pte, CP0_BADVADDR; \
- lui ptr, %hi(current_set); \
srl pte, pte, 22; \
- lw ptr, %lo(current_set)(ptr); \
+ GET_CURRENT(ptr); \
sll pte, pte, 2; \
lw ptr, THREAD_PGDIR(ptr); \
addu ptr, pte, ptr; \
diff --git a/arch/mips/kernel/r4k_switch.S b/arch/mips/kernel/r4k_switch.S
index 78ced5659..97e253028 100644
--- a/arch/mips/kernel/r4k_switch.S
+++ b/arch/mips/kernel/r4k_switch.S
@@ -1,4 +1,4 @@
-/* $Id: r4k_switch.S,v 1.8 1996/07/10 01:24:20 dm Exp $
+/*
* r4k_switch.S: R4xx0 specific task switching code.
*
* Copyright (C) 1994, 1995, 1996 by Ralf Baechle and Andreas Busse
@@ -9,6 +9,7 @@
#include <asm/asm.h>
#include <asm/bootinfo.h>
#include <asm/cachectl.h>
+#include <asm/current.h>
#include <asm/fpregdef.h>
#include <asm/mipsconfig.h>
#include <asm/mipsregs.h>
@@ -24,8 +25,7 @@
.set mips3
.align 5
LEAF(r4xx0_resume)
- lui t5, %hi(current_set)
- lw t0, %lo(current_set)(t5)
+ GET_CURRENT(t0)
mfc0 t1, CP0_STATUS
nop
sw t1, THREAD_STATUS(t0)
@@ -43,7 +43,6 @@
1:
FPU_SAVE_16EVEN(t0, t1) # clobbers t1
2:
- sw a0, %lo(current_set)(t5)
lw a3, TASK_MM(a0)
lw a2, THREAD_STATUS(a0)
lw a3, MM_CONTEXT(a3)
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index 2e2b074f9..7616fa7c6 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -7,6 +7,7 @@
*/
#include <linux/config.h>
#include <linux/errno.h>
+#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/sched.h>
#include <linux/kernel.h>
@@ -123,17 +124,17 @@ void (*irq_setup)(void);
*/
unsigned long isa_slot_offset;
-static void default_irq_setup(void)
+__initfunc(static void default_irq_setup(void))
{
panic("Unknown machtype in init_IRQ");
}
-static void default_fd_cacheflush(const void *addr, size_t size)
+__initfunc(static void default_fd_cacheflush(const void *addr, size_t size))
{
}
-void setup_arch(char **cmdline_p,
- unsigned long * memory_start_p, unsigned long * memory_end_p)
+__initfunc(void setup_arch(char **cmdline_p,
+ unsigned long * memory_start_p, unsigned long * memory_end_p))
{
unsigned long memory_end;
tag* atag;
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c
index 848f0742b..304dc6418 100644
--- a/arch/mips/kernel/signal.c
+++ b/arch/mips/kernel/signal.c
@@ -307,7 +307,10 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
case SIGCONT: case SIGCHLD: case SIGWINCH:
continue;
- case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU:
+ case SIGTSTP: case SIGTTIN: case SIGTTOU:
+ if (is_orphaned_pgrp(current->pgrp))
+ continue;
+ case SIGSTOP:
if (current->flags & PF_PTRACED)
continue;
current->state = TASK_STOPPED;
@@ -318,11 +321,15 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
schedule();
continue;
- case SIGIOT: case SIGFPE: case SIGSEGV: case SIGBUS:
+ case SIGQUIT: case SIGILL: case SIGTRAP:
+ case SIGABRT: case SIGFPE: case SIGSEGV:
+ case SIGBUS:
+ lock_kernel();
if (current->binfmt && current->binfmt->core_dump) {
if (current->binfmt->core_dump(signr, regs))
signr |= 0x80;
}
+ unlock_kernel();
/* fall through */
default:
spin_lock_irq(&current->sigmask_lock);
diff --git a/arch/mips/kernel/syscalls.h b/arch/mips/kernel/syscalls.h
index 4cf778acb..6c7d3988c 100644
--- a/arch/mips/kernel/syscalls.h
+++ b/arch/mips/kernel/syscalls.h
@@ -174,6 +174,7 @@ SYS(sys_mlock, 2)
SYS(sys_munlock, 2) /* 4155 */
SYS(sys_mlockall, 1)
SYS(sys_munlockall, 0)
+SYS(sys_nfsservctl, 3)
SYS(sys_sched_setparam,2)
SYS(sys_sched_getparam,2)
SYS(sys_sched_setscheduler,3) /* 4160 */
diff --git a/arch/mips/kernel/sysirix.c b/arch/mips/kernel/sysirix.c
index 9a4ddca3f..7917664fd 100644
--- a/arch/mips/kernel/sysirix.c
+++ b/arch/mips/kernel/sysirix.c
@@ -17,6 +17,8 @@
#include <linux/elf.h>
#include <linux/msg.h>
#include <linux/shm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
#include <linux/utsname.h>
#include <asm/ptrace.h>
@@ -24,26 +26,7 @@
#include <asm/pgtable.h>
#include <asm/uaccess.h>
-/* 2,000 lines of complete and utter shit coming up... */
-
-/* Utility routines. */
-static inline struct task_struct *find_process_by_pid(pid_t pid)
-{
- struct task_struct *p, *q;
-
- if (pid == 0)
- p = current;
- else {
- p = 0;
- for_each_task(q) {
- if (q && q->pid == pid) {
- p = q;
- break;
- }
- }
- }
- return p;
-}
+/* 2,300 lines of complete and utter shit coming up... */
/* The sysmp commands supported thus far. */
#define MP_PGSIZE 14 /* Return system page size in v1. */
@@ -70,7 +53,6 @@ asmlinkage int irix_sysmp(struct pt_regs *regs)
break;
}
-out:
unlock_kernel();
return error;
}
@@ -114,7 +96,7 @@ asmlinkage int irix_prctl(struct pt_regs *regs)
printk("irix_prctl[%s:%d]: Wants PR_ISBLOCKED\n",
current->comm, current->pid);
- task = find_process_by_pid(regs->regs[base + 5]);
+ task = find_task_by_pid(regs->regs[base + 5]);
if(!task) {
error = -ESRCH;
break;
@@ -233,7 +215,6 @@ asmlinkage int irix_prctl(struct pt_regs *regs)
break;
}
-out:
unlock_kernel();
return error;
}
@@ -658,7 +639,6 @@ asmlinkage int irix_mount(char *dev_name, char *dir_name, unsigned long flags,
dev_name, dir_name, flags, type, data, datalen);
ret = sys_mount(dev_name, dir_name, type, flags, data);
-out:
unlock_kernel();
return ret;
}
@@ -781,22 +761,23 @@ asmlinkage int irix_setpgrp(int flags)
printk("returning %d\n", current->pgrp);
#endif
-out:
unlock_kernel();
return error;
}
asmlinkage int irix_times(struct tms * tbuf)
{
+ int error;
+
lock_kernel();
if (tbuf) {
- int error = verify_area(VERIFY_WRITE,tbuf,sizeof *tbuf);
+ error = verify_area(VERIFY_WRITE,tbuf,sizeof *tbuf);
if (error)
goto out;
- __put_user(current->utime,&tbuf->tms_utime);
- __put_user(current->stime,&tbuf->tms_stime);
- __put_user(current->cutime,&tbuf->tms_cutime);
- __put_user(current->cstime,&tbuf->tms_cstime);
+ __put_user(current->times.tms_utime,&tbuf->tms_utime);
+ __put_user(current->times.tms_stime,&tbuf->tms_stime);
+ __put_user(current->times.tms_cutime,&tbuf->tms_cutime);
+ __put_user(current->times.tms_cstime,&tbuf->tms_cstime);
}
error = 0;
@@ -845,169 +826,6 @@ out:
return error;
}
-/* sys_poll() support... */
-#define POLL_ROUND_UP(x,y) (((x)+(y)-1)/(y))
-
-#define POLLIN 1
-#define POLLPRI 2
-#define POLLOUT 4
-#define POLLERR 8
-#define POLLHUP 16
-#define POLLNVAL 32
-#define POLLRDNORM 64
-#define POLLWRNORM POLLOUT
-#define POLLRDBAND 128
-#define POLLWRBAND 256
-
-#define LINUX_POLLIN (POLLRDNORM | POLLRDBAND | POLLIN)
-#define LINUX_POLLOUT (POLLWRBAND | POLLWRNORM | POLLOUT)
-#define LINUX_POLLERR (POLLERR)
-
-static inline void free_wait(select_table * p)
-{
- struct select_table_entry * entry = p->entry + p->nr;
-
- while (p->nr > 0) {
- p->nr--;
- entry--;
- remove_wait_queue(entry->wait_address,&entry->wait);
- }
-}
-
-
-/* Copied directly from fs/select.c */
-static int check(int flag, select_table * wait, struct file * file)
-{
- struct inode * inode;
- struct file_operations *fops;
- int (*select) (struct inode *, struct file *, int, select_table *);
-
- inode = file->f_inode;
- if ((fops = file->f_op) && (select = fops->select))
- return select(inode, file, flag, wait)
- || (wait && select(inode, file, flag, NULL));
- if (S_ISREG(inode->i_mode))
- return 1;
- return 0;
-}
-
-struct poll {
- int fd;
- short events;
- short revents;
-};
-
-int irix_poll(struct poll * ufds, size_t nfds, int timeout)
-{
- int i,j, count, fdcount, error, retflag;
- struct poll * fdpnt;
- struct poll * fds, *fds1;
- select_table wait_table, *wait;
- struct select_table_entry *entry;
-
- lock_kernel();
- if ((error = verify_area(VERIFY_READ, ufds, nfds*sizeof(struct poll))))
- goto out;
-
- if (nfds > NR_OPEN) {
- error = -EINVAL;
- goto out;
- }
-
- if (!(entry = (struct select_table_entry*)__get_free_page(GFP_KERNEL))
- || !(fds = (struct poll *)kmalloc(nfds*sizeof(struct poll), GFP_KERNEL))) {
- error = -ENOMEM;
- goto out;
- }
-
- copy_from_user(fds, ufds, nfds*sizeof(struct poll));
-
- if (timeout < 0)
- current->timeout = 0x7fffffff;
- else {
- current->timeout = jiffies + POLL_ROUND_UP(timeout, (1000/HZ));
- if (current->timeout <= jiffies)
- current->timeout = 0;
- }
-
- count = 0;
- wait_table.nr = 0;
- wait_table.entry = entry;
- wait = &wait_table;
-
- for(fdpnt = fds, j = 0; j < (int)nfds; j++, fdpnt++) {
- i = fdpnt->fd;
- fdpnt->revents = 0;
- if (!current->files->fd[i] || !current->files->fd[i]->f_inode)
- fdpnt->revents = POLLNVAL;
- }
-repeat:
- current->state = TASK_INTERRUPTIBLE;
- for(fdpnt = fds, j = 0; j < (int)nfds; j++, fdpnt++) {
- i = fdpnt->fd;
-
- if(i < 0) continue;
- if (!current->files->fd[i] || !current->files->fd[i]->f_inode) continue;
-
- if ((fdpnt->events & LINUX_POLLIN)
- && check(SEL_IN, wait, current->files->fd[i])) {
- retflag = 0;
- if (fdpnt->events & POLLIN)
- retflag = POLLIN;
- if (fdpnt->events & POLLRDNORM)
- retflag = POLLRDNORM;
- fdpnt->revents |= retflag;
- count++;
- wait = NULL;
- }
-
- if ((fdpnt->events & LINUX_POLLOUT) &&
- check(SEL_OUT, wait, current->files->fd[i])) {
- fdpnt->revents |= (LINUX_POLLOUT & fdpnt->events);
- count++;
- wait = NULL;
- }
-
- if (check(SEL_EX, wait, current->files->fd[i])) {
- fdpnt->revents |= POLLHUP;
- count++;
- wait = NULL;
- }
- }
-
- if ((current->signal & (~current->blocked))) {
- error = -EINTR;
- goto out;
- }
-
- wait = NULL;
- if (!count && current->timeout > jiffies) {
- schedule();
- goto repeat;
- }
-
- free_wait(&wait_table);
- free_page((unsigned long) entry);
-
- /* OK, now copy the revents fields back to user space. */
- fds1 = fds;
- fdcount = 0;
- for(i=0; i < (int)nfds; i++, ufds++, fds++) {
- if (fds->revents) {
- fdcount++;
- }
- put_user(fds->revents, &ufds->revents);
- }
- kfree(fds1);
- current->timeout = 0;
- current->state = TASK_RUNNING;
- error = fdcount;
-
-out:
- unlock_kernel();
- return error;
-}
-
asmlinkage unsigned long irix_gethostid(void)
{
lock_kernel();
@@ -1263,7 +1081,6 @@ asmlinkage int irix_BSDsetpgrp(int pid, int pgrp)
printk("error = %d\n", error);
#endif
-out:
unlock_kernel();
return error;
}
@@ -1443,11 +1260,11 @@ asmlinkage int irix_lxstat(int version, char *filename, struct stat *statbuf)
if(error)
goto out;
error = irix_xstat32_xlate(&kb, statbuf);
- goto error;
+ goto out;
}
case 3: {
- sys_newlstat(filename, statbuf);
+ error = sys_newlstat(filename, statbuf);
#ifdef DEBUG_XSTAT
printk("error[%d]\n", error);
#endif
@@ -1456,7 +1273,7 @@ asmlinkage int irix_lxstat(int version, char *filename, struct stat *statbuf)
irix_xstat64_xlate(statbuf);
error = 0;
- goto error;
+ goto out;
}
default:
@@ -1466,7 +1283,7 @@ asmlinkage int irix_lxstat(int version, char *filename, struct stat *statbuf)
out:
unlock_kernel();
- return errno;
+ return error;
}
extern asmlinkage int sys_newfstat(unsigned int fd, struct stat * statbuf);
@@ -2018,13 +1835,13 @@ out:
asmlinkage int irix_getmountid(char *fname, unsigned long *midbuf)
{
- int errno;
+ int error;
lock_kernel();
printk("[%s:%d] irix_getmountid(%s, %p)\n",
current->comm, current->pid, fname, midbuf);
- errno = verify_area(VERIFY_WRITE, midbuf, (sizeof(unsigned long) * 4));
- if(errno)
+ error = verify_area(VERIFY_WRITE, midbuf, (sizeof(unsigned long) * 4));
+ if(error)
goto out;
/*
@@ -2142,7 +1959,7 @@ asmlinkage int irix_ngetdents(unsigned int fd, void * dirent, unsigned int count
buf.error = 0;
error = file->f_op->readdir(file->f_inode, file, &buf, irix_filldir32);
if (error < 0)
- goto out
+ goto out;
lastdirent = buf.previous;
if (!lastdirent) {
error = buf.error;
@@ -2431,6 +2248,8 @@ asmlinkage int irix_fcntl(int fd, int cmd, int arg)
asmlinkage int irix_ulimit(int cmd, int arg)
{
+ int retval;
+
lock_kernel();
switch(cmd) {
case 1:
diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c
index aa4547456..fd57f6d0e 100644
--- a/arch/mips/kernel/time.c
+++ b/arch/mips/kernel/time.c
@@ -7,6 +7,7 @@
* found in some MIPS systems.
*/
#include <linux/errno.h>
+#include <linux/init.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/param.h>
@@ -299,7 +300,7 @@ static struct irqaction irq0 = { timer_interrupt, 0, 0, "timer", NULL, NULL};
void (*board_time_init)(struct irqaction *irq);
-void time_init(void)
+__initfunc(void time_init(void))
{
unsigned int year, mon, day, hour, min, sec;
int i;
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index 17b1f9a28..cdbcacb43 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -17,6 +17,7 @@
* Modified for R3000 by Paul M. Antoine, 1995, 1996
*/
#include <linux/config.h>
+#include <linux/init.h>
#include <linux/mm.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
@@ -110,10 +111,8 @@ void show_registers(char * str, struct pt_regs * regs, long err)
/*
* Dump the stack
*/
- if (STACK_MAGIC != *(u32 *)current->kernel_stack_page)
- printk("Corrupted stack page\n");
printk("Process %s (pid: %d, stackpage=%08lx)\nStack: ",
- current->comm, current->pid, current->kernel_stack_page);
+ current->comm, current->pid, (unsigned long)current);
for(i=0;i<5;i++)
printk("%08x ", *sp++);
stack = (int *) sp;
@@ -389,7 +388,7 @@ void do_reserved(struct pt_regs *regs)
unlock_kernel();
}
-static void watch_init(unsigned long cputype)
+static inline void watch_init(unsigned long cputype)
{
switch(cputype) {
case CPU_R10000:
@@ -427,7 +426,7 @@ extern asmlinkage void r6000_restore_fp_context(struct sigcontext *sc);
extern asmlinkage void r4xx0_resume(void *tsk);
extern asmlinkage void r2300_resume(void *tsk);
-void trap_init(void)
+__initfunc(void trap_init(void))
{
extern char except_vec0_r4000, except_vec0_r4600, except_vec0_r2300;
extern char except_vec1_generic, except_vec2_generic;
diff --git a/arch/mips/mips/Makefile b/arch/mips/mips/Makefile
new file mode 100644
index 000000000..b252e2fe4
--- /dev/null
+++ b/arch/mips/mips/Makefile
@@ -0,0 +1,39 @@
+#
+# PROM Entries for the big endian firmware used in the Mips Computer
+# System, Inc. machines. Beware: some of the machines seem to be
+# different.
+#
+# Copyright (C) 1997 Ralf Baechle
+#
+prom-entries= reset exec restart reinit reboot autoboot open read write ioctl \
+ close getchar putchar showchar gets puts printf initproto protoenable \
+ protodisable getpkt putpkt orw_rmw orh_rmw orb_rmw andw_rmw andh_rmw \
+ andb_rmw flushcache clearcache setjmp longjmp bevutlb getenv setenv \
+ atob strcmp strlen strcpy strcat parser range argvize help dumpcmd \
+ setenvcmd unsetenvcmd printenvcmd bevexcept enablecmd disablecmd \
+ clearnofault notimplement nv_get nv_set
+asm-files=$(addsuffix .S,$(prom-entries))
+object-files=$(addsuffix .o,$(prom-entries))
+
+CC=mipsel-linux-gcc
+AR=mipsel-linux-ar
+CFLAGS=-O2 -mno-abicalls -fno-pic -G0 -Wall
+
+all: libprom.a
+
+libprom.a: $(asm-files)
+ set -e;for i in $(prom-entries); do \
+ $(CC) $(CFLAGS) -c -o $$i.o $$i.S; \
+ $(AR) rcv libprom.a $$i.o; \
+ done
+
+$(asm-files): mkprom
+ set -e;for i in $(prom-entries); do \
+ mkprom $$i; \
+ done
+
+clean:
+ rm -f $(object-files)
+
+distclean:
+ rm -rf $(asm-files) libprom.a
diff --git a/arch/mips/mips/mkprom b/arch/mips/mips/mkprom
new file mode 100755
index 000000000..9e4cdf465
--- /dev/null
+++ b/arch/mips/mips/mkprom
@@ -0,0 +1,25 @@
+#
+# Generate PROM library stubs for the firmware used in the
+# Mips Computer System, Inc. machines. Beware: some of the
+# machines seem to be different.
+#
+# Copyright (C) 1997 Ralf Baechle
+#
+fname=$1
+ucase=`echo $fname | tr 'a-z' 'A-Z'`
+cat << EOF | sed -e "s/@1@/$fname/" -e "s/@2@/$ucase/" >$fname.S
+/*
+ * WARNING: This file has been generated automatically. Do not edit!
+ *
+ * Stub for the Mips firmware @1@() function.
+ */
+#include <asm/asm.h>
+#include <asm/regdef.h>
+#include <asm/mipsprom.h>
+
+LEAF(mips_prom_@1@)
+ lw t0,__mips_prom_entry_offset
+ addu t0,PROM_@2@
+ jr t0
+ END(mips_prom_@1@)
+EOF
diff --git a/arch/mips/mm/Makefile b/arch/mips/mm/Makefile
index d12159903..1205b2bf3 100644
--- a/arch/mips/mm/Makefile
+++ b/arch/mips/mm/Makefile
@@ -9,6 +9,6 @@
O_TARGET := mm.o
O_OBJS := extable.o init.o fault.o r4xx0.o r2300.o r6000.o tfp.o \
- andes.o loadmmu.o stack.o
+ andes.o loadmmu.o
include $(TOPDIR)/Rules.make
diff --git a/arch/mips/mm/fault.c b/arch/mips/mm/fault.c
index 4fdd98155..3ad703b1f 100644
--- a/arch/mips/mm/fault.c
+++ b/arch/mips/mm/fault.c
@@ -70,7 +70,7 @@ good_area:
if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
goto bad_area;
}
- handle_mm_fault(vma, address, writeaccess);
+ handle_mm_fault(tsk, vma, address, writeaccess);
up(&mm->mmap_sem);
goto out;
diff --git a/arch/mips/mm/r4xx0.c b/arch/mips/mm/r4xx0.c
index 5f1bcbfa6..f83f41df8 100644
--- a/arch/mips/mm/r4xx0.c
+++ b/arch/mips/mm/r4xx0.c
@@ -1,4 +1,4 @@
-/* $Id: r4xx0.c,v 1.19 1996/08/02 11:11:36 dm Exp $
+/*
* r4xx0.c: R4000 processor variant specific MMU/Cache routines.
*
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
@@ -325,28 +325,6 @@ static inline void r4k_flush_cache_all_d32i32(void)
restore_flags(flags);
}
-static inline struct vm_area_struct *
-find_mm_vma(struct mm_struct *mm, unsigned long addr)
-{
- struct vm_area_struct * result = NULL;
-
- if (mm) {
- struct vm_area_struct * tree = mm->mmap_avl;
- for (;;) {
- if (tree == avl_empty)
- break;
- if (tree->vm_end > addr) {
- result = tree;
- if (tree->vm_start <= addr)
- break;
- tree = tree->vm_avl_left;
- } else
- tree = tree->vm_avl_right;
- }
- }
- return result;
-}
-
static void
r4k_flush_cache_range_s16d16i16(struct mm_struct *mm,
unsigned long start,
@@ -362,7 +340,7 @@ r4k_flush_cache_range_s16d16i16(struct mm_struct *mm,
#ifdef DEBUG_CACHE
printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
#endif
- vma = find_mm_vma(mm, start);
+ vma = find_vma(mm, start);
if(vma) {
if(mm->context != current->mm->context) {
r4k_flush_cache_all_s16d16i16();
@@ -407,7 +385,7 @@ r4k_flush_cache_range_s32d16i16(struct mm_struct *mm,
#ifdef DEBUG_CACHE
printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
#endif
- vma = find_mm_vma(mm, start);
+ vma = find_vma(mm, start);
if(vma) {
if(mm->context != current->mm->context) {
r4k_flush_cache_all_s32d16i16();
@@ -451,7 +429,7 @@ static void r4k_flush_cache_range_s64d16i16(struct mm_struct *mm,
#ifdef DEBUG_CACHE
printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
#endif
- vma = find_mm_vma(mm, start);
+ vma = find_vma(mm, start);
if(vma) {
if(mm->context != current->mm->context) {
r4k_flush_cache_all_s64d16i16();
@@ -495,7 +473,7 @@ static void r4k_flush_cache_range_s128d16i16(struct mm_struct *mm,
#ifdef DEBUG_CACHE
printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
#endif
- vma = find_mm_vma(mm, start);
+ vma = find_vma(mm, start);
if(vma) {
if(mm->context != current->mm->context) {
r4k_flush_cache_all_s128d16i16();
@@ -539,7 +517,7 @@ static void r4k_flush_cache_range_s16d32i32(struct mm_struct *mm,
#ifdef DEBUG_CACHE
printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
#endif
- vma = find_mm_vma(mm, start);
+ vma = find_vma(mm, start);
if(vma) {
if(mm->context != current->mm->context) {
r4k_flush_cache_all_s16d32i32();
@@ -583,7 +561,7 @@ static void r4k_flush_cache_range_s32d32i32(struct mm_struct *mm,
#ifdef DEBUG_CACHE
printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
#endif
- vma = find_mm_vma(mm, start);
+ vma = find_vma(mm, start);
if(vma) {
if(mm->context != current->mm->context) {
r4k_flush_cache_all_s32d32i32();
@@ -627,7 +605,7 @@ static void r4k_flush_cache_range_s64d32i32(struct mm_struct *mm,
#ifdef DEBUG_CACHE
printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
#endif
- vma = find_mm_vma(mm, start);
+ vma = find_vma(mm, start);
if(vma) {
if(mm->context != current->mm->context) {
r4k_flush_cache_all_s64d32i32();
@@ -671,7 +649,7 @@ static void r4k_flush_cache_range_s128d32i32(struct mm_struct *mm,
#ifdef DEBUG_CACHE
printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
#endif
- vma = find_mm_vma(mm, start);
+ vma = find_vma(mm, start);
if(vma) {
if(mm->context != current->mm->context) {
r4k_flush_cache_all_s128d32i32();
diff --git a/arch/mips/mm/stack.c b/arch/mips/mm/stack.c
deleted file mode 100644
index 89fb6dc64..000000000
--- a/arch/mips/mm/stack.c
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Kernel stack allocation/deallocation
- *
- * 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) 1996, 1997 by Ralf Baechle
- *
- * (This is _bad_ if the free page pool is fragmented ...)
- */
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <asm/processor.h>
-
-extern unsigned long alloc_kernel_stack(struct task_struct *tsk)
-{
- unsigned long stack;
- stack = __get_free_pages(GFP_KERNEL, 1, 0);
-
- return stack;
-}
-
-extern void free_kernel_stack(unsigned long stack)
-{
- free_pages(stack, 1);
-}
diff --git a/arch/mips/sgi/kernel/indy_int.c b/arch/mips/sgi/kernel/indy_int.c
index 19b744fdb..fe60c03c8 100644
--- a/arch/mips/sgi/kernel/indy_int.c
+++ b/arch/mips/sgi/kernel/indy_int.c
@@ -16,6 +16,8 @@
#include <linux/timex.h>
#include <linux/malloc.h>
#include <linux/random.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
#include <asm/bitops.h>
#include <asm/bootinfo.h>
@@ -51,6 +53,7 @@ extern asmlinkage void indyIRQ(void);
extern void rs_kgdb_hook(int);
#endif
+unsigned int local_irq_count[NR_CPUS];
unsigned long spurious_count = 0;
/* Local IRQ's are layed out logically like this:
@@ -255,6 +258,15 @@ int get_irq_list(char *buf)
return len;
}
+atomic_t __mips_bh_counter;
+
+#ifdef __SMP__
+#error Send superfluous SMP boxes to ralf@uni-koblenz.de
+#else
+#define irq_enter(cpu, irq) (++local_irq_count[cpu])
+#define irq_exit(cpu, irq) (--local_irq_count[cpu])
+#endif
+
/*
* do_IRQ handles IRQ's that have been installed without the
* SA_INTERRUPT flag: it uses the full signal-handling return
@@ -264,8 +276,9 @@ int get_irq_list(char *buf)
*/
asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
{
- lock_kernel();
struct irqaction * action = *(irq + irq_action);
+
+ lock_kernel();
kstat.interrupts[irq]++;
printk("Got irq %d, press a key.", irq);
prom_getchar();
diff --git a/arch/mips/sgi/kernel/setup.c b/arch/mips/sgi/kernel/setup.c
index 58b7695b3..e0482e116 100644
--- a/arch/mips/sgi/kernel/setup.c
+++ b/arch/mips/sgi/kernel/setup.c
@@ -9,6 +9,7 @@
#include <linux/kernel.h>
#include <linux/sched.h>
+#include <asm/reboot.h>
#include <asm/vector.h>
#include <asm/sgialib.h>
#include <asm/sgi.h>
diff --git a/arch/mips/sgi/prom/misc.c b/arch/mips/sgi/prom/misc.c
index 47051a1b3..53ee61cfe 100644
--- a/arch/mips/sgi/prom/misc.c
+++ b/arch/mips/sgi/prom/misc.c
@@ -1,9 +1,9 @@
-/* $Id: misc.c,v 1.3 1996/08/07 02:54:12 dm Exp $
+/*
* misc.c: Miscellaneous ARCS PROM routines.
*
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
*/
-
+#include <linux/config.h>
#include <linux/kernel.h>
#include <asm/sgialib.h>
@@ -51,7 +51,9 @@ void prom_halt(void)
{
shutoff_r4600_cache();
initialize_kbd();
+#if CONFIG_SCSI_SGIWD93
reset_wd33c93(sgiwd93_host);
+#endif
cli();
romvec->halt();
}
@@ -60,7 +62,9 @@ void prom_powerdown(void)
{
shutoff_r4600_cache();
initialize_kbd();
+#if CONFIG_SCSI_SGIWD93
reset_wd33c93(sgiwd93_host);
+#endif
cli();
romvec->pdown();
}
@@ -70,7 +74,9 @@ void prom_restart(void)
{
shutoff_r4600_cache();
initialize_kbd();
+#if CONFIG_SCSI_SGIWD93
reset_wd33c93(sgiwd93_host);
+#endif
cli();
romvec->restart();
}
@@ -79,7 +85,9 @@ void prom_reboot(void)
{
shutoff_r4600_cache();
initialize_kbd();
+#if CONFIG_SCSI_SGIWD93
reset_wd33c93(sgiwd93_host);
+#endif
cli();
romvec->reboot();
}
@@ -88,7 +96,9 @@ void prom_imode(void)
{
shutoff_r4600_cache();
initialize_kbd();
+#if CONFIG_SCSI_SGIWD93
reset_wd33c93(sgiwd93_host);
+#endif
cli();
romvec->imode();
}
diff --git a/arch/mips/sni/.cvsignore b/arch/mips/sni/.cvsignore
new file mode 100644
index 000000000..4671378ae
--- /dev/null
+++ b/arch/mips/sni/.cvsignore
@@ -0,0 +1 @@
+.depend
diff --git a/arch/mips/sni/Makefile b/arch/mips/sni/Makefile
index f0bc3e600..9bd570ff0 100644
--- a/arch/mips/sni/Makefile
+++ b/arch/mips/sni/Makefile
@@ -13,7 +13,7 @@
all: sni.o
O_TARGET := sni.o
-O_OBJS := hw-access.o int-handler.o pci.o reset.o setup.o
+O_OBJS := hw-access.o int-handler.o io.o pci.o reset.o setup.o
int-handler.o: int-handler.S
diff --git a/arch/mips/sni/int-handler.S b/arch/mips/sni/int-handler.S
index f60c82251..d051c8b13 100644
--- a/arch/mips/sni/int-handler.S
+++ b/arch/mips/sni/int-handler.S
@@ -1,7 +1,7 @@
/*
* SNI RM200 PCI specific interrupt handler code.
*
- * Copyright (C) 1994, 1995, 1996 by Ralf Baechle
+ * Copyright (C) 1994 - 1997 by Ralf Baechle
*/
#include <asm/asm.h>
#include <linux/config.h>
@@ -150,30 +150,17 @@ poll_second: li a0,0x0f
#endif /* CONFIG_PCNET32 */
-/*
- * FIXME: This is definatly wrong but I'll have to do it this way
- * 'till I get more hardware info.
- * XXX: Apparently the NCR is attached to interrupt #2.
- */
#ifdef CONFIG_SCSI_NCR53C8XX
/*
- * FIXME: detect this address
- */
-#define NCR_BASE 0xb8000000
-
-/* Offsets from base I/O address. */
-#define NCR_INTF 0x14
-
-/*
* ... check if we were interrupted by the NCR ...
*/
-3: lb t0,NCR_BASE+NCR_INTF
- andi t0,7
- beqz t0,3f # no NCR interrupt?
+3: lb t0,PCIMT_CSITPEND
+ andi t0,0x40
+ bnez t0,3f # bit 6 == 0 -> SCSI IRQ
nop # delay slot
jal do_fast_IRQ
- li a0,5 # delay slot
+ li a0,PCIMT_IRQ_SCSI # delay slot
j return
nop # delay slot
diff --git a/arch/mips/sni/io.c b/arch/mips/sni/io.c
new file mode 100644
index 000000000..f62fdc2d7
--- /dev/null
+++ b/arch/mips/sni/io.c
@@ -0,0 +1,172 @@
+/*
+ * 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.
+ *
+ * Low level I/O functions for SNI.
+ */
+#include <linux/string.h>
+#include <asm/mipsconfig.h>
+#include <asm/addrspace.h>
+#include <asm/system.h>
+#include <asm/spinlock.h>
+#include <asm/sni.h>
+
+unsigned char sni_map_isa_cache;
+
+#define unused __attribute__((unused))
+
+/*
+ * The PCIMT_CSMAPISA is shared by all processors; we need locking.
+ *
+ * XXX It's legal to use all the I/O memory access functions in interrupt
+ * code, so we need to use the _irq locking stuff which may result in
+ * significant IRQ latencies.
+ */
+static spinlock_t csmapisa_lock unused = SPIN_LOCK_UNLOCKED;
+
+/*
+ * Urgs... We only can see a 16mb window of the 4gb EISA address space
+ * at PCIMT_EISA_BASE. Maladia segmentitis ...
+ *
+ * XXX Check out if accessing PCIMT_CSMAPISA really is slow.
+ * For now assume so.
+ */
+static inline void update_isa_cache(unsigned long address)
+{
+ unsigned char upper;
+
+ upper = address >> 24;
+ if (sni_map_isa_cache != upper) {
+ sni_map_isa_cache = upper;
+ *(volatile unsigned char *)PCIMT_CSMAPISA = ~upper;
+ }
+}
+
+static unsigned char sni_readb(unsigned long addr)
+{
+ unsigned char res;
+
+ spin_lock_irq(&csmapisa_lock);
+ update_isa_cache(addr);
+ addr &= 0xffffff;
+ res = *(volatile unsigned char *) (PCIMT_EISA_BASE + addr);
+ spin_unlock_irq(&csmapisa_lock);
+
+ return res;
+}
+
+static unsigned short sni_readw(unsigned long addr)
+{
+ unsigned short res;
+
+ spin_lock_irq(&csmapisa_lock);
+ update_isa_cache(addr);
+ addr &= 0xffffff;
+ res = *(volatile unsigned char *) (PCIMT_EISA_BASE + addr);
+ spin_unlock_irq(&csmapisa_lock);
+
+ return res;
+}
+
+static unsigned int sni_readl(unsigned long addr)
+{
+ unsigned int res;
+
+ spin_lock_irq(&csmapisa_lock);
+ update_isa_cache(addr);
+ addr &= 0xffffff;
+ res = *(volatile unsigned char *) (PCIMT_EISA_BASE + addr);
+ spin_unlock_irq(&csmapisa_lock);
+
+ return res;
+}
+
+static void sni_writeb(unsigned char val, unsigned long addr)
+{
+ spin_lock_irq(&csmapisa_lock);
+ update_isa_cache(addr);
+ addr &= 0xffffff;
+ *(volatile unsigned char *) (PCIMT_EISA_BASE + addr) = val;
+ spin_unlock_irq(&csmapisa_lock);
+}
+
+static void sni_writew(unsigned short val, unsigned long addr)
+{
+ spin_lock_irq(&csmapisa_lock);
+ update_isa_cache(addr);
+ addr &= 0xffffff;
+ *(volatile unsigned char *) (PCIMT_EISA_BASE + addr) = val;
+ spin_unlock_irq(&csmapisa_lock);
+}
+
+static void sni_writel(unsigned int val, unsigned long addr)
+{
+ spin_lock_irq(&csmapisa_lock);
+ update_isa_cache(addr);
+ addr &= 0xffffff;
+ *(volatile unsigned char *) (PCIMT_EISA_BASE + addr) = val;
+ spin_unlock_irq(&csmapisa_lock);
+}
+
+static void sni_memset_io(unsigned long addr, int val, unsigned long len)
+{
+ unsigned long waddr;
+
+ waddr = PCIMT_EISA_BASE | (addr & 0xffffff);
+ spin_lock_irq(&csmapisa_lock);
+ while(len) {
+ unsigned long fraglen;
+
+ fraglen = (~addr + 1) & 0xffffff;
+ fraglen = (fraglen < len) ? fraglen : len;
+ update_isa_cache(addr);
+ memset((char *)waddr, val, fraglen);
+ addr += fraglen;
+ waddr = waddr + fraglen - 0x1000000;
+ len -= fraglen;
+ }
+ spin_unlock_irq(&csmapisa_lock);
+}
+
+static void sni_memcpy_fromio(unsigned long to, unsigned long from, unsigned long len)
+{
+ unsigned long waddr;
+
+ waddr = PCIMT_EISA_BASE | (from & 0xffffff);
+ spin_lock_irq(&csmapisa_lock);
+ while(len) {
+ unsigned long fraglen;
+
+ fraglen = (~from + 1) & 0xffffff;
+ fraglen = (fraglen < len) ? fraglen : len;
+ update_isa_cache(from);
+ memcpy((void *)to, (void *)waddr, fraglen);
+ to += fraglen;
+ from += fraglen;
+ waddr = waddr + fraglen - 0x1000000;
+ len -= fraglen;
+ }
+ spin_unlock_irq(&csmapisa_lock);
+}
+
+static void sni_memcpy_toio(unsigned long to, unsigned long from, unsigned long len)
+{
+ unsigned long waddr;
+
+ waddr = PCIMT_EISA_BASE | (to & 0xffffff);
+ spin_lock_irq(&csmapisa_lock);
+ while(len) {
+ unsigned long fraglen;
+
+ fraglen = (~to + 1) & 0xffffff;
+ fraglen = (fraglen < len) ? fraglen : len;
+ update_isa_cache(to);
+ memcpy((char *)to + PCIMT_EISA_BASE, (void *)from, fraglen);
+ to += fraglen;
+ from += fraglen;
+ waddr = waddr + fraglen - 0x1000000;
+ len -= fraglen;
+ }
+ spin_unlock_irq(&csmapisa_lock);
+}
diff --git a/arch/mips/sni/pci.c b/arch/mips/sni/pci.c
index 06edb268f..917d07a81 100644
--- a/arch/mips/sni/pci.c
+++ b/arch/mips/sni/pci.c
@@ -7,6 +7,7 @@
*/
#include <linux/config.h>
#include <linux/bios32.h>
+#include <linux/init.h>
#include <linux/pci.h>
#include <linux/types.h>
#include <asm/byteorder.h>
@@ -18,18 +19,26 @@
extern inline u32 mkaddr(unsigned char bus, unsigned char dev_fn,
unsigned char where)
{
- return (((bus & 0xff) << 0x10) |
- ((dev_fn & 0xff) << 0x08) |
- ((where & 0xfc)));
+ return ((bus & 0xff) << 0x10) |
+ ((dev_fn & 0xff) << 0x08) |
+ (where & 0xfc);
}
static unsigned long sni_rm200_pcibios_fixup (unsigned long memory_start,
unsigned long memory_end)
{
- /* I guess it's ok to do exactly nothing. */
+ /*
+ * TODO: Fix PCI_INTERRUPT_LINE register for onboard cards.
+ * Take care of RM300 revision D boards for where the network
+ * slot became an ordinary PCI slot.
+ */
return memory_start;
}
+/*
+ * We can't address 8 and 16 bit words directly. Instead we have to
+ * read/write a 32bit word and mask/modify the data we actually want.
+ */
static int sni_rm200_pcibios_read_config_byte (unsigned char bus,
unsigned char dev_fn,
unsigned char where,
@@ -39,7 +48,7 @@ static int sni_rm200_pcibios_read_config_byte (unsigned char bus,
*(volatile u32 *)PCIMT_CONFIG_ADDRESS = mkaddr(bus, dev_fn, where);
res = *(volatile u32 *)PCIMT_CONFIG_DATA;
- res = le32_to_cpu(res);
+ res = (le32_to_cpu(res) >> ((where & 3) << 3)) & 0xff;
*val = res;
return PCIBIOS_SUCCESSFUL;
@@ -56,7 +65,7 @@ static int sni_rm200_pcibios_read_config_word (unsigned char bus,
return PCIBIOS_BAD_REGISTER_NUMBER;
*(volatile u32 *)PCIMT_CONFIG_ADDRESS = mkaddr(bus, dev_fn, where);
res = *(volatile u32 *)PCIMT_CONFIG_DATA;
- res = le32_to_cpu(res);
+ res = (le32_to_cpu(res) >> ((where & 3) << 3)) & 0xffff;
*val = res;
return PCIBIOS_SUCCESSFUL;
@@ -110,7 +119,7 @@ static int sni_rm200_pcibios_write_config_dword (unsigned char bus,
return PCIBIOS_SUCCESSFUL;
}
-unsigned long sni_rm200_pcibios_init(unsigned long memory_start, unsigned long memory_end)
+__initfunc(unsigned long sni_rm200_pcibios_init(unsigned long memory_start, unsigned long memory_end))
{
_pcibios_fixup = sni_rm200_pcibios_fixup;
_pcibios_read_config_byte = sni_rm200_pcibios_read_config_byte;
diff --git a/arch/mips/sni/setup.c b/arch/mips/sni/setup.c
index 1a7a1387d..7fa76a490 100644
--- a/arch/mips/sni/setup.c
+++ b/arch/mips/sni/setup.c
@@ -5,11 +5,12 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 1996 by Ralf Baechle
+ * Copyright (C) 1996, 1997 by Ralf Baechle
*/
#include <asm/ptrace.h>
#include <linux/ioport.h>
#include <linux/sched.h>
+#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/timex.h>
#include <linux/pci.h>
@@ -40,8 +41,7 @@ extern void sni_machine_restart(char *command);
extern void sni_machine_halt(void);
extern void sni_machine_power_off(void);
-static void
-sni_irq_setup(void)
+__initfunc(static void sni_irq_setup(void))
{
set_except_vector(0, sni_rm200_pci_handle_int);
request_region(0x20,0x20, "pic1");
@@ -57,7 +57,7 @@ sni_irq_setup(void)
void (*board_time_init)(struct irqaction *irq);
-static void sni_rm200_pci_time_init(struct irqaction *irq)
+__initfunc(static void sni_rm200_pci_time_init(struct irqaction *irq))
{
/* set the clock to 100 Hz */
outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */
@@ -67,8 +67,9 @@ static void sni_rm200_pci_time_init(struct irqaction *irq)
}
unsigned char aux_device_present;
-unsigned long sni_rm200_pcibios_init (unsigned long memory_start,
- unsigned long memory_end);
+extern unsigned long sni_rm200_pcibios_init (unsigned long memory_start,
+ unsigned long memory_end);
+extern unsigned char sni_map_isa_cache;
/*
* A bit more gossip about the iron we're running on ...
@@ -92,8 +93,7 @@ static inline void sni_pcimt_detect(void)
printk("%s.\n", boardtype);
}
-void
-sni_rm200_pci_setup(void)
+__initfunc(void sni_rm200_pci_setup(void))
{
tag *atag;
@@ -127,7 +127,14 @@ sni_rm200_pci_setup(void)
fd_cacheflush = sni_fd_cacheflush; // Will go away
feature = &sni_rm200_pci_feature;
port_base = SNI_PORT_BASE;
+
+ /*
+ * Setup (E)ISA I/O memory access stuff
+ */
isa_slot_offset = 0xb0000000;
+ // sni_map_isa_cache = 0;
+ EISA_bus = 1;
+
request_region(0x00,0x20,"dma1");
request_region(0x40,0x20,"timer");
/* XXX FIXME: CONFIG_RTC */
@@ -140,8 +147,6 @@ sni_rm200_pci_setup(void)
_machine_halt = sni_machine_halt;
_machine_power_off = sni_machine_power_off;
- if (mips_machtype == MACH_SNI_RM200_PCI)
- EISA_bus = 1;
aux_device_present = 0xaa;
/*
diff --git a/arch/mips/tools/.cvsignore b/arch/mips/tools/.cvsignore
new file mode 100644
index 000000000..2a1642034
--- /dev/null
+++ b/arch/mips/tools/.cvsignore
@@ -0,0 +1 @@
+.depend offset.s offset.h
diff --git a/arch/mips/tools/offset.c b/arch/mips/tools/offset.c
index 3bb46de6e..a8660dcf6 100644
--- a/arch/mips/tools/offset.c
+++ b/arch/mips/tools/offset.c
@@ -77,12 +77,11 @@ void output_task_defines(void)
{
text("/* MIPS task_struct offsets. */");
offset("#define TASK_STATE ", struct task_struct, state);
+ offset("#define TASK_COUNTER ", struct task_struct, counter);
offset("#define TASK_PRIORITY ", struct task_struct, priority);
offset("#define TASK_SIGNAL ", struct task_struct, signal);
offset("#define TASK_BLOCKED ", struct task_struct, blocked);
offset("#define TASK_FLAGS ", struct task_struct, flags);
- offset("#define TASK_SAVED_KSTACK ", struct task_struct, saved_kernel_stack);
- offset("#define TASK_KSTACK_PG ", struct task_struct, kernel_stack_page);
offset("#define TASK_MM ", struct task_struct, mm);
linefeed;
}
diff --git a/arch/mips/tools/offset.h b/arch/mips/tools/offset.h
deleted file mode 100644
index c5e6f37fa..000000000
--- a/arch/mips/tools/offset.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/* DO NOT TOUCH, AUTOGENERATED BY OFFSET.C */
-
-#ifndef _MIPS_OFFSET_H
-#define _MIPS_OFFSET_H
-
-/* MIPS pt_regs offsets. */
-#define PT_R0 24
-#define PT_R1 28
-#define PT_R2 32
-#define PT_R3 36
-#define PT_R4 40
-#define PT_R5 44
-#define PT_R6 48
-#define PT_R7 52
-#define PT_R8 56
-#define PT_R9 60
-#define PT_R10 64
-#define PT_R11 68
-#define PT_R12 72
-#define PT_R13 76
-#define PT_R14 80
-#define PT_R15 84
-#define PT_R16 88
-#define PT_R17 92
-#define PT_R18 96
-#define PT_R19 100
-#define PT_R20 104
-#define PT_R21 108
-#define PT_R22 112
-#define PT_R23 116
-#define PT_R24 120
-#define PT_R25 124
-#define PT_R26 128
-#define PT_R27 132
-#define PT_R28 136
-#define PT_R29 140
-#define PT_R30 144
-#define PT_R31 148
-#define PT_LO 152
-#define PT_HI 156
-#define PT_OR2 160
-#define PT_OR7 164
-#define PT_EPC 168
-#define PT_BVADDR 172
-#define PT_STATUS 176
-#define PT_CAUSE 180
-#define PT_SIZE 184
-
-/* MIPS task_struct offsets. */
-#define TASK_STATE 0
-#define TASK_PRIORITY 8
-#define TASK_SIGNAL 12
-#define TASK_BLOCKED 16
-#define TASK_FLAGS 20
-#define TASK_SAVED_KSTACK 84
-#define TASK_KSTACK_PG 88
-#define TASK_MM 912
-
-/* MIPS specific thread_struct offsets. */
-#define THREAD_REG16 544
-#define THREAD_REG17 548
-#define THREAD_REG18 552
-#define THREAD_REG19 556
-#define THREAD_REG20 560
-#define THREAD_REG21 564
-#define THREAD_REG22 568
-#define THREAD_REG23 572
-#define THREAD_REG28 576
-#define THREAD_REG29 580
-#define THREAD_REG30 584
-#define THREAD_REG31 588
-#define THREAD_STATUS 592
-#define THREAD_FPU 600
-#define THREAD_BVADDR 864
-#define THREAD_ECODE 868
-#define THREAD_TRAPNO 872
-#define THREAD_KSP 876
-#define THREAD_PGDIR 880
-#define THREAD_MFLAGS 884
-#define THREAD_CURDS 888
-#define THREAD_TRAMP 892
-#define THREAD_OLDCTX 896
-
-/* Linux mm_struct offsets. */
-#define MM_COUNT 0
-#define MM_PGD 4
-#define MM_CONTEXT 8
-
-#endif /* !(_MIPS_OFFSET_H) */
diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S
index e137e1171..c2a2989ec 100644
--- a/arch/ppc/kernel/misc.S
+++ b/arch/ppc/kernel/misc.S
@@ -855,5 +855,6 @@ sys_call_table:
.long sys_mremap
.long SYMBOL_NAME(sys_setresuid)
.long SYMBOL_NAME(sys_getresuid)
- .space (NR_syscalls-165)*4
+ .long SYMBOL_NAME(sys_nfsservctl)
+ .space (NR_syscalls-166)*4
diff --git a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c
index 8dc0e61ca..ee21c5cbe 100644
--- a/arch/ppc/kernel/process.c
+++ b/arch/ppc/kernel/process.c
@@ -29,6 +29,24 @@
#include <asm/io.h>
#include <asm/ppc_machine.h>
+
+/*
+ * Initial task structure. Make this a per-architecture thing,
+ * because different architectures tend to have different
+ * alignment requirements and potentially different initial
+ * setup.
+ */
+static unsigned long init_kernel_stack[1024] = { STACK_MAGIC, };
+unsigned long init_user_stack[1024] = { STACK_MAGIC, };
+static struct vm_area_struct init_mmap = INIT_MMAP;
+static struct fs_struct init_fs = INIT_FS;
+static struct files_struct init_files = INIT_FILES;
+static struct signal_struct init_signals = INIT_SIGNALS;
+
+struct mm_struct init_mm = INIT_MM;
+struct task_struct init_task = INIT_TASK;
+
+
int dump_fpu(void);
void hard_reset_now(void);
void switch_to(struct task_struct *, struct task_struct *);
diff --git a/arch/ppc/kernel/ptrace.c b/arch/ppc/kernel/ptrace.c
index 2d960c8cd..dc8a95302 100644
--- a/arch/ppc/kernel/ptrace.c
+++ b/arch/ppc/kernel/ptrace.c
@@ -42,18 +42,6 @@
static int regoff[] = {
};
-/* change a pid into a task struct. */
-static inline struct task_struct * get_task(int pid)
-{
- int i;
-
- for (i = 1; i < NR_TASKS; i++) {
- if (task[i] != NULL && (task[i]->pid == pid))
- return task[i];
- }
- return NULL;
-}
-
/*
* Get contents of register REGNO in task TASK.
*/
@@ -394,7 +382,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
if (pid == 1) /* you may not mess with init */
goto out;
ret = -ESRCH;
- if (!(child = get_task(pid)))
+ if (!(child = find_task_by_pid(pid)))
goto out;
ret = -EPERM;
if (request == PTRACE_ATTACH) {
diff --git a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c
index 6a6ffdb89..ee2381dba 100644
--- a/arch/ppc/mm/init.c
+++ b/arch/ppc/mm/init.c
@@ -58,69 +58,62 @@ pte_t __bad_page(void)
void show_mem(void)
{
- unsigned long i,free = 0,total = 0,reserved = 0;
- unsigned long shared = 0;
- PTE *ptr;
- unsigned long full = 0, overflow = 0;
- unsigned int ti;
-
- printk("Mem-info:\n");
- show_free_areas();
- printk("Free swap: %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10));
- i = MAP_NR(high_memory);
- while (i-- > 0) {
- total++;
- if (PageReserved(mem_map+i))
- reserved++;
- else if (!atomic_read(&mem_map[i].count))
- free++;
- else
- shared += atomic_read(&mem_map[i].count) - 1;
- }
- printk("%lu pages of RAM\n",total);
- printk("%lu free pages\n",free);
- printk("%lu reserved pages\n",reserved);
- printk("%lu pages shared\n",shared);
- show_buffers();
+ struct task_struct *p;
+ unsigned long i,free = 0,total = 0,reserved = 0;
+ unsigned long shared = 0;
+ PTE *ptr;
+ unsigned long full = 0, overflow = 0;
+ unsigned int ti;
+
+ printk("Mem-info:\n");
+ show_free_areas();
+ printk("Free swap: %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10));
+ i = MAP_NR(high_memory);
+ while (i-- > 0) {
+ total++;
+ if (PageReserved(mem_map+i))
+ reserved++;
+ else if (!atomic_read(&mem_map[i].count))
+ free++;
+ else
+ shared += atomic_read(&mem_map[i].count) - 1;
+ }
+ printk("%lu pages of RAM\n",total);
+ printk("%lu free pages\n",free);
+ printk("%lu reserved pages\n",reserved);
+ printk("%lu pages shared\n",shared);
+ show_buffers();
#ifdef CONFIG_NET
- show_net_buffers();
+ show_net_buffers();
#endif
#ifdef HASHSTATS
- printk("Hash Hits %u entries (buckets)\n",(Hash_size/sizeof(struct _PTE))/8);
- for ( i = 0; i < (Hash_size/sizeof(struct _PTE))/8; i++ )
- {
- if ( hashhits[i] >= 20 )
- {
- printk("[%lu] \t %lu\n", i,hashhits[i]);
- }
- }
+ printk("Hash Hits %u entries (buckets)\n",(Hash_size/sizeof(struct _PTE))/8);
+ for ( i = 0; i < (Hash_size/sizeof(struct _PTE))/8; i++ ) {
+ if ( hashhits[i] >= 20 )
+ printk("[%lu] \t %lu\n", i,hashhits[i]);
+ }
#endif
- for ( ptr = Hash ; ptr <= Hash+Hash_size ; ptr++)
- {
- if (ptr->v)
- {
- full++;
- if (ptr->h == 1)
- overflow++;
- }
- }
- printk("Hash Table: %dkB Buckets: %dk PTEs: %d/%d (%%%d full) %d overflowed\n",
- Hash_size>>10, (Hash_size/(sizeof(PTE)*8)) >> 10,
- full,Hash_size/sizeof(PTE),
- (full*100)/(Hash_size/sizeof(PTE)),
- overflow);
- printk(" Task context vsid0\n");
- for ( ti = 0; ti < NR_TASKS ; ti++ );
- {
- if ( task[ti] )
- {
- printk("%5d %8x %8x\n",
- task[ti]->pid,task[ti]->mm->context,
- ((SEGREG *)task[ti]->tss.segs)[0].vsid);
- }
- }
-
+ for ( ptr = Hash ; ptr <= Hash+Hash_size ; ptr++) {
+ if (ptr->v) {
+ full++;
+ if (ptr->h == 1)
+ overflow++;
+ }
+ }
+ printk("Hash Table: %dkB Buckets: %dk PTEs: %d/%d (%%%d full) %d overflowed\n",
+ Hash_size>>10, (Hash_size/(sizeof(PTE)*8)) >> 10,
+ full,Hash_size/sizeof(PTE),
+ (full*100)/(Hash_size/sizeof(PTE)),
+ overflow);
+ printk(" Task context vsid0\n");
+ read_lock(&tasklist_lock);
+ for_each_task(p) {
+ printk("%5d %8x %8x\n",
+ p->pid,p->mm->context,
+ ((SEGREG *)p->tss.segs)[0].vsid);
+ }
+ read_unlock(&tasklist_lock);
}
extern unsigned long free_area_init(unsigned long, unsigned long);
diff --git a/arch/sparc/Makefile b/arch/sparc/Makefile
index 587cfc616..92c73de32 100644
--- a/arch/sparc/Makefile
+++ b/arch/sparc/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.27 1997/04/07 06:54:08 davem Exp $
+# $Id: Makefile,v 1.28 1997/05/01 01:41:21 davem Exp $
# sparc/Makefile
#
# Makefile for the architecture dependent flags and dependencies on the
@@ -21,7 +21,7 @@ CFLAGS := $(CFLAGS) -pipe -fcall-used-g5 -fcall-used-g7
#LINKFLAGS = -N -Ttext 0xf0004000
LINKFLAGS = -T arch/sparc/vmlinux.lds
-HEAD := arch/sparc/kernel/head.o
+HEAD := arch/sparc/kernel/head.o arch/sparc/kernel/init_task.o
SUBDIRS := $(SUBDIRS) arch/sparc/kernel arch/sparc/lib arch/sparc/mm \
arch/sparc/prom
diff --git a/arch/sparc/ap1000/bnet.c b/arch/sparc/ap1000/bnet.c
index 9305b0a55..974501d79 100644
--- a/arch/sparc/ap1000/bnet.c
+++ b/arch/sparc/ap1000/bnet.c
@@ -872,12 +872,12 @@ static void reply_kill(struct cap_request *req)
len = req->size - sizeof(*req);
if (len == 0) {
int pid = req->data[1];
- for_each_task(p)
- if (p->pid == pid) {
- send_sig(sig,p,1);
- return;
- }
- printk("cell %d: no task with pid %d\n",mpp_cid(),pid);
+ p = find_task_by_pid(pid);
+
+ if(p)
+ send_sig(sig, p, 1);
+ else
+ printk("cell %d: no task with pid %d\n",mpp_cid(),pid);
return;
}
@@ -889,9 +889,11 @@ static void reply_kill(struct cap_request *req)
read_bif(name,len);
name[len] = 0;
+ read_lock(&tasklist_lock);
for_each_task(p)
if (strcmp(name,p->comm) == 0)
send_sig(sig,p,1);
+ read_unlock(&tasklist_lock);
}
diff --git a/arch/sparc/ap1000/hw.c b/arch/sparc/ap1000/hw.c
index c36150c4e..aabe15a3b 100644
--- a/arch/sparc/ap1000/hw.c
+++ b/arch/sparc/ap1000/hw.c
@@ -86,14 +86,21 @@ static void show_task(struct task_struct *t)
static void show_ptasks(void)
{
extern struct task_struct *task[];
+ struct task_struct *p;
int i;
int count=0;
- for (i=MPP_TASK_BASE;i<NR_TASKS;i++)
- if (task[i]) {
- show_task(task[i]);
+ read_lock(&tasklist_lock);
+ for_each_task(p) {
+ struct task_struct **tp = p->tarray_ptr;
+
+ if(tp >= &task[MPP_TASK_BASE]) {
+ show_task(p);
count++;
}
+ }
+ read_unlock(&tasklist_lock);
+
if (count == 0)
printk("no parallel tasks on cell %d\n",mpp_cid());
}
@@ -101,14 +108,18 @@ static void show_ptasks(void)
static void show_utasks(void)
{
extern struct task_struct *task[];
+ struct task_struct *p;
int i;
int count=0;
- for (i=0;i<NR_TASKS;i++)
- if (task[i] && task[i]->uid > 1) {
+ read_lock(&tasklist_lock);
+ for_each_task(p) {
+ if(p->uid > 1) {
show_task(task[i]);
count++;
}
+ }
+ read_unlock(&tasklist_lock);
if (count == 0)
printk("no user tasks on cell %d\n",mpp_cid());
@@ -118,15 +129,19 @@ static void show_utasks(void)
static void show_otasks(void)
{
extern struct task_struct *task[];
+ struct task_struct *p;
int i;
int count=0;
extern int ap_current_uid;
- for (i=0;i<NR_TASKS;i++)
- if (task[i] && task[i]->uid == ap_current_uid) {
+ read_lock(&tasklist_lock);
+ for_each_task(p) {
+ if(p->uid == ap_current_uid) {
show_task(task[i]);
count++;
}
+ }
+ read_unlock(&tasklist_lock);
if (count == 0)
printk("no tasks on cell %d\n",mpp_cid());
diff --git a/arch/sparc/ap1000/mpp.c b/arch/sparc/ap1000/mpp.c
index 021c1a2e5..84ef7f28e 100644
--- a/arch/sparc/ap1000/mpp.c
+++ b/arch/sparc/ap1000/mpp.c
@@ -66,6 +66,7 @@ int mpp_weight(struct task_struct *tsk)
if (block_parallel_tasks) return -1000;
+ /* XXX task[] fixme */
if (last_task && last_task != tsk->taskid && task[last_task] &&
!msc_switch_ok()) return -1000;
diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile
index f73a52fb3..d3307e463 100644
--- a/arch/sparc/kernel/Makefile
+++ b/arch/sparc/kernel/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.39 1997/04/01 02:21:44 davem Exp $
+# $Id: Makefile,v 1.40 1997/05/01 01:40:36 davem Exp $
# Makefile for the linux kernel.
#
# Note! Dependencies are done automagically by 'make dep', which also
@@ -28,7 +28,7 @@ else
CHECKASM_CC = $(CC)
endif
-all: kernel.o head.o
+all: kernel.o head.o init_task.o
O_TARGET := kernel.o
IRQ_OBJS := irq.o sun4m_irq.o sun4c_irq.o
diff --git a/arch/sparc/kernel/etrap.S b/arch/sparc/kernel/etrap.S
index b93094919..fc6c4cead 100644
--- a/arch/sparc/kernel/etrap.S
+++ b/arch/sparc/kernel/etrap.S
@@ -1,4 +1,4 @@
-/* $Id: etrap.S,v 1.23 1997/03/04 16:26:25 jj Exp $
+/* $Id: etrap.S,v 1.26 1997/05/01 08:53:32 davem Exp $
* etrap.S: Sparc trap window preparation for entry into the
* Linux kernel.
*
@@ -129,15 +129,23 @@ tsetup_patch2:
trap_setup_from_user:
/* We can't use %curptr yet. */
LOAD_CURRENT(t_kstack, t_twinmask)
+
+ mov 1, %t_twinmask
+ sll %t_twinmask, (PAGE_SHIFT + 1), %t_twinmask
+ sub %t_twinmask, (TRACEREG_SZ + REGWIN_SZ), %t_twinmask
+ add %t_kstack, %t_twinmask, %t_kstack
+
mov 1, %t_twinmask
- ld [%t_kstack + AOFF_task_saved_kernel_stack], %t_kstack
sll %t_twinmask, %t_psr, %t_twinmask ! t_twinmask = (1 << psr)
/* Build pt_regs frame. */
STORE_PT_ALL(t_kstack, t_psr, t_pc, t_npc, g2)
/* Clear current->tss.w_saved */
- LOAD_CURRENT(curptr, g1)
+ mov 1, %curptr
+ sll %curptr, (PAGE_SHIFT + 1), %curptr
+ sub %curptr, (TRACEREG_SZ + REGWIN_SZ), %curptr
+ sub %t_kstack, %curptr, %curptr
st %g0, [%curptr + AOFF_task_tss + AOFF_thread_w_saved]
/* See if we are in the trap window. */
diff --git a/arch/sparc/kernel/head.S b/arch/sparc/kernel/head.S
index eea3528bf..90965e26e 100644
--- a/arch/sparc/kernel/head.S
+++ b/arch/sparc/kernel/head.S
@@ -1,4 +1,4 @@
-/* $Id: head.S,v 1.81 1997/04/16 07:15:48 davem Exp $
+/* $Id: head.S,v 1.82 1997/05/01 01:40:38 davem Exp $
* head.S: The initial boot code for the Sparc port of Linux.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -393,12 +393,6 @@ C_LABEL(trapbase_cpu3):
BAD_TRAP(0xf7) BAD_TRAP(0xf8) BAD_TRAP(0xf9) BAD_TRAP(0xfa) BAD_TRAP(0xfb)
BAD_TRAP(0xfc) BAD_TRAP(0xfd) BAD_TRAP(0xfe) BAD_TRAP(0xff)
- .globl C_LABEL(cpu0_stack), C_LABEL(cpu1_stack), C_LABEL(cpu2_stack)
- .globl C_LABEL(cpu3_stack)
-C_LABEL(cpu0_stack): .skip 0x2000
-C_LABEL(cpu1_stack): .skip 0x2000
-C_LABEL(cpu2_stack): .skip 0x2000
-C_LABEL(cpu3_stack): .skip 0x2000
#endif
.skip 4096
@@ -742,6 +736,9 @@ go_to_highmem:
jmpl %g1, %g0
nop
+ /* This is to align init_task_union properly, be careful. -DaveM */
+ .align 8192
+
/* The code above should be at beginning and we have to take care about
* short jumps, as branching to .text.init section from .text is usually
* impossible */
@@ -986,12 +983,10 @@ sun4c_continue_boot:
/* Initialize the umask value for init_task just in case.
* But first make current_set[0] point to something useful.
*/
- set C_LABEL(init_task), %g6
+ set C_LABEL(init_task_union), %g6
set C_LABEL(current_set), %g2
st %g6, [%g2]
- set C_LABEL(bootup_kernel_stack), %g3
- st %g3, [%g6 + AOFF_task_kernel_stack_page]
st %g0, [%g6 + AOFF_task_tss + AOFF_thread_uwinmask]
/* Compute NWINDOWS and stash it away. Now uses %wim trick explained
diff --git a/arch/sparc/kernel/init_task.c b/arch/sparc/kernel/init_task.c
new file mode 100644
index 000000000..d0fc09346
--- /dev/null
+++ b/arch/sparc/kernel/init_task.c
@@ -0,0 +1,18 @@
+#include <linux/mm.h>
+#include <linux/sched.h>
+
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+
+static struct vm_area_struct init_mmap = INIT_MMAP;
+static struct fs_struct init_fs = INIT_FS;
+static struct files_struct init_files = INIT_FILES;
+static struct signal_struct init_signals = INIT_SIGNALS;
+struct mm_struct init_mm = INIT_MM;
+
+/* .text section in head.S is aligned at 2 page boundry and this gets linked
+ * right after that so that the init_task_union is aligned properly as well.
+ * We really don't need this special alignment like the Intel does, but
+ * I do it anyways for completeness.
+ */
+union task_union init_task_union __attribute__((__section__(".text"))) = { INIT_TASK };
diff --git a/arch/sparc/kernel/irq.c b/arch/sparc/kernel/irq.c
index 70042857f..b22f008a1 100644
--- a/arch/sparc/kernel/irq.c
+++ b/arch/sparc/kernel/irq.c
@@ -1,4 +1,4 @@
-/* $Id: irq.c,v 1.72 1997/04/20 11:41:26 ecd Exp $
+/* $Id: irq.c,v 1.75 1997/05/08 20:57:37 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
@@ -313,8 +313,180 @@ spinlock_t global_bh_lock = SPIN_LOCK_UNLOCKED;
/* Global IRQ locking depth. */
atomic_t global_irq_count = ATOMIC_INIT(0);
+#ifdef DEBUG_IRQLOCK
+
+static unsigned long previous_irqholder;
+
+#undef INIT_STUCK
+#define INIT_STUCK 100000000
+
+#undef STUCK
+#define STUCK \
+if (!--stuck) {printk("wait_on_irq CPU#%d stuck at %08lx, waiting for %08lx (local=%d, global=%d)\n", cpu, where, previous_irqholder, local_count, atomic_read(&global_irq_count)); stuck = INIT_STUCK; }
+
+static inline void wait_on_irq(int cpu, unsigned long where)
+{
+ int stuck = INIT_STUCK;
+ int local_count = local_irq_count[cpu];
+
+ /* Are we the only one in an interrupt context? */
+ while (local_count != atomic_read(&global_irq_count)) {
+ /*
+ * No such luck. Now we need to release the lock,
+ * _and_ release our interrupt context, because
+ * otherwise we'd have dead-locks and live-locks
+ * and other fun things.
+ */
+ atomic_sub(local_count, &global_irq_count);
+ spin_unlock(&global_irq_lock);
+
+ /*
+ * Wait for everybody else to go away and release
+ * their things before trying to get the lock again.
+ */
+ for (;;) {
+ STUCK;
+ if (atomic_read(&global_irq_count))
+ continue;
+ if (*((unsigned char *)&global_irq_lock))
+ continue;
+ if (spin_trylock(&global_irq_lock))
+ break;
+ }
+ atomic_add(local_count, &global_irq_count);
+ }
+}
+
+#undef INIT_STUCK
+#define INIT_STUCK 10000000
+
+#undef STUCK
+#define STUCK \
+if (!--stuck) {printk("get_irqlock stuck at %08lx, waiting for %08lx\n", where, previous_irqholder); stuck = INIT_STUCK;}
+
+static inline void get_irqlock(int cpu, unsigned long where)
+{
+ int stuck = INIT_STUCK;
+
+ if (!spin_trylock(&global_irq_lock)) {
+ /* do we already hold the lock? */
+ if ((unsigned char) cpu == global_irq_holder)
+ return;
+ /* Uhhuh.. Somebody else got it. Wait.. */
+ do {
+ do {
+ STUCK;
+ barrier();
+ } while (*((unsigned char *)&global_irq_lock));
+ } while (!spin_trylock(&global_irq_lock));
+ }
+ /*
+ * Ok, we got the lock bit.
+ * But that's actually just the easy part.. Now
+ * we need to make sure that nobody else is running
+ * in an interrupt context.
+ */
+ wait_on_irq(cpu, where);
+
+ /*
+ * Finally.
+ */
+ global_irq_holder = cpu;
+ previous_irqholder = where;
+}
+
+void __global_cli(void)
+{
+ int cpu = smp_processor_id();
+ unsigned long where;
+
+ __asm__("mov %%i7, %0" : "=r" (where));
+ __cli();
+ get_irqlock(cpu, where);
+}
+
+void __global_sti(void)
+{
+ release_irqlock(smp_processor_id());
+ __sti();
+}
+
+unsigned long __global_save_flags(void)
+{
+ return global_irq_holder == (unsigned char) smp_processor_id();
+}
+
+void __global_restore_flags(unsigned long flags)
+{
+ if(flags & 1) {
+ __global_cli();
+ } else {
+ /* release_irqlock() */
+ if(global_irq_holder == smp_processor_id()) {
+ global_irq_holder = NO_PROC_ID;
+ spin_unlock(&global_irq_lock);
+ }
+ if(!(flags & 2))
+ __sti();
+ }
+}
+
+#undef INIT_STUCK
+#define INIT_STUCK 200000000
+
+#undef STUCK
+#define STUCK \
+if (!--stuck) {printk("irq_enter stuck (irq=%d, cpu=%d, global=%d)\n",irq,cpu,global_irq_holder); stuck = INIT_STUCK;}
+
+#define VERBOSE_IRQLOCK_DEBUGGING
+
+void irq_enter(int cpu, int irq, void *_opaque)
+{
+#ifdef VERBOSE_IRQLOCK_DEBUGGING
+ extern void smp_show_backtrace_all_cpus(void);
+#endif
+ int stuck = INIT_STUCK;
+
+ hardirq_enter(cpu);
+ barrier();
+ while (*((unsigned char *)&global_irq_lock)) {
+ if ((unsigned char) cpu == global_irq_holder) {
+ struct pt_regs *regs = _opaque;
+ int sbh_cnt = atomic_read(&__sparc_bh_counter);
+ int globl_locked = *((unsigned char *)&global_irq_lock);
+ int globl_icount = atomic_read(&global_irq_count);
+ int local_count = local_irq_count[cpu];
+ unsigned long pc = regs->pc;
+
+ /* It is very important that we load the state variables
+ * before we do the first call to printk() as printk()
+ * could end up changing them...
+ */
+
+ printk("CPU[%d]: BAD! Local IRQ's enabled, global disabled "
+ "interrupt at PC[%08lx]\n", cpu, pc);
+ printk("CPU[%d]: bhcnt[%d] glocked[%d] gicnt[%d] licnt[%d]\n",
+ cpu, sbh_cnt, globl_locked, globl_icount, local_count);
+#ifdef VERBOSE_IRQLOCK_DEBUGGING
+ printk("Performing backtrace on all cpus, write this down!\n");
+ smp_show_backtrace_all_cpus();
+#endif
+ break;
+ }
+ STUCK;
+ barrier();
+ }
+}
+
+void irq_exit(int cpu, int irq)
+{
+ hardirq_exit(cpu);
+ release_irqlock(cpu);
+}
+
+#endif /* DEBUG_IRQLOCK */
+
/* There has to be a better way. */
-/* XXX Must write faster version in irqlock.S -DaveM */
void synchronize_irq(void)
{
int cpu = smp_processor_id();
@@ -371,7 +543,7 @@ void handler_irq(int irq, struct pt_regs * regs)
if(irq < 10)
smp_irq_rotate(cpu);
#endif
- irq_enter(cpu, cpu_irq);
+ irq_enter(cpu, cpu_irq, regs);
action = *(cpu_irq + irq_action);
kstat.interrupts[cpu_irq]++;
do {
@@ -392,7 +564,7 @@ void sparc_floppy_irq(int irq, void *dev_id, struct pt_regs *regs)
int cpu = smp_processor_id();
disable_pil_irq(irq);
- irq_enter(cpu, irq);
+ irq_enter(cpu, irq, regs);
floppy_interrupt(irq, dev_id, regs);
irq_exit(cpu, irq);
enable_pil_irq(irq);
diff --git a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c
index 96c57e963..1adc9e817 100644
--- a/arch/sparc/kernel/process.c
+++ b/arch/sparc/kernel/process.c
@@ -1,4 +1,4 @@
-/* $Id: process.c,v 1.93 1997/04/11 08:55:40 davem Exp $
+/* $Id: process.c,v 1.98 1997/05/14 20:44:54 davem Exp $
* linux/arch/sparc/kernel/process.c
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -41,6 +41,8 @@
extern void fpsave(unsigned long *, unsigned long *, void *, unsigned long *);
+struct task_struct *current_set[NR_CPUS] = {&init_task, };
+
#ifndef __SMP__
#define SUN4C_FAULT_HIGH 100
@@ -192,6 +194,37 @@ void show_regwindow(struct reg_window *rw)
rw->ins[4], rw->ins[5], rw->ins[6], rw->ins[7]);
}
+static spinlock_t sparc_backtrace_lock = SPIN_LOCK_UNLOCKED;
+
+void show_backtrace(void)
+{
+ struct reg_window *rw;
+ unsigned long flags;
+ unsigned long fp;
+ int cpu = smp_processor_id();
+
+ spin_lock_irqsave(&sparc_backtrace_lock, flags);
+ __asm__ __volatile__("mov %%i6, %0" : "=r" (fp));
+ rw = (struct reg_window *) fp;
+ while(rw) {
+ printk("CPU[%d]: ARGS[%08lx,%08lx,%08lx,%08lx,%08lx,%08lx] "
+ "FP[%08lx] CALLER[%08lx]\n", cpu,
+ rw->ins[0], rw->ins[1], rw->ins[2], rw->ins[3],
+ rw->ins[4], rw->ins[5],
+ rw->ins[6],
+ rw->ins[7]);
+ rw = (struct reg_window *) rw->ins[6];
+ }
+ spin_unlock_irqrestore(&sparc_backtrace_lock, flags);
+}
+
+#ifdef __SMP__
+void smp_show_backtrace_all_cpus(void)
+{
+ xc0((smpfunc_t) show_backtrace);
+}
+#endif
+
void show_stackframe(struct sparc_stackf *sf)
{
unsigned long size;
@@ -441,12 +474,12 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
if(regs->psr & PSR_PS)
stack_offset -= REGWIN_SZ;
- childregs = ((struct pt_regs *) (p->kernel_stack_page + stack_offset));
+ childregs = ((struct pt_regs *) (((unsigned long)p) + stack_offset));
copy_regs(childregs, regs);
new_stack = (((struct reg_window *) childregs) - 1);
copy_regwin(new_stack, (((struct reg_window *) regs) - 1));
- p->tss.ksp = p->saved_kernel_stack = (unsigned long) new_stack;
+ p->tss.ksp = (unsigned long) new_stack;
#ifdef __SMP__
p->tss.kpc = (((unsigned long) ret_from_smpfork) - 0x8);
p->tss.kpsr = current->tss.fork_kpsr | PSR_PIL;
@@ -467,7 +500,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
p->tss.flags &= ~SPARC_FLAG_KTHREAD;
p->tss.current_ds = USER_DS;
- if (sp != current->tss.kregs->u_regs[UREG_FP]) {
+ if (sp != regs->u_regs[UREG_FP]) {
struct sparc_stackf *childstack;
struct sparc_stackf *parentstack;
@@ -475,9 +508,8 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
* This is a clone() call with supplied user stack.
* Set some valid stack frames to give to the child.
*/
- childstack = (struct sparc_stackf *)sp;
- parentstack = (struct sparc_stackf *)
- current->tss.kregs->u_regs[UREG_FP];
+ childstack = (struct sparc_stackf *) sp;
+ parentstack = (struct sparc_stackf *) regs->u_regs[UREG_FP];
#if 0
printk("clone: parent stack:\n");
diff --git a/arch/sparc/kernel/ptrace.c b/arch/sparc/kernel/ptrace.c
index 647081eda..732b3006d 100644
--- a/arch/sparc/kernel/ptrace.c
+++ b/arch/sparc/kernel/ptrace.c
@@ -24,18 +24,6 @@
#define MAGIC_CONSTANT 0x80000000
-/* change a pid into a task struct. */
-static inline struct task_struct * get_task(int pid)
-{
- int i;
-
- for (i = 1; i < NR_TASKS; i++) {
- if (task[i] != NULL && (task[i]->pid == pid))
- return task[i];
- }
- return NULL;
-}
-
/*
* This routine gets a long from any process space by following the page
* tables. NOTE! You should check that the long isn't on a page boundary,
@@ -53,7 +41,7 @@ static unsigned long get_long(struct task_struct * tsk,
repeat:
pgdir = pgd_offset(vma->vm_mm, addr);
if (pgd_none(*pgdir)) {
- do_no_page(tsk, vma, addr, 0);
+ handle_mm_fault(tsk, vma, addr, 0);
goto repeat;
}
if (pgd_bad(*pgdir)) {
@@ -63,7 +51,7 @@ repeat:
}
pgmiddle = pmd_offset(pgdir, addr);
if (pmd_none(*pgmiddle)) {
- do_no_page(tsk, vma, addr, 0);
+ handle_mm_fault(tsk, vma, addr, 0);
goto repeat;
}
if (pmd_bad(*pgmiddle)) {
@@ -73,7 +61,7 @@ repeat:
}
pgtable = pte_offset(pgmiddle, addr);
if (!pte_present(*pgtable)) {
- do_no_page(tsk, vma, addr, 0);
+ handle_mm_fault(tsk, vma, addr, 0);
goto repeat;
}
page = pte_page(*pgtable);
@@ -106,7 +94,7 @@ static void put_long(struct task_struct * tsk, struct vm_area_struct * vma,
repeat:
pgdir = pgd_offset(vma->vm_mm, addr);
if (!pgd_present(*pgdir)) {
- do_no_page(tsk, vma, addr, 1);
+ handle_mm_fault(tsk, vma, addr, 1);
goto repeat;
}
if (pgd_bad(*pgdir)) {
@@ -116,7 +104,7 @@ repeat:
}
pgmiddle = pmd_offset(pgdir, addr);
if (pmd_none(*pgmiddle)) {
- do_no_page(tsk, vma, addr, 1);
+ handle_mm_fault(tsk, vma, addr, 1);
goto repeat;
}
if (pmd_bad(*pgmiddle)) {
@@ -126,12 +114,12 @@ repeat:
}
pgtable = pte_offset(pgmiddle, addr);
if (!pte_present(*pgtable)) {
- do_no_page(tsk, vma, addr, 1);
+ handle_mm_fault(tsk, vma, addr, 1);
goto repeat;
}
page = pte_page(*pgtable);
if (!pte_write(*pgtable)) {
- do_wp_page(tsk, vma, addr, 1);
+ handle_mm_fault(tsk, vma, addr, 1);
goto repeat;
}
/* this is a hack for non-kernel-mapped video buffers and similar */
@@ -533,7 +521,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
goto out;
}
#endif
- if(!(child = get_task(pid))) {
+ if(!(child = find_task_by_pid(pid))) {
pt_error_return(regs, ESRCH);
goto out;
}
diff --git a/arch/sparc/kernel/setup.c b/arch/sparc/kernel/setup.c
index f2af0b763..aa204db06 100644
--- a/arch/sparc/kernel/setup.c
+++ b/arch/sparc/kernel/setup.c
@@ -1,4 +1,4 @@
-/* $Id: setup.c,v 1.83 1997/04/01 02:21:49 davem Exp $
+/* $Id: setup.c,v 1.84 1997/05/08 17:45:16 davem Exp $
* linux/arch/sparc/kernel/setup.c
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -83,7 +83,8 @@ void prom_sync_me(void)
#ifdef __SMP__
global_irq_holder = NO_PROC_ID;
- global_irq_lock = global_bh_lock = 0;
+ *((unsigned char *)&global_irq_lock) = 0;
+ *((unsigned char *)&global_bh_lock) = 0;
#endif
__save_and_cli(flags);
__asm__ __volatile__("rd %%tbr, %0\n\t" : "=r" (prom_tbr));
diff --git a/arch/sparc/kernel/signal.c b/arch/sparc/kernel/signal.c
index 8a07ae0be..fd5fa634e 100644
--- a/arch/sparc/kernel/signal.c
+++ b/arch/sparc/kernel/signal.c
@@ -1,4 +1,4 @@
-/* $Id: signal.c,v 1.73 1997/04/16 05:56:05 davem Exp $
+/* $Id: signal.c,v 1.74 1997/05/15 19:57:09 davem Exp $
* linux/arch/sparc/kernel/signal.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
@@ -780,8 +780,10 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs,
case SIGQUIT: case SIGILL: case SIGTRAP:
case SIGABRT: case SIGFPE: case SIGSEGV: case SIGBUS:
if(current->binfmt && current->binfmt->core_dump) {
+ lock_kernel();
if(current->binfmt->core_dump(signr, regs))
signr |= 0x80;
+ unlock_kernel();
}
#ifdef DEBUG_SIGNALS
/* Very useful to debug dynamic linker problems */
diff --git a/arch/sparc/kernel/smp.c b/arch/sparc/kernel/smp.c
index 6622f88f0..beef2df14 100644
--- a/arch/sparc/kernel/smp.c
+++ b/arch/sparc/kernel/smp.c
@@ -4,16 +4,18 @@
*/
#include <asm/head.h>
-#include <asm/ptrace.h>
-#include <asm/atomic.h>
#include <linux/kernel.h>
+#include <linux/sched.h>
#include <linux/tasks.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <linux/kernel_stat.h>
+#include <asm/ptrace.h>
+#include <asm/atomic.h>
+
#include <asm/delay.h>
#include <asm/irq.h>
#include <asm/page.h>
@@ -24,6 +26,9 @@
#include <asm/hardirq.h>
#include <asm/softirq.h>
+#define __KERNEL_SYSCALLS__
+#include <linux/unistd.h>
+
#define IRQ_RESCHEDULE 13
#define IRQ_STOP_CPU 14
#define IRQ_CROSS_CALL 15
@@ -33,6 +38,9 @@ extern int linux_num_cpus;
extern void calibrate_delay(void);
+/* XXX Let's get rid of this thing if we can... */
+extern struct task_struct *current_set[NR_CPUS];
+
volatile int smp_processors_ready = 0;
unsigned long cpu_present_map = 0;
@@ -118,16 +126,6 @@ void smp_store_cpu_info(int id)
cpu_data[id].udelay_val = loops_per_sec; /* this is it on sparc. */
}
-/*
- * Architecture specific routine called by the kernel just before init is
- * fired off. This allows the BP to have everything in order [we hope].
- * At the end of this all the AP's will hit the system scheduling and off
- * we go. Each AP will load the system gdt's and jump through the kernel
- * init into idle(). At this point the scheduler will one day take over
- * and give them jobs to do. smp_callin is a standard routine
- * we use to track CPU's as they power up.
- */
-
void smp_commence(void)
{
/*
@@ -144,7 +142,7 @@ static void smp_setup_percpu_timer(void);
void smp_callin(void)
{
- int cpuid = smp_processor_id();
+ int cpuid = hard_smp_processor_id();
local_flush_cache_all();
local_flush_tlb_all();
@@ -183,6 +181,25 @@ void smp_callin(void)
__sti();
}
+extern int cpu_idle(void *unused);
+extern void init_IRQ(void);
+
+/* Only broken Intel needs this, thus it should not even be referenced
+ * globally...
+ */
+void initialize_secondary(void)
+{
+}
+
+/* Activate a secondary processor. */
+int start_secondary(void *unused)
+{
+ trap_init();
+ init_IRQ();
+ smp_callin();
+ return cpu_idle(NULL);
+}
+
void cpu_panic(void)
{
printk("CPU[%d]: Returns from cpu_idle!\n", smp_processor_id());
@@ -220,6 +237,7 @@ void smp_boot_cpus(void)
cpu_number_map[boot_cpu_id] = 0;
cpu_logical_map[0] = boot_cpu_id;
klock_info.akp = boot_cpu_id;
+ current->processor = boot_cpu_id;
smp_store_cpu_info(boot_cpu_id);
set_irq_udt(mid_xlate[boot_cpu_id]);
smp_setup_percpu_timer();
@@ -233,10 +251,19 @@ void smp_boot_cpus(void)
if(cpu_present_map & (1 << i)) {
extern unsigned long sparc_cpu_startup;
unsigned long *entry = &sparc_cpu_startup;
+ struct task_struct *p;
int timeout;
+ /* Cook up an idler for this guy. */
+ kernel_thread(start_secondary, NULL, CLONE_PID);
+
+ p = task[++cpucount];
+
+ p->processor = i;
+ current_set[i] = p;
+
/* See trampoline.S for details... */
- entry += ((i-1) * 6);
+ entry += ((i-1) * 3);
/* whirrr, whirrr, whirrrrrrrrr... */
printk("Starting CPU %d at %p\n", i, entry);
@@ -253,10 +280,10 @@ void smp_boot_cpus(void)
}
if(cpu_callin_map[i]) {
/* Another "Red Snapper". */
- cpucount++;
cpu_number_map[i] = i;
cpu_logical_map[i] = i;
} else {
+ cpucount--;
printk("Processor %d is stuck.\n", i);
}
}
@@ -364,26 +391,17 @@ struct smp_funcall {
unsigned long processors_out[NR_CPUS]; /* Set when ipi exited. */
} ccall_info;
-/* Returns failure code if for example any of the cpu's failed to respond
- * within a certain timeout period.
- */
-
-#define CCALL_TIMEOUT 5000000 /* enough for initial testing */
-
static spinlock_t cross_call_lock = SPIN_LOCK_UNLOCKED;
/* Cross calls must be serialized, at least currently. */
void smp_cross_call(smpfunc_t func, unsigned long arg1, unsigned long arg2,
unsigned long arg3, unsigned long arg4, unsigned long arg5)
{
- unsigned long me = smp_processor_id();
- unsigned long flags, mask;
- int i, timeout;
-
if(smp_processors_ready) {
- __save_flags(flags);
- __cli();
- spin_lock(&cross_call_lock);
+ register int ncpus = smp_num_cpus;
+ unsigned long flags;
+
+ spin_lock_irqsave(&cross_call_lock, flags);
/* Init function glue. */
ccall_info.func = func;
@@ -393,56 +411,47 @@ void smp_cross_call(smpfunc_t func, unsigned long arg1, unsigned long arg2,
ccall_info.arg4 = arg4;
ccall_info.arg5 = arg5;
- /* Init receive/complete mapping. */
- for(i = 0; i < smp_num_cpus; i++) {
- ccall_info.processors_in[i] = 0;
- ccall_info.processors_out[i] = 0;
+ /* Init receive/complete mapping, plus fire the IPI's off. */
+ {
+ register void (*send_ipi)(int,int) = set_cpu_int;
+ register unsigned long mask;
+ register int i;
+
+ mask = (cpu_present_map & ~(1 << smp_processor_id()));
+ for(i = 0; i < ncpus; i++) {
+ if(mask & (1 << i)) {
+ ccall_info.processors_in[i] = 0;
+ ccall_info.processors_out[i] = 0;
+ send_ipi(mid_xlate[i], IRQ_CROSS_CALL);
+ } else {
+ ccall_info.processors_in[i] = 1;
+ ccall_info.processors_out[i] = 1;
+ }
+ }
}
- ccall_info.processors_in[me] = 1;
- ccall_info.processors_out[me] = 1;
- /* Fire it off. */
- mask = (cpu_present_map & ~(1 << me));
- for(i = 0; i < 4; i++) {
- if(mask & (1 << i))
- set_cpu_int(mid_xlate[i], IRQ_CROSS_CALL);
- }
+ /* First, run local copy. */
+ func(arg1, arg2, arg3, arg4, arg5);
- /* For debugging purposes right now we can timeout
- * on both callin and callexit.
- */
- timeout = CCALL_TIMEOUT;
- for(i = 0; i < smp_num_cpus; i++) {
- while(!ccall_info.processors_in[i] && timeout-- > 0)
- barrier();
- if(!ccall_info.processors_in[i])
- goto procs_time_out;
- }
+ {
+ register int i;
- /* Run local copy. */
- func(arg1, arg2, arg3, arg4, arg5);
+ i = 0;
+ do {
+ while(!ccall_info.processors_in[i])
+ barrier();
+ } while(++i < ncpus);
- /* Spin on proc dispersion. */
- timeout = CCALL_TIMEOUT;
- for(i = 0; i < smp_num_cpus; i++) {
- while(!ccall_info.processors_out[i] && timeout-- > 0)
- barrier();
- if(!ccall_info.processors_out[i])
- goto procs_time_out;
+ i = 0;
+ do {
+ while(!ccall_info.processors_out[i])
+ barrier();
+ } while(++i < ncpus);
}
- spin_unlock(&cross_call_lock);
- __restore_flags(flags);
- return; /* made it... */
-
-procs_time_out:
- printk("smp: Wheee, penguin drops off the bus\n");
- spin_unlock(&cross_call_lock);
- __restore_flags(flags);
- return; /* why me... why me... */
- }
- /* Just need to run local copy. */
- func(arg1, arg2, arg3, arg4, arg5);
+ spin_unlock_irqrestore(&cross_call_lock, flags);
+ } else
+ func(arg1, arg2, arg3, arg4, arg5); /* Just need to run local copy. */
}
void smp_flush_cache_all(void)
@@ -453,43 +462,98 @@ void smp_flush_tlb_all(void)
void smp_flush_cache_mm(struct mm_struct *mm)
{
- if(mm->context != NO_CONTEXT)
- xc1((smpfunc_t) local_flush_cache_mm, (unsigned long) mm);
+ if(mm->context != NO_CONTEXT) {
+ if(mm->cpu_vm_mask == (1 << smp_processor_id()))
+ local_flush_cache_mm(mm);
+ else
+ xc1((smpfunc_t) local_flush_cache_mm, (unsigned long) mm);
+ }
}
void smp_flush_tlb_mm(struct mm_struct *mm)
{
- if(mm->context != NO_CONTEXT)
- xc1((smpfunc_t) local_flush_tlb_mm, (unsigned long) mm);
+ if(mm->context != NO_CONTEXT) {
+ if(mm->cpu_vm_mask == (1 << smp_processor_id())) {
+ local_flush_tlb_mm(mm);
+ } else {
+ xc1((smpfunc_t) local_flush_tlb_mm, (unsigned long) mm);
+ if(mm->count == 1 && current->mm == mm)
+ mm->cpu_vm_mask = (1 << smp_processor_id());
+ }
+ }
}
void smp_flush_cache_range(struct mm_struct *mm, unsigned long start,
unsigned long end)
{
- if(mm->context != NO_CONTEXT)
- xc3((smpfunc_t) local_flush_cache_range, (unsigned long) mm,
- start, end);
+ if(mm->context != NO_CONTEXT) {
+ if(mm->cpu_vm_mask == (1 << smp_processor_id()))
+ local_flush_cache_range(mm, start, end);
+ else
+ xc3((smpfunc_t) local_flush_cache_range, (unsigned long) mm,
+ start, end);
+ }
}
void smp_flush_tlb_range(struct mm_struct *mm, unsigned long start,
unsigned long end)
{
- if(mm->context != NO_CONTEXT)
- xc3((smpfunc_t) local_flush_tlb_range, (unsigned long) mm,
- start, end);
+ if(mm->context != NO_CONTEXT) {
+ if(mm->cpu_vm_mask == (1 << smp_processor_id()))
+ local_flush_tlb_range(mm, start, end);
+ else
+ xc3((smpfunc_t) local_flush_tlb_range, (unsigned long) mm,
+ start, end);
+ }
}
void smp_flush_cache_page(struct vm_area_struct *vma, unsigned long page)
-{ xc2((smpfunc_t) local_flush_cache_page, (unsigned long) vma, page); }
+{
+ struct mm_struct *mm = vma->vm_mm;
+
+ if(mm->context != NO_CONTEXT) {
+ if(mm->cpu_vm_mask == (1 << smp_processor_id()))
+ local_flush_cache_page(vma, page);
+ else
+ xc2((smpfunc_t) local_flush_cache_page,
+ (unsigned long) vma, page);
+ }
+}
void smp_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
-{ xc2((smpfunc_t) local_flush_tlb_page, (unsigned long) vma, page); }
+{
+ struct mm_struct *mm = vma->vm_mm;
+
+ if(mm->context != NO_CONTEXT) {
+ if(mm->cpu_vm_mask == (1 << smp_processor_id()))
+ local_flush_tlb_page(vma, page);
+ else
+ xc2((smpfunc_t) local_flush_tlb_page, (unsigned long) vma, page);
+ }
+}
void smp_flush_page_to_ram(unsigned long page)
-{ xc1((smpfunc_t) local_flush_page_to_ram, page); }
+{
+ /* Current theory is that those who call this are the one's
+ * who have just dirtied their cache with the pages contents
+ * in kernel space, therefore we only run this on local cpu.
+ *
+ * XXX This experiment failed, research further... -DaveM
+ */
+#if 1
+ xc1((smpfunc_t) local_flush_page_to_ram, page);
+#else
+ local_flush_page_to_ram(page);
+#endif
+}
void smp_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr)
-{ xc2((smpfunc_t) local_flush_sig_insns, (unsigned long) mm, insn_addr); }
+{
+ if(mm->cpu_vm_mask == (1 << smp_processor_id()))
+ local_flush_sig_insns(mm, insn_addr);
+ else
+ xc2((smpfunc_t) local_flush_sig_insns, (unsigned long) mm, insn_addr);
+}
/* Reschedule call back. */
void smp_reschedule_irq(void)
diff --git a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c
index 645aafb35..38896ab22 100644
--- a/arch/sparc/kernel/sparc_ksyms.c
+++ b/arch/sparc/kernel/sparc_ksyms.c
@@ -1,4 +1,4 @@
-/* $Id: sparc_ksyms.c,v 1.56 1997/04/18 05:44:35 davem Exp $
+/* $Id: sparc_ksyms.c,v 1.59 1997/05/08 17:45:20 davem Exp $
* arch/sparc/kernel/ksyms.c: Sparc specific ksyms support.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -38,6 +38,7 @@
#include <asm/dma.h>
#endif
#include <asm/a.out.h>
+#include <asm/spinlock.h>
struct poll {
int fd;
@@ -50,9 +51,9 @@ extern int svr4_setcontext (svr4_ucontext_t *, struct pt_regs *);
extern unsigned long sunos_mmap(unsigned long, unsigned long, unsigned long,
unsigned long, unsigned long, unsigned long);
void _sigpause_common (unsigned int set, struct pt_regs *);
-extern void __copy_1page(void *, const void *);
+extern void (*__copy_1page)(void *, const void *);
extern void __memmove(void *, const void *, __kernel_size_t);
-extern void *bzero_1page(void *);
+extern void (*bzero_1page)(void *);
extern void *__bzero(void *, size_t);
extern void *__memscan_zero(void *, size_t);
extern void *__memscan_generic(void *, int, size_t);
@@ -87,17 +88,47 @@ EXPORT_SYMBOL(klock_info);
EXPORT_SYMBOL_PRIVATE(_lock_kernel);
EXPORT_SYMBOL_PRIVATE(_unlock_kernel);
EXPORT_SYMBOL_PRIVATE(_spinlock_waitfor);
+#ifdef SPIN_LOCK_DEBUG
+EXPORT_SYMBOL(_spin_lock);
+EXPORT_SYMBOL(_spin_unlock);
+EXPORT_SYMBOL(_spin_trylock);
+EXPORT_SYMBOL(_spin_lock_irq);
+EXPORT_SYMBOL(_spin_unlock_irq);
+EXPORT_SYMBOL(_spin_lock_irqsave);
+EXPORT_SYMBOL(_spin_unlock_irqrestore);
+EXPORT_SYMBOL(_read_lock);
+EXPORT_SYMBOL(_read_unlock);
+EXPORT_SYMBOL(_read_lock_irq);
+EXPORT_SYMBOL(_read_unlock_irq);
+EXPORT_SYMBOL(_read_lock_irqsave);
+EXPORT_SYMBOL(_read_unlock_irqrestore);
+EXPORT_SYMBOL(_write_lock);
+EXPORT_SYMBOL(_write_unlock);
+EXPORT_SYMBOL(_write_lock_irq);
+EXPORT_SYMBOL(_write_unlock_irq);
+EXPORT_SYMBOL(_write_lock_irqsave);
+EXPORT_SYMBOL(_write_unlock_irqrestore);
+#else
EXPORT_SYMBOL_PRIVATE(_rw_read_enter);
EXPORT_SYMBOL_PRIVATE(_rw_read_exit);
EXPORT_SYMBOL_PRIVATE(_rw_write_enter);
+#endif
EXPORT_SYMBOL(__sparc_bh_counter);
#ifdef __SMP__
+#ifdef DEBUG_IRQLOCK
+EXPORT_SYMBOL(irq_enter);
+EXPORT_SYMBOL(irq_exit);
+EXPORT_SYMBOL(__global_restore_flags);
+EXPORT_SYMBOL(__global_sti);
+EXPORT_SYMBOL(__global_cli);
+#else
EXPORT_SYMBOL_PRIVATE(_irq_enter);
EXPORT_SYMBOL_PRIVATE(_irq_exit);
EXPORT_SYMBOL_PRIVATE(_global_restore_flags);
EXPORT_SYMBOL_PRIVATE(_global_sti);
EXPORT_SYMBOL_PRIVATE(_global_cli);
#endif
+#endif
EXPORT_SYMBOL(page_offset);
EXPORT_SYMBOL(stack_top);
diff --git a/arch/sparc/kernel/sys_sunos.c b/arch/sparc/kernel/sys_sunos.c
index 5f5b19504..3fafe7f9c 100644
--- a/arch/sparc/kernel/sys_sunos.c
+++ b/arch/sparc/kernel/sys_sunos.c
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos.c,v 1.78 1997/04/16 05:56:12 davem Exp $
+/* $Id: sys_sunos.c,v 1.79 1997/04/23 23:01:15 ecd Exp $
* sys_sunos.c: SunOS specific syscall compatibility support.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -20,6 +20,7 @@
#include <linux/resource.h>
#include <linux/ipc.h>
#include <linux/shm.h>
+#include <linux/msg.h>
#include <linux/sem.h>
#include <linux/signal.h>
#include <linux/uio.h>
@@ -1031,7 +1032,48 @@ asmlinkage int sunos_semsys(int op, unsigned long arg1, unsigned long arg2,
unlock_kernel();
return ret;
}
-
+
+extern asmlinkage int sys_msgget (key_t key, int msgflg);
+extern asmlinkage int sys_msgrcv (int msqid, struct msgbuf *msgp,
+ size_t msgsz, long msgtyp, int msgflg);
+extern asmlinkage int sys_msgsnd (int msqid, struct msgbuf *msgp,
+ size_t msgsz, int msgflg);
+extern asmlinkage int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf);
+
+asmlinkage int sunos_msgsys(int op, unsigned long arg1, unsigned long arg2,
+ unsigned long arg3, unsigned long arg4)
+{
+ struct sparc_stackf *sp;
+ unsigned long arg5;
+ int rval;
+
+ lock_kernel();
+ switch(op) {
+ case 0:
+ rval = sys_msgget((key_t)arg1, (int)arg2);
+ break;
+ case 1:
+ rval = sys_msgctl((int)arg1, (int)arg2,
+ (struct msqid_ds *)arg3);
+ break;
+ case 2:
+ sp = (struct sparc_stackf *)current->tss.kregs->u_regs[UREG_FP];
+ arg5 = sp->xxargs[0];
+ rval = sys_msgrcv((int)arg1, (struct msgbuf *)arg2,
+ (size_t)arg3, (long)arg4, (int)arg5);
+ break;
+ case 3:
+ rval = sys_msgsnd((int)arg1, (struct msgbuf *)arg2,
+ (size_t)arg3, (int)arg4);
+ break;
+ default:
+ rval = -EINVAL;
+ break;
+ }
+ unlock_kernel();
+ return rval;
+}
+
extern asmlinkage int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr);
extern asmlinkage int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf);
extern asmlinkage int sys_shmdt (char *shmaddr);
diff --git a/arch/sparc/kernel/systbls.S b/arch/sparc/kernel/systbls.S
index 61b41056b..a166e3490 100644
--- a/arch/sparc/kernel/systbls.S
+++ b/arch/sparc/kernel/systbls.S
@@ -1,4 +1,4 @@
-/* $Id: systbls.S,v 1.60 1997/04/19 08:52:15 jj Exp $
+/* $Id: systbls.S,v 1.62 1997/04/23 23:01:08 ecd Exp $
* systbls.S: System call entry point tables for OS compatibility.
* The native Linux system call table lives here also.
*
@@ -106,15 +106,26 @@ C_LABEL(sys_call_table):
.long C_LABEL(sys_nis_syscall), C_LABEL(sys_stime), C_LABEL(sys_nis_syscall)
.long C_LABEL(sys_nis_syscall), C_LABEL(sys_llseek)
/* "We are the Knights of the Forest of Ni!!" */
- .long C_LABEL(sys_mlock), C_LABEL(sys_munlock), C_LABEL(sys_mlockall)
- .long C_LABEL(sys_munlockall), C_LABEL(sys_sched_setparam)
- .long C_LABEL(sys_sched_getparam), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
- .long C_LABEL(sys_nis_syscall), C_LABEL(sys_sched_get_priority_max), C_LABEL(sys_sched_get_priority_min)
- .long C_LABEL(sys_sched_rr_get_interval), C_LABEL(sys_nanosleep)
+ .long C_LABEL(sys_mlock)
+ .long C_LABEL(sys_munlock)
+ .long C_LABEL(sys_mlockall)
+/*240*/ .long C_LABEL(sys_munlockall)
+ .long C_LABEL(sys_sched_setparam)
+ .long C_LABEL(sys_sched_getparam)
+ .long C_LABEL(sys_sched_setscheduler)
+ .long C_LABEL(sys_sched_getscheduler)
+/*245*/ .long C_LABEL(sys_sched_yield)
+ .long C_LABEL(sys_sched_get_priority_max)
+ .long C_LABEL(sys_sched_get_priority_min)
+ .long C_LABEL(sys_sched_rr_get_interval)
+ .long C_LABEL(sys_nanosleep)
/*250*/ .long C_LABEL(sys_mremap)
.long C_LABEL(sys_sysctl)
- .long C_LABEL(sys_getsid), C_LABEL(sys_fdatasync), C_LABEL(sys_nfsservctl)
- .long C_LABEL(sys_aplib), C_LABEL(sys_nis_syscall)
+ .long C_LABEL(sys_getsid)
+ .long C_LABEL(sys_fdatasync)
+ .long C_LABEL(sys_nfsservctl)
+/*255*/ .long C_LABEL(sys_aplib)
+ .long C_LABEL(sys_nis_syscall)
/* Now the SunOS syscall table. */
@@ -179,7 +190,7 @@ C_LABEL(sunos_sys_table):
.long C_LABEL(sunos_getdomainname), C_LABEL(sys_setdomainname)
.long C_LABEL(sunos_nosys), C_LABEL(sys_quotactl), C_LABEL(sunos_nosys)
.long C_LABEL(sunos_mount), C_LABEL(sys_ustat), C_LABEL(sunos_semsys)
- .long C_LABEL(sunos_nosys), C_LABEL(sunos_shmsys), C_LABEL(sunos_audit)
+ .long C_LABEL(sunos_msgsys), C_LABEL(sunos_shmsys), C_LABEL(sunos_audit)
.long C_LABEL(sunos_nosys), C_LABEL(sunos_getdents), C_LABEL(sys_setsid)
.long C_LABEL(sys_fchdir), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
.long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
diff --git a/arch/sparc/kernel/tadpole.c b/arch/sparc/kernel/tadpole.c
index bea6336c5..03fe3cff9 100644
--- a/arch/sparc/kernel/tadpole.c
+++ b/arch/sparc/kernel/tadpole.c
@@ -4,6 +4,8 @@
*/
#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
#include <asm/asi.h>
#include <asm/oplib.h>
diff --git a/arch/sparc/kernel/trampoline.S b/arch/sparc/kernel/trampoline.S
index c59a2531a..9ee5bd14a 100644
--- a/arch/sparc/kernel/trampoline.S
+++ b/arch/sparc/kernel/trampoline.S
@@ -1,4 +1,4 @@
-/* $Id: trampoline.S,v 1.6 1997/04/14 05:38:33 davem Exp $
+/* $Id: trampoline.S,v 1.9 1997/05/01 08:53:34 davem Exp $
* trampoline.S: SMP cpu boot-up trampoline code.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -7,6 +7,7 @@
#include <asm/cprefix.h>
#include <asm/head.h>
#include <asm/psr.h>
+#include <asm/page.h>
#include <asm/asi.h>
#include <asm/ptrace.h>
#include <asm/vaddrs.h>
@@ -25,27 +26,18 @@
C_LABEL(sparc_cpu_startup):
cpu1_startup:
sethi %hi(C_LABEL(trapbase_cpu1)), %g3
- or %g3, %lo(C_LABEL(trapbase_cpu1)), %g3
- sethi %hi(C_LABEL(cpu1_stack)), %g2
- or %g2, %lo(C_LABEL(cpu1_stack)), %g2
b 1f
- nop
+ or %g3, %lo(C_LABEL(trapbase_cpu1)), %g3
cpu2_startup:
sethi %hi(C_LABEL(trapbase_cpu2)), %g3
- or %g3, %lo(C_LABEL(trapbase_cpu2)), %g3
- sethi %hi(C_LABEL(cpu2_stack)), %g2
- or %g2, %lo(C_LABEL(cpu2_stack)), %g2
b 1f
- nop
+ or %g3, %lo(C_LABEL(trapbase_cpu2)), %g3
cpu3_startup:
sethi %hi(C_LABEL(trapbase_cpu3)), %g3
- or %g3, %lo(C_LABEL(trapbase_cpu3)), %g3
- sethi %hi(C_LABEL(cpu3_stack)), %g2
- or %g2, %lo(C_LABEL(cpu3_stack)), %g2
b 1f
- nop
+ or %g3, %lo(C_LABEL(trapbase_cpu3)), %g3
1:
/* Set up a sane %psr -- PIL<0xf> S<0x1> PS<0x1> CWP<0x0> */
@@ -62,14 +54,16 @@ cpu3_startup:
wr %g3, 0x0, %tbr
WRITE_PAUSE
- /* Give ourselves a stack. */
- set 0x2000, %g5
- add %g2, %g5, %g2 ! end of stack
- sub %g2, REGWIN_SZ, %sp
- mov 0, %fp
+ /* Give ourselves a stack and curptr. */
+ set C_LABEL(current_set), %g5
+ srl %g3, 10, %g4
+ and %g4, 0xc, %g4
+ ld [%g5 + %g4], %g6
- /* Set up curptr. */
- set C_LABEL(init_task), %g6
+ mov 1, %sp
+ sll %sp, (PAGE_SHIFT + 1), %sp
+ sub %sp, REGWIN_SZ, %sp
+ add %g6, %sp, %sp
/* Turn on traps (PSR_ET). */
rd %psr, %g1
diff --git a/arch/sparc/kernel/wof.S b/arch/sparc/kernel/wof.S
index bad0088f4..890676bfb 100644
--- a/arch/sparc/kernel/wof.S
+++ b/arch/sparc/kernel/wof.S
@@ -1,4 +1,4 @@
-/* $Id: wof.S,v 1.33 1997/03/04 16:26:35 jj Exp $
+/* $Id: wof.S,v 1.36 1997/05/01 08:53:35 davem Exp $
* wof.S: Sparc window overflow handler.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -234,15 +234,20 @@ spwin_user_stack_is_bolixed:
spnwin_patch3: and %twin_tmp, 0xff, %twin_tmp ! patched on 7win Sparcs
st %twin_tmp, [%curptr + AOFF_task_tss + AOFF_thread_uwinmask]
- /* Jump onto kernel stack for this process... */
- ld [%curptr + AOFF_task_saved_kernel_stack], %sp
+ mov 1, %sp
+ sll %sp, (PAGE_SHIFT + 1), %sp
+ sub %sp, (TRACEREG_SZ + REGWIN_SZ), %sp
+ add %curptr, %sp, %sp
/* Restore the saved globals and build a pt_regs frame. */
mov %saved_g5, %g5
- mov %g6, %l4
mov %saved_g6, %g6
STORE_PT_ALL(sp, t_psr, t_pc, t_npc, g1)
- mov %l4, %g6
+
+ mov 1, %g6
+ sll %g6, (PAGE_SHIFT + 1), %g6
+ sub %g6, (TRACEREG_SZ + REGWIN_SZ), %g6
+ sub %sp, %g6, %g6
/* Turn on traps and call c-code to deal with it. */
wr %t_psr, PSR_ET, %psr
diff --git a/arch/sparc/kernel/wuf.S b/arch/sparc/kernel/wuf.S
index 7550dd627..cb407aa69 100644
--- a/arch/sparc/kernel/wuf.S
+++ b/arch/sparc/kernel/wuf.S
@@ -1,4 +1,4 @@
-/* $Id: wuf.S,v 1.31 1997/03/04 16:26:37 jj Exp $
+/* $Id: wuf.S,v 1.34 1997/05/01 08:53:36 davem Exp $
* wuf.S: Window underflow trap handler for the Sparc.
*
* Copyright (C) 1995 David S. Miller
@@ -145,14 +145,17 @@ fwin_user_stack_is_bolixed:
* to the trap window and call c-code to deal with this.
*/
LOAD_CURRENT(l4, l5)
- ld [%l4 + AOFF_task_saved_kernel_stack], %l5
+
+ mov 1, %l5
+ sll %l5, (PAGE_SHIFT + 1), %l5
+ sub %l5, (TRACEREG_SZ + REGWIN_SZ), %l5
+ add %l4, %l5, %l5
/* Store globals into pt_regs frame. */
STORE_PT_GLOBALS(l5)
STORE_PT_YREG(l5, g3)
- /* Save kernel %sp in global while we change windows. */
- mov %l5, %g2
+ /* Save current in a global while we change windows. */
mov %l4, %curptr
save %g0, %g0, %g0
@@ -166,7 +169,10 @@ fwin_user_stack_is_bolixed:
/* LOCATION: Window 'T' */
- mov %g2, %sp /* Jump onto kernel %sp being held */
+ mov 1, %sp
+ sll %sp, (PAGE_SHIFT + 1), %sp
+ sub %sp, (TRACEREG_SZ + REGWIN_SZ), %sp
+ add %curptr, %sp, %sp
/* Build rest of pt_regs. */
STORE_PT_INS(sp)
diff --git a/arch/sparc/lib/Makefile b/arch/sparc/lib/Makefile
index 1bf49bf13..cefe7a851 100644
--- a/arch/sparc/lib/Makefile
+++ b/arch/sparc/lib/Makefile
@@ -1,13 +1,11 @@
-# $Id: Makefile,v 1.23 1997/04/18 05:44:39 davem Exp $
+# $Id: Makefile,v 1.24 1997/05/08 17:45:26 davem Exp $
# Makefile for Sparc library files..
#
-CFLAGS := $(CFLAGS) -ansi
-
OBJS = mul.o rem.o sdiv.o udiv.o umul.o urem.o ashrdi3.o memcpy.o memset.o \
strlen.o checksum.o blockops.o memscan.o memcmp.o strncmp.o \
strncpy_from_user.o divdi3.o udivdi3.o strlen_user.o \
- copy_user.o locks.o atomic.o bitops.o
+ copy_user.o locks.o atomic.o bitops.o debuglocks.o
ifdef SMP
OBJS += irqlock.o
diff --git a/arch/sparc/lib/blockops.S b/arch/sparc/lib/blockops.S
index f8a9e80df..c11ab1b20 100644
--- a/arch/sparc/lib/blockops.S
+++ b/arch/sparc/lib/blockops.S
@@ -1,4 +1,4 @@
-/* $Id: blockops.S,v 1.5 1996/09/24 05:22:56 davem Exp $
+/* $Id: blockops.S,v 1.6 1997/05/03 02:01:54 davem Exp $
* blockops.S: Common block zero optimized routines.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -46,25 +46,7 @@
.text
.align 4
- .globl C_LABEL(bzero_2page), C_LABEL(bzero_1page)
-C_LABEL(bzero_2page):
- /* %o0 = buf */
- or %g0, %g0, %g1
- or %o0, %g0, %o1
- or %g0, 0x20, %g2
-1:
- BLAST_BLOCK(%o0, 0x00)
- BLAST_BLOCK(%o0, 0x40)
- BLAST_BLOCK(%o0, 0x80)
- BLAST_BLOCK(%o0, 0xc0)
- subcc %g2, 1, %g2
- bne 1b
- add %o0, 0x100, %o0
-
- retl
- mov %o1, %o0
-
-C_LABEL(bzero_1page):
+generic_bzero_1page:
/* %o0 = buf */
or %g0, %g0, %g1
or %o0, %g0, %o1
@@ -79,10 +61,9 @@ C_LABEL(bzero_1page):
add %o0, 0x100, %o0
retl
- mov %o1, %o0
+ nop
- .globl C_LABEL(__copy_1page)
-C_LABEL(__copy_1page):
+__generic_copy_1page:
/* %o0 = dst, %o1 = src */
or %g0, 0x10, %g1
1:
@@ -101,3 +82,9 @@ C_LABEL(__copy_1page):
retl
nop
+
+ .data
+ .align 4
+ .globl C_LABEL(bzero_1page), C_LABEL(__copy_1page)
+C_LABEL(bzero_1page): .word generic_bzero_1page
+C_LABEL(__copy_1page): .word __generic_copy_1page
diff --git a/arch/sparc/lib/debuglocks.c b/arch/sparc/lib/debuglocks.c
new file mode 100644
index 000000000..006cba5a8
--- /dev/null
+++ b/arch/sparc/lib/debuglocks.c
@@ -0,0 +1,463 @@
+/* $Id: debuglocks.c,v 1.1 1997/05/08 18:13:34 davem Exp $
+ * debuglocks.c: Debugging versions of SMP locking primitives.
+ *
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <asm/psr.h>
+#include <asm/system.h>
+#include <asm/spinlock.h>
+
+/* To enable this code, just define SPIN_LOCK_DEBUG in asm/spinlock.h */
+#ifdef SPIN_LOCK_DEBUG
+
+/* Some notes on how these debugging routines work. When a lock is acquired
+ * an extra debugging member lock->owner_pc is set to the caller of the lock
+ * acquisition routine. Right before releasing a lock, the debugging program
+ * counter is cleared to zero.
+ *
+ * Furthermore, since PC's are 4 byte aligned on Sparc, we stuff the CPU
+ * number of the owner in the lowest two bits.
+ */
+
+#undef INIT_STUCK
+#define INIT_STUCK 100000000
+
+#undef STUCK
+#define STUCK \
+if(!--stuck) { printk("spin_lock(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", lock, cpu, caller, lock->owner_pc & ~3, lock->owner_pc & 3); stuck = INIT_STUCK; }
+
+void _spin_lock(spinlock_t *lock)
+{
+ unsigned long caller;
+ unsigned long val;
+ int cpu = smp_processor_id();
+ int stuck = INIT_STUCK;
+
+ __asm__ __volatile__("mov %%i7, %0" : "=r" (caller));
+again:
+ __asm__ __volatile__("ldstub [%1], %0" : "=r" (val) : "r" (&(lock->lock)));
+ if(val) {
+ while(lock->lock) {
+ STUCK;
+ barrier();
+ }
+ goto again;
+ }
+ lock->owner_pc = (cpu & 3) | (caller & ~3);
+}
+
+int _spin_trylock(spinlock_t *lock)
+{
+ unsigned long val;
+ unsigned long caller;
+ int cpu = smp_processor_id();
+
+ __asm__ __volatile__("mov %%i7, %0" : "=r" (caller));
+ __asm__ __volatile__("ldstub [%1], %0" : "=r" (val) : "r" (&(lock->lock)));
+ if(!val) {
+ /* We got it, record our identity for debugging. */
+ lock->owner_pc = (cpu & 3) | (caller & ~3);
+ }
+ return val == 0;
+}
+
+void _spin_unlock(spinlock_t *lock)
+{
+ lock->owner_pc = 0;
+ __asm__ __volatile__("stb %%g0, [%0]" : : "r" (&(lock->lock)) : "memory");
+}
+
+#undef INIT_STUCK
+#define INIT_STUCK 100000000
+
+#undef STUCK
+#define STUCK \
+if(!--stuck) { printk("spin_lock_irq(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", lock, cpu, caller, lock->owner_pc & ~3, lock->owner_pc & 3); stuck = INIT_STUCK; }
+
+void _spin_lock_irq(spinlock_t *lock)
+{
+ unsigned long caller;
+ unsigned long val;
+ int cpu = smp_processor_id();
+ int stuck = INIT_STUCK;
+
+ __cli();
+ __asm__ __volatile__("mov %%i7, %0" : "=r" (caller));
+again:
+ __asm__ __volatile__("ldstub [%1], %0" : "=r" (val) : "r" (&(lock->lock)));
+ if(val) {
+ while(lock->lock) {
+ STUCK;
+ barrier();
+ }
+ goto again;
+ }
+ lock->owner_pc = (cpu & 3) | (caller & ~3);
+}
+
+void _spin_unlock_irq(spinlock_t *lock)
+{
+ lock->owner_pc = 0;
+ __asm__ __volatile__("stb %%g0, [%0]" : : "r" (&(lock->lock)) : "memory");
+ __sti();
+}
+
+#undef INIT_STUCK
+#define INIT_STUCK 100000000
+
+#undef STUCK
+#define STUCK \
+if(!--stuck) { printk("spin_lock_irq(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", lock, cpu, caller, lock->owner_pc & ~3, lock->owner_pc & 3); stuck = INIT_STUCK; }
+
+/* Caller macro does __save_and_cli(flags) for us. */
+void _spin_lock_irqsave(spinlock_t *lock)
+{
+ unsigned long caller;
+ unsigned long val;
+ int cpu = smp_processor_id();
+ int stuck = INIT_STUCK;
+
+ __asm__ __volatile__("mov %%i7, %0" : "=r" (caller));
+again:
+ __asm__ __volatile__("ldstub [%1], %0" : "=r" (val) : "r" (&(lock->lock)));
+ if(val) {
+ while(lock->lock) {
+ STUCK;
+ barrier();
+ }
+ goto again;
+ }
+ lock->owner_pc = (cpu & 3) | (caller & ~3);
+}
+
+void _spin_unlock_irqrestore(spinlock_t *lock)
+{
+ lock->owner_pc = 0;
+ __asm__ __volatile__("stb %%g0, [%0]" : : "r" (&(lock->lock)) : "memory");
+}
+
+#undef INIT_STUCK
+#define INIT_STUCK 100000000
+
+#undef STUCK
+#define STUCK \
+if(!--stuck) { printk("read_lock(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", rw, cpu, caller, rw->owner_pc & ~3, rw->owner_pc & 3); stuck = INIT_STUCK; }
+
+void _read_lock(rwlock_t *rw)
+{
+ unsigned long flags;
+ unsigned long caller;
+ unsigned long val;
+ int cpu = smp_processor_id();
+ int stuck = INIT_STUCK;
+
+ __asm__ __volatile__("mov %%i7, %0" : "=r" (caller));
+ __save_and_cli(flags);
+wlock_again:
+ __asm__ __volatile__("ldstub [%1 + 3], %0" : "=r" (val) : "r" (&(rw->lock)));
+ if(val) {
+ while(rw->lock & 0xff) {
+ STUCK;
+ barrier();
+ }
+ goto wlock_again;
+ }
+clock_again:
+ __asm__ __volatile__("ldstub [%1 + 2], %0" : "=r" (val) : "r" (&(rw->lock)));
+ if(val) {
+ while(rw->lock & 0xff00) {
+ STUCK;
+ barrier();
+ }
+ goto clock_again;
+ }
+ (*((unsigned short *)&rw->lock))++;
+ barrier();
+ (*(((unsigned short *)&rw->lock)+1)) = 0;
+ __restore_flags(flags);
+}
+
+#undef INIT_STUCK
+#define INIT_STUCK 100000000
+
+#undef STUCK
+#define STUCK \
+if(!--stuck) { printk("read_unlock(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", rw, cpu, caller, rw->owner_pc & ~3, rw->owner_pc & 3); stuck = INIT_STUCK; }
+
+void _read_unlock(rwlock_t *rw)
+{
+ unsigned long flags, val, caller;
+ int cpu = smp_processor_id();
+ int stuck = INIT_STUCK;
+
+ __asm__ __volatile__("mov %%i7, %0" : "=r" (caller));
+ __save_and_cli(flags);
+clock_again:
+ __asm__ __volatile__("ldstub [%1 + 2], %0" : "=r" (val) : "r" (&(rw->lock)));
+ if(val) {
+ while(rw->lock & 0xff00) {
+ STUCK;
+ barrier();
+ }
+ goto clock_again;
+ }
+ (*((unsigned short *)&rw->lock))--;
+ barrier();
+ (*(((unsigned char *)&rw->lock)+2))=0;
+ __restore_flags(flags);
+}
+
+#undef INIT_STUCK
+#define INIT_STUCK 100000000
+
+#undef STUCK
+#define STUCK \
+if(!--stuck) { printk("write_lock(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", rw, cpu, caller, rw->owner_pc & ~3, rw->owner_pc & 3); stuck = INIT_STUCK; }
+
+void _write_lock(rwlock_t *rw)
+{
+ unsigned long flags, val, caller;
+ int cpu = smp_processor_id();
+ int stuck = INIT_STUCK;
+
+ __asm__ __volatile__("mov %%i7, %0" : "=r" (caller));
+ __save_and_cli(flags);
+wlock_again:
+ __asm__ __volatile__("ldstub [%1 + 3], %0" : "=r" (val) : "r" (&(rw->lock)));
+ if(val) {
+ while(rw->lock & 0xff) {
+ STUCK;
+ barrier();
+ }
+ goto wlock_again;
+ }
+ rw->owner_pc = (cpu & 3) | (caller & ~3);
+ while(rw->lock & ~0xff) {
+ STUCK;
+ barrier();
+ }
+}
+
+void _write_unlock(rwlock_t *rw)
+{
+ rw->owner_pc = 0;
+ barrier();
+ rw->lock = 0;
+}
+
+#undef INIT_STUCK
+#define INIT_STUCK 100000000
+
+#undef STUCK
+#define STUCK \
+if(!--stuck) { printk("read_lock_irq(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", rw, cpu, caller, rw->owner_pc & ~3, rw->owner_pc & 3); stuck = INIT_STUCK; }
+
+void _read_lock_irq(rwlock_t *rw)
+{
+ unsigned long caller;
+ unsigned long val;
+ int cpu = smp_processor_id();
+ int stuck = INIT_STUCK;
+
+ __asm__ __volatile__("mov %%i7, %0" : "=r" (caller));
+ __cli();
+wlock_again:
+ __asm__ __volatile__("ldstub [%1 + 3], %0" : "=r" (val) : "r" (&(rw->lock)));
+ if(val) {
+ while(rw->lock & 0xff) {
+ STUCK;
+ barrier();
+ }
+ goto wlock_again;
+ }
+clock_again:
+ __asm__ __volatile__("ldstub [%1 + 2], %0" : "=r" (val) : "r" (&(rw->lock)));
+ if(val) {
+ while(rw->lock & 0xff00) {
+ STUCK;
+ barrier();
+ }
+ goto clock_again;
+ }
+ (*((unsigned short *)&rw->lock))++;
+ barrier();
+ (*(((unsigned short *)&rw->lock)+1)) = 0;
+}
+
+#undef INIT_STUCK
+#define INIT_STUCK 100000000
+
+#undef STUCK
+#define STUCK \
+if(!--stuck) { printk("read_unlock_irq(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", rw, cpu, caller, rw->owner_pc & ~3, rw->owner_pc & 3); stuck = INIT_STUCK; }
+
+void _read_unlock_irq(rwlock_t *rw)
+{
+ unsigned long val, caller;
+ int stuck = INIT_STUCK;
+ int cpu = smp_processor_id();
+
+ __asm__ __volatile__("mov %%i7, %0" : "=r" (caller));
+clock_again:
+ __asm__ __volatile__("ldstub [%1 + 2], %0" : "=r" (val) : "r" (&(rw->lock)));
+ if(val) {
+ while(rw->lock & 0xff00) {
+ STUCK;
+ barrier();
+ }
+ goto clock_again;
+ }
+ (*((unsigned short *)&rw->lock))--;
+ barrier();
+ (*(((unsigned char *)&rw->lock)+2))=0;
+ __sti();
+}
+
+#undef INIT_STUCK
+#define INIT_STUCK 100000000
+
+#undef STUCK
+#define STUCK \
+if(!--stuck) { printk("write_lock_irq(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", rw, cpu, caller, rw->owner_pc & ~3, rw->owner_pc & 3); stuck = INIT_STUCK; }
+
+void _write_lock_irq(rwlock_t *rw)
+{
+ unsigned long val, caller;
+ int cpu = smp_processor_id();
+ int stuck = INIT_STUCK;
+
+ __asm__ __volatile__("mov %%i7, %0" : "=r" (caller));
+ __cli();
+wlock_again:
+ __asm__ __volatile__("ldstub [%1 + 3], %0" : "=r" (val) : "r" (&(rw->lock)));
+ if(val) {
+ while(rw->lock & 0xff) {
+ STUCK;
+ barrier();
+ }
+ goto wlock_again;
+ }
+ rw->owner_pc = (cpu & 3) | (caller & ~3);
+ while(rw->lock & ~0xff) {
+ STUCK;
+ barrier();
+ }
+}
+
+void _write_unlock_irq(rwlock_t *rw)
+{
+ rw->owner_pc = 0;
+ barrier();
+ rw->lock = 0;
+ __sti();
+}
+
+#undef INIT_STUCK
+#define INIT_STUCK 100000000
+
+#undef STUCK
+#define STUCK \
+if(!--stuck) { printk("read_lock_irqsave(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", rw, cpu, caller, rw->owner_pc & ~3, rw->owner_pc & 3); stuck = INIT_STUCK; }
+
+/* Caller does __save_and_cli(flags) for us. */
+void _read_lock_irqsave(rwlock_t *rw)
+{
+ unsigned long caller;
+ unsigned long val;
+ int cpu = smp_processor_id();
+ int stuck = INIT_STUCK;
+
+ __asm__ __volatile__("mov %%i7, %0" : "=r" (caller));
+wlock_again:
+ __asm__ __volatile__("ldstub [%1 + 3], %0" : "=r" (val) : "r" (&(rw->lock)));
+ if(val) {
+ while(rw->lock & 0xff) {
+ STUCK;
+ barrier();
+ }
+ goto wlock_again;
+ }
+clock_again:
+ __asm__ __volatile__("ldstub [%1 + 2], %0" : "=r" (val) : "r" (&(rw->lock)));
+ if(val) {
+ while(rw->lock & 0xff00) {
+ STUCK;
+ barrier();
+ }
+ goto clock_again;
+ }
+ (*((unsigned short *)&rw->lock))++;
+ barrier();
+ (*(((unsigned short *)&rw->lock)+1)) = 0;
+}
+
+#undef INIT_STUCK
+#define INIT_STUCK 100000000
+
+#undef STUCK
+#define STUCK \
+if(!--stuck) { printk("read_unlock_irqrestore(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", rw, cpu, caller, rw->owner_pc & ~3, rw->owner_pc & 3); stuck = INIT_STUCK; }
+
+void _read_unlock_irqrestore(rwlock_t *rw)
+{
+ unsigned long val, caller;
+ int cpu = smp_processor_id();
+ int stuck = INIT_STUCK;
+
+ __asm__ __volatile__("mov %%i7, %0" : "=r" (caller));
+clock_again:
+ __asm__ __volatile__("ldstub [%1 + 2], %0" : "=r" (val) : "r" (&(rw->lock)));
+ if(val) {
+ while(rw->lock & 0xff00) {
+ STUCK;
+ barrier();
+ }
+ goto clock_again;
+ }
+ (*((unsigned short *)&rw->lock))--;
+ barrier();
+ (*(((unsigned char *)&rw->lock)+2))=0;
+}
+
+#undef INIT_STUCK
+#define INIT_STUCK 100000000
+
+#undef STUCK
+#define STUCK \
+if(!--stuck) { printk("write_lock_irqsave(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", rw, cpu, caller, rw->owner_pc & ~3, rw->owner_pc & 3); stuck = INIT_STUCK; }
+
+/* Caller does __save_and_cli(flags) for us. */
+void _write_lock_irqsave(rwlock_t *rw)
+{
+ unsigned long val, caller;
+ int cpu = smp_processor_id();
+ int stuck = INIT_STUCK;
+
+ __asm__ __volatile__("mov %%i7, %0" : "=r" (caller));
+wlock_again:
+ __asm__ __volatile__("ldstub [%1 + 3], %0" : "=r" (val) : "r" (&(rw->lock)));
+ if(val) {
+ while(rw->lock & 0xff) {
+ STUCK;
+ barrier();
+ }
+ goto wlock_again;
+ }
+ rw->owner_pc = (cpu & 3) | (caller & ~3);
+ while(rw->lock & ~0xff) {
+ STUCK;
+ barrier();
+ }
+}
+
+void _write_unlock_irqrestore(rwlock_t *rw)
+{
+ rw->owner_pc = 0;
+ barrier();
+ rw->lock = 0;
+}
+
+#endif /* SPIN_LOCK_DEBUG */
diff --git a/arch/sparc/lib/irqlock.S b/arch/sparc/lib/irqlock.S
index db7dd26c3..23194e723 100644
--- a/arch/sparc/lib/irqlock.S
+++ b/arch/sparc/lib/irqlock.S
@@ -1,4 +1,4 @@
-/* $Id: irqlock.S,v 1.2 1997/04/19 04:33:37 davem Exp $
+/* $Id: irqlock.S,v 1.4 1997/05/01 02:26:54 davem Exp $
* irqlock.S: High performance IRQ global locking and interrupt entry.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
diff --git a/arch/sparc/mm/Makefile b/arch/sparc/mm/Makefile
index 4ae57f18f..f7b9b367c 100644
--- a/arch/sparc/mm/Makefile
+++ b/arch/sparc/mm/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.24 1997/04/20 14:11:49 ecd Exp $
+# $Id: Makefile,v 1.25 1997/05/03 05:09:11 davem Exp $
# Makefile for the linux Sparc-specific parts of the memory manager.
#
# Note! Dependencies are done automagically by 'make dep', which also
@@ -9,12 +9,30 @@
O_TARGET := mm.o
O_OBJS := fault.o init.o sun4c.o srmmu.o hypersparc.o viking.o \
- loadmmu.o generic.o asyncd.o extable.o
+ tsunami.o loadmmu.o generic.o asyncd.o extable.o
include $(TOPDIR)/Rules.make
+ifdef SMP
+
+hypersparc.o: hypersparc.S
+ $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o hypersparc.o hypersparc.S
+
+viking.o: viking.S
+ $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o viking.o viking.S
+
+tsunami.o: tsunami.S
+ $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o tsunami.o tsunami.S
+
+else
+
hypersparc.o: hypersparc.S
$(CC) -D__ASSEMBLY__ -ansi -c -o hypersparc.o hypersparc.S
viking.o: viking.S
$(CC) -D__ASSEMBLY__ -ansi -c -o viking.o viking.S
+
+tsunami.o: tsunami.S
+ $(CC) -D__ASSEMBLY__ -ansi -c -o tsunami.o tsunami.S
+
+endif
diff --git a/arch/sparc/mm/asyncd.c b/arch/sparc/mm/asyncd.c
index 5d9d476a5..46635db97 100644
--- a/arch/sparc/mm/asyncd.c
+++ b/arch/sparc/mm/asyncd.c
@@ -1,4 +1,4 @@
-/* $Id: asyncd.c,v 1.9 1996/12/18 06:43:22 tridge Exp $
+/* $Id: asyncd.c,v 1.10 1997/05/15 21:14:24 davem Exp $
* The asyncd kernel daemon. This handles paging on behalf of
* processes that receive page faults due to remote (async) memory
* accesses.
@@ -153,7 +153,7 @@ static int fault_in_page(int taskid,
if(!pte)
goto no_memory;
if(!pte_present(*pte)) {
- do_no_page(tsk, vma, address, write);
+ handle_mm_fault(tsk, vma, address, write);
goto finish_up;
}
set_pte(pte, pte_mkyoung(*pte));
@@ -165,12 +165,11 @@ static int fault_in_page(int taskid,
flush_tlb_page(vma, address);
goto finish_up;
}
- do_wp_page(tsk, vma, address, write);
+ handle_mm_fault(tsk, vma, address, write);
/* Fall through for do_wp_page */
finish_up:
stats.success++;
- update_mmu_cache(vma, address, *pte);
return 0;
no_memory:
diff --git a/arch/sparc/mm/fault.c b/arch/sparc/mm/fault.c
index cfac6bcc2..0d6490860 100644
--- a/arch/sparc/mm/fault.c
+++ b/arch/sparc/mm/fault.c
@@ -1,4 +1,4 @@
-/* $Id: fault.c,v 1.91 1997/03/18 17:56:00 jj Exp $
+/* $Id: fault.c,v 1.92 1997/05/15 21:14:21 davem Exp $
* fault.c: Page fault handlers for the Sparc.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -229,7 +229,7 @@ good_area:
if(!(vma->vm_flags & (VM_READ | VM_EXEC)))
goto bad_area;
}
- handle_mm_fault(vma, address, write);
+ handle_mm_fault(current, vma, address, write);
up(&mm->mmap_sem);
goto out;
/*
@@ -370,7 +370,7 @@ good_area:
else
if(!(vma->vm_flags & (VM_READ | VM_EXEC)))
goto bad_area;
- handle_mm_fault(vma, address, write);
+ handle_mm_fault(current, vma, address, write);
up(&mm->mmap_sem);
return;
bad_area:
diff --git a/arch/sparc/mm/hypersparc.S b/arch/sparc/mm/hypersparc.S
index 4e5a19301..62e2022e0 100644
--- a/arch/sparc/mm/hypersparc.S
+++ b/arch/sparc/mm/hypersparc.S
@@ -1,4 +1,4 @@
-/* $Id: hypersparc.S,v 1.4 1997/04/19 04:33:39 davem Exp $
+/* $Id: hypersparc.S,v 1.7 1997/05/03 05:09:12 davem Exp $
* hypersparc.S: High speed Hypersparc mmu/cache operations.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -79,7 +79,7 @@ hypersparc_flush_cache_mm:
sta %g0, [%o0 + %o4] ASI_M_FLUSH_USER
hypersparc_flush_cache_mm_out:
retl
- sta %g0, [%g0 + %g0] ASI_M_FLUSH_IWHOLE ! hyper_flush_whole_icache
+ nop
/* The things we do for performance... */
hypersparc_flush_cache_range:
@@ -126,7 +126,7 @@ hypersparc_flush_cache_range:
bne 1b
sta %g0, [%o3 + %g5] ASI_M_FLUSH_USER
retl
- sta %g0, [%g0 + %g0] ASI_M_FLUSH_IWHOLE
+ nop
/* Below our threshold, flush one page at a time. */
0:
@@ -166,7 +166,7 @@ hypersparc_flush_cache_range:
sta %o3, [%g7] ASI_M_MMUREGS
hypersparc_flush_cache_range_out:
retl
- sta %g0, [%g0 + %g0] ASI_M_FLUSH_IWHOLE
+ nop
/* HyperSparc requires a valid mapping where we are about to flush
* in order to check for a physical tag match during the flush.
@@ -221,12 +221,12 @@ hypersparc_flush_cache_page:
sta %o2, [%g4] ASI_M_MMUREGS
hypersparc_flush_cache_page_out:
retl
- sta %g0, [%g0 + %g0] ASI_M_FLUSH_IWHOLE
+ nop
hypersparc_flush_sig_insns:
- flush %o2
+ flush %o1
retl
- flush %o2 + 4
+ flush %o1 + 4
/* HyperSparc is copy-back. */
hypersparc_flush_page_to_ram:
@@ -289,7 +289,7 @@ hypersparc_flush_tlb_mm:
cmp %o1, -1
be hypersparc_flush_tlb_mm_out
#endif
- mov 0x300, %g2
+ mov 0x300, %g2
sta %o1, [%g1] ASI_M_MMUREGS
sta %g0, [%g2] ASI_M_FLUSH_PROBE
hypersparc_flush_tlb_mm_out:
@@ -304,7 +304,7 @@ hypersparc_flush_tlb_range:
cmp %o3, -1
be hypersparc_flush_tlb_range_out
#endif
- srl %o1, SRMMU_PGDIR_SHIFT, %o1
+ srl %o1, SRMMU_PGDIR_SHIFT, %o1
sta %o3, [%g1] ASI_M_MMUREGS
sll %o1, SRMMU_PGDIR_SHIFT, %o1
sethi %hi(1 << SRMMU_PGDIR_SHIFT), %o4
@@ -324,13 +324,67 @@ hypersparc_flush_tlb_page:
mov SRMMU_CTX_REG, %g1
ld [%o0 + AOFF_mm_context], %o3
andn %o1, (PAGE_SIZE - 1), %o1
- lda [%g1] ASI_M_MMUREGS, %g5
#ifndef __SMP__
cmp %o3, -1
be hypersparc_flush_tlb_page_out
#endif
+ lda [%g1] ASI_M_MMUREGS, %g5
sta %o3, [%g1] ASI_M_MMUREGS
sta %g0, [%o1] ASI_M_FLUSH_PROBE
hypersparc_flush_tlb_page_out:
retl
sta %g5, [%g1] ASI_M_MMUREGS
+
+ /* High speed page clear/copy. */
+ .globl hypersparc_bzero_1page, hypersparc_copy_1page
+hypersparc_bzero_1page:
+ clr %g1
+ mov 32, %g2
+ add %g2, %g2, %g3
+ add %g2, %g3, %g4
+ add %g2, %g4, %g5
+ add %g2, %g5, %g7
+ add %g2, %g7, %o2
+ add %g2, %o2, %o3
+ mov 16, %o1
+1:
+ stda %g0, [%o0 + %g0] ASI_M_BFILL
+ stda %g0, [%o0 + %g2] ASI_M_BFILL
+ stda %g0, [%o0 + %g3] ASI_M_BFILL
+ stda %g0, [%o0 + %g4] ASI_M_BFILL
+ stda %g0, [%o0 + %g5] ASI_M_BFILL
+ stda %g0, [%o0 + %g7] ASI_M_BFILL
+ stda %g0, [%o0 + %o2] ASI_M_BFILL
+ stda %g0, [%o0 + %o3] ASI_M_BFILL
+ subcc %o1, 1, %o1
+ bne 1b
+ add %o0, 256, %o0
+
+ retl
+ nop
+
+hypersparc_copy_1page:
+ sub %o1, %o0, %o2 ! difference
+ mov 16, %g1
+1:
+ sta %o0, [%o0 + %o2] ASI_M_BCOPY
+ add %o0, 32, %o0
+ sta %o0, [%o0 + %o2] ASI_M_BCOPY
+ add %o0, 32, %o0
+ sta %o0, [%o0 + %o2] ASI_M_BCOPY
+ add %o0, 32, %o0
+ sta %o0, [%o0 + %o2] ASI_M_BCOPY
+ add %o0, 32, %o0
+ sta %o0, [%o0 + %o2] ASI_M_BCOPY
+ add %o0, 32, %o0
+ sta %o0, [%o0 + %o2] ASI_M_BCOPY
+ add %o0, 32, %o0
+ sta %o0, [%o0 + %o2] ASI_M_BCOPY
+ add %o0, 32, %o0
+ sta %o0, [%o0 + %o2] ASI_M_BCOPY
+ subcc %g1, 1, %g1
+ bne 1b
+ add %o0, 32, %o0
+
+ retl
+ nop
diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c
index 9d3afdbdf..b04064efb 100644
--- a/arch/sparc/mm/srmmu.c
+++ b/arch/sparc/mm/srmmu.c
@@ -1,4 +1,4 @@
-/* $Id: srmmu.c,v 1.136 1997/04/20 14:11:51 ecd Exp $
+/* $Id: srmmu.c,v 1.146 1997/05/18 21:11:09 davem Exp $
* srmmu.c: SRMMU specific routines for memory management.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -77,12 +77,20 @@ ctxd_t *srmmu_context_table;
/* Don't change this without changing access to this
* in arch/sparc/mm/viking.S
*/
-struct srmmu_trans {
+static struct srmmu_trans {
unsigned long vbase;
unsigned long pbase;
unsigned long size;
} srmmu_map[SPARC_PHYS_BANKS];
+#define SRMMU_HASHSZ 256
+
+/* Not static, viking.S uses it. */
+struct srmmu_trans *srmmu_v2p_hash[SRMMU_HASHSZ];
+static struct srmmu_trans *srmmu_p2v_hash[SRMMU_HASHSZ];
+
+#define srmmu_ahashfn(addr) ((addr) >> 24)
+
static int viking_mxcc_present = 0;
void srmmu_frob_mem_map(unsigned long start_mem)
@@ -113,31 +121,26 @@ void srmmu_frob_mem_map(unsigned long start_mem)
/* Physical memory can be _very_ non-contiguous on the sun4m, especially
* the SS10/20 class machines and with the latest openprom revisions.
- * So we have to crunch the free page pool.
+ * So we have to do a quick lookup.
*/
static inline unsigned long srmmu_v2p(unsigned long vaddr)
{
- int i;
+ struct srmmu_trans *tp = srmmu_v2p_hash[srmmu_ahashfn(vaddr)];
- for(i=0; srmmu_map[i].size != 0; i++) {
- if(srmmu_map[i].vbase <= vaddr &&
- (srmmu_map[i].vbase + srmmu_map[i].size > vaddr)) {
- return (vaddr - srmmu_map[i].vbase) + srmmu_map[i].pbase;
- }
- }
- return 0xffffffffUL;
+ if(tp)
+ return (vaddr - tp->vbase + tp->pbase);
+ else
+ return 0xffffffffUL;
}
static inline unsigned long srmmu_p2v(unsigned long paddr)
{
- int i;
+ struct srmmu_trans *tp = srmmu_p2v_hash[srmmu_ahashfn(paddr)];
- for(i=0; srmmu_map[i].size != 0; i++) {
- if(srmmu_map[i].pbase <= paddr &&
- (srmmu_map[i].pbase + srmmu_map[i].size > paddr))
- return (paddr - srmmu_map[i].pbase) + srmmu_map[i].vbase;
- }
- return 0xffffffffUL;
+ if(tp)
+ return (paddr - tp->pbase + tp->vbase);
+ else
+ return 0xffffffffUL;
}
/* In general all page table modifications should use the V8 atomic
@@ -659,27 +662,6 @@ static void srmmu_set_pte_cacheable(pte_t *ptep, pte_t pteval)
srmmu_set_entry(ptep, pte_val(pteval));
}
-static void srmmu_set_pte_nocache_hyper(pte_t *ptep, pte_t pteval)
-{
- unsigned long page = ((unsigned long)ptep) & PAGE_MASK;
-
- srmmu_set_entry(ptep, pte_val(pteval));
- __asm__ __volatile__("
- lda [%0] %2, %%g4
- orcc %%g4, 0x0, %%g0
- be 2f
- sethi %%hi(%7), %%g5
-1: subcc %%g5, %6, %%g5 ! hyper_flush_cache_page
- bne 1b
- sta %%g0, [%1 + %%g5] %3
- lda [%4] %5, %%g0
-2:" : /* no outputs */
- : "r" (page | 0x400), "r" (page), "i" (ASI_M_FLUSH_PROBE),
- "i" (ASI_M_FLUSH_PAGE), "r" (SRMMU_FAULT_STATUS), "i" (ASI_M_MMUREGS),
- "r" (vac_line_size), "i" (PAGE_SIZE)
- : "g4", "g5", "cc");
-}
-
static void srmmu_set_pte_nocache_cypress(pte_t *ptep, pte_t pteval)
{
register unsigned long a, b, c, d, e, f, g;
@@ -860,134 +842,27 @@ static void srmmu_unlockarea(char *vaddr, unsigned long len)
*/
struct task_struct *srmmu_alloc_task_struct(void)
{
- return (struct task_struct *) kmalloc(sizeof(struct task_struct), GFP_KERNEL);
-}
-
-unsigned long srmmu_alloc_kernel_stack(struct task_struct *tsk)
-{
- unsigned long kstk = __get_free_pages(GFP_KERNEL, 1, 0);
-
- if(!kstk)
- kstk = (unsigned long) vmalloc(PAGE_SIZE << 1);
-
- return kstk;
+ return (struct task_struct *) __get_free_pages(GFP_KERNEL, 1, 0);
}
static void srmmu_free_task_struct(struct task_struct *tsk)
{
- kfree(tsk);
-}
-
-static void srmmu_free_kernel_stack(unsigned long stack)
-{
- if(stack < VMALLOC_START)
- free_pages(stack, 1);
- else
- vfree((char *)stack);
-}
-
-/* Tsunami flushes. It's page level tlb invalidation is not very
- * useful at all, you must be in the context that page exists in to
- * get a match.
- */
-static void tsunami_flush_cache_all(void)
-{
- flush_user_windows();
- tsunami_flush_icache();
- tsunami_flush_dcache();
-}
-
-static void tsunami_flush_cache_mm(struct mm_struct *mm)
-{
- FLUSH_BEGIN(mm)
- flush_user_windows();
- tsunami_flush_icache();
- tsunami_flush_dcache();
- FLUSH_END
-}
-
-static void tsunami_flush_cache_range(struct mm_struct *mm, unsigned long start, unsigned long end)
-{
- FLUSH_BEGIN(mm)
- flush_user_windows();
- tsunami_flush_icache();
- tsunami_flush_dcache();
- FLUSH_END
-}
-
-static void tsunami_flush_cache_page(struct vm_area_struct *vma, unsigned long page)
-{
- FLUSH_BEGIN(vma->vm_mm)
- flush_user_windows();
- tsunami_flush_icache();
- tsunami_flush_dcache();
- FLUSH_END
-}
-
-/* Tsunami does not have a Copy-back style virtual cache. */
-static void tsunami_flush_page_to_ram(unsigned long page)
-{
-}
-
-/* However, Tsunami is not IO coherent. */
-static void tsunami_flush_page_for_dma(unsigned long page)
-{
- tsunami_flush_icache();
- tsunami_flush_dcache();
-}
-
-/* Tsunami has harvard style split I/D caches which do not snoop each other,
- * so we have to flush on-stack sig insns. Only the icache need be flushed
- * since the Tsunami has a write-through data cache.
- */
-static void tsunami_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr)
-{
- tsunami_flush_icache();
-}
-
-static void tsunami_flush_chunk(unsigned long chunk)
-{
+ free_pages((unsigned long)tsk, 1);
}
-static void tsunami_flush_tlb_all(void)
-{
- srmmu_flush_whole_tlb();
- module_stats.invall++;
-}
-
-static void tsunami_flush_tlb_mm(struct mm_struct *mm)
-{
- FLUSH_BEGIN(mm)
- srmmu_flush_whole_tlb();
- module_stats.invmm++;
- FLUSH_END
-}
-
-static void tsunami_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end)
-{
- FLUSH_BEGIN(mm)
- srmmu_flush_whole_tlb();
- module_stats.invrnge++;
- FLUSH_END
-}
-
-static void tsunami_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
-{
- struct mm_struct *mm = vma->vm_mm;
-
- FLUSH_BEGIN(mm)
- __asm__ __volatile__("
- lda [%0] %3, %%g5
- sta %1, [%0] %3
- sta %%g0, [%2] %4
- sta %%g5, [%0] %3"
- : /* no outputs */
- : "r" (SRMMU_CTX_REG), "r" (mm->context), "r" (page & PAGE_MASK),
- "i" (ASI_M_MMUREGS), "i" (ASI_M_FLUSH_PROBE)
- : "g5");
- module_stats.invpg++;
- FLUSH_END
-}
+/* tsunami.S */
+extern void tsunami_flush_cache_all(void);
+extern void tsunami_flush_cache_mm(struct mm_struct *mm);
+extern void tsunami_flush_cache_range(struct mm_struct *mm, unsigned long start, unsigned long end);
+extern void tsunami_flush_cache_page(struct vm_area_struct *vma, unsigned long page);
+extern void tsunami_flush_page_to_ram(unsigned long page);
+extern void tsunami_flush_page_for_dma(unsigned long page);
+extern void tsunami_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr);
+extern void tsunami_flush_chunk(unsigned long chunk);
+extern void tsunami_flush_tlb_all(void);
+extern void tsunami_flush_tlb_mm(struct mm_struct *mm);
+extern void tsunami_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end);
+extern void tsunami_flush_tlb_page(struct vm_area_struct *vma, unsigned long page);
/* Swift flushes. It has the recommended SRMMU specification flushing
* facilities, so we can do things in a more fine grained fashion than we
@@ -1364,18 +1239,31 @@ extern void hypersparc_flush_tlb_all(void);
extern void hypersparc_flush_tlb_mm(struct mm_struct *mm);
extern void hypersparc_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end);
extern void hypersparc_flush_tlb_page(struct vm_area_struct *vma, unsigned long page);
+extern void hypersparc_bzero_1page(void *);
+extern void hypersparc_copy_1page(void *, const void *);
+
+static void srmmu_set_pte_nocache_hyper(pte_t *ptep, pte_t pteval)
+{
+ unsigned long page = ((unsigned long)ptep) & PAGE_MASK;
+
+ srmmu_set_entry(ptep, pte_val(pteval));
+ hypersparc_flush_page_to_ram(page);
+}
static void hypersparc_ctxd_set(ctxd_t *ctxp, pgd_t *pgdp)
{
+ srmmu_set_entry((pte_t *)ctxp, __pte((SRMMU_ET_PTD | (srmmu_v2p((unsigned long) pgdp) >> 4))));
+ hypersparc_flush_page_to_ram((unsigned long)ctxp);
hyper_flush_whole_icache();
- set_pte((pte_t *)ctxp, __pte((SRMMU_ET_PTD | (srmmu_v2p((unsigned long) pgdp) >> 4))));
}
static void hypersparc_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdp)
{
unsigned long page = ((unsigned long) pgdp) & PAGE_MASK;
- hypersparc_flush_page_to_ram(page);
+ if(pgdp != swapper_pg_dir)
+ hypersparc_flush_page_to_ram(page);
+
if(tsk->mm->context != NO_CONTEXT) {
flush_cache_mm(tsk->mm);
ctxd_set(&srmmu_context_table[tsk->mm->context], pgdp);
@@ -1429,26 +1317,29 @@ static void cypress_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdp)
static void hypersparc_switch_to_context(struct task_struct *tsk)
{
- hyper_flush_whole_icache();
if(tsk->mm->context == NO_CONTEXT) {
+ ctxd_t *ctxp;
+
alloc_context(tsk->mm);
- flush_cache_mm(tsk->mm);
- ctxd_set(&srmmu_context_table[tsk->mm->context], tsk->mm->pgd);
- flush_tlb_mm(tsk->mm);
+ ctxp = &srmmu_context_table[tsk->mm->context];
+ srmmu_set_entry((pte_t *)ctxp, __pte((SRMMU_ET_PTD | (srmmu_v2p((unsigned long) tsk->mm->pgd) >> 4))));
+ hypersparc_flush_page_to_ram((unsigned long)ctxp);
}
+ hyper_flush_whole_icache();
srmmu_set_context(tsk->mm->context);
}
static void hypersparc_init_new_context(struct mm_struct *mm)
{
- hyper_flush_whole_icache();
+ ctxd_t *ctxp;
alloc_context(mm);
- flush_cache_mm(mm);
- ctxd_set(&srmmu_context_table[mm->context], mm->pgd);
- flush_tlb_mm(mm);
+ ctxp = &srmmu_context_table[mm->context];
+ srmmu_set_entry((pte_t *)ctxp, __pte((SRMMU_ET_PTD | (srmmu_v2p((unsigned long) mm->pgd) >> 4))));
+ hypersparc_flush_page_to_ram((unsigned long)ctxp);
+ hyper_flush_whole_icache();
if(mm == current->mm)
srmmu_set_context(mm->context);
}
@@ -2150,6 +2041,32 @@ check_and_return:
MKTRACE(("success\n"));
init_task.mm->mmap->vm_start = page_offset = low_base;
stack_top = page_offset - PAGE_SIZE;
+#if 1
+ for(entry = 0; srmmu_map[entry].size; entry++) {
+ printk("[%d]: v[%08lx,%08lx](%lx) p[%08lx]\n", entry,
+ srmmu_map[entry].vbase,
+ srmmu_map[entry].vbase + srmmu_map[entry].size,
+ srmmu_map[entry].size,
+ srmmu_map[entry].pbase);
+ }
+#endif
+
+ /* Now setup the p2v/v2p hash tables. */
+ for(entry = 0; entry < SRMMU_HASHSZ; entry++)
+ srmmu_v2p_hash[entry] = srmmu_p2v_hash[entry] = NULL;
+ for(entry = 0; srmmu_map[entry].size; entry++) {
+ unsigned long addr;
+
+ for(addr = srmmu_map[entry].vbase;
+ addr < (srmmu_map[entry].vbase + srmmu_map[entry].size);
+ addr += (1 << 24))
+ srmmu_v2p_hash[srmmu_ahashfn(addr)] = &srmmu_map[entry];
+ for(addr = srmmu_map[entry].pbase;
+ addr < (srmmu_map[entry].pbase + srmmu_map[entry].size);
+ addr += (1 << 24))
+ srmmu_p2v_hash[srmmu_ahashfn(addr)] = &srmmu_map[entry];
+ }
+
return; /* SUCCESS! */
}
@@ -2338,7 +2255,7 @@ static void srmmu_vac_update_mmu_cache(struct vm_area_struct * vma,
start += PAGE_SIZE;
}
}
- } while ((vmaring = vmaring->vm_next_share) != inode->i_mmap);
+ } while ((vmaring = vmaring->vm_next_share) != NULL);
if(alias_found && !(pte_val(pte) & _SUN4C_PAGE_NOCACHE)) {
pgdp = srmmu_pgd_offset(vma->vm_mm, address);
@@ -2355,13 +2272,19 @@ static void srmmu_vac_update_mmu_cache(struct vm_area_struct * vma,
static void hypersparc_destroy_context(struct mm_struct *mm)
{
if(mm->context != NO_CONTEXT && mm->count == 1) {
+ ctxd_t *ctxp;
+
/* HyperSparc is copy-back, any data for this
* process in a modified cache line is stale
* and must be written back to main memory now
* else we eat shit later big time.
*/
flush_cache_mm(mm);
- ctxd_set(&srmmu_context_table[mm->context], swapper_pg_dir);
+
+ ctxp = &srmmu_context_table[mm->context];
+ srmmu_set_entry((pte_t *)ctxp, __pte((SRMMU_ET_PTD | (srmmu_v2p((unsigned long) swapper_pg_dir) >> 4))));
+ hypersparc_flush_page_to_ram((unsigned long)ctxp);
+
flush_tlb_mm(mm);
free_context(mm->context);
mm->context = NO_CONTEXT;
@@ -2450,6 +2373,11 @@ static void poke_hypersparc(void)
hyper_flush_whole_icache();
clear = srmmu_get_faddr();
clear = srmmu_get_fstatus();
+
+#ifdef __SMP__
+ /* Avoid unnecessary cross calls. */
+ flush_page_for_dma = local_flush_page_for_dma;
+#endif
}
__initfunc(static void init_hypersparc(void))
@@ -2482,6 +2410,14 @@ __initfunc(static void init_hypersparc(void))
update_mmu_cache = srmmu_vac_update_mmu_cache;
sparc_update_rootmmu_dir = hypersparc_update_rootmmu_dir;
poke_srmmu = poke_hypersparc;
+
+ /* High performance page copy/clear. */
+ { extern void (*__copy_1page)(void *, const void *);
+ extern void (*bzero_1page)(void *);
+
+ __copy_1page = hypersparc_copy_1page;
+ bzero_1page = hypersparc_bzero_1page;
+ }
}
static void poke_cypress(void)
@@ -3014,9 +2950,7 @@ __initfunc(void ld_mmu_srmmu(void))
mmu_p2v = srmmu_p2v;
/* Task struct and kernel stack allocating/freeing. */
- alloc_kernel_stack = srmmu_alloc_kernel_stack;
alloc_task_struct = srmmu_alloc_task_struct;
- free_kernel_stack = srmmu_free_kernel_stack;
free_task_struct = srmmu_free_task_struct;
quick_kernel_fault = srmmu_quick_kernel_fault;
diff --git a/arch/sparc/mm/sun4c.c b/arch/sparc/mm/sun4c.c
index ebeada4c7..a0ffc10ed 100644
--- a/arch/sparc/mm/sun4c.c
+++ b/arch/sparc/mm/sun4c.c
@@ -1,4 +1,4 @@
-/* $Id: sun4c.c,v 1.143 1997/04/11 00:42:14 davem Exp $
+/* $Id: sun4c.c,v 1.148 1997/05/18 21:11:19 davem Exp $
* sun4c.c: Doing in software what should be done in hardware.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -1093,8 +1093,7 @@ static void sun4c_quick_kernel_fault(unsigned long address)
panic("sun4c kernel fault handler bolixed...");
}
-/*
- * 4 page buckets for task struct and kernel stack allocation.
+/* 2 page buckets for task struct and kernel stack allocation.
*
* TASK_STACK_BEGIN
* bucket[0]
@@ -1105,24 +1104,17 @@ static void sun4c_quick_kernel_fault(unsigned long address)
*
* Each slot looks like:
*
- * page 1 -- task struct
- * page 2 -- unmapped, for stack redzone (maybe use for pgd)
- * page 3/4 -- kernel stack
+ * page 1 -- task struct + beginning of kernel stack
+ * page 2 -- rest of kernel stack
*/
-struct task_bucket {
- struct task_struct task;
- char _unused1[PAGE_SIZE - sizeof(struct task_struct)];
- char kstack[(PAGE_SIZE*3)];
-};
-
-struct task_bucket *sun4c_bucket[NR_TASKS];
+union task_union *sun4c_bucket[NR_TASKS];
static int sun4c_lowbucket_avail;
-#define BUCKET_EMPTY ((struct task_bucket *) 0)
-#define BUCKET_SIZE (PAGE_SIZE << 2)
-#define BUCKET_SHIFT 14 /* log2(sizeof(struct task_bucket)) */
+#define BUCKET_EMPTY ((union task_union *) 0)
+#define BUCKET_SHIFT (PAGE_SHIFT + 1) /* log2(sizeof(struct task_bucket)) */
+#define BUCKET_SIZE (1 << BUCKET_SHIFT)
#define BUCKET_NUM(addr) ((((addr) - SUN4C_LOCK_VADDR) >> BUCKET_SHIFT))
#define BUCKET_ADDR(num) (((num) << BUCKET_SHIFT) + SUN4C_LOCK_VADDR)
#define BUCKET_PTE(page) \
@@ -1177,10 +1169,10 @@ static inline void garbage_collect(int entry)
{
int start, end;
- /* 16 buckets per segment... */
- entry &= ~15;
+ /* 32 buckets per segment... */
+ entry &= ~31;
start = entry;
- for(end = (start + 16); start < end; start++)
+ for(end = (start + 32); start < end; start++)
if(sun4c_bucket[start] != BUCKET_EMPTY)
return;
@@ -1190,121 +1182,70 @@ static inline void garbage_collect(int entry)
static struct task_struct *sun4c_alloc_task_struct(void)
{
- unsigned long addr, page;
+ unsigned long addr, pages;
int entry;
- page = get_free_page(GFP_KERNEL);
- if(!page)
+ pages = __get_free_pages(GFP_KERNEL, 1, 0);
+ if(!pages)
return (struct task_struct *) 0;
for(entry = sun4c_lowbucket_avail; entry < NR_TASKS; entry++)
if(sun4c_bucket[entry] == BUCKET_EMPTY)
break;
if(entry == NR_TASKS) {
- free_page(page);
+ free_pages(pages, 1);
return (struct task_struct *) 0;
}
if(entry >= sun4c_lowbucket_avail)
sun4c_lowbucket_avail = entry + 1;
addr = BUCKET_ADDR(entry);
- sun4c_bucket[entry] = (struct task_bucket *) addr;
+ sun4c_bucket[entry] = (union task_union *) addr;
if(sun4c_get_segmap(addr) == invalid_segment)
get_locked_segment(addr);
- sun4c_put_pte(addr, BUCKET_PTE(page));
+ sun4c_put_pte(addr, BUCKET_PTE(pages));
+ sun4c_put_pte(addr + PAGE_SIZE, BUCKET_PTE(pages + PAGE_SIZE));
return (struct task_struct *) addr;
}
-static unsigned long sun4c_alloc_kernel_stack(struct task_struct *tsk)
-{
- unsigned long saddr = (unsigned long) tsk;
- unsigned long page[2];
-
- if(!saddr)
- return 0;
- page[0] = __get_free_page(GFP_KERNEL);
- if(!page[0])
- return 0;
- page[1] = __get_free_page(GFP_KERNEL);
- if(!page[1]) {
- free_page(page[0]);
- return 0;
- }
-
- saddr += PAGE_SIZE << 1;
- sun4c_put_pte(saddr, BUCKET_PTE(page[0]));
- sun4c_put_pte(saddr + PAGE_SIZE, BUCKET_PTE(page[1]));
- return saddr;
-}
-
-static void sun4c_free_kernel_stack_hw(unsigned long stack)
-{
- unsigned long page[2];
-
- page[0] = BUCKET_PTE_PAGE(sun4c_get_pte(stack));
- page[1] = BUCKET_PTE_PAGE(sun4c_get_pte(stack+PAGE_SIZE));
-
- /* We are deleting a mapping, so the flushes here are mandatory. */
- sun4c_flush_page_hw(stack);
- sun4c_flush_page_hw(stack + PAGE_SIZE);
-
- sun4c_put_pte(stack, 0);
- sun4c_put_pte(stack + PAGE_SIZE, 0);
- free_page(page[0]);
- free_page(page[1]);
-}
-
static void sun4c_free_task_struct_hw(struct task_struct *tsk)
{
unsigned long tsaddr = (unsigned long) tsk;
- unsigned long page = BUCKET_PTE_PAGE(sun4c_get_pte(tsaddr));
+ unsigned long pages = BUCKET_PTE_PAGE(sun4c_get_pte(tsaddr));
int entry = BUCKET_NUM(tsaddr);
/* We are deleting a mapping, so the flush here is mandatory. */
sun4c_flush_page_hw(tsaddr);
+ sun4c_flush_page_hw(tsaddr + PAGE_SIZE);
sun4c_put_pte(tsaddr, 0);
+ sun4c_put_pte(tsaddr + PAGE_SIZE, 0);
sun4c_bucket[entry] = BUCKET_EMPTY;
if(entry < sun4c_lowbucket_avail)
sun4c_lowbucket_avail = entry;
- free_page(page);
+ free_pages(pages, 1);
garbage_collect(entry);
}
-static void sun4c_free_kernel_stack_sw(unsigned long stack)
-{
- unsigned long page[2];
-
- page[0] = BUCKET_PTE_PAGE(sun4c_get_pte(stack));
- page[1] = BUCKET_PTE_PAGE(sun4c_get_pte(stack+PAGE_SIZE));
-
- /* We are deleting a mapping, so the flushes here are mandatory. */
- sun4c_flush_page_sw(stack);
- sun4c_flush_page_sw(stack + PAGE_SIZE);
-
- sun4c_put_pte(stack, 0);
- sun4c_put_pte(stack + PAGE_SIZE, 0);
- free_page(page[0]);
- free_page(page[1]);
-}
-
static void sun4c_free_task_struct_sw(struct task_struct *tsk)
{
unsigned long tsaddr = (unsigned long) tsk;
- unsigned long page = BUCKET_PTE_PAGE(sun4c_get_pte(tsaddr));
+ unsigned long pages = BUCKET_PTE_PAGE(sun4c_get_pte(tsaddr));
int entry = BUCKET_NUM(tsaddr);
/* We are deleting a mapping, so the flush here is mandatory. */
sun4c_flush_page_sw(tsaddr);
+ sun4c_flush_page_sw(tsaddr + PAGE_SIZE);
sun4c_put_pte(tsaddr, 0);
+ sun4c_put_pte(tsaddr + PAGE_SIZE, 0);
sun4c_bucket[entry] = BUCKET_EMPTY;
if(entry < sun4c_lowbucket_avail)
sun4c_lowbucket_avail = entry;
- free_page(page);
+ free_pages(pages, 1);
garbage_collect(entry);
}
@@ -1312,8 +1253,8 @@ __initfunc(static void sun4c_init_buckets(void))
{
int entry;
- if(sizeof(struct task_bucket) != (PAGE_SIZE << 2)) {
- prom_printf("task bucket not 4 pages!\n");
+ if(sizeof(union task_union) != (PAGE_SIZE << 1)) {
+ prom_printf("task union not 2 pages!\n");
prom_halt();
}
for(entry = 0; entry < NR_TASKS; entry++)
@@ -2526,7 +2467,7 @@ static void sun4c_vac_alias_fixup(struct vm_area_struct *vma, unsigned long addr
start += PAGE_SIZE;
}
}
- } while ((vmaring = vmaring->vm_next_share) != inode->i_mmap);
+ } while ((vmaring = vmaring->vm_next_share) != NULL);
if(alias_found && !(pte_val(pte) & _SUN4C_PAGE_NOCACHE)) {
pgdp = sun4c_pgd_offset(vma->vm_mm, address);
@@ -2645,7 +2586,6 @@ __initfunc(void ld_mmu_sun4c(void))
flush_tlb_mm = sun4c_flush_tlb_mm_hw;
flush_tlb_range = sun4c_flush_tlb_range_hw;
flush_tlb_page = sun4c_flush_tlb_page_hw;
- free_kernel_stack = sun4c_free_kernel_stack_hw;
free_task_struct = sun4c_free_task_struct_hw;
switch_to_context = sun4c_switch_to_context_hw;
destroy_context = sun4c_destroy_context_hw;
@@ -2658,7 +2598,6 @@ __initfunc(void ld_mmu_sun4c(void))
flush_tlb_mm = sun4c_flush_tlb_mm_sw;
flush_tlb_range = sun4c_flush_tlb_range_sw;
flush_tlb_page = sun4c_flush_tlb_page_sw;
- free_kernel_stack = sun4c_free_kernel_stack_sw;
free_task_struct = sun4c_free_task_struct_sw;
switch_to_context = sun4c_switch_to_context_sw;
destroy_context = sun4c_destroy_context_sw;
@@ -2736,7 +2675,6 @@ __initfunc(void ld_mmu_sun4c(void))
mmu_p2v = sun4c_p2v;
/* Task struct and kernel stack allocating/freeing. */
- alloc_kernel_stack = sun4c_alloc_kernel_stack;
alloc_task_struct = sun4c_alloc_task_struct;
quick_kernel_fault = sun4c_quick_kernel_fault;
diff --git a/arch/sparc/mm/tsunami.S b/arch/sparc/mm/tsunami.S
new file mode 100644
index 000000000..2a598cd7b
--- /dev/null
+++ b/arch/sparc/mm/tsunami.S
@@ -0,0 +1,90 @@
+/* $Id: tsunami.S,v 1.1 1997/05/03 05:09:09 davem Exp $
+ * tsunami.S: High speed MicroSparc-I mmu/cache operations.
+ *
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <asm/ptrace.h>
+#include <asm/psr.h>
+#include <asm/asi.h>
+#include <asm/page.h>
+#include <asm/pgtsrmmu.h>
+
+#define WINDOW_FLUSH(tmp1, tmp2) \
+ mov 0, tmp1; \
+98: ld [%g6 + AOFF_task_tss + AOFF_thread_uwinmask], tmp2; \
+ orcc %g0, tmp2, %g0; \
+ add tmp1, 1, tmp1; \
+ bne 98b; \
+ save %sp, -64, %sp; \
+99: subcc tmp1, 1, tmp1; \
+ bne 99b; \
+ restore %g0, %g0, %g0;
+
+ .text
+ .align 4
+
+ .globl tsunami_flush_cache_all, tsunami_flush_cache_mm
+ .globl tsunami_flush_cache_range, tsunami_flush_cache_page
+ .globl tsunami_flush_page_to_ram, tsunami_flush_page_for_dma
+ .globl tsunami_flush_sig_insns, tsunami_flush_chunk
+ .globl tsunami_flush_tlb_all, tsunami_flush_tlb_mm
+ .globl tsunami_flush_tlb_range, tsunami_flush_tlb_page
+
+ /* Sliiick... */
+tsunami_flush_cache_page:
+ ld [%o0 + 0x0], %o0 /* XXX vma->vm_mm, GROSS XXX */
+tsunami_flush_cache_mm:
+tsunami_flush_cache_range:
+ ld [%o0 + AOFF_mm_context], %g2
+#ifndef __SMP__
+ cmp %g2, -1
+ be tsunami_flush_cache_out
+#endif
+tsunami_flush_cache_all:
+ WINDOW_FLUSH(%g4, %g5)
+tsunami_flush_page_for_dma:
+ sta %g0, [%g0] ASI_M_DC_FLCLEAR
+ sta %g0, [%g0] ASI_M_IC_FLCLEAR
+tsunami_flush_cache_out:
+tsunami_flush_page_to_ram:
+tsunami_flush_chunk:
+ retl
+ nop
+
+tsunami_flush_sig_insns:
+ flush %o1
+ retl
+ flush %o1 + 4
+
+ /* More slick stuff... */
+tsunami_flush_tlb_mm:
+tsunami_flush_tlb_range:
+#ifndef __SMP__
+ ld [%o0 + AOFF_mm_context], %g2
+ cmp %g2, -1
+ be tsunami_flush_tlb_out
+#endif
+tsunami_flush_tlb_all:
+ mov 0x400, %o1
+ sta %g0, [%o1] ASI_M_FLUSH_PROBE
+tsunami_flush_tlb_out:
+ retl
+ nop
+
+ /* This one can be done in a fine grained manner... */
+tsunami_flush_tlb_page:
+ ld [%o0 + 0x00], %o0 /* XXX vma->vm_mm GROSS XXX */
+ mov SRMMU_CTX_REG, %g1
+ ld [%o0 + AOFF_mm_context], %o3
+ andn %o1, (PAGE_SIZE - 1), %o1
+#ifndef __SMP__
+ cmp %o3, -1
+ be tsunami_flush_tlb_page_out
+#endif
+ lda [%g1] ASI_M_MMUREGS, %g5
+ sta %o3, [%g1] ASI_M_MMUREGS
+ sta %g0, [%o1] ASI_M_FLUSH_PROBE
+tsunami_flush_tlb_page_out:
+ retl
+ sta %g5, [%g1] ASI_M_MMUREGS
diff --git a/arch/sparc/mm/viking.S b/arch/sparc/mm/viking.S
index f61aa4398..19d426ec7 100644
--- a/arch/sparc/mm/viking.S
+++ b/arch/sparc/mm/viking.S
@@ -1,4 +1,4 @@
-/* $Id: viking.S,v 1.2 1997/04/20 21:21:49 ecd Exp $
+/* $Id: viking.S,v 1.3 1997/05/04 10:02:14 ecd Exp $
* viking.S: High speed Viking cache/mmu operations
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
@@ -38,40 +38,26 @@
viking_flush_page:
viking_flush_chunk:
- sethi %hi(C_LABEL(srmmu_map)), %g2
- or %g2, %lo(C_LABEL(srmmu_map)), %g3
- ld [%g3 + 8], %g2
- cmp %g2, 0
- be 3f
+ sethi %hi(C_LABEL(srmmu_v2p_hash)), %g2
+ or %g2, %lo(C_LABEL(srmmu_v2p_hash)), %g2
+ srl %o0, 24, %o1
+ sll %o1, 2, %o1
+
+ ld [%g2 + %o1], %g3
+ cmp %g3, 0
+ bne 1f
and %o0, PAGE_MASK, %o0
- ld [%g3], %o1
-1:
- cmp %o1, %o0
- bgu,a 2f
- add %g3, 0xc, %g3
-
- add %o1, %g2, %g2
- cmp %g2, %o0
- bleu,a 2f
- add %g3, 0xc, %g3
+ retl
+ nop
+1:
+ ld [%g3], %o1
sub %o0, %o1, %g2
ld [%g3 + 4], %o0
add %g2, %o0, %g3
- b 4f
- srl %g3, 12, %g1 ! ppage >> 12
-
-2:
- ld [%g3 + 8], %g2
- cmp %g2, 0
- bne,a 1b
- ld [%g3], %o1
-3:
- retl
- nop
+ srl %g3, 12, %g1 ! ppage >> 12
-4:
clr %o1 ! set counter, 0 - 127
sethi %hi(KERNBASE + PAGE_SIZE - 0x80000000), %o3
sethi %hi(0x80000000), %o4
@@ -131,40 +117,27 @@ viking_flush_chunk:
viking_mxcc_flush_page:
- sethi %hi(C_LABEL(srmmu_map)), %g2
- or %g2, %lo(C_LABEL(srmmu_map)), %g3
- ld [%g3 + 8], %g2
- cmp %g2, 0
- be 3f
+ sethi %hi(C_LABEL(srmmu_v2p_hash)), %g2
+ or %g2, %lo(C_LABEL(srmmu_v2p_hash)), %g2
+ srl %o0, 24, %o1
+ sll %o1, 2, %o1
+
+ ld [%g2 + %o1], %g3
+ cmp %g3, 0
+ bne 1f
and %o0, PAGE_MASK, %o0
- ld [%g3], %o1
-1:
- cmp %o1, %o0
- bgu,a 2f
- add %g3, 0xc, %g3
-
- add %o1, %g2, %g2
- cmp %g2, %o0
- bleu,a 2f
- add %g3, 0xc, %g3
+ retl
+ nop
+1:
+ ld [%g3], %o1
sub %o0, %o1, %g2
ld [%g3 + 4], %o0
+ sethi %hi(PAGE_SIZE), %g4
add %g2, %o0, %g3
- sethi %hi(PAGE_SIZE), %g4
- b 4f
- add %g3, %g4, %g3 ! ppage + PAGE_SIZE
-
-2:
- ld [%g3 + 8], %g2
- cmp %g2, 0
- bne,a 1b
- ld [%g3], %o1
-3:
- retl
- nop
-4:
+ add %g3, %g4, %g3 ! ppage + PAGE_SIZE
+
mov 0x10, %g2 ! set cacheable bit
sethi %hi(MXCC_SRCSTREAM), %o2
or %o2, %lo(MXCC_SRCSTREAM), %o2
diff --git a/arch/sparc/prom/console.c b/arch/sparc/prom/console.c
index 9551094d0..4c999477b 100644
--- a/arch/sparc/prom/console.c
+++ b/arch/sparc/prom/console.c
@@ -1,4 +1,4 @@
-/* $Id: console.c,v 1.11 1997/03/18 17:58:10 jj Exp $
+/* $Id: console.c,v 1.14 1997/05/14 20:44:58 davem Exp $
* console.c: Routines that deal with sending and receiving IO
* to/from the current console device using the PROM.
*
@@ -14,6 +14,9 @@
#include <asm/system.h>
#include <linux/string.h>
+/* XXX Let's get rid of this thing if we can... */
+extern struct task_struct *current_set[NR_CPUS];
+
/* Non blocking get character from console input device, returns -1
* if no input was taken. This can be used for polling.
*/
@@ -38,11 +41,12 @@ prom_nbgetchar(void)
}
break;
case PROM_AP1000:
+ default:
i = -1;
break;
};
__asm__ __volatile__("ld [%0], %%g6\n\t" : :
- "r" (&current_set[smp_processor_id()]) :
+ "r" (&current_set[hard_smp_processor_id()]) :
"memory");
restore_flags(flags);
return i; /* Ugh, we could spin forever on unsupported proms ;( */
@@ -81,9 +85,12 @@ prom_nbputchar(char c)
#endif
break;
+ default:
+ i = -1;
+ break;
};
__asm__ __volatile__("ld [%0], %%g6\n\t" : :
- "r" (&current_set[smp_processor_id()]) :
+ "r" (&current_set[hard_smp_processor_id()]) :
"memory");
restore_flags(flags);
return i; /* Ugh, we could spin forever on unsupported proms ;( */
@@ -130,7 +137,7 @@ prom_query_input_device()
save_flags(flags); cli();
st_p = (*romvec->pv_v2devops.v2_inst2pkg)(*romvec->pv_v2bootargs.fd_stdin);
__asm__ __volatile__("ld [%0], %%g6\n\t" : :
- "r" (&current_set[smp_processor_id()]) :
+ "r" (&current_set[hard_smp_processor_id()]) :
"memory");
restore_flags(flags);
if(prom_node_has_property(st_p, "keyboard"))
@@ -177,7 +184,7 @@ prom_query_output_device()
save_flags(flags); cli();
st_p = (*romvec->pv_v2devops.v2_inst2pkg)(*romvec->pv_v2bootargs.fd_stdout);
__asm__ __volatile__("ld [%0], %%g6\n\t" : :
- "r" (&current_set[smp_processor_id()]) :
+ "r" (&current_set[hard_smp_processor_id()]) :
"memory");
restore_flags(flags);
propl = prom_getproperty(st_p, "device_type", propb, sizeof(propb));
@@ -208,6 +215,7 @@ prom_query_output_device()
}
break;
case PROM_AP1000:
+ default:
return PROMDEV_I_UNK;
};
return PROMDEV_O_UNK;
diff --git a/arch/sparc/prom/devmap.c b/arch/sparc/prom/devmap.c
index 841d63a47..cd99ac3d6 100644
--- a/arch/sparc/prom/devmap.c
+++ b/arch/sparc/prom/devmap.c
@@ -1,4 +1,4 @@
-/* $Id: devmap.c,v 1.3 1996/09/19 20:27:19 davem Exp $
+/* $Id: devmap.c,v 1.5 1997/05/14 20:44:59 davem Exp $
* promdevmap.c: Map device/IO areas to virtual addresses.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -11,6 +11,9 @@
#include <asm/openprom.h>
#include <asm/oplib.h>
+/* XXX Let's get rid of this thing if we can... */
+extern struct task_struct *current_set[NR_CPUS];
+
/* Just like the routines in palloc.c, these should not be used
* by the kernel at all. Bootloader facility mainly. And again,
* this is only available on V2 proms and above.
@@ -33,7 +36,7 @@ prom_mapio(char *vhint, int ios, unsigned int paddr, unsigned int num_bytes)
ret = (*(romvec->pv_v2devops.v2_dumb_mmap))(vhint, ios, paddr,
num_bytes);
__asm__ __volatile__("ld [%0], %%g6\n\t" : :
- "r" (&current_set[smp_processor_id()]) :
+ "r" (&current_set[hard_smp_processor_id()]) :
"memory");
restore_flags(flags);
return ret;
@@ -49,7 +52,7 @@ prom_unmapio(char *vaddr, unsigned int num_bytes)
save_flags(flags); cli();
(*(romvec->pv_v2devops.v2_dumb_munmap))(vaddr, num_bytes);
__asm__ __volatile__("ld [%0], %%g6\n\t" : :
- "r" (&current_set[smp_processor_id()]) :
+ "r" (&current_set[hard_smp_processor_id()]) :
"memory");
restore_flags(flags);
return;
diff --git a/arch/sparc/prom/devops.c b/arch/sparc/prom/devops.c
index 2b33dd2b7..f7feb0815 100644
--- a/arch/sparc/prom/devops.c
+++ b/arch/sparc/prom/devops.c
@@ -1,4 +1,4 @@
-/* $Id: devops.c,v 1.7 1997/03/18 17:58:19 jj Exp $
+/* $Id: devops.c,v 1.10 1997/05/14 20:44:59 davem Exp $
* devops.c: Device operations using the PROM.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -10,6 +10,9 @@
#include <asm/openprom.h>
#include <asm/oplib.h>
+/* XXX Let's get rid of this thing if we can... */
+extern struct task_struct *current_set[NR_CPUS];
+
/* Open the device described by the string 'dstr'. Returns the handle
* to that device used for subsequent operations on that device.
* Returns -1 on failure.
@@ -35,7 +38,7 @@ prom_devopen(char *dstr)
break;
};
__asm__ __volatile__("ld [%0], %%g6\n\t" : :
- "r" (&current_set[smp_processor_id()]) :
+ "r" (&current_set[hard_smp_processor_id()]) :
"memory");
restore_flags(flags);
@@ -57,10 +60,11 @@ prom_devclose(int dhandle)
(*(romvec->pv_v2devops.v2_dev_close))(dhandle);
break;
case PROM_AP1000:
+ default:
break;
};
__asm__ __volatile__("ld [%0], %%g6\n\t" : :
- "r" (&current_set[smp_processor_id()]) :
+ "r" (&current_set[hard_smp_processor_id()]) :
"memory");
restore_flags(flags);
return 0;
@@ -83,10 +87,11 @@ prom_seek(int dhandle, unsigned int seekhi, unsigned int seeklo)
(*(romvec->pv_v2devops.v2_dev_seek))(dhandle, seekhi, seeklo);
break;
case PROM_AP1000:
+ default:
break;
};
__asm__ __volatile__("ld [%0], %%g6\n\t" : :
- "r" (&current_set[smp_processor_id()]) :
+ "r" (&current_set[hard_smp_processor_id()]) :
"memory");
restore_flags(flags);
diff --git a/arch/sparc/prom/misc.c b/arch/sparc/prom/misc.c
index d23d93f61..fede033dd 100644
--- a/arch/sparc/prom/misc.c
+++ b/arch/sparc/prom/misc.c
@@ -1,4 +1,4 @@
-/* $Id: misc.c,v 1.13 1997/04/10 05:12:59 davem Exp $
+/* $Id: misc.c,v 1.15 1997/05/14 20:45:00 davem Exp $
* misc.c: Miscellaneous prom functions that don't belong
* anywhere else.
*
@@ -13,6 +13,9 @@
#include <asm/oplib.h>
#include <asm/auxio.h>
+/* XXX Let's get rid of this thing if we can... */
+extern struct task_struct *current_set[NR_CPUS];
+
/* Reset and reboot the machine with the command 'bcommand'. */
void
prom_reboot(char *bcommand)
@@ -22,7 +25,7 @@ prom_reboot(char *bcommand)
(*(romvec->pv_reboot))(bcommand);
/* Never get here. */
__asm__ __volatile__("ld [%0], %%g6\n\t" : :
- "r" (&current_set[smp_processor_id()]) :
+ "r" (&current_set[hard_smp_processor_id()]) :
"memory");
restore_flags(flags);
}
@@ -40,7 +43,7 @@ prom_feval(char *fstring)
else
(*(romvec->pv_fortheval.v2_eval))(fstring);
__asm__ __volatile__("ld [%0], %%g6\n\t" : :
- "r" (&current_set[smp_processor_id()]) :
+ "r" (&current_set[hard_smp_processor_id()]) :
"memory");
restore_flags(flags);
}
@@ -72,7 +75,7 @@ prom_cmdline(void)
save_flags(flags); cli();
(*(romvec->pv_abort))();
__asm__ __volatile__("ld [%0], %%g6\n\t" : :
- "r" (&current_set[smp_processor_id()]) :
+ "r" (&current_set[hard_smp_processor_id()]) :
"memory");
restore_flags(flags);
install_linux_ticker();
@@ -97,7 +100,7 @@ again:
(*(romvec->pv_halt))();
/* Never get here. */
__asm__ __volatile__("ld [%0], %%g6\n\t" : :
- "r" (&current_set[smp_processor_id()]) :
+ "r" (&current_set[hard_smp_processor_id()]) :
"memory");
restore_flags(flags);
goto again; /* PROM is out to get me -DaveM */
diff --git a/arch/sparc/prom/mp.c b/arch/sparc/prom/mp.c
index cf71cca60..8f07f9d40 100644
--- a/arch/sparc/prom/mp.c
+++ b/arch/sparc/prom/mp.c
@@ -1,4 +1,4 @@
-/* $Id: mp.c,v 1.7 1997/03/18 17:58:23 jj Exp $
+/* $Id: mp.c,v 1.9 1997/05/14 20:45:01 davem Exp $
* mp.c: OpenBoot Prom Multiprocessor support routines. Don't call
* these on a UP or else you will halt and catch fire. ;)
*
@@ -12,6 +12,9 @@
#include <asm/openprom.h>
#include <asm/oplib.h>
+/* XXX Let's get rid of this thing if we can... */
+extern struct task_struct *current_set[NR_CPUS];
+
/* Start cpu with prom-tree node 'cpunode' using context described
* by 'ctable_reg' in context 'ctx' at program counter 'pc'.
*
@@ -36,7 +39,7 @@ prom_startcpu(int cpunode, struct linux_prom_registers *ctable_reg, int ctx, cha
break;
};
__asm__ __volatile__("ld [%0], %%g6\n\t" : :
- "r" (&current_set[smp_processor_id()]) :
+ "r" (&current_set[hard_smp_processor_id()]) :
"memory");
restore_flags(flags);
@@ -65,7 +68,7 @@ prom_stopcpu(int cpunode)
break;
};
__asm__ __volatile__("ld [%0], %%g6\n\t" : :
- "r" (&current_set[smp_processor_id()]) :
+ "r" (&current_set[hard_smp_processor_id()]) :
"memory");
restore_flags(flags);
@@ -94,7 +97,7 @@ prom_idlecpu(int cpunode)
break;
};
__asm__ __volatile__("ld [%0], %%g6\n\t" : :
- "r" (&current_set[smp_processor_id()]) :
+ "r" (&current_set[hard_smp_processor_id()]) :
"memory");
restore_flags(flags);
@@ -123,7 +126,7 @@ prom_restartcpu(int cpunode)
break;
};
__asm__ __volatile__("ld [%0], %%g6\n\t" : :
- "r" (&current_set[smp_processor_id()]) :
+ "r" (&current_set[hard_smp_processor_id()]) :
"memory");
restore_flags(flags);
diff --git a/arch/sparc/prom/segment.c b/arch/sparc/prom/segment.c
index cb1def0e1..96b543727 100644
--- a/arch/sparc/prom/segment.c
+++ b/arch/sparc/prom/segment.c
@@ -1,4 +1,4 @@
-/* $Id: segment.c,v 1.3 1996/09/19 20:27:28 davem Exp $
+/* $Id: segment.c,v 1.5 1997/05/14 20:45:02 davem Exp $
* segment.c: Prom routine to map segments in other contexts before
* a standalone is completely mapped. This is for sun4 and
* sun4c architectures only.
@@ -12,6 +12,9 @@
#include <asm/openprom.h>
#include <asm/oplib.h>
+/* XXX Let's get rid of this thing if we can... */
+extern struct task_struct *current_set[NR_CPUS];
+
/* Set physical segment 'segment' at virtual address 'vaddr' in
* context 'ctx'.
*/
@@ -22,7 +25,7 @@ prom_putsegment(int ctx, unsigned long vaddr, int segment)
save_flags(flags); cli();
(*(romvec->pv_setctxt))(ctx, (char *) vaddr, segment);
__asm__ __volatile__("ld [%0], %%g6\n\t" : :
- "r" (&current_set[smp_processor_id()]) :
+ "r" (&current_set[hard_smp_processor_id()]) :
"memory");
restore_flags(flags);
return;
diff --git a/arch/sparc/prom/tree.c b/arch/sparc/prom/tree.c
index e5e2ceb3d..251b2ee6a 100644
--- a/arch/sparc/prom/tree.c
+++ b/arch/sparc/prom/tree.c
@@ -1,4 +1,4 @@
-/* $Id: tree.c,v 1.16 1997/03/19 14:53:16 davem Exp $
+/* $Id: tree.c,v 1.18 1997/05/14 20:45:03 davem Exp $
* tree.c: Basic device tree traversal/scanning for the Linux
* prom library.
*
@@ -15,10 +15,12 @@
#include <asm/openprom.h>
#include <asm/oplib.h>
+/* XXX Let's get rid of this thing if we can... */
+extern struct task_struct *current_set[NR_CPUS];
/* Macro to restore "current" to the g6 register. */
#define restore_current() __asm__ __volatile__("ld [%0], %%g6\n\t" : : \
- "r" (&current_set[smp_processor_id()]) : \
+ "r" (&current_set[hard_smp_processor_id()]) : \
"memory")
static char promlib_buf[128];
diff --git a/arch/sparc64/Makefile b/arch/sparc64/Makefile
index bacf9b095..a70f9ebf8 100644
--- a/arch/sparc64/Makefile
+++ b/arch/sparc64/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.15 1997/04/14 17:04:49 jj Exp $
+# $Id: Makefile,v 1.16 1997/05/04 07:21:08 davem Exp $
# sparc64/Makefile
#
# Makefile for the architecture dependent flags and dependencies on the
@@ -29,7 +29,7 @@ CFLAGS := $(CFLAGS) -pipe \
LINKFLAGS = -T arch/sparc64/vmlinux.lds
-HEAD := arch/sparc64/kernel/head.o
+HEAD := arch/sparc64/kernel/head.o arch/sparc64/kernel/init_task.o
SUBDIRS := $(SUBDIRS) arch/sparc64/kernel arch/sparc64/lib arch/sparc64/mm \
arch/sparc64/prom
diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig
index 9ecbf90b4..fbc4a5073 100644
--- a/arch/sparc64/defconfig
+++ b/arch/sparc64/defconfig
@@ -40,6 +40,7 @@ SUN_FB_CGFOURTEEN=y
SUN_FB_BWTWO=y
SUN_FB_LEO=y
TADPOLE_FB_WEITEK=y
+SUN_FB_CREATOR=y
#
# Misc Linux/SPARC drivers
@@ -132,8 +133,8 @@ CONFIG_SUNLANCE=y
#
# Filesystems
#
-CONFIG_QUOTA=y
-CONFIG_MINIX_FS=y
+# CONFIG_QUOTA is not set
+# CONFIG_MINIX_FS is not set
CONFIG_EXT2_FS=y
# CONFIG_FAT_FS is not set
# CONFIG_MSDOS_FS is not set
@@ -141,7 +142,9 @@ CONFIG_EXT2_FS=y
# CONFIG_UMSDOS_FS is not set
CONFIG_PROC_FS=y
CONFIG_NFS_FS=y
-# CONFIG_ROOT_NFS is not set
+CONFIG_ROOT_NFS=y
+CONFIG_RNFS_BOOTP=y
+# CONFIG_RNFS_RARP is not set
# CONFIG_NFSD is not set
CONFIG_SUNRPC=y
CONFIG_LOCKD=y
diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile
index d66fa06e7..4a07295e1 100644
--- a/arch/sparc64/kernel/Makefile
+++ b/arch/sparc64/kernel/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.16 1997/04/17 20:35:37 jj Exp $
+# $Id: Makefile,v 1.20 1997/05/18 08:42:11 davem Exp $
# Makefile for the linux kernel.
#
# Note! Dependencies are done automagically by 'make dep', which also
@@ -13,12 +13,12 @@
.S.o:
$(CC) -D__ASSEMBLY__ -ansi -c $< -o $*.o
-all: kernel.o head.o
+all: kernel.o head.o init_task.o
O_TARGET := kernel.o
O_OBJS := etrap.o rtrap.o hack.o process.o setup.o cpu.o idprom.o \
systbls.o traps.o entry.o devices.o auxio.o ioport.o \
- irq.o time.o sys_sparc.o
+ irq.o time.o sys_sparc.o signal.o winfixup.o
OX_OBJS := sparc64_ksyms.o
ifdef CONFIG_SPARC32_COMPAT
@@ -26,12 +26,17 @@ ifdef CONFIG_SPARC32_COMPAT
endif
ifdef CONFIG_BINFMT_ELF32
- O_OBJS += sparcelf32.o
+ O_OBJS += binfmt_elf32.o
endif
head.o: head.S ttable.S itlb_miss.S dtlb_miss.S dtlb_prot.S
$(CC) -D__ASSEMBLY__ -ansi -c $*.S -o $*.o
+#
+# This is just to get the dependencies...
+#
+binfmt_elf32.o: $(TOPDIR)/fs/binfmt_elf.c
+
check_asm: dummy
@echo "#include <linux/sched.h>" > tmp.c
$(CC) -E tmp.c -o tmp.i
diff --git a/arch/sparc64/kernel/binfmt_elf32.c b/arch/sparc64/kernel/binfmt_elf32.c
new file mode 100644
index 000000000..05d50fe56
--- /dev/null
+++ b/arch/sparc64/kernel/binfmt_elf32.c
@@ -0,0 +1,34 @@
+/* binfmt_elf32.c: Support 32-bit Sparc ELF binaries on Ultra.
+ *
+ */
+
+#define ELF_ARCH EM_SPARC
+#define ELF_CLASS ELFCLASS32
+#define ELF_DATA ELFDATA2MSB;
+
+#include <asm/processor.h>
+#include <linux/module.h>
+#include <linux/config.h>
+
+#define elf_addr_t u32
+#define elf_caddr_t u32
+#undef start_thread
+#define start_thread start_thread32
+#define init_elf_binfmt init_elf32_binfmt
+#undef CONFIG_BINFMT_ELF
+#ifdef CONFIG_BINFMT_ELF32
+#define CONFIG_BINFMT_ELF CONFIG_BINFMT_ELF32
+#endif
+#undef CONFIG_BINFMT_ELF_MODULE
+#ifdef CONFIG_BINFMT_ELF32_MODULE
+#define CONFIG_BINFMT_ELF_MODULE CONFIG_BINFMT_ELF32_MODULE
+#endif
+#define ELF_FLAGS_INIT current->tss.flags |= SPARC_FLAG_32BIT
+
+MODULE_DESCRIPTION("Binary format loader for compatibility with 32bit SparcLinux binaries on the Ultra");
+MODULE_AUTHOR("Eric Youngdale, David S. Miller, Jakub Jelinek");
+
+#undef MODULE_DESCRIPTION
+#undef MODULE_AUTHOR
+
+#include "../../../fs/binfmt_elf.c"
diff --git a/arch/sparc64/kernel/dtlb_prot.S b/arch/sparc64/kernel/dtlb_prot.S
index 8eec19260..2cf372ca9 100644
--- a/arch/sparc64/kernel/dtlb_prot.S
+++ b/arch/sparc64/kernel/dtlb_prot.S
@@ -1,4 +1,4 @@
-/* $Id: dtlb_prot.S,v 1.10 1997/03/25 09:47:13 davem Exp $
+/* $Id: dtlb_prot.S,v 1.12 1997/05/18 10:04:43 davem Exp $
* dtlb_prot.S: Data TLB protection code, this is included directly
* into the trap table.
*
@@ -18,30 +18,30 @@
/*0x04*/ srlx %g1, 8, %g3 ! Position PGD offset
/*0x08*/ sllx %g1, 2, %g4 ! Position PMD offset
/*0x0c*/ and %g3, %g2, %g3 ! Mask PGD offset
- /*0x10*/ and %g4, %g2, %g3 ! Mask PMD offset
+ /*0x10*/ and %g4, %g2, %g4 ! Mask PMD offset
/*0x14*/ ldxa [%g7 + %g3] ASI_PHYS_USE_EC, %g5 ! Load PGD
- /*0x18*/ ldxa [%g5 + %g3] ASI_PHYS_USE_EC, %g4 ! Load PMD
+ /*0x18*/ ldxa [%g5 + %g4] ASI_PHYS_USE_EC, %g4 ! Load PMD
/*0x1c*/ ldxa [%g0] ASI_DMMU_TSB_8KB_PTR, %g1 ! For PTE offset
/* ICACHE line 2 */
/*0x20*/ srlx %g1, 1, %g1 ! PTE offset
/*0x24*/ ldxa [%g4 + %g1] ASI_PHYS_USE_EC, %g3 ! Load PTE
/*0x28*/ andcc %g3, _PAGE_WRITE, %g0 ! Writable?
- /*0x2c*/ be,pt %xcc, sparc64_dtlb_fault ! Nope...
+ /*0x2c*/ be,pt %xcc, sparc64_dtlb_prot_catch ! Nope...
/*0x30*/ or %g3, (MODIFIED_BITS), %g3 ! Yes it is
/*0x34*/ mov TLB_TAG_ACCESS, %g5 ! Get the page
- /*0x38*/ ldxa [%g5] ASI_DMMU, %g1 ! From MMU
- /*0x3c*/ add %g2, 7, %g5 ! Compute mask
+ /*0x38*/ add %g1, %g4, %g1 ! to get a tmpreg
+ /*0x3c*/ ldxa [%g5] ASI_DMMU, %g4 ! From MMU
/* ICACHE line 3 */
- /*0x40*/ andn %g1, %g5, %g1 ! Mask page
- /*0x44*/ or %g1, 0x10, %g1 ! 2ndary Context
- /*0x48*/ stxa %g0, [%g1] ASI_DMMU_DEMAP ! TLB flush page
- /*0x4c*/ membar #Sync ! Synchronize
- /*0x50*/ stxa %g3, [%g4 + %g1] ASI_PHYS_USE_EC ! Update sw PTE
- /*0x54*/ stxa %g3, [%g0] ASI_DTLB_DATA_IN ! TLB load
- /*0x58*/ retry ! Trap return
- /*0x5c*/ nop
+ /*0x40*/ add %g2, 7, %g5 ! Compute mask
+ /*0x44*/ andn %g4, %g5, %g4 ! Mask page
+ /*0x48*/ or %g4, 0x10, %g4 ! 2ndary Context
+ /*0x4c*/ stxa %g0, [%g4] ASI_DMMU_DEMAP ! TLB flush page
+ /*0x50*/ membar #Sync ! Synchronize
+ /*0x54*/ stxa %g3, [%g1] ASI_PHYS_USE_EC ! Update sw PTE
+ /*0x58*/ stxa %g3, [%g0] ASI_DTLB_DATA_IN ! TLB load
+ /*0x5c*/ retry ! Trap return
/* ICACHE line 4 */
/*0x60*/ nop
diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S
index 16fe5c8a0..589d1661a 100644
--- a/arch/sparc64/kernel/entry.S
+++ b/arch/sparc64/kernel/entry.S
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.14 1997/04/14 06:56:54 davem Exp $
+/* $Id: entry.S,v 1.21 1997/05/18 10:04:44 davem Exp $
* arch/sparc64/kernel/entry.S: Sparc64 trap low-level entry points.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -24,31 +24,70 @@
.text
.align 4
-/* FIXME: This is still debugging hack */
- .globl sparc64_dtlb_fault, sparc64_dtlb_refbit_catch, sparc64_itlb_refbit_catch
-sparc64_dtlb_fault:
+ .globl sparc64_dtlb_prot_catch, sparc64_dtlb_refbit_catch
+ .globl sparc64_itlb_refbit_catch
+
+ /* Note, DMMU SFAR not updated for fast tlb data access miss
+ * traps, so we must use tag access to find the right page.
+ * However for DMMU fast protection traps it is updated so
+ * we use, but we must also clear it _before_ we enable interrupts
+ * and save state because there is a race where we can push a user
+ * window right now in etrap, a protection fault happens (for example
+ * to update the dirty bit) and since we left crap in the sfsr
+ * it will not get updated properly.
+ */
+sparc64_dtlb_prot_catch:
+ wr %g0, ASI_DMMU, %asi
rdpr %pstate, %g1
wrpr %g1, PSTATE_AG|PSTATE_MG, %pstate
+ rdpr %tl, %g2
+ ldxa [%g0 + TLB_TAG_ACCESS] %asi, %g5
+ ldxa [%g0 + TLB_SFSR] %asi, %g4
+ cmp %g2, 1
+ stxa %g0, [%g0 + TLB_SFSR] %asi
+ bgu,a %icc, winfix_trampoline
+ rdpr %tpc, %g5
ba,pt %xcc, etrap
rd %pc, %g7
- call sparc64_dtlb_fault_handler
- nop
+ b,a,pt %xcc, 1f
sparc64_dtlb_refbit_catch:
+ wr %g0, ASI_DMMU, %asi
rdpr %pstate, %g1
wrpr %g1, PSTATE_AG|PSTATE_MG, %pstate
+ rdpr %tl, %g2
+ ldxa [%g0 + TLB_TAG_ACCESS] %asi, %g5
+ cmp %g2, 1
+ clr %g4 ! sfsr not updated for tlb misses
+ bgu,a %icc, winfix_trampoline
+ rdpr %tpc, %g5
ba,pt %xcc, etrap
rd %pc, %g7
- call sparc64_dtlb_refbit_handler
- add %sp, STACK_BIAS + REGWIN_SZ, %o0
+1:
+ mov %l5, %o4 ! raw tag access
+ mov %l4, %o5 ! raw sfsr
+ srlx %l5, PAGE_SHIFT, %o3
+ clr %o1 ! text_fault == 0
+ sllx %o3, PAGE_SHIFT, %o3 ! address
+ and %l4, 0x4, %o2 ! write == sfsr.W
+ call do_sparc64_fault
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0 ! pt_regs ptr
+ ba,a,pt %xcc, rtrap
sparc64_itlb_refbit_catch:
rdpr %pstate, %g1
wrpr %g1, PSTATE_AG|PSTATE_MG, %pstate
ba,pt %xcc, etrap
rd %pc, %g7
- call sparc64_dtlb_refbit_handler
- nop
+
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC], %o3
+ mov 1, %o1 ! text_fault == 1
+ clr %o2 ! write == 0
+ clr %o4 ! tag access (N/A)
+ clr %o5 ! raw sfsr (N/A)
+ call do_sparc64_fault
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0 ! pt_regs ptr
+ ba,a,pt %xcc, rtrap
/* Note check out head.h, this code isn't even used for UP,
* for SMP things will be different. In particular the data
@@ -121,6 +160,7 @@ breakpoint_trap:
ba,a,pt %xcc, rtrap
.globl sys_pipe, sys_execve, sys_sigpause, sys_nis_syscall
+ .globl sys_sigsuspend, sys_sigreturn
sys_pipe:
sethi %hi(sparc_pipe), %g1
@@ -147,12 +187,35 @@ sys_sigpause:
ld [%curptr + AOFF_task_flags], %l5
andcc %l5, 0x20, %g0
+ be,pt %icc, rtrap
+ nop
+ call syscall_trace
+ nop
+ ba,a,pt %xcc, rtrap
+
+sys_sigsuspend:
+ call do_sigsuspend
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0
+
+ ld [%curptr + AOFF_task_flags], %l5
+ andcc %l5, 0x20, %g0
be,pt %icc, ret_sys_call
- clr %o0
+ nop
call syscall_trace
nop
- ba,pt %xcc, ret_sys_call
- clr %o0
+ ba,a,pt %xcc, rtrap
+
+sys_sigreturn:
+ call do_sigreturn
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0
+
+ ld [%curptr + AOFF_task_flags], %l5
+ andcc %l5, 0x20, %g0
+ be,pt %icc, ret_sys_call
+ nop
+ call syscall_trace
+ nop
+ ba,a,pt %xcc, rtrap
/* This is how fork() was meant to be done, 11 instruction entry. -DaveM */
.globl sys_fork, sys_vfork, sys_clone
@@ -200,7 +263,7 @@ linux_syscall_trace:
.globl ret_from_syscall
ret_from_syscall:
ba,pt %xcc, ret_sys_call
- ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_I0], %o0
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0], %o0
/* Linux native and SunOS system calls enter here... */
.align 4
@@ -232,13 +295,18 @@ syscall_is_too_hard:
call %l7
mov %i5, %o5
- stx %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_I0]
-
+ stx %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]
+#if 0
+ /* Debugging... */
+ call syscall_trace_exit
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0], %o0
+#endif
.globl ret_sys_call
ret_sys_call:
ldx [%curptr + AOFF_task_flags], %l6
mov %ulo(TSTATE_XCARRY | TSTATE_ICARRY), %g2
- ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_TSTATE], %g3
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE], %g3
cmp %o0, -ENOIOCTLCMD
sllx %g2, 32, %g2
bgeu,pn %xcc, 1f
@@ -247,34 +315,34 @@ ret_sys_call:
/* System call success, clear Carry condition code. */
andn %g3, %g2, %g3
clr %l6
- stx %g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_TSTATE]
+ stx %g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE]
bne,pn %icc, linux_syscall_trace2
- ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_TNPC], %l1 /* pc = npc */
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %l1 /* pc = npc */
add %l1, 0x4, %l2 /* npc = npc+4 */
- stx %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_TPC]
+ stx %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC]
ba,pt %xcc, rtrap
- stx %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_TNPC]
+ stx %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC]
1:
/* System call failure, set Carry condition code.
* Also, get abs(errno) to return to the process.
*/
sub %g0, %o0, %o0
or %g3, %g2, %g3
- stx %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_I0]
+ stx %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]
mov 1, %l6
- stx %g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_TSTATE]
+ stx %g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE]
bne,pn %icc, linux_syscall_trace2
- ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_TNPC], %l1 /* pc = npc */
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %l1 /* pc = npc */
add %l1, 0x4, %l2 /* npc = npc+4 */
- stx %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_TPC]
+ stx %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC]
ba,pt %xcc, rtrap
- stx %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_TNPC]
+ stx %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC]
linux_syscall_trace2:
call syscall_trace
add %l1, 0x4, %l2 /* npc = npc+4 */
- stx %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_TPC]
+ stx %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC]
ba,pt %xcc, rtrap
- stx %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_TNPC]
+ stx %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC]
/* End of entry.S */
diff --git a/arch/sparc64/kernel/etrap.S b/arch/sparc64/kernel/etrap.S
index 7d293a88b..f936b3071 100644
--- a/arch/sparc64/kernel/etrap.S
+++ b/arch/sparc64/kernel/etrap.S
@@ -1,34 +1,39 @@
-/* $Id: etrap.S,v 1.11 1997/04/14 17:04:45 jj Exp $
+/* $Id: etrap.S,v 1.17 1997/05/18 22:52:09 davem Exp $
* etrap.S: Preparing for entry into the kernel on Sparc V9.
*
- * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
*/
#include <asm/asi.h>
#include <asm/pstate.h>
#include <asm/ptrace.h>
+#include <asm/page.h>
#include <asm/spitfire.h>
#include <asm/head.h>
-/* We assume that pstate, when entering this, has AG and IE bits set, MG and IG clear */
+ /* We assume that pstate, when entering this, has AG and
+ * IE bits set, MG and IG clear.
+ *
+ * We also guarentee for caller that AG %g4 and %g5 will have
+ * their values preserved and left in %l4 and %l5 respectively
+ * for him (fault handling needs this).
+ */
.text
.align 32
.globl etrap, etrap_irq
etrap:
- rdpr %pil, %g4
+ rdpr %pil, %g2
etrap_irq:
rdpr %tstate, %g1
- sllx %g4, 20, %g4
- rdpr %tpc, %g2
- or %g1, %g4, %g1
- rdpr %tnpc, %g3
+ sllx %g2, 20, %g2
+ or %g1, %g2, %g1
/* What happens more often? etrap when already in priv or from userland? */
andcc %g1, TSTATE_PRIV, %g0
bne,a,pn %xcc, 1f
- sub %sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g5
+ sub %sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2
/* Just when going from userland to privileged mode,
* we have to change this stuff.
@@ -38,41 +43,48 @@ etrap_irq:
* trap level until PRIMARY_CONTEXT is set to zero, else
* we fall out of NUCLEUS too soon and crash hard.
*/
- rdpr %wstate, %g5
- mov PRIMARY_CONTEXT, %g7
- ldxa [%g7] ASI_DMMU, %g4
- mov SECONDARY_CONTEXT, %g6
- stxa %g0, [%g7] ASI_DMMU
- stxa %g4, [%g6] ASI_DMMU
- wrpr %g0, 0x0, %tl
+ mov PRIMARY_CONTEXT, %g1
+ ldxa [%g1] ASI_DMMU, %g2
+ stxa %g0, [%g1] ASI_DMMU
- sll %g5, 3, %g5
- sethi %uhi(KERNBASE), %g4
- or %g4, %ulo(KERNBASE), %g4
- sethi %hi(current_set), %g6
- or %g6, %lo(current_set), %g6
- sllx %g4, 32, %g4
- wrpr %g5, %wstate
- rdpr %canrestore, %g5
- ldx [%g6 + %g4], %g6
-#ifdef __SMP__
-/* FIXME: Fix the above insn for SMP */
-#endif
- wrpr %g0, 0, %canrestore
- wrpr %g5, 0, %otherwin
- ba,pt %xcc, 2f
- ldx [%g6 + AOFF_task_saved_kernel_stack], %g5
+ mov SECONDARY_CONTEXT, %g1
+ stxa %g2, [%g1] ASI_DMMU
+
+ rd %pic, %g1
+ sethi %hi((PAGE_SIZE<<1)-TRACEREG_SZ-REGWIN_SZ), %g2
+ or %g2, %lo((PAGE_SIZE<<1)-TRACEREG_SZ-REGWIN_SZ), %g2
+ add %g1, %g2, %g2
+ rdpr %tstate, %g1
1:
+ stx %g1, [%g2 + REGWIN_SZ + PT_V9_TSTATE]
+ rdpr %tpc, %g1
+ rdpr %tnpc, %g3
+ stx %g1, [%g2 + REGWIN_SZ + PT_V9_TPC]
+ rd %y, %g1
+ stx %g3, [%g2 + REGWIN_SZ + PT_V9_TNPC]
+ stx %g1, [%g2 + REGWIN_SZ + PT_V9_Y]
+
wrpr %g0, 0x0, %tl
-2:
- rd %y, %g4
- stx %g1, [%g5 + REGWIN_SZ + PT_V9_TSTATE]
- stx %g2, [%g5 + REGWIN_SZ + PT_V9_TPC]
- stx %g3, [%g5 + REGWIN_SZ + PT_V9_TNPC]
- stx %g4, [%g5 + REGWIN_SZ + PT_V9_Y]
rdpr %pstate, %g1
- save %g5, -STACK_BIAS, %sp
+ save %g2, -STACK_BIAS, %sp
+
+ /* Must guarentee that here andcc of TSTATE_PRIV at the top is
+ * still valid in %ccr register. Don't show this trick to your
+ * mom. -DaveM
+ */
+ bne,pn %xcc, 1f
+ rdpr %canrestore, %g3
+ wrpr %g0, 0, %canrestore
+ wrpr %g3, 0, %otherwin
+
+ rdpr %wstate, %g6
+ sll %g6, 3, %g6
+ wrpr %g6, %wstate
+
+1:
mov %g1, %l1
+ mov %g4, %l4
+ mov %g5, %l5
mov %g7, %l2
wrpr %l1, PSTATE_AG, %pstate
stx %g1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G1]
@@ -91,24 +103,13 @@ etrap_irq:
stx %i6, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I6]
stx %i7, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I7]
wrpr %l1, (PSTATE_IE | PSTATE_AG), %pstate
- sethi %uhi(KERNBASE), %g4
- or %g4, %ulo(KERNBASE), %g4
- sethi %hi(current_set), %g6
- or %g6, %lo(current_set), %g6
- sllx %g4, 32, %g4
+ srlx %sp, 43, %g4
+ rd %pic, %g6
jmpl %l2 + 0x4, %g0
- ldx [%g6 + %g4], %g6
-#ifdef __SMP__
-/* FIXME: Fix the above insn for SMP */
-#endif
+ sllx %g4, 43, %g4
.globl etraptl1
etraptl1:
- rdpr %tl, %g4
rdpr %tstate, %g1
- sub %g4, 1, %g4
- rdpr %tpc, %g2
- rdpr %tnpc, %g3
- wrpr %g4, 0x0, %tl
ba,pt %xcc, 1b
- sub %sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g5
+ sub %sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2
diff --git a/arch/sparc64/kernel/hack.S b/arch/sparc64/kernel/hack.S
index 0aca22a77..034bda2d0 100644
--- a/arch/sparc64/kernel/hack.S
+++ b/arch/sparc64/kernel/hack.S
@@ -4,8 +4,6 @@
to compile... */
.text
.align 8
- .globl _sigpause_common
-_sigpause_common: retl;nop
.globl breakpoint
breakpoint: retl;nop
.globl do_cee
@@ -36,8 +34,6 @@ do_fpother_tl1: retl;nop
do_iae: retl;nop
.globl do_iae_tl1
do_iae_tl1: retl;nop
- .globl do_ill
-do_ill: retl;nop
.globl do_ill_tl1
do_ill_tl1: retl;nop
.globl do_irq
@@ -48,8 +44,6 @@ do_irq_tl1: retl;nop
do_lddfmna: retl;nop
.globl do_lddfmna_tl1
do_lddfmna_tl1: retl;nop
- .globl do_mna
-do_mna: retl;nop
.globl do_mna_tl1
do_mna_tl1: retl;nop
.globl do_paw
@@ -60,8 +54,6 @@ do_paw_tl1: retl;nop
do_privact: retl;nop
.globl do_privop
do_privop: retl;nop
- .globl do_signal
-do_signal: retl;nop
.globl do_stdfmna
do_stdfmna: retl;nop
.globl do_stdfmna_tl1
@@ -200,15 +192,7 @@ sunos_write: retl;nop
sunos_writev: retl;nop
.globl sys_ptrace
sys_ptrace: retl;nop
- .globl sys_sigreturn
-sys_sigreturn: retl;nop
- .globl sys_sigstack
-sys_sigstack: retl;nop
- .globl sys_sigsuspend
-sys_sigsuspend: retl;nop
.globl syscall_trace
syscall_trace: retl;nop
.globl sys32_ptrace
sys32_ptrace: retl;nop
- .globl do_sigpause
-do_sigpause: retl;nop
diff --git a/arch/sparc64/kernel/head.S b/arch/sparc64/kernel/head.S
index fdbe87aa3..4babe3eb4 100644
--- a/arch/sparc64/kernel/head.S
+++ b/arch/sparc64/kernel/head.S
@@ -1,4 +1,4 @@
-/* $Id: head.S,v 1.27 1997/04/04 00:49:49 davem Exp $
+/* $Id: head.S,v 1.30 1997/05/18 22:52:12 davem Exp $
* head.S: Initial boot code for the Sparc64 port of Linux.
*
* Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -262,16 +262,22 @@ sun4u_init:
stx %g6, [%g2 + %g4]
stx %g5, [%g3 + %g4]
- sethi %hi(init_task), %g6
- or %g6, %lo(init_task), %g6
+ sethi %hi(init_task_union), %g6
+ or %g6, %lo(init_task_union), %g6
add %g6, %g4, %g6 ! g6 usage is fixed as well
mov %sp, %l6
mov %o4, %l7
- sethi %hi(bootup_kernel_stack + 0x2000 - STACK_BIAS - REGWIN_SZ), %g5
- or %g5, %lo(bootup_kernel_stack + 0x2000 - STACK_BIAS - REGWIN_SZ), %g5
- add %g5, %g4, %sp
+ /* Setup "Linux Current Register", thanks Sun 8-) */
+ wr %g0, 0x1, %pcr
+ wr %g6, 0x0, %pic
+
+ mov 1, %g5
+ sllx %g5, (PAGE_SHIFT + 1), %g5
+ sub %g5, (REGWIN_SZ + STACK_BIAS), %g5
+ add %g6, %g5, %sp
mov 0, %fp
+
wrpr %g0, 0, %wstate
wrpr %g0, 0x0, %tl
@@ -287,14 +293,20 @@ sun4u_init:
add %l2, 1, %l2
add %l0, %g4, %o0
1:
- call bzero_1page
+ clr %o1
+ sethi %hi(PAGE_SIZE), %o2
+ or %o2, %lo(PAGE_SIZE), %o2
+ call __memset
add %l0, %l2, %l0
cmp %l0, %l1
blu,pt %xcc, 1b
add %l0, %g4, %o0
/* Now clear empty_zero_page */
- call bzero_1page
+ clr %o1
+ sethi %hi(PAGE_SIZE), %o2
+ or %o2, %lo(PAGE_SIZE), %o2
+ call __memset
mov %g4, %o0
mov %l6, %o1 ! OpenPROM stack
@@ -361,6 +373,9 @@ bootup_kernel_stack:
#include "ttable.S"
+ /* This is just anal retentiveness on my part... */
+ .align 16384
+
.data
.align 8
.globl nwindows, nwindowsm1
diff --git a/arch/sparc64/kernel/init_task.c b/arch/sparc64/kernel/init_task.c
new file mode 100644
index 000000000..d0fc09346
--- /dev/null
+++ b/arch/sparc64/kernel/init_task.c
@@ -0,0 +1,18 @@
+#include <linux/mm.h>
+#include <linux/sched.h>
+
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+
+static struct vm_area_struct init_mmap = INIT_MMAP;
+static struct fs_struct init_fs = INIT_FS;
+static struct files_struct init_files = INIT_FILES;
+static struct signal_struct init_signals = INIT_SIGNALS;
+struct mm_struct init_mm = INIT_MM;
+
+/* .text section in head.S is aligned at 2 page boundry and this gets linked
+ * right after that so that the init_task_union is aligned properly as well.
+ * We really don't need this special alignment like the Intel does, but
+ * I do it anyways for completeness.
+ */
+union task_union init_task_union __attribute__((__section__(".text"))) = { INIT_TASK };
diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c
index 5ec62a6b6..4e2bbe016 100644
--- a/arch/sparc64/kernel/process.c
+++ b/arch/sparc64/kernel/process.c
@@ -1,4 +1,4 @@
-/* $Id: process.c,v 1.6 1997/04/07 18:57:07 jj Exp $
+/* $Id: process.c,v 1.11 1997/05/18 22:52:19 davem Exp $
* arch/sparc64/kernel/process.c
*
* Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -346,7 +346,14 @@ void flush_thread(void)
}
/* Now, this task is no longer a kernel thread. */
- current->tss.flags &= ~SPARC_FLAG_KTHREAD;
+ if(current->tss.flags & SPARC_FLAG_KTHREAD) {
+ current->tss.flags &= ~SPARC_FLAG_KTHREAD;
+
+ /* exec_mmap() set context to NO_CONTEXT, here is
+ * where we grab a new one.
+ */
+ get_mmu_context(current);
+ }
current->tss.current_ds = USER_DS;
}
@@ -416,6 +423,64 @@ clone_stackframe(struct sparc_stackf *dst, struct sparc_stackf *src)
return sp;
}
+/* Standard stuff. */
+static inline void shift_window_buffer(int first_win, int last_win,
+ struct thread_struct *tp)
+{
+ int i;
+
+ for(i = first_win; i < last_win; i++) {
+ tp->rwbuf_stkptrs[i] = tp->rwbuf_stkptrs[i+1];
+ memcpy(&tp->reg_window[i], &tp->reg_window[i+1],
+ sizeof(struct reg_window));
+ }
+}
+
+void synchronize_user_stack(void)
+{
+ struct thread_struct *tp = &current->tss;
+ unsigned long window = tp->w_saved;
+
+ flush_user_windows();
+ if(window) {
+ int winsize = REGWIN_SZ;
+
+ if(tp->flags & SPARC_FLAG_32BIT)
+ winsize = REGWIN32_SZ;
+
+ window -= 1;
+ do {
+ unsigned long sp = tp->rwbuf_stkptrs[window];
+ struct reg_window *rwin = &tp->reg_window[window];
+
+ if(!copy_to_user((char *)sp, rwin, winsize)) {
+ shift_window_buffer(window, tp->w_saved - 1, tp);
+ tp->w_saved--;
+ }
+ } while(window--);
+ }
+}
+
+void fault_in_user_windows(struct pt_regs *regs)
+{
+ struct thread_struct *tp = &current->tss;
+ unsigned long window = tp->w_saved;
+ int winsize = REGWIN_SZ;
+
+ if(tp->flags & SPARC_FLAG_32BIT)
+ winsize = REGWIN32_SZ;
+ if(window) {
+ window -= 1;
+ do {
+ unsigned long sp = tp->rwbuf_stkptrs[window];
+ struct reg_window *rwin = &tp->reg_window[window];
+
+ if(copy_to_user((char *)sp, rwin, winsize))
+ do_exit(SIGILL);
+ } while(window--);
+ }
+ current->tss.w_saved = 0;
+}
/* Copy a Sparc thread. The fork() return value conventions
* under SunOS are nothing short of bletcherous:
@@ -453,19 +518,18 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
#endif
/* Calculate offset to stack_frame & pt_regs */
- stack_offset = (PAGE_SIZE - TRACEREG_SZ);
+ stack_offset = ((PAGE_SIZE<<1) - TRACEREG_SZ);
if(regs->tstate & TSTATE_PRIV)
stack_offset -= REGWIN_SZ;
- childregs = ((struct pt_regs *) (p->kernel_stack_page + stack_offset));
+ childregs = ((struct pt_regs *) (((unsigned long)p) + stack_offset));
*childregs = *regs;
new_stack = (((struct reg_window *) childregs) - 1);
old_stack = (((struct reg_window *) regs) - 1);
*new_stack = *old_stack;
- p->saved_kernel_stack = ((unsigned long) new_stack);
- p->tss.ksp = p->saved_kernel_stack - STACK_BIAS;
+ p->tss.ksp = ((unsigned long) new_stack) - STACK_BIAS;
p->tss.kpc = ((unsigned long) ret_from_syscall) - 0x8;
p->tss.kregs = childregs;
@@ -485,7 +549,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
p->tss.current_ds = USER_DS;
#if 0
- if (sp != current->tss.kregs->u_regs[UREG_FP]) {
+ if (sp != regs->u_regs[UREG_FP]) {
struct sparc_stackf *childstack;
struct sparc_stackf *parentstack;
@@ -494,8 +558,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
* Set some valid stack frames to give to the child.
*/
childstack = (struct sparc_stackf *)sp;
- parentstack = (struct sparc_stackf *)
- current->tss.kregs->u_regs[UREG_FP];
+ parentstack = (struct sparc_stackf *)regs->u_regs[UREG_FP];
#if 0
printk("clone: parent stack:\n");
diff --git a/arch/sparc64/kernel/rtrap.S b/arch/sparc64/kernel/rtrap.S
index dfebd7ad8..1c4c4df04 100644
--- a/arch/sparc64/kernel/rtrap.S
+++ b/arch/sparc64/kernel/rtrap.S
@@ -1,4 +1,4 @@
-/* $Id: rtrap.S,v 1.11 1997/04/03 13:03:50 davem Exp $
+/* $Id: rtrap.S,v 1.14 1997/05/18 08:42:14 davem Exp $
* rtrap.S: Preparing for return from trap on Sparc V9.
*
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -71,12 +71,11 @@ rtrap:
/* We came here from to_user, ie. we have now AG.
* Also have to push user context back into primary.
*/
- restore
-
mov SECONDARY_CONTEXT, %g6
mov PRIMARY_CONTEXT, %g7
ldxa [%g6] ASI_DMMU, %g4
stxa %g4, [%g7] ASI_DMMU
+ membar #Sync /* XXX flushi would be better -DaveM */
rdpr %wstate, %g1
rdpr %otherwin, %g2
@@ -84,7 +83,6 @@ rtrap:
wrpr %g2, %g0, %canrestore
wrpr %g1, %g0, %wstate
wrpr %g0, %g0, %otherwin
- retry
1:
restore
retry
@@ -101,9 +99,14 @@ to_user:
ldx [%g6 + AOFF_task_blocked], %o0
or %l7, PSTATE_AG, %l7 ! Will need this for setting back wstate
andncc %l0, %o0, %g0
- be,pt %xcc, 3b
+ be,pt %xcc, check_user_wins
mov %l5, %o2
mov %l6, %o3
- add %sp, STACK_BIAS + REGWIN_SZ, %o1
call do_signal
+ add %sp, STACK_BIAS + REGWIN_SZ, %o1
+check_user_wins:
+ ldx [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2
+ brz,pt %o2, 3b
+ add %sp, STACK_BIAS + REGWIN_SZ, %o1
+ call fault_in_user_windows
add %o7, 3b-.-4, %o7
diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c
index 170e5563e..47d900977 100644
--- a/arch/sparc64/kernel/setup.c
+++ b/arch/sparc64/kernel/setup.c
@@ -1,4 +1,4 @@
-/* $Id: setup.c,v 1.5 1997/04/04 00:49:52 davem Exp $
+/* $Id: setup.c,v 1.6 1997/05/04 07:21:04 davem Exp $
* linux/arch/sparc64/kernel/setup.c
*
* Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu)
@@ -261,6 +261,8 @@ __initfunc(void setup_arch(char **cmdline_p,
*cmdline_p = prom_getbootargs();
strcpy(saved_command_line, *cmdline_p);
+ prom_printf("BOOT: args[%s] saved[%s]\n", *cmdline_p, saved_command_line);
+
printk("ARCH: SUN4U\n");
boot_flags_init(*cmdline_p);
diff --git a/arch/sparc64/kernel/signal.c b/arch/sparc64/kernel/signal.c
new file mode 100644
index 000000000..1a595491a
--- /dev/null
+++ b/arch/sparc64/kernel/signal.c
@@ -0,0 +1,438 @@
+/* $Id: signal.c,v 1.2 1997/05/18 08:42:15 davem Exp $
+ * arch/sparc64/kernel/signal.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/wait.h>
+#include <linux/ptrace.h>
+#include <linux/unistd.h>
+#include <linux/mm.h>
+
+#include <asm/uaccess.h>
+#include <asm/bitops.h>
+#include <asm/ptrace.h>
+#include <asm/svr4.h>
+#include <asm/pgtable.h>
+#include <asm/fpumacro.h>
+#include <asm/smp_lock.h>
+
+#define _S(nr) (1<<((nr)-1))
+
+#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
+
+asmlinkage int sys_wait4(pid_t pid, unsigned long *stat_addr,
+ int options, unsigned long *ru);
+
+asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs,
+ unsigned long orig_o0, int ret_from_syscall);
+
+/* This turned off for production... */
+/* #define DEBUG_SIGNALS 1 */
+
+/*
+ * The new signal frame, intended to be used for Linux applications only
+ * (we have enough in there to work with clone).
+ * All the interesting bits are in the info field.
+ */
+
+struct new_signal_frame {
+ struct sparc_stackf ss;
+ __siginfo_t info;
+ __siginfo_fpu_t * fpu_save;
+ unsigned int insns [2];
+ __siginfo_fpu_t fpu_state;
+};
+
+/* Align macros */
+#define NF_ALIGNEDSZ (((sizeof(struct new_signal_frame) + 7) & (~7)))
+
+/*
+ * atomically swap in the new signal mask, and wait for a signal.
+ * This is really tricky on the Sparc, watch out...
+ */
+asmlinkage void _sigpause_common(unsigned int set, struct pt_regs *regs)
+{
+ unsigned int mask;
+
+#ifdef CONFIG_SPARC32_COMPAT
+ if (current->tss.flags & SPARC_FLAG_32BIT) {
+ extern asmlinkage void _sigpause32_common(unsigned int, struct pt_regs *);
+ _sigpause32_common(set, regs);
+ return;
+ }
+#endif
+ spin_lock_irq(&current->sigmask_lock);
+ mask = current->blocked;
+ current->blocked = set & _BLOCKABLE;
+ spin_unlock_irq(&current->sigmask_lock);
+
+ regs->tpc = regs->tnpc;
+ regs->tnpc += 4;
+
+ /* Condition codes and return value where set here for sigpause,
+ * and so got used by setup_frame, which again causes sigreturn()
+ * to return -EINTR.
+ */
+ while (1) {
+ current->state = TASK_INTERRUPTIBLE;
+ schedule();
+ /*
+ * Return -EINTR and set condition code here,
+ * so the interrupted system call actually returns
+ * these.
+ */
+ regs->tstate |= (TSTATE_ICARRY|TSTATE_XCARRY);
+ regs->u_regs[UREG_I0] = EINTR;
+ if (do_signal(mask, regs, 0, 0))
+ return;
+ }
+}
+
+asmlinkage void do_sigpause(unsigned int set, struct pt_regs *regs)
+{
+ _sigpause_common(set, regs);
+}
+
+asmlinkage void do_sigsuspend(struct pt_regs *regs)
+{
+ _sigpause_common(regs->u_regs[UREG_I0], regs);
+}
+
+
+static inline void
+restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu)
+{
+#ifdef __SMP__
+ if (current->flags & PF_USEDFPU)
+ regs->tstate &= ~(TSTATE_PEF);
+#else
+ if (current == last_task_used_math) {
+ last_task_used_math = 0;
+ regs->tstate &= ~(TSTATE_PEF);
+ }
+#endif
+ current->used_math = 1;
+ current->flags &= ~PF_USEDFPU;
+
+ copy_from_user(&current->tss.float_regs[0],
+ &fpu->si_float_regs[0],
+ (sizeof(unsigned int) * 64));
+ __get_user(current->tss.fsr, &fpu->si_fsr);
+}
+
+void do_sigreturn(struct pt_regs *regs)
+{
+ struct new_signal_frame *sf;
+ unsigned long tpc, tnpc, tstate;
+ __siginfo_fpu_t *fpu_save;
+ int mask;
+
+#ifdef CONFIG_SPARC32_COMPAT
+ if (current->tss.flags & SPARC_FLAG_32BIT) {
+ extern asmlinkage void do_sigreturn32(struct pt_regs *);
+ do_sigreturn32(regs);
+ return;
+ }
+#endif
+ synchronize_user_stack ();
+ sf = (struct new_signal_frame *) regs->u_regs [UREG_FP];
+ /* 1. Make sure we are not getting garbage from the user */
+ if (verify_area (VERIFY_READ, sf, sizeof (*sf))){
+ goto segv;
+ }
+ if (((unsigned long) sf) & 3){
+ goto segv;
+ }
+ get_user(tpc, &sf->info.si_regs.tpc);
+ __get_user(tnpc, &sf->info.si_regs.tnpc);
+ if ((tpc | tnpc) & 3){
+ goto segv;
+ }
+ regs->tpc = tpc;
+ regs->tnpc = tnpc;
+
+ /* 2. Restore the state */
+ __get_user(regs->y, &sf->info.si_regs.y);
+ __get_user(tstate, &sf->info.si_regs.tstate);
+ copy_from_user(regs->u_regs, sf->info.si_regs.u_regs, sizeof(regs->u_regs));
+
+ /* User can only change condition codes and FPU enabling in %tstate. */
+ regs->tstate &= ~(TSTATE_ICC | TSTATE_PEF);
+ regs->tstate |= (tstate & (TSTATE_ICC | TSTATE_PEF));
+
+ __get_user(fpu_save, &sf->fpu_save);
+ if (fpu_save)
+ restore_fpu_state(regs, &sf->fpu_state);
+ __get_user(mask, &sf->info.si_mask);
+ current->blocked = mask & _BLOCKABLE;
+ return;
+segv:
+ lock_kernel();
+ do_exit(SIGSEGV);
+}
+
+/* Checks if the fp is valid */
+static int invalid_frame_pointer(void *fp, int fplen)
+{
+ if ((((unsigned long) fp) & 7) || ((unsigned long)fp) > 0x80000000000ULL - fplen)
+ return 1;
+ return 0;
+}
+
+static inline void
+save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu)
+{
+#ifdef __SMP__
+ if (current->flags & PF_USEDFPU) {
+ fpsave(&current->tss.float_regs[0], &current->tss.fsr);
+ regs->tstate &= ~(TSTATE_PEF);
+ current->flags &= ~(PF_USEDFPU);
+ }
+#else
+ if (current == last_task_used_math) {
+ fpsave((unsigned long *)&current->tss.float_regs[0], &current->tss.fsr);
+ last_task_used_math = 0;
+ regs->tstate &= ~(TSTATE_PEF);
+ }
+#endif
+ copy_to_user(&fpu->si_float_regs[0], &current->tss.float_regs[0],
+ (sizeof(unsigned int) * 64));
+ __put_user(current->tss.fsr, &fpu->si_fsr);
+ current->used_math = 0;
+}
+
+static inline void
+new_setup_frame(struct sigaction *sa, struct pt_regs *regs,
+ int signo, unsigned long oldmask)
+{
+ struct new_signal_frame *sf;
+ int sigframe_size;
+ unsigned long tmp;
+ int i;
+
+ /* 1. Make sure everything is clean */
+ synchronize_user_stack();
+ sigframe_size = NF_ALIGNEDSZ;
+ if (!current->used_math)
+ sigframe_size -= sizeof(__siginfo_fpu_t);
+
+ sf = (struct new_signal_frame *)(regs->u_regs[UREG_FP] - sigframe_size);
+
+ if (invalid_frame_pointer (sf, sigframe_size)){
+ lock_kernel ();
+ do_exit(SIGILL);
+ }
+
+ if (current->tss.w_saved != 0){
+ printk ("%s[%d]: Invalid user stack frame for "
+ "signal delivery.\n", current->comm, current->pid);
+ lock_kernel ();
+ do_exit (SIGILL);
+ }
+
+ /* 2. Save the current process state */
+ copy_to_user(&sf->info.si_regs, regs, sizeof (*regs));
+
+ if (current->used_math) {
+ save_fpu_state(regs, &sf->fpu_state);
+ __put_user((u64)&sf->fpu_state, &sf->fpu_save);
+ } else {
+ __put_user(0, &sf->fpu_save);
+ }
+
+ __put_user(oldmask, &sf->info.si_mask);
+ for (i = 0; i < sizeof(struct reg_window)/8; i++) {
+ __get_user(tmp, (((u64 *)regs->u_regs[UREG_FP])+i));
+ __put_user(tmp, (((u64 *)sf)+i));
+ }
+
+ /* 3. return to kernel instructions */
+ __put_user(0x821020d8, &sf->insns[0]); /* mov __NR_sigreturn, %g1 */
+ __put_user(0x91d02011, &sf->insns[1]); /* t 0x11 */
+
+ /* 4. signal handler back-trampoline and parameters */
+ regs->u_regs[UREG_FP] = (unsigned long) sf;
+ regs->u_regs[UREG_I0] = signo;
+ regs->u_regs[UREG_I1] = (unsigned long) &sf->info;
+ regs->u_regs[UREG_I7] = (unsigned long) (&(sf->insns[0]) - 2);
+
+ /* 5. signal handler */
+ regs->tpc = (unsigned long) sa->sa_handler;
+ regs->tnpc = (regs->tpc + 4);
+
+ /* Flush instruction space. */
+ __asm__ __volatile__ ("flush %0; flush %0 + 4" : : "r" (&(sf->insns[0])));
+
+}
+
+static inline void handle_signal(unsigned long signr, struct sigaction *sa,
+ unsigned long oldmask, struct pt_regs *regs)
+{
+ new_setup_frame(sa, regs, signr, oldmask);
+ if(sa->sa_flags & SA_ONESHOT)
+ sa->sa_handler = NULL;
+ if(!(sa->sa_flags & SA_NOMASK))
+ current->blocked |= (sa->sa_mask | _S(signr)) & _BLOCKABLE;
+}
+
+static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs,
+ struct sigaction *sa)
+{
+ switch(regs->u_regs[UREG_I0]) {
+ case ERESTARTNOHAND:
+ no_system_call_restart:
+ regs->u_regs[UREG_I0] = EINTR;
+ regs->tstate |= (TSTATE_ICARRY|TSTATE_XCARRY);
+ break;
+ case ERESTARTSYS:
+ if(!(sa->sa_flags & SA_RESTART))
+ goto no_system_call_restart;
+ /* fallthrough */
+ case ERESTARTNOINTR:
+ regs->u_regs[UREG_I0] = orig_i0;
+ regs->tpc -= 4;
+ regs->tnpc -= 4;
+ }
+}
+
+/* Note that 'init' is a special process: it doesn't get signals it doesn't
+ * want to handle. Thus you cannot kill init even with a SIGKILL even by
+ * mistake.
+ */
+asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs,
+ unsigned long orig_i0, int restart_syscall)
+{
+ unsigned long signr, mask = ~current->blocked;
+ struct sigaction *sa;
+
+#ifdef CONFIG_SPARC32_COMPAT
+ if (current->tss.flags & SPARC_FLAG_32BIT) {
+ extern asmlinkage int do_signal32(unsigned long, struct pt_regs *,
+ unsigned long, int);
+ return do_signal32(oldmask, regs, orig_i0, restart_syscall);
+ }
+#endif
+ while ((signr = current->signal & mask) != 0) {
+ signr = ffz(~signr);
+ clear_bit(signr, &current->signal);
+ sa = current->sig->action + signr;
+ signr++;
+ if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
+ current->exit_code = signr;
+ current->state = TASK_STOPPED;
+ notify_parent(current);
+ schedule();
+ if (!(signr = current->exit_code))
+ continue;
+ current->exit_code = 0;
+ if (signr == SIGSTOP)
+ continue;
+ if (_S(signr) & current->blocked) {
+ current->signal |= _S(signr);
+ continue;
+ }
+ sa = current->sig->action + signr - 1;
+ }
+ if(sa->sa_handler == SIG_IGN) {
+ if(signr != SIGCHLD)
+ continue;
+
+ /* sys_wait4() grabs the master kernel lock, so
+ * we need not do so, that sucker should be
+ * threaded and would not be that difficult to
+ * do anyways.
+ */
+ while(sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
+ ;
+ continue;
+ }
+ if(sa->sa_handler == SIG_DFL) {
+ if(current->pid == 1)
+ continue;
+ switch(signr) {
+ case SIGCONT: case SIGCHLD: case SIGWINCH:
+ continue;
+
+ case SIGTSTP: case SIGTTIN: case SIGTTOU:
+ if (is_orphaned_pgrp(current->pgrp))
+ continue;
+
+ case SIGSTOP:
+ if (current->flags & PF_PTRACED)
+ continue;
+ current->state = TASK_STOPPED;
+ current->exit_code = signr;
+ if(!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
+ SA_NOCLDSTOP))
+ notify_parent(current);
+ schedule();
+ continue;
+
+ case SIGQUIT: case SIGILL: case SIGTRAP:
+ case SIGABRT: case SIGFPE: case SIGSEGV: case SIGBUS:
+ if(current->binfmt && current->binfmt->core_dump) {
+ if(current->binfmt->core_dump(signr, regs))
+ signr |= 0x80;
+ }
+#ifdef DEBUG_SIGNALS
+ /* Very useful to debug dynamic linker problems */
+ printk ("Sig ILL going...\n");
+ show_regs (regs);
+#endif
+ /* fall through */
+ default:
+ current->signal |= _S(signr & 0x7f);
+ current->flags |= PF_SIGNALED;
+ do_exit(signr);
+ }
+ }
+ if(restart_syscall)
+ syscall_restart(orig_i0, regs, sa);
+ handle_signal(signr, sa, oldmask, regs);
+ return 1;
+ }
+ if(restart_syscall &&
+ (regs->u_regs[UREG_I0] == ERESTARTNOHAND ||
+ regs->u_regs[UREG_I0] == ERESTARTSYS ||
+ regs->u_regs[UREG_I0] == ERESTARTNOINTR)) {
+ /* replay the system call when we are done */
+ regs->u_regs[UREG_I0] = orig_i0;
+ regs->tpc -= 4;
+ regs->tnpc -= 4;
+ }
+ return 0;
+}
+
+asmlinkage int
+sys_sigstack(struct sigstack *ssptr, struct sigstack *ossptr)
+{
+ int ret = -EFAULT;
+
+ lock_kernel();
+ /* First see if old state is wanted. */
+ if(ossptr) {
+ if (put_user ((u64)current->tss.sstk_info.the_stack, &ossptr->the_stack) ||
+ __put_user (current->tss.sstk_info.cur_status, &ossptr->cur_status))
+ goto out;
+ }
+
+ /* Now see if we want to update the new state. */
+ if(ssptr) {
+ if (get_user ((u64)current->tss.sstk_info.the_stack, &ssptr->the_stack) ||
+ __put_user (current->tss.sstk_info.cur_status, &ssptr->cur_status))
+ goto out;
+ }
+ ret = 0;
+out:
+ unlock_kernel();
+ return ret;
+}
diff --git a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c
index e1129dfd6..d8e61511d 100644
--- a/arch/sparc64/kernel/signal32.c
+++ b/arch/sparc64/kernel/signal32.c
@@ -1,4 +1,4 @@
-/* $Id: signal32.c,v 1.6 1997/04/16 10:27:17 jj Exp $
+/* $Id: signal32.c,v 1.8 1997/05/18 08:42:15 davem Exp $
* arch/sparc64/kernel/signal32.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
@@ -30,8 +30,6 @@
#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
-#define synchronize_user_stack() do { } while (0)
-
asmlinkage int sys_wait4(pid_t pid, unsigned long *stat_addr,
int options, unsigned long *ru);
@@ -117,17 +115,6 @@ asmlinkage void _sigpause32_common(unsigned int set, struct pt_regs *regs)
}
}
-asmlinkage void do_sigpause32(unsigned int set, struct pt_regs *regs)
-{
- _sigpause32_common(set, regs);
-}
-
-asmlinkage void do_sigsuspend32(struct pt_regs *regs)
-{
- _sigpause32_common(regs->u_regs[UREG_I0], regs);
-}
-
-
static inline void
restore_fpu_state32(struct pt_regs *regs, __siginfo_fpu32_t *fpu)
{
@@ -248,7 +235,9 @@ setup_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc,
{
struct signal_sframe32 *sframep;
struct sigcontext32 *sc;
+#if 0
int window = 0;
+#endif
int old_status = current->tss.sstk_info.cur_status;
unsigned psr;
int i;
@@ -424,7 +413,9 @@ setup_svr4_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc,
svr4_mcontext_t *mc;
svr4_gwindows_t *gw;
svr4_ucontext_t *uc;
+#if 0
int window = 0;
+#endif
unsigned psr;
int i;
diff --git a/arch/sparc64/kernel/sparcelf32.c b/arch/sparc64/kernel/sparcelf32.c
deleted file mode 100644
index 855c636e4..000000000
--- a/arch/sparc64/kernel/sparcelf32.c
+++ /dev/null
@@ -1,1281 +0,0 @@
-/* sparcelf32.c: Support 32-bit Sparc ELF binaries on Ultra.
- *
- * This is just binfmt_elf.c with hooks so that the types are those
- * for a 32-bit ELF binaries.
- */
-
-/* This makes it work. */
-#define ELF_ARCH EM_SPARC
-#define ELF_CLASS ELFCLASS32
-#define ELF_DATA ELFDATA2MSB;
-
-/*
- * linux/fs/binfmt_elf.c
- *
- * These are the functions used to load ELF format executables as used
- * on SVr4 machines. Information on the format may be found in the book
- * "UNIX SYSTEM V RELEASE 4 Programmers Guide: Ansi C and Programming Support
- * Tools".
- *
- * Copyright 1993, 1994: Eric Youngdale (ericy@cais.com).
- */
-
-#include <linux/module.h>
-
-#include <linux/fs.h>
-#include <linux/stat.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/mman.h>
-#include <linux/a.out.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/binfmts.h>
-#include <linux/string.h>
-#include <linux/fcntl.h>
-#include <linux/ptrace.h>
-#include <linux/malloc.h>
-#include <linux/shm.h>
-#include <linux/personality.h>
-#include <linux/elfcore.h>
-#include <linux/init.h>
-
-#include <asm/uaccess.h>
-#include <asm/pgtable.h>
-
-#include <linux/config.h>
-
-#define DLINFO_ITEMS 12
-
-#include <linux/elf.h>
-
-static int load_elf32_binary(struct linux_binprm * bprm, struct pt_regs * regs);
-static int load_elf32_library(int fd);
-extern int dump_fpu (struct pt_regs *, elf_fpregset_t *);
-extern void dump_thread(struct pt_regs *, struct user *);
-
-extern unsigned long get_unmapped_area(unsigned long addr, unsigned long len);
-
-/*
- * If we don't support core dumping, then supply a NULL so we
- * don't even try.
- */
-#ifdef USE_ELF_CORE_DUMP
-static int elf32_core_dump(long signr, struct pt_regs * regs);
-#else
-#define elf32_core_dump NULL
-#endif
-
-#define ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(ELF_EXEC_PAGESIZE-1))
-#define ELF_PAGEOFFSET(_v) ((_v) & (ELF_EXEC_PAGESIZE-1))
-
-static struct linux_binfmt elf32_format = {
-#ifndef MODULE
- NULL, NULL, load_elf32_binary, load_elf32_library, elf32_core_dump
-#else
- NULL, &__this_module, load_elf32_binary, load_elf32_library, elf32_core_dump
-#endif
-};
-
-static void set_brk(unsigned long start, unsigned long end)
-{
- start = PAGE_ALIGN(start);
- end = PAGE_ALIGN(end);
- if (end <= start)
- return;
- do_mmap(NULL, start, end - start,
- PROT_READ | PROT_WRITE | PROT_EXEC,
- MAP_FIXED | MAP_PRIVATE, 0);
-}
-
-
-/* We need to explicitly zero any fractional pages
- after the data section (i.e. bss). This would
- contain the junk from the file that should not
- be in memory */
-
-
-static void padzero(unsigned long elf_bss)
-{
- unsigned long nbyte;
-
- nbyte = elf_bss & (PAGE_SIZE-1);
- if (nbyte) {
- nbyte = PAGE_SIZE - nbyte;
- clear_user((void *) elf_bss, nbyte);
- }
-}
-
-__u32 *create_elf32_tables(char *p, int argc, int envc,
- struct elfhdr * exec,
- unsigned long load_addr,
- unsigned long interp_load_addr, int ibcs)
-{
- __u32 *argv, *envp;
- __u32 *sp, *csp;
-
- /*
- * Force 16 byte alignment here for generality.
- */
- sp = (__u32 *) (~15UL & (unsigned long) p);
- csp = sp;
- csp -= exec ? DLINFO_ITEMS*2 : 2;
- csp -= envc+1;
- csp -= argc+1;
- if (!(((unsigned long) csp) & 4))
- sp--;
-
- /*
- * Put the ELF interpreter info on the stack
- */
-#define NEW_AUX_ENT(nr, id, val) \
- __put_user ((id), sp+(nr*2)); \
- __put_user ((val), sp+(nr*2+1)); \
-
- sp -= 2;
- NEW_AUX_ENT(0, AT_NULL, 0);
-
- if (exec) {
- sp -= 11*2;
-
- NEW_AUX_ENT (0, AT_PHDR, load_addr + exec->e_phoff);
- NEW_AUX_ENT (1, AT_PHENT, sizeof (struct elf_phdr));
- NEW_AUX_ENT (2, AT_PHNUM, exec->e_phnum);
- NEW_AUX_ENT (3, AT_PAGESZ, PAGE_SIZE);
- NEW_AUX_ENT (4, AT_BASE, interp_load_addr);
- NEW_AUX_ENT (5, AT_FLAGS, 0);
- NEW_AUX_ENT (6, AT_ENTRY, (__u32) exec->e_entry);
- NEW_AUX_ENT (7, AT_UID, (__u32) current->uid);
- NEW_AUX_ENT (8, AT_EUID, (__u32) current->euid);
- NEW_AUX_ENT (9, AT_GID, (__u32) current->gid);
- NEW_AUX_ENT (10, AT_EGID, (__u32) current->egid);
- }
-#undef NEW_AUX_ENT
-
- sp -= envc+1;
- envp = (__u32 *) sp;
- sp -= argc+1;
- argv = (__u32 *) sp;
- if (!ibcs) {
- __put_user(((__u32)(long) envp),--sp);
- __put_user(((__u32)(long) argv),--sp);
- }
-
- __put_user((__u32)argc,--sp);
- current->mm->arg_start = (unsigned long) p;
- while (argc-->0) {
- __put_user(((__u32)(long)p),argv++);
- p += strlen_user(p);
- }
- __put_user(NULL, argv);
- current->mm->arg_end = current->mm->env_start = (unsigned long) p;
- while (envc-->0) {
- __put_user(((__u32)(long)p),envp++);
- p += strlen_user(p);
- }
- __put_user(NULL, envp);
- current->mm->env_end = (unsigned long) p;
- return sp;
-}
-
-
-/* This is much more generalized than the library routine read function,
- so we keep this separate. Technically the library read function
- is only provided so that we can read a.out libraries that have
- an ELF header */
-
-static unsigned long load_elf32_interp(struct elfhdr * interp_elf_ex,
- struct inode * interpreter_inode,
- unsigned long *interp_load_addr)
-{
- struct file * file;
- struct elf_phdr *elf_phdata = NULL;
- struct elf_phdr *eppnt;
- unsigned long load_addr;
- int load_addr_set = 0;
- int elf_exec_fileno;
- int retval;
- unsigned long last_bss, elf_bss;
- unsigned long error;
- int i;
-
- elf_bss = 0;
- last_bss = 0;
- error = load_addr = 0;
-
- /* First of all, some simple consistency checks */
- if ((interp_elf_ex->e_type != ET_EXEC &&
- interp_elf_ex->e_type != ET_DYN) ||
- !elf_check_arch(interp_elf_ex->e_machine) ||
- (!interpreter_inode->i_op ||
- !interpreter_inode->i_op->default_file_ops->mmap)){
- return ~0UL;
- }
-
- /* Now read in all of the header information */
-
- if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > PAGE_SIZE)
- return ~0UL;
-
- elf_phdata = (struct elf_phdr *)
- kmalloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum,
- GFP_KERNEL);
- if (!elf_phdata)
- return ~0UL;
-
- /*
- * If the size of this structure has changed, then punt, since
- * we will be doing the wrong thing.
- */
- if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr))
- {
- kfree(elf_phdata);
- return ~0UL;
- }
-
- retval = read_exec(interpreter_inode, interp_elf_ex->e_phoff,
- (char *) elf_phdata,
- sizeof(struct elf_phdr) * interp_elf_ex->e_phnum, 1);
-
- if (retval < 0) {
- kfree (elf_phdata);
- return retval;
- }
-
- elf_exec_fileno = open_inode(interpreter_inode, O_RDONLY);
- if (elf_exec_fileno < 0) {
- kfree(elf_phdata);
- return ~0UL;
- }
-
- file = current->files->fd[elf_exec_fileno];
-
- eppnt = elf_phdata;
- for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++)
- if (eppnt->p_type == PT_LOAD) {
- int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
- int elf_prot = 0;
- unsigned long vaddr = 0;
- unsigned long k;
-
- if (eppnt->p_flags & PF_R) elf_prot = PROT_READ;
- if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
- if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
- if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) {
- elf_type |= MAP_FIXED;
- vaddr = eppnt->p_vaddr;
- } else {
- load_addr = get_unmapped_area(0, eppnt->p_filesz +
- ELF_PAGEOFFSET(eppnt->p_vaddr));
- }
-
- error = do_mmap(file,
- load_addr + ELF_PAGESTART(vaddr),
- eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr),
- elf_prot,
- elf_type,
- eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr));
-
- if (error > -1024UL) {
- /* Real error */
- sys_close(elf_exec_fileno);
- kfree(elf_phdata);
- return ~0UL;
- }
-
- if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) {
- load_addr = error;
- load_addr_set = 1;
- }
-
- /*
- * Find the end of the file mapping for this phdr, and keep
- * track of the largest address we see for this.
- */
- k = load_addr + eppnt->p_vaddr + eppnt->p_filesz;
- if (k > elf_bss) elf_bss = k;
-
- /*
- * Do the same thing for the memory mapping - between
- * elf_bss and last_bss is the bss section.
- */
- k = load_addr + eppnt->p_memsz + eppnt->p_vaddr;
- if (k > last_bss) last_bss = k;
- }
-
- /* Now use mmap to map the library into memory. */
-
- sys_close(elf_exec_fileno);
-
- /*
- * Now fill out the bss section. First pad the last page up
- * to the page boundary, and then perform a mmap to make sure
- * that there are zeromapped pages up to and including the last
- * bss page.
- */
- padzero(elf_bss);
- elf_bss = ELF_PAGESTART(elf_bss + ELF_EXEC_PAGESIZE - 1); /* What we have mapped so far */
-
- /* Map the last of the bss segment */
- if (last_bss > elf_bss)
- do_mmap(NULL, elf_bss, last_bss-elf_bss,
- PROT_READ|PROT_WRITE|PROT_EXEC,
- MAP_FIXED|MAP_PRIVATE, 0);
- kfree(elf_phdata);
-
- *interp_load_addr = load_addr;
- return ((unsigned long) interp_elf_ex->e_entry) + load_addr;
-}
-
-static unsigned long load_aout32_interp(struct exec * interp_ex,
- struct inode * interpreter_inode)
-{
- int retval;
- unsigned long elf_entry;
-
- current->mm->brk = interp_ex->a_bss +
- (current->mm->end_data = interp_ex->a_data +
- (current->mm->end_code = interp_ex->a_text));
- elf_entry = interp_ex->a_entry;
-
-
- if (N_MAGIC(*interp_ex) == OMAGIC) {
- do_mmap(NULL, 0, interp_ex->a_text+interp_ex->a_data,
- PROT_READ|PROT_WRITE|PROT_EXEC,
- MAP_FIXED|MAP_PRIVATE, 0);
- retval = read_exec(interpreter_inode, 32, (char *) 0,
- interp_ex->a_text+interp_ex->a_data, 0);
- } else if (N_MAGIC(*interp_ex) == ZMAGIC || N_MAGIC(*interp_ex) == QMAGIC) {
- do_mmap(NULL, 0, interp_ex->a_text+interp_ex->a_data,
- PROT_READ|PROT_WRITE|PROT_EXEC,
- MAP_FIXED|MAP_PRIVATE, 0);
- retval = read_exec(interpreter_inode,
- N_TXTOFF(*interp_ex) ,
- (char *) N_TXTADDR(*interp_ex),
- interp_ex->a_text+interp_ex->a_data, 0);
- } else
- retval = -1;
-
- if (retval >= 0)
- do_mmap(NULL, ELF_PAGESTART(interp_ex->a_text + interp_ex->a_data + ELF_EXEC_PAGESIZE - 1),
- interp_ex->a_bss,
- PROT_READ|PROT_WRITE|PROT_EXEC,
- MAP_FIXED|MAP_PRIVATE, 0);
- if (retval < 0) return ~0UL;
- return elf_entry;
-}
-
-/*
- * These are the functions used to load ELF style executables and shared
- * libraries. There is no binary dependent code anywhere else.
- */
-
-#define INTERPRETER_NONE 0
-#define INTERPRETER_AOUT 1
-#define INTERPRETER_ELF 2
-
-
-static inline int
-do_load_elf32_binary(struct linux_binprm * bprm, struct pt_regs * regs)
-{
- struct elfhdr elf_ex;
- struct elfhdr interp_elf_ex;
- struct file * file;
- struct exec interp_ex;
- struct inode *interpreter_inode;
- unsigned long load_addr;
- int load_addr_set = 0;
- unsigned int interpreter_type = INTERPRETER_NONE;
- unsigned char ibcs2_interpreter;
- int i;
- int old_fs;
- int error;
- struct elf_phdr * elf_ppnt, *elf_phdata;
- int elf_exec_fileno;
- unsigned long elf_bss, k, elf_brk;
- int retval;
- char * elf_interpreter;
- unsigned long elf_entry, interp_load_addr = 0;
- int status;
- unsigned long start_code, end_code, end_data;
- unsigned long elf_stack;
- char passed_fileno[6];
-
- ibcs2_interpreter = 0;
- status = 0;
- load_addr = 0;
- elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */
-
- if (elf_ex.e_ident[0] != 0x7f ||
- strncmp(&elf_ex.e_ident[1], "ELF",3) != 0) {
- return -ENOEXEC;
- }
-
-
- /* First of all, some simple consistency checks */
- if ((elf_ex.e_type != ET_EXEC &&
- elf_ex.e_type != ET_DYN) ||
- (! elf_check_arch(elf_ex.e_machine)) ||
- (!bprm->inode->i_op || !bprm->inode->i_op->default_file_ops ||
- !bprm->inode->i_op->default_file_ops->mmap)){
- return -ENOEXEC;
- }
-
- /* Now read in all of the header information */
-
- elf_phdata = (struct elf_phdr *) kmalloc(elf_ex.e_phentsize *
- elf_ex.e_phnum, GFP_KERNEL);
- if (elf_phdata == NULL) {
- return -ENOMEM;
- }
-
- retval = read_exec(bprm->inode, elf_ex.e_phoff, (char *) elf_phdata,
- elf_ex.e_phentsize * elf_ex.e_phnum, 1);
- if (retval < 0) {
- kfree (elf_phdata);
- return retval;
- }
-
- elf_ppnt = elf_phdata;
-
- elf_bss = 0;
- elf_brk = 0;
-
- elf_exec_fileno = open_inode(bprm->inode, O_RDONLY);
-
- if (elf_exec_fileno < 0) {
- kfree (elf_phdata);
- return elf_exec_fileno;
- }
-
- file = current->files->fd[elf_exec_fileno];
-
- elf_stack = ~0UL;
- elf_interpreter = NULL;
- start_code = ~0UL;
- end_code = 0;
- end_data = 0;
-
- for(i=0;i < elf_ex.e_phnum; i++){
- if (elf_ppnt->p_type == PT_INTERP) {
- if ( elf_interpreter != NULL )
- {
- kfree (elf_phdata);
- kfree(elf_interpreter);
- sys_close(elf_exec_fileno);
- return -EINVAL;
- }
-
- /* This is the program interpreter used for
- * shared libraries - for now assume that this
- * is an a.out format binary
- */
-
- elf_interpreter = (char *) kmalloc(elf_ppnt->p_filesz,
- GFP_KERNEL);
- if (elf_interpreter == NULL) {
- kfree (elf_phdata);
- sys_close(elf_exec_fileno);
- return -ENOMEM;
- }
-
- retval = read_exec(bprm->inode,elf_ppnt->p_offset,
- elf_interpreter,
- elf_ppnt->p_filesz, 1);
- /* If the program interpreter is one of these two,
- then assume an iBCS2 image. Otherwise assume
- a native linux image. */
- if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 ||
- strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0)
- ibcs2_interpreter = 1;
-#if 0
- printk("Using ELF interpreter %s\n", elf_interpreter);
-#endif
- if (retval >= 0) {
- old_fs = get_fs(); /* This could probably be optimized */
- set_fs(get_ds());
- retval = open_namei(elf_interpreter, 0, 0,
- &interpreter_inode, NULL);
- set_fs(old_fs);
- }
-
- if (retval >= 0)
- retval = read_exec(interpreter_inode,0,bprm->buf,128, 1);
-
- if (retval >= 0) {
- interp_ex = *((struct exec *) bprm->buf); /* exec-header */
- interp_elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */
-
- }
- if (retval < 0) {
- kfree (elf_phdata);
- kfree(elf_interpreter);
- sys_close(elf_exec_fileno);
- return retval;
- }
- }
- elf_ppnt++;
- }
-
- /* Some simple consistency checks for the interpreter */
- if (elf_interpreter){
- interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT;
-
- /* Now figure out which format our binary is */
- if ((N_MAGIC(interp_ex) != OMAGIC) &&
- (N_MAGIC(interp_ex) != ZMAGIC) &&
- (N_MAGIC(interp_ex) != QMAGIC))
- interpreter_type = INTERPRETER_ELF;
-
- if (interp_elf_ex.e_ident[0] != 0x7f ||
- strncmp(&interp_elf_ex.e_ident[1], "ELF",3) != 0)
- interpreter_type &= ~INTERPRETER_ELF;
-
- if (!interpreter_type)
- {
- kfree(elf_interpreter);
- kfree(elf_phdata);
- sys_close(elf_exec_fileno);
- return -ELIBBAD;
- }
- }
-
- /* OK, we are done with that, now set up the arg stuff,
- and then start this sucker up */
-
- if (!bprm->sh_bang) {
- char * passed_p;
-
- if (interpreter_type == INTERPRETER_AOUT) {
- sprintf(passed_fileno, "%d", elf_exec_fileno);
- passed_p = passed_fileno;
-
- if (elf_interpreter) {
- bprm->p = copy_strings(1,&passed_p,bprm->page,bprm->p,2);
- bprm->argc++;
- }
- }
- if (!bprm->p) {
- if (elf_interpreter) {
- kfree(elf_interpreter);
- }
- kfree (elf_phdata);
- sys_close(elf_exec_fileno);
- return -E2BIG;
- }
- }
-
- /* OK, This is the point of no return */
- flush_old_exec(bprm);
-
- current->mm->end_data = 0;
- current->mm->end_code = 0;
- current->mm->start_mmap = ELF_START_MMAP;
- current->mm->mmap = NULL;
- elf_entry = (unsigned long) elf_ex.e_entry;
-
- /* Do this so that we can load the interpreter, if need be. We will
- change some of these later */
- current->mm->rss = 0;
- bprm->p = setup_arg_pages(bprm->p, bprm);
- current->mm->start_stack = bprm->p;
-
- /* Now we do a little grungy work by mmaping the ELF image into
- the correct location in memory. At this point, we assume that
- the image should be loaded at fixed address, not at a variable
- address. */
-
- old_fs = get_fs();
- set_fs(get_ds());
- for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) {
- if (elf_ppnt->p_type == PT_LOAD) {
- int elf_prot = 0;
- if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ;
- if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
- if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
-
- error = do_mmap(file,
- ELF_PAGESTART(elf_ppnt->p_vaddr),
- (elf_ppnt->p_filesz +
- ELF_PAGEOFFSET(elf_ppnt->p_vaddr)),
- elf_prot,
- (MAP_FIXED | MAP_PRIVATE |
- MAP_DENYWRITE | MAP_EXECUTABLE),
- (elf_ppnt->p_offset -
- ELF_PAGEOFFSET(elf_ppnt->p_vaddr)));
-
-#ifdef LOW_ELF_STACK
- if (ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack)
- elf_stack = ELF_PAGESTART(elf_ppnt->p_vaddr);
-#endif
-
- if (!load_addr_set) {
- load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset;
- load_addr_set = 1;
- }
- k = elf_ppnt->p_vaddr;
- if (k < start_code) start_code = k;
- k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
- if (k > elf_bss) elf_bss = k;
-#if 1
- if ((elf_ppnt->p_flags & PF_X) && end_code < k)
-#else
- if ( !(elf_ppnt->p_flags & PF_W) && end_code < k)
-#endif
- end_code = k;
- if (end_data < k) end_data = k;
- k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
- if (k > elf_brk) elf_brk = k;
- }
- }
- set_fs(old_fs);
-
- if (elf_interpreter) {
- if (interpreter_type & 1)
- elf_entry = load_aout32_interp(&interp_ex,
- interpreter_inode);
- else if (interpreter_type & 2)
- elf_entry = load_elf32_interp(&interp_elf_ex,
- interpreter_inode,
- &interp_load_addr);
-
- iput(interpreter_inode);
- kfree(elf_interpreter);
-
- if (elf_entry == ~0UL) {
- printk("Unable to load interpreter\n");
- kfree(elf_phdata);
- send_sig(SIGSEGV, current, 0);
- return 0;
- }
- }
-
- kfree(elf_phdata);
-
- if (interpreter_type != INTERPRETER_AOUT) sys_close(elf_exec_fileno);
- current->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX);
-
- if (current->exec_domain && current->exec_domain->module)
- __MOD_DEC_USE_COUNT(current->exec_domain->module);
- if (current->binfmt && current->binfmt->module)
- __MOD_DEC_USE_COUNT(current->binfmt->module);
- current->exec_domain = lookup_exec_domain(current->personality);
- current->binfmt = &elf32_format;
- if (current->exec_domain && current->exec_domain->module)
- __MOD_INC_USE_COUNT(current->exec_domain->module);
- if (current->binfmt && current->binfmt->module)
- __MOD_INC_USE_COUNT(current->binfmt->module);
-
-#ifndef VM_STACK_FLAGS
- current->executable = bprm->inode;
- bprm->inode->i_count++;
-#endif
-#ifdef LOW_ELF_STACK
- current->start_stack = bprm->p = elf_stack - 4;
-#endif
- current->suid = current->euid = current->fsuid = bprm->e_uid;
- current->sgid = current->egid = current->fsgid = bprm->e_gid;
- current->flags &= ~PF_FORKNOEXEC;
- bprm->p = (unsigned long)
- create_elf32_tables((char *)bprm->p,
- bprm->argc,
- bprm->envc,
- (interpreter_type == INTERPRETER_ELF ? &elf_ex : NULL),
- load_addr,
- interp_load_addr,
- (interpreter_type == INTERPRETER_AOUT ? 0 : 1));
- if (interpreter_type == INTERPRETER_AOUT)
- current->mm->arg_start += strlen(passed_fileno) + 1;
- current->mm->start_brk = current->mm->brk = elf_brk;
- current->mm->end_code = end_code;
- current->mm->start_code = start_code;
- current->mm->end_data = end_data;
- current->mm->start_stack = bprm->p;
-
- /* Calling set_brk effectively mmaps the pages that we need for the bss and break
- sections */
- set_brk(elf_bss, elf_brk);
-
- padzero(elf_bss);
-
-#if 0
- printk("(start_brk) %x\n" , current->mm->start_brk);
- printk("(end_code) %x\n" , current->mm->end_code);
- printk("(start_code) %x\n" , current->mm->start_code);
- printk("(end_data) %x\n" , current->mm->end_data);
- printk("(start_stack) %x\n" , current->mm->start_stack);
- printk("(brk) %x\n" , current->mm->brk);
-#endif
-
- if ( current->personality == PER_SVR4 )
- {
- /* Why this, you ask??? Well SVr4 maps page 0 as read-only,
- and some applications "depend" upon this behavior.
- Since we do not have the power to recompile these, we
- emulate the SVr4 behavior. Sigh. */
- error = do_mmap(NULL, 0, 4096, PROT_READ | PROT_EXEC,
- MAP_FIXED | MAP_PRIVATE, 0);
- }
-
-#ifdef ELF_PLAT_INIT
- /*
- * The ABI may specify that certain registers be set up in special
- * ways (on i386 %edx is the address of a DT_FINI function, for
- * example. This macro performs whatever initialization to
- * the regs structure is required.
- */
- ELF_PLAT_INIT(regs);
-#endif
-
-
- start_thread32(regs, elf_entry, bprm->p);
- if (current->flags & PF_PTRACED)
- send_sig(SIGTRAP, current, 0);
- return 0;
-}
-
-static int
-load_elf32_binary(struct linux_binprm * bprm, struct pt_regs * regs)
-{
- int retval;
-
- MOD_INC_USE_COUNT;
- retval = do_load_elf32_binary(bprm, regs);
- MOD_DEC_USE_COUNT;
- return retval;
-}
-
-/* This is really simpleminded and specialized - we are loading an
- a.out library that is given an ELF header. */
-
-static inline int
-do_load_elf32_library(int fd){
- struct file * file;
- struct elfhdr elf_ex;
- struct elf_phdr *elf_phdata = NULL;
- struct inode * inode;
- unsigned long len;
- int elf_bss;
- int retval;
- unsigned long bss;
- int error;
- int i,j, k;
-
- len = 0;
- file = current->files->fd[fd];
- inode = file->f_inode;
- elf_bss = 0;
-
- if (!file || !file->f_op)
- return -EACCES;
-
- /* seek to the beginning of the file */
- if (file->f_op->llseek) {
- if ((error = file->f_op->llseek(inode, file, 0, 0)) != 0)
- return -ENOEXEC;
- } else
- file->f_pos = 0;
-
- set_fs(KERNEL_DS);
- error = file->f_op->read(inode, file, (char *) &elf_ex, sizeof(elf_ex));
- set_fs(USER_DS);
- if (error != sizeof(elf_ex))
- return -ENOEXEC;
-
- if (elf_ex.e_ident[0] != 0x7f ||
- strncmp(&elf_ex.e_ident[1], "ELF",3) != 0)
- return -ENOEXEC;
-
- /* First of all, some simple consistency checks */
- if (elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 ||
- !elf_check_arch(elf_ex.e_machine) ||
- (!inode->i_op || !inode->i_op->default_file_ops->mmap))
- return -ENOEXEC;
-
- /* Now read in all of the header information */
-
- if (sizeof(struct elf_phdr) * elf_ex.e_phnum > PAGE_SIZE)
- return -ENOEXEC;
-
- elf_phdata = (struct elf_phdr *)
- kmalloc(sizeof(struct elf_phdr) * elf_ex.e_phnum, GFP_KERNEL);
- if (elf_phdata == NULL)
- return -ENOMEM;
-
- retval = read_exec(inode, elf_ex.e_phoff, (char *) elf_phdata,
- sizeof(struct elf_phdr) * elf_ex.e_phnum, 1);
-
- j = 0;
- for(i=0; i<elf_ex.e_phnum; i++)
- if ((elf_phdata + i)->p_type == PT_LOAD) j++;
-
- if (j != 1) {
- kfree(elf_phdata);
- return -ENOEXEC;
- }
-
- while(elf_phdata->p_type != PT_LOAD) elf_phdata++;
-
- /* Now use mmap to map the library into memory. */
- error = do_mmap(file,
- ELF_PAGESTART(elf_phdata->p_vaddr),
- (elf_phdata->p_filesz +
- ELF_PAGEOFFSET(elf_phdata->p_vaddr)),
- PROT_READ | PROT_WRITE | PROT_EXEC,
- MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE,
- (elf_phdata->p_offset -
- ELF_PAGEOFFSET(elf_phdata->p_vaddr)));
-
- k = elf_phdata->p_vaddr + elf_phdata->p_filesz;
- if (k > elf_bss) elf_bss = k;
-
- if (error != ELF_PAGESTART(elf_phdata->p_vaddr)) {
- kfree(elf_phdata);
- return error;
- }
-
- padzero(elf_bss);
-
- len = ELF_PAGESTART(elf_phdata->p_filesz + elf_phdata->p_vaddr+ ELF_EXEC_PAGESIZE - 1);
- bss = elf_phdata->p_memsz + elf_phdata->p_vaddr;
- if (bss > len)
- do_mmap(NULL, len, bss-len,
- PROT_READ|PROT_WRITE|PROT_EXEC,
- MAP_FIXED|MAP_PRIVATE, 0);
- kfree(elf_phdata);
- return 0;
-}
-
-static int load_elf32_library(int fd)
-{
- int retval;
-
- MOD_INC_USE_COUNT;
- retval = do_load_elf32_library(fd);
- MOD_DEC_USE_COUNT;
- return retval;
-}
-
-/*
- * Note that some platforms still use traditional core dumps and not
- * the ELF core dump. Each platform can select it as appropriate.
- */
-#ifdef USE_ELF_CORE_DUMP
-
-/*
- * ELF core dumper
- *
- * Modelled on fs/exec.c:aout_core_dump()
- * Jeremy Fitzhardinge <jeremy@sw.oz.au>
- */
-/*
- * These are the only things you should do on a core-file: use only these
- * functions to write out all the necessary info.
- */
-static int dump_write(struct file *file, const void *addr, int nr)
-{
- return file->f_op->write(file->f_inode, file, addr, nr) == nr;
-}
-
-static int dump_seek(struct file *file, off_t off)
-{
- if (file->f_op->llseek) {
- if (file->f_op->llseek(file->f_inode, file, off, 0) != off)
- return 0;
- } else
- file->f_pos = off;
- return 1;
-}
-
-/*
- * Decide whether a segment is worth dumping; default is yes to be
- * sure (missing info is worse than too much; etc).
- * Personally I'd include everything, and use the coredump limit...
- *
- * I think we should skip something. But I am not sure how. H.J.
- */
-static inline int maydump(struct vm_area_struct *vma)
-{
- if (!(vma->vm_flags & (VM_READ|VM_WRITE|VM_EXEC)))
- return 0;
-#if 1
- if (vma->vm_flags & (VM_WRITE|VM_GROWSUP|VM_GROWSDOWN))
- return 1;
- if (vma->vm_flags & (VM_READ|VM_EXEC|VM_EXECUTABLE|VM_SHARED))
- return 0;
-#endif
- return 1;
-}
-
-#define roundup(x, y) ((((x)+((y)-1))/(y))*(y))
-
-/* An ELF note in memory */
-struct memelfnote
-{
- const char *name;
- int type;
- unsigned int datasz;
- void *data;
-};
-
-static int notesize(struct memelfnote *en)
-{
- int sz;
-
- sz = sizeof(struct elf_note);
- sz += roundup(strlen(en->name), 4);
- sz += roundup(en->datasz, 4);
-
- return sz;
-}
-
-/* #define DEBUG */
-
-#define DUMP_WRITE(addr, nr) \
- do { if (!dump_write(file, (addr), (nr))) return 0; } while(0)
-#define DUMP_SEEK(off) \
- do { if (!dump_seek(file, (off))) return 0; } while(0)
-
-static int writenote(struct memelfnote *men, struct file *file)
-{
- struct elf_note en;
-
- en.n_namesz = strlen(men->name);
- en.n_descsz = men->datasz;
- en.n_type = men->type;
-
- DUMP_WRITE(&en, sizeof(en));
- DUMP_WRITE(men->name, en.n_namesz);
- /* XXX - cast from long long to long to avoid need for libgcc.a */
- DUMP_SEEK(roundup((unsigned long)file->f_pos, 4)); /* XXX */
- DUMP_WRITE(men->data, men->datasz);
- DUMP_SEEK(roundup((unsigned long)file->f_pos, 4)); /* XXX */
-
- return 1;
-}
-#undef DUMP_WRITE
-#undef DUMP_SEEK
-
-#define DUMP_WRITE(addr, nr) \
- if (!dump_write(&file, (addr), (nr))) \
- goto close_coredump;
-#define DUMP_SEEK(off) \
- if (!dump_seek(&file, (off))) \
- goto close_coredump;
-/*
- * Actual dumper
- *
- * This is a two-pass process; first we find the offsets of the bits,
- * and then they are actually written out. If we run out of core limit
- * we just truncate.
- */
-static int elf32_core_dump(long signr, struct pt_regs * regs)
-{
- int has_dumped = 0;
- struct file file;
- struct inode *inode;
- unsigned short fs;
- char corefile[6+sizeof(current->comm)];
- int segs;
- int i;
- size_t size;
- struct vm_area_struct *vma;
- struct elfhdr elf;
- off_t offset = 0, dataoff;
- int limit = current->rlim[RLIMIT_CORE].rlim_cur;
- int numnote = 4;
- struct memelfnote notes[4];
- struct elf_prstatus prstatus; /* NT_PRSTATUS */
- elf_fpregset_t fpu; /* NT_PRFPREG */
- struct elf_prpsinfo psinfo; /* NT_PRPSINFO */
-
- if (!current->dumpable || limit < PAGE_SIZE || current->mm->count != 1)
- return 0;
- current->dumpable = 0;
-
-#ifndef CONFIG_BINFMT_ELF32
- MOD_INC_USE_COUNT;
-#endif
-
- /* Count what's needed to dump, up to the limit of coredump size */
- segs = 0;
- size = 0;
- for(vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) {
- if (maydump(vma))
- {
- int sz = vma->vm_end-vma->vm_start;
-
- if (size+sz >= limit)
- break;
- else
- size += sz;
- }
-
- segs++;
- }
-#ifdef DEBUG
- printk("elf_core_dump: %d segs taking %d bytes\n", segs, size);
-#endif
-
- /* Set up header */
- memcpy(elf.e_ident, ELFMAG, SELFMAG);
- elf.e_ident[EI_CLASS] = ELF_CLASS;
- elf.e_ident[EI_DATA] = ELF_DATA;
- elf.e_ident[EI_VERSION] = EV_CURRENT;
- memset(elf.e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD);
-
- elf.e_type = ET_CORE;
- elf.e_machine = ELF_ARCH;
- elf.e_version = EV_CURRENT;
- elf.e_entry = 0;
- elf.e_phoff = sizeof(elf);
- elf.e_shoff = 0;
- elf.e_flags = 0;
- elf.e_ehsize = sizeof(elf);
- elf.e_phentsize = sizeof(struct elf_phdr);
- elf.e_phnum = segs+1; /* Include notes */
- elf.e_shentsize = 0;
- elf.e_shnum = 0;
- elf.e_shstrndx = 0;
-
- fs = get_fs();
- set_fs(KERNEL_DS);
- memcpy(corefile,"core.",5);
-#if 0
- memcpy(corefile+5,current->comm,sizeof(current->comm));
-#else
- corefile[4] = '\0';
-#endif
- if (open_namei(corefile,O_CREAT | 2 | O_TRUNC,0600,&inode,NULL)) {
- inode = NULL;
- goto end_coredump;
- }
- if (!S_ISREG(inode->i_mode))
- goto end_coredump;
- if (!inode->i_op || !inode->i_op->default_file_ops)
- goto end_coredump;
- file.f_mode = 3;
- file.f_flags = 0;
- file.f_count = 1;
- file.f_inode = inode;
- file.f_pos = 0;
- file.f_reada = 0;
- file.f_op = inode->i_op->default_file_ops;
- if (file.f_op->open)
- if (file.f_op->open(inode,&file))
- goto end_coredump;
- if (!file.f_op->write)
- goto close_coredump;
- has_dumped = 1;
- current->flags |= PF_DUMPCORE;
-
- DUMP_WRITE(&elf, sizeof(elf));
- offset += sizeof(elf); /* Elf header */
- offset += (segs+1) * sizeof(struct elf_phdr); /* Program headers */
-
- /*
- * Set up the notes in similar form to SVR4 core dumps made
- * with info from their /proc.
- */
- memset(&psinfo, 0, sizeof(psinfo));
- memset(&prstatus, 0, sizeof(prstatus));
-
- notes[0].name = "CORE";
- notes[0].type = NT_PRSTATUS;
- notes[0].datasz = sizeof(prstatus);
- notes[0].data = &prstatus;
- prstatus.pr_info.si_signo = prstatus.pr_cursig = signr;
- prstatus.pr_sigpend = current->signal;
- prstatus.pr_sighold = current->blocked;
- psinfo.pr_pid = prstatus.pr_pid = current->pid;
- psinfo.pr_ppid = prstatus.pr_ppid = current->p_pptr->pid;
- psinfo.pr_pgrp = prstatus.pr_pgrp = current->pgrp;
- psinfo.pr_sid = prstatus.pr_sid = current->session;
- prstatus.pr_utime.tv_sec = CT_TO_SECS(current->utime);
- prstatus.pr_utime.tv_usec = CT_TO_USECS(current->utime);
- prstatus.pr_stime.tv_sec = CT_TO_SECS(current->stime);
- prstatus.pr_stime.tv_usec = CT_TO_USECS(current->stime);
- prstatus.pr_cutime.tv_sec = CT_TO_SECS(current->cutime);
- prstatus.pr_cutime.tv_usec = CT_TO_USECS(current->cutime);
- prstatus.pr_cstime.tv_sec = CT_TO_SECS(current->cstime);
- prstatus.pr_cstime.tv_usec = CT_TO_USECS(current->cstime);
-
- /*
- * This transfers the registers from regs into the standard
- * coredump arrangement, whatever that is.
- */
-#ifdef ELF_CORE_COPY_REGS
- ELF_CORE_COPY_REGS(prstatus.pr_reg, regs)
-#else
- if (sizeof(elf_gregset_t) != sizeof(struct pt_regs))
- {
- printk("sizeof(elf_gregset_t) (%ld) != sizeof(struct pt_regs) (%ld)\n",
- sizeof(elf_gregset_t), sizeof(struct pt_regs));
- }
- else
- *(struct pt_regs *)&prstatus.pr_reg = *regs;
-#endif
-
- notes[1].name = "CORE";
- notes[1].type = NT_PRPSINFO;
- notes[1].datasz = sizeof(psinfo);
- notes[1].data = &psinfo;
- psinfo.pr_state = current->state;
- psinfo.pr_sname = (current->state < 0 || current->state > 5) ? '.' : "RSDZTD"[current->state];
- psinfo.pr_zomb = psinfo.pr_sname == 'Z';
- psinfo.pr_nice = current->priority-15;
- psinfo.pr_flag = current->flags;
- psinfo.pr_uid = current->uid;
- psinfo.pr_gid = current->gid;
- {
- int i, len;
-
- set_fs(fs);
-
- len = current->mm->arg_end - current->mm->arg_start;
- len = len >= ELF_PRARGSZ ? ELF_PRARGSZ : len;
- copy_from_user(&psinfo.pr_psargs,
- (const char *)current->mm->arg_start, len);
- for(i = 0; i < len; i++)
- if (psinfo.pr_psargs[i] == 0)
- psinfo.pr_psargs[i] = ' ';
- psinfo.pr_psargs[len] = 0;
-
- set_fs(KERNEL_DS);
- }
- strncpy(psinfo.pr_fname, current->comm, sizeof(psinfo.pr_fname));
-
- notes[2].name = "CORE";
- notes[2].type = NT_TASKSTRUCT;
- notes[2].datasz = sizeof(*current);
- notes[2].data = current;
-
- /* Try to dump the fpu. */
- prstatus.pr_fpvalid = dump_fpu (regs, &fpu);
- if (!prstatus.pr_fpvalid)
- {
- numnote--;
- }
- else
- {
- notes[3].name = "CORE";
- notes[3].type = NT_PRFPREG;
- notes[3].datasz = sizeof(fpu);
- notes[3].data = &fpu;
- }
-
- /* Write notes phdr entry */
- {
- struct elf_phdr phdr;
- int sz = 0;
-
- for(i = 0; i < numnote; i++)
- sz += notesize(&notes[i]);
-
- phdr.p_type = PT_NOTE;
- phdr.p_offset = offset;
- phdr.p_vaddr = 0;
- phdr.p_paddr = 0;
- phdr.p_filesz = sz;
- phdr.p_memsz = 0;
- phdr.p_flags = 0;
- phdr.p_align = 0;
-
- offset += phdr.p_filesz;
- DUMP_WRITE(&phdr, sizeof(phdr));
- }
-
- /* Page-align dumped data */
- dataoff = offset = roundup(offset, PAGE_SIZE);
-
- /* Write program headers for segments dump */
- for(vma = current->mm->mmap, i = 0;
- i < segs && vma != NULL; vma = vma->vm_next) {
- struct elf_phdr phdr;
- size_t sz;
-
- i++;
-
- sz = vma->vm_end - vma->vm_start;
-
- phdr.p_type = PT_LOAD;
- phdr.p_offset = offset;
- phdr.p_vaddr = vma->vm_start;
- phdr.p_paddr = 0;
- phdr.p_filesz = maydump(vma) ? sz : 0;
- phdr.p_memsz = sz;
- offset += phdr.p_filesz;
- phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0;
- if (vma->vm_flags & VM_WRITE) phdr.p_flags |= PF_W;
- if (vma->vm_flags & VM_EXEC) phdr.p_flags |= PF_X;
- phdr.p_align = PAGE_SIZE;
-
- DUMP_WRITE(&phdr, sizeof(phdr));
- }
-
- for(i = 0; i < numnote; i++)
- if (!writenote(&notes[i], &file))
- goto close_coredump;
-
- set_fs(fs);
-
- DUMP_SEEK(dataoff);
-
- for(i = 0, vma = current->mm->mmap;
- i < segs && vma != NULL;
- vma = vma->vm_next) {
- unsigned long addr = vma->vm_start;
- unsigned long len = vma->vm_end - vma->vm_start;
-
- i++;
- if (!maydump(vma))
- continue;
-#ifdef DEBUG
- printk("elf_core_dump: writing %08lx %lx\n", addr, len);
-#endif
- DUMP_WRITE((void *)addr, len);
- }
-
- if ((off_t) file.f_pos != offset) {
- /* Sanity check */
- printk("elf_core_dump: file.f_pos (%ld) != offset (%ld)\n",
- (off_t) file.f_pos, offset);
- }
-
- close_coredump:
- if (file.f_op->release)
- file.f_op->release(inode,&file);
-
- end_coredump:
- set_fs(fs);
- iput(inode);
-#ifndef CONFIG_BINFMT_ELF32
- MOD_DEC_USE_COUNT;
-#endif
- return has_dumped;
-}
-#endif /* USE_ELF_CORE_DUMP */
-
-__initfunc(int init_elf32_binfmt(void))
-{
- return register_binfmt(&elf32_format);
-}
-
-#ifdef MODULE
-
-int init_module(void)
-{
- /* Install the COFF, ELF and XOUT loaders.
- * N.B. We *rely* on the table being the right size with the
- * right number of free slots...
- */
- return init_elf32_binfmt();
-}
-
-
-void cleanup_module( void)
-{
- /* Remove the COFF and ELF loaders. */
- unregister_binfmt(&elf32_format);
-}
-#endif
diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c
index e9911daed..147b60c34 100644
--- a/arch/sparc64/kernel/sys_sparc32.c
+++ b/arch/sparc64/kernel/sys_sparc32.c
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc32.c,v 1.9 1997/04/21 08:34:24 jj Exp $
+/* $Id: sys_sparc32.c,v 1.13 1997/05/18 04:16:44 davem Exp $
* sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
*
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -27,15 +27,19 @@
#include <linux/nfs_fs.h>
#include <linux/smb_fs.h>
#include <linux/ncp_fs.h>
+#include <linux/quota.h>
#include <asm/types.h>
#include <asm/poll.h>
#include <asm/ipc.h>
#include <asm/uaccess.h>
-/* As gcc will warn about casting u32 to some ptr, we have to cast it to unsigned long first, and that's what is A() for.
- * You just do (void *)A(x), instead of having to type (void *)((unsigned long)x) or instead of just (void *)x, which will
- * produce warnings */
+/* As gcc will warn about casting u32 to some ptr, we have to cast it to
+ * unsigned long first, and that's what is A() for.
+ * You just do (void *)A(x), instead of having to
+ * type (void *)((unsigned long)x) or instead of just (void *)x, which will
+ * produce warnings.
+ */
#define A(x) ((unsigned long)x)
extern asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on);
@@ -138,6 +142,10 @@ extern asmlinkage int sys_sendmsg(int fd, struct msghdr *msg, unsigned flags);
extern asmlinkage int sys_recvmsg(int fd, struct msghdr *msg, unsigned int flags);
extern asmlinkage int sys_socketcall(int call, unsigned long *args);
extern asmlinkage int sys_nfsservctl(int cmd, void *argp, void *resp);
+extern asmlinkage int sys_listen(int fd, int backlog);
+extern asmlinkage int sys_socket(int family, int type, int protocol);
+extern asmlinkage int sys_socketpair(int family, int type, int protocol, int usockvec[2]);
+extern asmlinkage int sys_shutdown(int fd, int how);
asmlinkage int sys32_ioperm(u32 from, u32 num, int on)
{
@@ -157,6 +165,17 @@ struct ipc_perm32
unsigned short seq;
};
+struct semid_ds32 {
+ struct ipc_perm32 sem_perm; /* permissions .. see ipc.h */
+ __kernel_time_t32 sem_otime; /* last semop time */
+ __kernel_time_t32 sem_ctime; /* last change time */
+ u32 sem_base; /* ptr to first semaphore in array */
+ u32 sem_pending; /* pending operations to be processed */
+ u32 sem_pending_last; /* last pending operation */
+ u32 undo; /* undo requests on this array */
+ unsigned short sem_nsems; /* no. of semaphores in array */
+};
+
struct msqid_ds32
{
struct ipc_perm32 msg_perm;
@@ -212,15 +231,62 @@ asmlinkage int sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u
err = sys_semget (first, second, third);
goto out;
case SEMCTL: {
- /* XXX union semun32 to union semun64 and back conversion */
union semun fourth;
+ void *pad;
+ unsigned long old_fs;
+ struct semid_ds s;
+
err = -EINVAL;
if (!ptr)
goto out;
err = -EFAULT;
- if(get_user(fourth.__pad, (void **)A(ptr)))
+ if(get_user(pad, (void **)A(ptr)))
goto out;
+ fourth.__pad = pad;
+ switch (third) {
+ case IPC_INFO:
+ case SEM_INFO:
+ case GETVAL:
+ case GETPID:
+ case GETNCNT:
+ case GETZCNT:
+ case GETALL:
+ case SETALL:
+ case IPC_RMID:
+ err = sys_semctl (first, second, third, fourth);
+ goto out;
+ case IPC_SET:
+ if (get_user (s.sem_perm.uid, &(((struct semid_ds32 *)A(pad))->sem_perm.uid)) ||
+ __get_user (s.sem_perm.gid, &(((struct semid_ds32 *)A(pad))->sem_perm.gid)) ||
+ __get_user (s.sem_perm.mode, &(((struct semid_ds32 *)A(pad))->sem_perm.mode))) {
+ err = -EFAULT;
+ goto out;
+ }
+ /* Fall through */
+ case SEM_STAT:
+ case IPC_STAT:
+ fourth.__pad = &s;
+ break;
+ }
+ old_fs = get_fs();
+ set_fs (KERNEL_DS);
err = sys_semctl (first, second, third, fourth);
+ set_fs (old_fs);
+ switch (third) {
+ case SEM_STAT:
+ case IPC_STAT:
+ if (put_user (s.sem_perm.key, &(((struct semid_ds32 *)A(pad))->sem_perm.key)) ||
+ __put_user (s.sem_perm.uid, &(((struct semid_ds32 *)A(pad))->sem_perm.uid)) ||
+ __put_user (s.sem_perm.gid, &(((struct semid_ds32 *)A(pad))->sem_perm.gid)) ||
+ __put_user (s.sem_perm.cuid, &(((struct semid_ds32 *)A(pad))->sem_perm.cuid)) ||
+ __put_user (s.sem_perm.cgid, &(((struct semid_ds32 *)A(pad))->sem_perm.cgid)) ||
+ __put_user (s.sem_perm.mode, &(((struct semid_ds32 *)A(pad))->sem_perm.mode)) ||
+ __put_user (s.sem_perm.seq, &(((struct semid_ds32 *)A(pad))->sem_perm.seq)) ||
+ __put_user (s.sem_otime, &(((struct semid_ds32 *)A(pad))->sem_otime)) ||
+ __put_user (s.sem_ctime, &(((struct semid_ds32 *)A(pad))->sem_ctime)) ||
+ __put_user (s.sem_nsems, &(((struct semid_ds32 *)A(pad))->sem_nsems)))
+ err = -EFAULT;
+ }
goto out;
}
default:
@@ -534,10 +600,50 @@ asmlinkage int sys32_rename(u32 oldname, u32 newname)
return sys_rename((const char *)A(oldname), (const char *)A(newname));
}
-/* XXX: Play with the addr, it will be ugly :(( */
+struct dqblk32 {
+ __u32 dqb_bhardlimit;
+ __u32 dqb_bsoftlimit;
+ __u32 dqb_curblocks;
+ __u32 dqb_ihardlimit;
+ __u32 dqb_isoftlimit;
+ __u32 dqb_curinodes;
+ __kernel_time_t32 dqb_btime;
+ __kernel_time_t32 dqb_itime;
+};
+
asmlinkage int sys32_quotactl(int cmd, u32 special, int id, u32 addr)
{
- return sys_quotactl(cmd, (const char *)A(special), id, (caddr_t)A(addr));
+ int cmds = cmd >> SUBCMDSHIFT;
+ int err;
+ struct dqblk d;
+ unsigned long old_fs;
+
+ switch (cmds) {
+ case Q_GETQUOTA:
+ break;
+ case Q_SETQUOTA:
+ case Q_SETUSE:
+ case Q_SETQLIM:
+ if (copy_from_user (&d, (struct dqblk32 *)A(addr), sizeof (struct dqblk32)))
+ return -EFAULT;
+ d.dqb_itime = ((struct dqblk32 *)&d)->dqb_itime;
+ d.dqb_btime = ((struct dqblk32 *)&d)->dqb_btime;
+ break;
+ default:
+ return sys_quotactl(cmd, (const char *)A(special), id, (caddr_t)A(addr));
+ }
+ old_fs = get_fs ();
+ set_fs (KERNEL_DS);
+ err = sys_quotactl(cmd, (const char *)A(special), id, (caddr_t)A(addr));
+ set_fs (old_fs);
+ if (cmds == Q_GETQUOTA) {
+ __kernel_time_t b = d.dqb_btime, i = d.dqb_itime;
+ ((struct dqblk32 *)&d)->dqb_itime = i;
+ ((struct dqblk32 *)&d)->dqb_btime = b;
+ if (copy_to_user ((struct dqblk32 *)A(addr), &d, sizeof (struct dqblk32)))
+ return -EFAULT;
+ }
+ return err;
}
static int put_statfs (u32 buf, struct statfs *s)
@@ -1599,20 +1705,224 @@ asmlinkage int sys32_getsockopt(int fd, int level, int optname, u32 optval, u32
return sys_getsockopt(fd, level, optname, (char *)A(optval), (int *)A(optlen));
}
-/* Continue here */
+struct msghdr32 {
+ u32 msg_name;
+ int msg_namelen;
+ u32 msg_iov;
+ __kernel_size_t32 msg_iovlen;
+ u32 msg_control;
+ __kernel_size_t32 msg_controllen;
+ unsigned msg_flags;
+};
+
+struct cmsghdr32 {
+ __kernel_size_t32 cmsg_len;
+ int cmsg_level;
+ int cmsg_type;
+ unsigned char cmsg_data[0];
+};
+
asmlinkage int sys32_sendmsg(int fd, u32 msg, unsigned flags)
{
- return sys_sendmsg(fd, (struct msghdr *)A(msg), flags);
+ struct msghdr m;
+ int count;
+ struct iovec *v;
+ struct iovec vf[UIO_FASTIOV];
+ u32 i, vector;
+ long ret;
+ unsigned long old_fs;
+
+ if (get_user ((long)m.msg_name, &(((struct msghdr32 *)A(msg))->msg_name)) ||
+ __get_user (m.msg_namelen, &(((struct msghdr32 *)A(msg))->msg_namelen)) ||
+ __get_user (vector, &(((struct msghdr32 *)A(msg))->msg_iov)) ||
+ __get_user (m.msg_iovlen, &(((struct msghdr32 *)A(msg))->msg_iovlen)) ||
+ __get_user ((long)m.msg_control, &(((struct msghdr32 *)A(msg))->msg_control)) ||
+ __get_user (m.msg_controllen, &(((struct msghdr32 *)A(msg))->msg_controllen)) ||
+ __get_user (m.msg_flags, &(((struct msghdr32 *)A(msg))->msg_flags)))
+ return -EFAULT;
+
+ count = m.msg_iovlen;
+ if (!count) return 0; if (count > UIO_MAXIOV) return -EINVAL;
+ if (count <= UIO_FASTIOV)
+ v = vf;
+ else {
+ lock_kernel ();
+ v = kmalloc (count * sizeof (struct iovec), GFP_KERNEL);
+ if (!v) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ }
+
+ for (i = 0; i < count; i++) {
+ if (__get_user ((unsigned long)(v[i].iov_base), &((((struct iovec32 *)A(vector))+i)->iov_base)) ||
+ __get_user (v[i].iov_len, &((((struct iovec32 *)A(vector))+i)->iov_len))) {
+ ret = -EFAULT;
+ goto out;
+ }
+ }
+
+ m.msg_iov = v;
+
+ if (m.msg_controllen) {
+ /* XXX Handle msg_control stuff... Or should that go into ip_sockglue.c etc.? */
+ }
+ old_fs = get_fs();
+ set_fs (KERNEL_DS);
+ ret = sys_sendmsg(fd, &m, flags);
+ set_fs (old_fs);
+out:
+ if (count > UIO_FASTIOV) {
+ kfree (v);
+ unlock_kernel ();
+ }
+ return ret;
}
asmlinkage int sys32_recvmsg(int fd, u32 msg, unsigned int flags)
{
- return sys_recvmsg(fd, (struct msghdr *)A(msg), flags);
+ struct msghdr m;
+ int count;
+ struct iovec *v;
+ struct iovec vf[UIO_FASTIOV];
+ u32 i, vector;
+ long ret;
+ unsigned long old_fs;
+
+ if (get_user ((long)m.msg_name, &(((struct msghdr32 *)A(msg))->msg_name)) ||
+ __get_user (m.msg_namelen, &(((struct msghdr32 *)A(msg))->msg_namelen)) ||
+ __get_user (vector, &(((struct msghdr32 *)A(msg))->msg_iov)) ||
+ __get_user (m.msg_iovlen, &(((struct msghdr32 *)A(msg))->msg_iovlen)) ||
+ __get_user ((long)m.msg_control, &(((struct msghdr32 *)A(msg))->msg_control)) ||
+ __get_user (m.msg_controllen, &(((struct msghdr32 *)A(msg))->msg_controllen)) ||
+ __get_user (m.msg_flags, &(((struct msghdr32 *)A(msg))->msg_flags)))
+ return -EFAULT;
+
+ count = m.msg_iovlen;
+ if (!count) return 0; if (count > UIO_MAXIOV) return -EINVAL;
+ if (count <= UIO_FASTIOV)
+ v = vf;
+ else {
+ lock_kernel ();
+ v = kmalloc (count * sizeof (struct iovec), GFP_KERNEL);
+ if (!v) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ }
+
+ for (i = 0; i < count; i++) {
+ if (__get_user ((unsigned long)(v[i].iov_base), &((((struct iovec32 *)A(vector))+i)->iov_base)) ||
+ __get_user (v[i].iov_len, &((((struct iovec32 *)A(vector))+i)->iov_len))) {
+ ret = -EFAULT;
+ goto out;
+ }
+ }
+
+ m.msg_iov = v;
+
+ if (m.msg_controllen) {
+ /* XXX Handle msg_control stuff... Or should that go into ip_sockglue.c etc.? */
+ }
+ old_fs = get_fs();
+ set_fs (KERNEL_DS);
+ ret = sys_recvmsg(fd, &m, flags);
+ set_fs (old_fs);
+ if (ret >= 0) {
+ /* XXX Handle msg_control stuff... */
+ if (put_user (m.msg_flags, &(((struct msghdr32 *)A(msg))->msg_flags)) ||
+ __put_user (m.msg_controllen, &(((struct msghdr32 *)A(msg))->msg_controllen)))
+ return -EFAULT;
+ }
+out:
+ if (count > UIO_FASTIOV) {
+ kfree (v);
+ unlock_kernel ();
+ }
+ return ret;
}
asmlinkage int sys32_socketcall(int call, u32 args)
{
- return sys_socketcall(call, (unsigned long *)A(args));
+ static unsigned char nargs[18]={0,3,3,3,2,3,3,3,
+ 4,4,4,6,6,2,5,5,3,3};
+ u32 a[6];
+ u32 a0,a1;
+ int err = -EINVAL;
+ int i;
+
+ lock_kernel();
+ if(call<1||call>SYS_RECVMSG)
+ goto out;
+ err = -EFAULT;
+
+ for (i = 0; i < nargs[call]; i++, args += sizeof (u32))
+ if (get_user(a[i], (u32 *)A(args)))
+ goto out;
+
+ a0=a[0];
+ a1=a[1];
+
+ switch(call)
+ {
+ case SYS_SOCKET:
+ err = sys_socket(a0, a1, a[2]);
+ break;
+ case SYS_BIND:
+ err = sys32_bind(a0, a1, a[2]);
+ break;
+ case SYS_CONNECT:
+ err = sys32_connect(a0, a1, a[2]);
+ break;
+ case SYS_LISTEN:
+ err = sys_listen(a0, a1);
+ break;
+ case SYS_ACCEPT:
+ err = sys32_accept(a0, a1, a[2]);
+ break;
+ case SYS_GETSOCKNAME:
+ err = sys32_getsockname(a0, a1, a[2]);
+ break;
+ case SYS_GETPEERNAME:
+ err = sys32_getpeername(a0, a1, a[2]);
+ break;
+ case SYS_SOCKETPAIR:
+ err = sys_socketpair(a0, a1, a[2], (int *)A(a[3]));
+ break;
+ case SYS_SEND:
+ err = sys32_send(a0, a1, a[2], a[3]);
+ break;
+ case SYS_SENDTO:
+ err = sys32_sendto(a0, a1, a[2], a[3], a[4], a[5]);
+ break;
+ case SYS_RECV:
+ err = sys32_recv(a0, a1, a[2], a[3]);
+ break;
+ case SYS_RECVFROM:
+ err = sys32_recvfrom(a0, a1, a[2], a[3], a[4], a[5]);
+ break;
+ case SYS_SHUTDOWN:
+ err = sys_shutdown(a0,a1);
+ break;
+ case SYS_SETSOCKOPT:
+ err = sys32_setsockopt(a0, a1, a[2], a[3], a[4]);
+ break;
+ case SYS_GETSOCKOPT:
+ err = sys32_getsockopt(a0, a1, a[2], a[3], a[4]);
+ break;
+ case SYS_SENDMSG:
+ err = sys32_sendmsg(a0, a1, a[2]);
+ break;
+ case SYS_RECVMSG:
+ err = sys32_recvmsg(a0, a1, a[2]);
+ break;
+ default:
+ err = -EINVAL;
+ break;
+ }
+out:
+ unlock_kernel();
+ return err;
}
extern void check_pending(int signum);
diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c
index 48648c39d..c9774df06 100644
--- a/arch/sparc64/kernel/traps.c
+++ b/arch/sparc64/kernel/traps.c
@@ -1,4 +1,4 @@
-/* $Id: traps.c,v 1.5 1997/04/14 06:56:55 davem Exp $
+/* $Id: traps.c,v 1.10 1997/05/18 08:42:16 davem Exp $
* arch/sparc/kernel/traps.c
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -22,6 +22,7 @@
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/unistd.h>
+#include <asm/uaccess.h>
/* #define TRAP_DEBUG */
@@ -42,6 +43,8 @@ void syscall_trace_entry(struct pt_regs *regs)
void syscall_trace_exit(struct pt_regs *regs)
{
+ printk("Syscall return check, reg dump.\n");
+ show_regs(regs);
}
void sparc64_dtlb_fault_handler (void)
@@ -116,25 +119,45 @@ void die_if_kernel(char *str, struct pt_regs *regs)
show_regs(regs);
printk("Instruction DUMP:");
instruction_dump ((unsigned int *) regs->tpc);
+ while(1)
+ barrier();
if(regs->tstate & TSTATE_PRIV)
do_exit(SIGKILL);
do_exit(SIGSEGV);
}
-void do_illegal_instruction(struct pt_regs *regs, unsigned long pc, unsigned long npc,
- unsigned long tstate)
+void do_illegal_instruction(struct pt_regs *regs)
{
+ unsigned long pc = regs->tpc;
+ unsigned long tstate = regs->tstate;
+
lock_kernel();
if(tstate & TSTATE_PRIV)
die_if_kernel("Kernel illegal instruction", regs);
-#ifdef TRAP_DEBUG
- printk("Ill instr. at pc=%016lx instruction is %08x\n",
- regs->tpc, *(unsigned int *)regs->tpc);
+#if 1
+ {
+ unsigned int insn;
+
+ printk("Ill instr. at pc=%016lx ", pc);
+ get_user(insn, ((unsigned int *)pc));
+ printk("insn=[%08x]\n", insn);
+ }
#endif
current->tss.sig_address = pc;
current->tss.sig_desc = SUBSIG_ILLINST;
send_sig(SIGILL, current, 1);
unlock_kernel();
+
+ while(1)
+ barrier();
+}
+
+void do_mna(struct pt_regs *regs)
+{
+ printk("AIEEE: do_mna at %016lx\n", regs->tpc);
+ show_regs(regs);
+ while(1)
+ barrier();
}
void do_priv_instruction(struct pt_regs *regs, unsigned long pc, unsigned long npc,
diff --git a/arch/sparc64/kernel/ttable.S b/arch/sparc64/kernel/ttable.S
index f22d85014..326382c3f 100644
--- a/arch/sparc64/kernel/ttable.S
+++ b/arch/sparc64/kernel/ttable.S
@@ -1,4 +1,4 @@
-/* $Id: ttable.S,v 1.11 1997/03/25 09:47:21 davem Exp $
+/* $Id: ttable.S,v 1.12 1997/05/17 08:22:30 davem Exp $
* ttable.S: Sparc V9 Trap Table(s) with SpitFire extensions.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -13,7 +13,7 @@ tl0_iax: ACCESS_EXCEPTION_TRAP(instruction_access_exception)
tl0_resv009: BTRAP(0x9)
tl0_iae: TRAP(do_iae)
tl0_resv00b: BTRAP(0xb) BTRAP(0xc) BTRAP(0xd) BTRAP(0xe) BTRAP(0xf)
-tl0_ill: TRAP(do_ill)
+tl0_ill: TRAP(do_illegal_instruction)
tl0_privop: TRAP(do_privop)
tl0_resv012: BTRAP(0x12) BTRAP(0x13) BTRAP(0x14) BTRAP(0x15) BTRAP(0x16) BTRAP(0x17)
tl0_resv018: BTRAP(0x18) BTRAP(0x19) BTRAP(0x1a) BTRAP(0x1b) BTRAP(0x1c) BTRAP(0x1d)
@@ -226,27 +226,3 @@ tl1_f4o: FILL_4_OTHER
tl1_f5o: FILL_5_OTHER
tl1_f6o: FILL_6_OTHER
tl1_f7o: FILL_7_OTHER
-
-#if 0
-/* Unless we are going to have software trap insns in the kernel code, we
- * don't need this. For now we just save 8KB.
- */
-
-#define BTRAPSTL1(x) BTRAPTL1(x) BTRAPTL1(x+1) BTRAPTL1(x+2) BTRAPTL1(x+3) BTRAPTL1(x+4) BTRAPTL1(x+5) BTRAPTL1(x+6) BTRAPTL1(x+7)
-
-tl1_sunos: BTRAPTL1(0x100)
-tl1_bkpt: BREAKPOINT_TRAP
-tl1_resv102: BTRAPTL1(0x102)
-tl1_flushw: FLUSH_WINDOW_TRAP
-tl1_resv104: BTRAPTL1(0x104) BTRAPTL1(0x105) BTRAPTL1(0x106)
-tl1_resv107: BTRAPTL1(0x107) BTRAPTL1(0x108) BTRAPTL1(0x109) BTRAPTL1(0x10a)
-tl1_resv10b: BTRAPTL1(0x10b) BTRAPTL1(0x10c) BTRAPTL1(0x10d) BTRAPTL1(0x10e)
-tl1_resv10f: BTRAPTL1(0x10f)
-tl1_resv110: BTRAPSTL1(0x110) BTRAPSTL1(0x118)
-tl1_resv120: BTRAPSTL1(0x120) BTRAPSTL1(0x128)
-tl1_resv130: BTRAPSTL1(0x130) BTRAPSTL1(0x138)
-tl1_resv140: BTRAPSTL1(0x140) BTRAPSTL1(0x148)
-tl1_resv150: BTRAPSTL1(0x150) BTRAPSTL1(0x158)
-tl1_resv160: BTRAPSTL1(0x160) BTRAPSTL1(0x168)
-tl1_resv170: BTRAPSTL1(0x170) BTRAPSTL1(0x178)
-#endif
diff --git a/arch/sparc64/kernel/winfixup.S b/arch/sparc64/kernel/winfixup.S
new file mode 100644
index 000000000..a8293c453
--- /dev/null
+++ b/arch/sparc64/kernel/winfixup.S
@@ -0,0 +1,101 @@
+/* $Id: winfixup.S,v 1.3 1997/05/18 22:52:26 davem Exp $
+ *
+ * winfixup.S: Handle cases where user stack pointer is found to be bogus.
+ *
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <asm/asi.h>
+#include <asm/head.h>
+#include <asm/page.h>
+#include <asm/ptrace.h>
+#include <asm/processor.h>
+#include <asm/asm_offsets.h>
+
+ .text
+ .align 32
+
+ /* Here are the rules, pay attention.
+ *
+ * The kernel is disallowed from touching user space while
+ * the trap level is greater than zero, except for from within
+ * the window spill/fill handlers. This must be followed
+ * so that we can easily detect the case where we tried to
+ * spill/fill with a bogus (or unmapped) user stack pointer.
+ *
+ * These are layed out in a special way for cache reasons,
+ * don't touch...
+ */
+ .globl winfix_trampoline, fill_fixup, spill_fixup
+fill_fixup:
+ ba,pt %xcc, etrap
+ rd %pc, %g7
+ mov %l5, %o4
+ mov %l4, %o5
+ srlx %l5, PAGE_SHIFT, %o3
+ clr %o1
+ sllx %o3, PAGE_SHIFT, %o3
+ and %l4, 0x4, %o2
+
+ call do_sparc64_fault
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0
+ ba,a,pt %xcc, rtrap
+ nop
+winfix_trampoline:
+ andn %g5, 0x7f, %g5
+ add %g5, 0x7c, %g5
+ wrpr %g5, %tnpc
+ done
+
+spill_fixup:
+ rd %pic, %g1
+ ldx [%g1 + AOFF_task_tss + AOFF_thread_w_saved], %g2
+ sll %g2, 3, %g5
+ ldx [%g1 + AOFF_task_tss + AOFF_thread_flags], %g7
+ add %g1, %g5, %g5
+ andcc %g7, SPARC_FLAG_32BIT, %g0
+ stx %sp, [%g5 + AOFF_task_tss + AOFF_thread_rwbuf_stkptrs]
+ sll %g2, 5, %g5
+
+ bne,pt %xcc, 1f
+ add %g1, %g5, %g5
+ stx %l0, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x00]
+ stx %l1, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x08]
+ stx %l2, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x10]
+ stx %l3, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x18]
+ stx %l4, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x20]
+ stx %l5, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x28]
+
+ stx %l6, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x30]
+ stx %l7, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x38]
+ stx %i0, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x40]
+ stx %i1, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x48]
+ stx %i2, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x50]
+ stx %i3, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x58]
+ stx %i4, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x60]
+ stx %i5, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x68]
+
+ stx %i6, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x70]
+ stx %i7, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x78]
+ b,a,pt %xcc, 2f
+ add %g2, 1, %g2
+1:
+ std %l0, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x00]
+ std %l2, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x08]
+ std %l4, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x10]
+ std %l6, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x18]
+
+ std %i0, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x20]
+ std %i2, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x28]
+ std %i4, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x30]
+ std %i6, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x38]
+ add %g2, 1, %g2
+2:
+ stx %g2, [%g1 + AOFF_task_tss + AOFF_thread_w_saved]
+ rdpr %tstate, %g1
+ nop
+
+ andcc %g1, TSTATE_PRIV, %g0
+ be,pn %xcc, fill_fixup
+ saved
+ retry
diff --git a/arch/sparc64/lib/blockops.S b/arch/sparc64/lib/blockops.S
index b3f06c18d..d0f023d1b 100644
--- a/arch/sparc64/lib/blockops.S
+++ b/arch/sparc64/lib/blockops.S
@@ -1,4 +1,4 @@
-/* $Id: blockops.S,v 1.5 1997/03/26 18:34:28 jj Exp $
+/* $Id: blockops.S,v 1.6 1997/05/18 04:16:49 davem Exp $
* arch/sparc64/lib/blockops.S: UltraSparc block zero optimized routines.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -31,37 +31,8 @@
.text
.align 4
- .globl bzero_2page, bzero_1page
-bzero_2page:
- /* %o0 = buf */
- mov %o0, %o1
- wr %g0, ASI_BLK_P, %asi
- mov 0x10, %g2
-
- membar #Sync|#StoreLoad
-
- fzero %f48
- fzero %f50
- fzero %f52
- fzero %f54
- fzero %f56
- fzero %f58
- fzero %f60
- fzero %f62
-1:
- BLAST_BLOCK(%o0, 0x000)
- BLAST_BLOCK(%o0, 0x100)
- BLAST_BLOCK(%o0, 0x200)
- BLAST_BLOCK(%o0, 0x300)
- subcc %g2, 1, %g2
- bne,pt %icc, 1b
- add %o0, 0x400, %o0
-
- membar #Sync|#LoadStore|#StoreStore
-
- retl
- mov %o1, %o0
-
+#if 0
+ .globl bzero_1page
bzero_1page:
/* %o0 = buf */
mov %o0, %o1
@@ -89,9 +60,36 @@ bzero_1page:
retl
mov %o1, %o0
+#endif
.globl __bfill64
__bfill64:
+#if 1
+ /* %o0 = buf, %o1 = 64-bit pattern */
+#define FILL_BLOCK(buf, offset) \
+ stx %o1, [buf + offset + 0x38]; \
+ stx %o1, [buf + offset + 0x30]; \
+ stx %o1, [buf + offset + 0x28]; \
+ stx %o1, [buf + offset + 0x20]; \
+ stx %o1, [buf + offset + 0x18]; \
+ stx %o1, [buf + offset + 0x10]; \
+ stx %o1, [buf + offset + 0x08]; \
+ stx %o1, [buf + offset + 0x00];
+
+ mov 0x20, %g2
+1:
+ FILL_BLOCK(%o0, 0x00)
+ FILL_BLOCK(%o0, 0x40)
+ FILL_BLOCK(%o0, 0x80)
+ FILL_BLOCK(%o0, 0xc0)
+ subcc %g2, 1, %g2
+ bne,pt %icc, 1b
+ add %o0, 0x100, %o0
+ retl
+ nop
+#undef FILL_BLOCK
+
+#else
/* %o0 = buf */
stx %o1, [%sp + 0x7ff + 128]
wr %g0, ASI_BLK_P, %asi
@@ -116,7 +114,9 @@ __bfill64:
retl
membar #Sync|#LoadStore|#StoreStore
+#endif
+#if 0
.globl __copy_1page
__copy_1page:
/* %o0 = dst, %o1 = src */
@@ -135,4 +135,4 @@ __copy_1page:
retl
membar #Sync|#LoadStore|#StoreStore
-
+#endif
diff --git a/arch/sparc64/lib/checksum.S b/arch/sparc64/lib/checksum.S
index 8a06003ee..b63f0d6e8 100644
--- a/arch/sparc64/lib/checksum.S
+++ b/arch/sparc64/lib/checksum.S
@@ -44,13 +44,13 @@
csum_partial_end_cruft:
andcc %o1, 8, %g0 ! check how much
be,pn %icc, 1f ! caller asks %o1 & 0x8
- and %o1, 4, %g3 ! nope, check for word remaining
+ and %o1, 4, %g5 ! nope, check for word remaining
ldd [%o0], %g2 ! load two
addcc %g2, %o2, %o2 ! add first word to sum
addccc %g3, %o2, %o2 ! add second word as well
add %o0, 8, %o0 ! advance buf ptr
addc %g0, %o2, %o2 ! add in final carry
-1: brz,pn %g3, 1f ! nope, skip this code
+1: brz,pn %g5, 1f ! nope, skip this code
andcc %o1, 3, %o1 ! check for trailing bytes
ld [%o0], %g2 ! load it
addcc %g2, %o2, %o2 ! add to sum
@@ -98,15 +98,17 @@ csum_partial: /* %o0=buf, %o1=len, %o2=sum */
srl %o2, 16, %g3
addc %g0, %g3, %g2
sll %o2, 16, %o2
+ and %o0, 0x4, %g7
sll %g2, 16, %g3
srl %o2, 16, %o2
or %g3, %o2, %o2
1: brz,pn %g7, csum_partial_fix_aligned
- nop
+ andn %o1, 0x7f, %o3
ld [%o0 + 0x00], %g2
sub %o1, 4, %o1
addcc %g2, %o2, %o2
add %o0, 4, %o0
+ andn %o1, 0x7f, %o3
addc %g0, %o2, %o2
csum_partial_fix_aligned:
brz,pt %o3, 3f ! none to do
@@ -115,9 +117,9 @@ csum_partial_fix_aligned:
CSUM_BIGCHUNK(%o0, 0x20, %o2, %o4, %o5, %g2, %g3, %g4, %g5)
CSUM_BIGCHUNK(%o0, 0x40, %o2, %o4, %o5, %g2, %g3, %g4, %g5)
CSUM_BIGCHUNK(%o0, 0x60, %o2, %o4, %o5, %g2, %g3, %g4, %g5)
- sub %o3, 128, %o3 ! detract from loop iters
addc %g0, %o2, %o2 ! sink in final carry
- brnz,pt %o3, 5b ! more to do
+ subcc %o3, 128, %o3 ! detract from loop iters
+ bne,pt %icc, 5b ! more to do
add %o0, 128, %o0 ! advance buf ptr
3: brz,pn %g1, cpte ! nope
andcc %o1, 0xf, %o3 ! anything left at all?
@@ -125,7 +127,7 @@ csum_partial_fix_aligned:
srl %g1, 1, %o4 ! compute offset
sub %g7, %g1, %g7 ! adjust jmp ptr
sub %g7, %o4, %g7 ! final jmp ptr adjust
- jmp %g7 + (cpte - 8 - 10b) ! enter the table
+ jmp %g7 + (11f-10b) ! enter the table
add %o0, %g1, %o0 ! advance buf ptr
cptbl: CSUM_LASTCHUNK(%o0, 0x68, %o2, %g2, %g3, %g4, %g5)
CSUM_LASTCHUNK(%o0, 0x58, %o2, %g2, %g3, %g4, %g5)
@@ -134,8 +136,8 @@ cptbl: CSUM_LASTCHUNK(%o0, 0x68, %o2, %g2, %g3, %g4, %g5)
CSUM_LASTCHUNK(%o0, 0x28, %o2, %g2, %g3, %g4, %g5)
CSUM_LASTCHUNK(%o0, 0x18, %o2, %g2, %g3, %g4, %g5)
CSUM_LASTCHUNK(%o0, 0x08, %o2, %g2, %g3, %g4, %g5)
- addc %g0, %o2, %o2 ! fetch final carry
- andcc %o1, 0xf, %g0 ! anything left at all?
+11: addc %g0, %o2, %o2 ! fetch final carry
+ andcc %o1, 0xf, %o3 ! anything left at all?
cpte: brnz,pn %o3, csum_partial_end_cruft ! yep, handle it
sethi %uhi(KERNBASE), %g4
mov %o2, %o0 ! return computed csum
@@ -322,13 +324,14 @@ __csum_partial_copy_sparc_generic:
andcc %o0, 0x4, %g0
or %g3, %g7, %g7
1: be,pt %icc, 3f
- andn %g1, 0x7f, %g0
+ andn %g1, 0x7f, %g2
EX(ld [%o0 + 0x00], %g4, add %g1, 0,#)
sub %g1, 4, %g1
EX2(st %g4, [%o1 + 0x00],#)
add %o0, 4, %o0
addcc %g4, %g7, %g7
add %o1, 4, %o1
+ andn %g1, 0x7f, %g2
addc %g0, %g7, %g7
cc_dword_aligned:
3: brz,pn %g2, 3f ! nope, less than one loop remains
@@ -365,7 +368,7 @@ cctbl: CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x68,%g2,%g3,%g4,%g5)
CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x08,%g2,%g3,%g4,%g5)
12: EXT(cctbl, 12b, 22f,#) ! note for exception table handling
addc %g0, %g7, %g7
- andcc %o3, 0xf, %g0 ! check for low bits set
+ andcc %g1, 0xf, %o3 ! check for low bits set
ccte: bne,pn %icc, cc_end_cruft ! something left, handle it out of band
sethi %uhi(KERNBASE), %g4 ! restore gfp
mov %g7, %o0 ! give em the computed checksum
@@ -555,7 +558,7 @@ __csum_partial_copy_end:
add %i1, %i2, %i1
2:
mov %i1, %o0
- wr %%g0, ASI_S, %%asi
+ wr %g0, ASI_S, %asi
call __bzero_noasi
mov %i3, %o1
1:
diff --git a/arch/sparc64/lib/copy_from_user.S b/arch/sparc64/lib/copy_from_user.S
index ba26a1c01..50ec7bb3d 100644
--- a/arch/sparc64/lib/copy_from_user.S
+++ b/arch/sparc64/lib/copy_from_user.S
@@ -15,12 +15,16 @@
#include <asm/ptrace.h>
#include <asm/asi.h>
+#include <asm/head.h>
+
+#define PRE_RETL sethi %uhi(KERNBASE), %g4; sllx %g4, 32, %g4;
#define EX(x,y,a,b,z) \
98: x,y; \
.section .fixup,z##alloc,z##execinstr; \
.align 4; \
-99: retl; \
+99: PRE_RETL \
+ retl; \
a, b, %o0; \
.section __ex_table,z##alloc; \
.align 4; \
@@ -33,6 +37,7 @@
.section .fixup,z##alloc,z##execinstr; \
.align 4; \
99: c, d, e; \
+ PRE_RETL \
retl; \
a, b, %o0; \
.section __ex_table,z##alloc; \
@@ -234,6 +239,7 @@ copy_user_last7:
EX(lduba [%o1] %asi, %g2, add %g0, 1,#)
stb %g2, [%o0]
1:
+ PRE_RETL
retl
clr %o0
@@ -332,6 +338,7 @@ short_table_end:
EX(lduba [%o1] %asi, %g2, add %g0, 1,#)
stb %g2, [%o0]
1:
+ PRE_RETL
retl
clr %o0
@@ -355,6 +362,7 @@ short_aligned_end:
.section .fixup,#alloc,#execinstr
.align 4
97:
+ PRE_RETL
retl
mov %o2, %o0
/* exception routine sets %g2 to (broken_insn - first_insn)>>2 */
@@ -388,6 +396,7 @@ short_aligned_end:
1:
and %g1, 0x7f, %o0
add %o0, %g7, %o0
+ PRE_RETL
retl
sub %o0, %g2, %o0
51:
@@ -413,6 +422,7 @@ short_aligned_end:
3:
sll %g2, 2, %g2
2:
+ PRE_RETL
retl
add %g1, %g2, %o0
52:
@@ -431,6 +441,7 @@ short_aligned_end:
add %g2, %g4, %g2
and %o2, 0xf, %o0
add %o0, %o3, %o0
+ PRE_RETL
retl
sub %o0, %g2, %o0
54:
@@ -441,6 +452,7 @@ short_aligned_end:
and %o2, 0xf, %o2
sub %o3, %o1, %o3
sub %o2, %o4, %o2
+ PRE_RETL
retl
add %o2, %o3, %o0
55:
@@ -452,5 +464,6 @@ short_aligned_end:
and %g2, 1, %g2
sll %o1, 1, %o1
add %o2, %g2, %o0
+ PRE_RETL
retl
add %o0, %o1, %o0
diff --git a/arch/sparc64/lib/copy_to_user.S b/arch/sparc64/lib/copy_to_user.S
index 47a6bd337..733953743 100644
--- a/arch/sparc64/lib/copy_to_user.S
+++ b/arch/sparc64/lib/copy_to_user.S
@@ -14,13 +14,17 @@
*/
#include <asm/ptrace.h>
+#include <asm/head.h>
#include <asm/asi.h>
+#define PRE_RETL sethi %uhi(KERNBASE), %g4; sllx %g4, 32, %g4;
+
#define EX(x,y,a,b,z) \
98: x,y; \
.section .fixup,z##alloc,z##execinstr; \
.align 4; \
-99: retl; \
+99: PRE_RETL \
+ retl; \
a, b, %o0; \
.section __ex_table,z##alloc; \
.align 4; \
@@ -33,6 +37,7 @@
.section .fixup,z##alloc,z##execinstr; \
.align 4; \
99: c, d, e; \
+ PRE_RETL \
retl; \
a, b, %o0; \
.section __ex_table,z##alloc; \
@@ -234,6 +239,7 @@ copy_user_last7:
ldub [%o1], %g2
EX(stba %g2, [%o0] %asi, add %g0, 1,#)
1:
+ PRE_RETL
retl
clr %o0
@@ -332,6 +338,7 @@ short_table_end:
ldub [%o1], %g2
EX(stba %g2, [%o0] %asi, add %g0, 1,#)
1:
+ PRE_RETL
retl
clr %o0
@@ -355,6 +362,7 @@ short_aligned_end:
.section .fixup,#alloc,#execinstr
.align 4
97:
+ PRE_RETL
retl
mov %o2, %o0
/* exception routine sets %g2 to (broken_insn - first_insn)>>2 */
@@ -388,6 +396,7 @@ short_aligned_end:
1:
and %g1, 0x7f, %o0
add %o0, %g7, %o0
+ PRE_RETL
retl
sub %o0, %g2, %o0
51:
@@ -413,6 +422,7 @@ short_aligned_end:
3:
sll %g2, 2, %g2
2:
+ PRE_RETL
retl
add %g1, %g2, %o0
52:
@@ -431,6 +441,7 @@ short_aligned_end:
add %g2, %g4, %g2
and %o2, 0xf, %o0
add %o0, %o3, %o0
+ PRE_RETL
retl
sub %o0, %g2, %o0
54:
@@ -441,6 +452,7 @@ short_aligned_end:
and %o2, 0xf, %o2
sub %o3, %o1, %o3
sub %o2, %o4, %o2
+ PRE_RETL
retl
add %o2, %o3, %o0
55:
@@ -452,5 +464,6 @@ short_aligned_end:
and %g2, 1, %g2
sll %o1, 1, %o1
add %o2, %g2, %o0
+ PRE_RETL
retl
add %o0, %o1, %o0
diff --git a/arch/sparc64/lib/strlen_user.S b/arch/sparc64/lib/strlen_user.S
index 24bea73fd..30beee3ff 100644
--- a/arch/sparc64/lib/strlen_user.S
+++ b/arch/sparc64/lib/strlen_user.S
@@ -8,6 +8,8 @@
* Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
*/
+#include <asm/asi.h>
+
#define LO_MAGIC 0x01010101
#define HI_MAGIC 0x80808080
@@ -19,21 +21,21 @@ __strlen_user:
be,pt %icc, 9f
sethi %hi(HI_MAGIC), %o4
10:
- ldub [%o0], %o5
+ lduba [%o0] ASI_S, %o5
brz,pn %o5, 21f
add %o0, 1, %o0
andcc %o0, 3, %g0
be,pn %icc, 4f
or %o4, %lo(HI_MAGIC), %o3
11:
- ldub [%o0], %o5
+ lduba [%o0] ASI_S, %o5
brz,pn %o5, 22f
add %o0, 1, %o0
andcc %o0, 3, %g0
be,pt %icc, 5f
sethi %hi(LO_MAGIC), %o4
12:
- ldub [%o0], %o5
+ lduba [%o0] ASI_S, %o5
brz,pn %o5, 23f
add %o0, 1, %o0
ba,pt %icc, 13f
@@ -45,7 +47,7 @@ __strlen_user:
5:
or %o4, %lo(LO_MAGIC), %o2
13:
- ld [%o0], %o5
+ lda [%o0] ASI_S, %o5
2:
sub %o5, %o2, %o4
andcc %o4, %o3, %g0
@@ -68,7 +70,7 @@ __strlen_user:
andcc %o5, 0xff, %g0
bne,a,pt %icc, 2b
14:
- ld [%o0], %o5
+ lda [%o0] ASI_S, %o5
add %o4, 1, %o4
1:
retl
diff --git a/arch/sparc64/lib/strncpy_from_user.S b/arch/sparc64/lib/strncpy_from_user.S
index 05a48eb5a..e0fb0f09b 100644
--- a/arch/sparc64/lib/strncpy_from_user.S
+++ b/arch/sparc64/lib/strncpy_from_user.S
@@ -24,14 +24,14 @@ __strncpy_from_user:
sub %g0, %o2, %o3
add %o0, %o2, %o0
10:
- ldub [%o1 + %o3], %o4
+ lduba [%o1 + %o3] ASI_S, %o4
1:
brz,pn %o4, 2f
stb %o4, [%o0 + %o3]
addcc %o3, 1, %o3
bne,pt %xcc, 1b
11:
- ldub [%o1 + %o3], %o4
+ lduba [%o1 + %o3] ASI_S, %o4
retl
mov %o2, %o0
2:
diff --git a/arch/sparc64/mm/asyncd.c b/arch/sparc64/mm/asyncd.c
index 4e7de16fb..0272b09c2 100644
--- a/arch/sparc64/mm/asyncd.c
+++ b/arch/sparc64/mm/asyncd.c
@@ -1,4 +1,4 @@
-/* $Id: asyncd.c,v 1.1 1996/12/26 10:24:24 davem Exp $
+/* $Id: asyncd.c,v 1.2 1997/05/15 21:14:32 davem Exp $
* The asyncd kernel daemon. This handles paging on behalf of
* processes that receive page faults due to remote (async) memory
* accesses.
@@ -153,7 +153,7 @@ static int fault_in_page(int taskid,
if(!pte)
goto no_memory;
if(!pte_present(*pte)) {
- do_no_page(tsk, vma, address, write);
+ handle_mm_fault(tsk, vma, address, write);
goto finish_up;
}
set_pte(pte, pte_mkyoung(*pte));
@@ -165,12 +165,11 @@ static int fault_in_page(int taskid,
flush_tlb_page(vma, address);
goto finish_up;
}
- do_wp_page(tsk, vma, address, write);
+ handle_mm_fault(tsk, vma, address, write);
/* Fall through for do_wp_page */
finish_up:
stats.success++;
- update_mmu_cache(vma, address, *pte);
return 0;
no_memory:
diff --git a/arch/sparc64/mm/fault.c b/arch/sparc64/mm/fault.c
index 0dd118c8e..dc28ac339 100644
--- a/arch/sparc64/mm/fault.c
+++ b/arch/sparc64/mm/fault.c
@@ -1,4 +1,4 @@
-/* $Id: fault.c,v 1.4 1997/03/11 17:37:07 jj Exp $
+/* $Id: fault.c,v 1.8 1997/05/18 04:16:52 davem Exp $
* arch/sparc64/mm/fault.c: Page fault handlers for the 64-bit Sparc.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -134,8 +134,11 @@ asmlinkage int lookup_fault(unsigned long pc, unsigned long ret_pc,
return 0;
}
+/* #define FAULT_TRACER */
+
asmlinkage void do_sparc64_fault(struct pt_regs *regs, int text_fault, int write,
- unsigned long address)
+ unsigned long address, unsigned long tag,
+ unsigned long sfsr)
{
struct vm_area_struct *vma;
struct task_struct *tsk = current;
@@ -143,7 +146,19 @@ asmlinkage void do_sparc64_fault(struct pt_regs *regs, int text_fault, int write
unsigned long fixup;
unsigned long g2;
int from_user = !(regs->tstate & TSTATE_PRIV);
-
+#ifdef FAULT_TRACER
+ static unsigned long last_addr = 0;
+ static int rcnt = 0;
+
+ printk("do_sparc64_fault(PC[%016lx],t[%d],w[%d],addr[%016lx]tag[%016lx]"
+ "sfar[%016lx])\n", regs->tpc, text_fault, write, address, tag, sfsr);
+ if(address == last_addr && rcnt++ > 5) {
+ printk("Wheee lotsa bogus faults, something wrong, spinning\n");
+ while(1)
+ barrier();
+ }
+ last_addr = address;
+#endif
lock_kernel ();
down(&mm->mmap_sem);
vma = find_vma(mm, address);
@@ -168,7 +183,7 @@ good_area:
if(!(vma->vm_flags & (VM_READ | VM_EXEC)))
goto bad_area;
}
- handle_mm_fault(vma, address, write);
+ handle_mm_fault(current, vma, address, write);
up(&mm->mmap_sem);
goto out;
/*
diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c
index 57ca5eb92..cf378a266 100644
--- a/arch/sparc64/mm/init.c
+++ b/arch/sparc64/mm/init.c
@@ -1,4 +1,4 @@
-/* $Id: init.c,v 1.24 1997/04/17 21:49:41 jj Exp $
+/* $Id: init.c,v 1.28 1997/05/18 04:16:53 davem Exp $
* arch/sparc64/mm/init.c
*
* Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -457,16 +457,18 @@ void sparc_ultra_unmapioaddr(unsigned long virt_addr)
pte_clear(ptep);
}
-#ifdef DEBUG_MMU
void sparc_ultra_dump_itlb(void)
{
int slot;
- prom_printf ("Contents of itlb:\n");
- for (slot = 0; slot < 64; slot+=2) {
- prom_printf ("%2x:%016lx,%016lx %2x:%016lx,%016lx\n",
+ printk ("Contents of itlb: ");
+ for (slot = 0; slot < 14; slot++) printk (" ");
+ printk ("%2x:%016lx,%016lx\n", 0, spitfire_get_itlb_tag(0), spitfire_get_itlb_data(0));
+ for (slot = 1; slot < 64; slot+=3) {
+ printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx %2x:%016lx,%016lx\n",
slot, spitfire_get_itlb_tag(slot), spitfire_get_itlb_data(slot),
- slot+1, spitfire_get_itlb_tag(slot+1), spitfire_get_itlb_data(slot+1));
+ slot+1, spitfire_get_itlb_tag(slot+1), spitfire_get_itlb_data(slot+1),
+ slot+2, spitfire_get_itlb_tag(slot+2), spitfire_get_itlb_data(slot+2));
}
}
@@ -474,14 +476,16 @@ void sparc_ultra_dump_dtlb(void)
{
int slot;
- prom_printf ("Contents of dtlb:\n");
- for (slot = 0; slot < 64; slot+=2) {
- prom_printf ("%2x:%016lx,%016lx %2x:%016lx,%016lx\n",
+ printk ("Contents of dtlb: ");
+ for (slot = 0; slot < 14; slot++) printk (" ");
+ printk ("%2x:%016lx,%016lx\n", 0, spitfire_get_dtlb_tag(0), spitfire_get_dtlb_data(0));
+ for (slot = 1; slot < 64; slot+=3) {
+ printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx %2x:%016lx,%016lx\n",
slot, spitfire_get_dtlb_tag(slot), spitfire_get_dtlb_data(slot),
- slot+1, spitfire_get_dtlb_tag(slot+1), spitfire_get_dtlb_data(slot+1));
+ slot+1, spitfire_get_dtlb_tag(slot+1), spitfire_get_dtlb_data(slot+1),
+ slot+2, spitfire_get_dtlb_tag(slot+2), spitfire_get_dtlb_data(slot+2));
}
}
-#endif
/* paging_init() sets up the page tables */
@@ -643,7 +647,7 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
high_memory = (void *) end_mem;
start_mem = PAGE_ALIGN(start_mem);
- num_physpages = (start_mem - phys_base - PAGE_OFFSET) >> PAGE_SHIFT;
+ num_physpages = (start_mem - PAGE_OFFSET) >> PAGE_SHIFT;
addr = PAGE_OFFSET;
while(addr < start_mem) {
@@ -694,6 +698,11 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
min_free_pages = 16;
free_pages_low = min_free_pages + (min_free_pages >> 1);
free_pages_high = min_free_pages + min_free_pages;
+
+#if 0
+ printk("Testing fault handling...\n");
+ *(char *)0x00000deadbef0000UL = 0;
+#endif
}
void free_initmem (void)
@@ -702,9 +711,14 @@ void free_initmem (void)
addr = (unsigned long)(&__init_begin);
for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
- mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved);
- atomic_set(&mem_map[MAP_NR(addr)].count, 1);
- free_page(addr);
+ unsigned long page = addr;
+
+ if(page < ((unsigned long)__va(phys_base)))
+ page += phys_base;
+
+ mem_map[MAP_NR(page)].flags &= ~(1 << PG_reserved);
+ atomic_set(&mem_map[MAP_NR(page)].count, 1);
+ free_page(page);
}
}
diff --git a/drivers/block/Makefile b/drivers/block/Makefile
index ab00e93fc..f8ec1abd9 100644
--- a/drivers/block/Makefile
+++ b/drivers/block/Makefile
@@ -30,6 +30,22 @@ else
endif
endif
+ifeq ($(CONFIG_ATARI_ACSI),y)
+ LX_OBJS += acsi.o
+else
+ ifeq ($(CONFIG_ATARI_ACSI),m)
+ MX_OBJS += acsi.o
+ endif
+endif
+
+ifeq ($(CONFIG_ATARI_SLM),y)
+ L_OBJS += acsi_slm.o
+else
+ ifeq ($(CONFIG_ATARI_SLM),m)
+ M_OBJS += acsi_slm.o
+ endif
+endif
+
ifeq ($(CONFIG_AMIGA_Z2RAM),y)
L_OBJS += z2ram.o
else
diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c
index 12c0fcd52..ab11b62a8 100644
--- a/drivers/block/amiflop.c
+++ b/drivers/block/amiflop.c
@@ -62,6 +62,7 @@
#include <linux/delay.h>
#include <linux/string.h>
#include <linux/mm.h>
+#include <linux/init.h>
#include <asm/setup.h>
#include <asm/uaccess.h>
@@ -1712,7 +1713,7 @@ static void fd_probe(int dev)
}
-static void probe_drives(void)
+__initfunc(static void probe_drives(void))
{
int drive,found;
@@ -1860,7 +1861,7 @@ static void fd_block_done(int irq, void *dummy, struct pt_regs *fp)
}
-int amiga_floppy_init(void)
+__initfunc(int amiga_floppy_init(void))
{
int i;
diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c
index 3cf489712..7a08808f2 100644
--- a/drivers/block/ataflop.c
+++ b/drivers/block/ataflop.c
@@ -75,6 +75,7 @@
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/malloc.h>
+#include <linux/init.h>
#include <asm/setup.h>
#include <asm/system.h>
@@ -1777,7 +1778,7 @@ static int fd_ioctl(struct inode *inode, struct file *filp,
/* Initialize the 'unit' variable for drive 'drive' */
-static void fd_probe( int drive )
+__initfunc(static void fd_probe( int drive ))
{
UD.connected = 0;
UDT = NULL;
@@ -1820,7 +1821,7 @@ static void fd_probe( int drive )
* declared absent.
*/
-static int fd_test_drive_present( int drive )
+__initfunc(static int fd_test_drive_present( int drive ))
{
unsigned long timeout;
unsigned char status;
@@ -1867,7 +1868,7 @@ static int fd_test_drive_present( int drive )
* floppies, additionally start the disk-change and motor-off timers.
*/
-static void config_types( void )
+__initfunc(static void config_types( void ))
{
int drive, cnt = 0;
@@ -2010,7 +2011,7 @@ static struct file_operations floppy_fops = {
floppy_revalidate, /* revalidate */
};
-int atari_floppy_init (void)
+__initfunc(int atari_floppy_init (void))
{
int i;
@@ -2070,7 +2071,7 @@ int atari_floppy_init (void)
}
-void atari_floppy_setup( char *str, int *ints )
+__initfunc(void atari_floppy_setup( char *str, int *ints ))
{
int i;
diff --git a/drivers/block/ez.c b/drivers/block/ez.c
index c6fc96a2f..82270915d 100644
--- a/drivers/block/ez.c
+++ b/drivers/block/ez.c
@@ -101,6 +101,7 @@
#include <linux/genhd.h>
#include <linux/hdreg.h>
#include <linux/ioport.h>
+#include <linux/init.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -256,7 +257,7 @@ static struct file_operations ez_fops = {
ez_revalidate /* revalidate new media */
};
-int ez_init (void) /* preliminary initialisation */
+__initfunc(int ez_init (void)) /* preliminary initialisation */
{
if (register_blkdev(MAJOR_NR,"ez",&ez_fops)) {
@@ -271,7 +272,7 @@ int ez_init (void) /* preliminary initialisation */
return 0;
}
-static void ez_geninit (struct gendisk *ignored) /* real init */
+__initfunc(static void ez_geninit (struct gendisk *ignored)) /* real init */
{ int i;
@@ -507,7 +508,7 @@ void cleanup_module(void)
syntax: ez=base[,irq[,rep[,nybble]]]
*/
-void ez_setup(char *str, int *ints)
+__initfunc(void ez_setup(char *str, int *ints))
{ if (ints[0] > 0) ez_base = ints[1];
if (ints[0] > 1) ez_irq = ints[2];
@@ -748,7 +749,7 @@ static void ez_doorlock( int func )
/* ez_media_check: check for and acknowledge the MC flag */
-static void ez_media_check( void )
+__initfunc(static void ez_media_check( void ))
{ int r;
@@ -768,7 +769,7 @@ static void ez_media_check( void )
disconnect();
}
-static int ez_identify( void )
+__initfunc(static int ez_identify( void ))
{ int k, r;
@@ -800,7 +801,7 @@ static int ez_identify( void )
#define word_val(n) (ez_scratch[2*n]+256*ez_scratch[2*n+1])
-static void ez_get_capacity( void )
+__initfunc(static void ez_get_capacity( void ))
{ int ez_cylinders;
@@ -821,7 +822,7 @@ static void ez_get_capacity( void )
ez_heads,ez_sectors);
}
-static void ez_standby_off( void )
+__initfunc(static void ez_standby_off( void ))
{ connect();
wait_for(0,NULL);
@@ -830,7 +831,7 @@ static void ez_standby_off( void )
disconnect();
}
-static int ez_port_check( void ) /* check for 8-bit port */
+__initfunc(static int ez_port_check( void )) /* check for 8-bit port */
{ int r;
@@ -843,7 +844,7 @@ static int ez_port_check( void ) /* check for 8-bit port */
return 0;
}
-static int ez_detect( void )
+__initfunc(static int ez_detect( void ))
{ int j, k;
char sig[EZ_SIGLEN] = EZ_SIG;
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index 9fc100ded..3f90981fd 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -140,6 +140,7 @@ static int allowed_drive_mask = 0x33;
#include <linux/mc146818rtc.h> /* CMOS defines */
#include <linux/ioport.h>
#include <linux/interrupt.h>
+#include <linux/init.h>
#include <asm/dma.h>
#include <asm/irq.h>
@@ -3727,7 +3728,7 @@ static struct file_operations floppy_fops = {
/* Determine the floppy disk controller type */
/* This routine was written by David C. Niemi */
-static char get_fdc_version(void)
+__initfunc(static char get_fdc_version(void))
{
int r;
@@ -3805,7 +3806,7 @@ static char get_fdc_version(void)
/* lilo configuration */
-static void floppy_set_flags(int *ints,int param, int param2)
+__initfunc(static void floppy_set_flags(int *ints,int param, int param2))
{
int i;
@@ -3818,7 +3819,7 @@ static void floppy_set_flags(int *ints,int param, int param2)
DPRINT("%s flag 0x%x\n", param2 ? "Setting" : "Clearing", param);
}
-static void daring(int *ints,int param, int param2)
+__initfunc(static void daring(int *ints,int param, int param2))
{
int i;
@@ -3834,7 +3835,7 @@ static void daring(int *ints,int param, int param2)
DPRINT("Assuming %s floppy hardware\n", param ? "standard" : "broken");
}
-static void set_cmos(int *ints, int dummy, int dummy2)
+__initfunc(static void set_cmos(int *ints, int dummy, int dummy2))
{
int current_drive=0;
@@ -3895,7 +3896,7 @@ static struct param_table {
{ "L40SX", 0, &print_unex, 0, 0 } };
#define FLOPPY_SETUP
-void floppy_setup(char *str, int *ints)
+__initfunc(void floppy_setup(char *str, int *ints))
{
int i;
int param;
@@ -3931,7 +3932,7 @@ void floppy_setup(char *str, int *ints)
static int have_no_fdc= -EIO;
-int floppy_init(void)
+__initfunc(int floppy_init(void))
{
int i,unit,drive;
@@ -4136,7 +4137,7 @@ extern char *get_options(char *str, int *ints);
char *floppy=NULL;
-static void parse_floppy_cfg_string(char *cfg)
+__initfunc(static void parse_floppy_cfg_string(char *cfg))
{
char *ptr;
int ints[11];
@@ -4152,7 +4153,7 @@ static void parse_floppy_cfg_string(char *cfg)
}
}
-static void mod_setup(char *pattern, void (*setup)(char *, int *))
+__initfunc(static void mod_setup(char *pattern, void (*setup)(char *, int *)))
{
unsigned long i;
char c;
diff --git a/drivers/block/genhd.c b/drivers/block/genhd.c
index aa11a3ee1..ad0e79b1b 100644
--- a/drivers/block/genhd.c
+++ b/drivers/block/genhd.c
@@ -191,7 +191,7 @@ static void extended_partition(struct gendisk *hd, kdev_t dev)
*/
bh->b_state = 0;
- if (le16_to_cpu(*(unsigned short *) (bh->b_data+510)) != MSDOS_LABEL_MAGIC)
+ if ((*(unsigned short *) (bh->b_data+510)) != cpu_to_le16(MSDOS_LABEL_MAGIC))
goto done;
p = (struct partition *) (0x1BE + bh->b_data);
@@ -316,7 +316,7 @@ read_mbr:
#ifdef CONFIG_BLK_DEV_IDE
check_table:
#endif
- if (le16_to_cpu(*(unsigned short *) (0x1fe + data)) != MSDOS_LABEL_MAGIC) {
+ if (*(unsigned short *) (0x1fe + data) != cpu_to_le16(MSDOS_LABEL_MAGIC)) {
brelse(bh);
return 0;
}
@@ -359,7 +359,7 @@ check_table:
goto read_mbr; /* start over with new MBR */
}
} else if (sig <= 0x1ae &&
- le16_to_cpu(*(unsigned short *)(data + sig)) == 0x55AA &&
+ *(unsigned short *)(data + sig) == cpu_to_le16(0x55AA) &&
(1 & *(unsigned char *)(data + sig + 2))) {
/* DM6 signature in MBR, courtesy of OnTrack */
(void) ide_xlate_1024 (dev, 0, " [DM6:MBR]");
@@ -424,7 +424,7 @@ check_table:
/*
* Check for old-style Disk Manager partition table
*/
- if (le16_to_cpu(*(unsigned short *) (data+0xfc)) == MSDOS_LABEL_MAGIC) {
+ if (*(unsigned short *) (data+0xfc) == cpu_to_le16(MSDOS_LABEL_MAGIC)) {
p = (struct partition *) (0x1be + data);
for (i = 4 ; i < 16 ; i++, current_minor++) {
p--;
@@ -573,12 +573,12 @@ static int sun_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sec
spc = be16_to_cpu(label->ntrks) * be16_to_cpu(label->nsect);
for(i=0; i < 8; i++, p++) {
unsigned long st_sector;
+ int num_sectors;
- /* We register all partitions, even if zero size, so that
- * the minor numbers end up ok as per SunOS interpretation.
- */
st_sector = first_sector + be32_to_cpu(p->start_cylinder) * spc;
- add_partition(hd, current_minor, st_sector, be32_to_cpu(p->num_sectors));
+ num_sectors = be32_to_cpu(p->num_sectors);
+ if (num_sectors)
+ add_partition(hd, current_minor, st_sector, num_sectors);
current_minor++;
}
printk("\n");
@@ -660,10 +660,10 @@ static int sgi_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sec
#include <asm/byteorder.h>
#include <linux/affs_hardblocks.h>
-static __inline__ __u32
-checksum_block(__u32 *m, int size)
+static __inline__ u32
+checksum_block(u32 *m, int size)
{
- __u32 sum = 0;
+ u32 sum = 0;
while (size--)
sum += htonl(*m++);
@@ -671,7 +671,7 @@ checksum_block(__u32 *m, int size)
}
static int
-amiga_partition(struct gendisk *hd, unsigned int dev, unsigned long first_sector)
+amiga_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector)
{
struct buffer_head *bh;
struct RigidDiskBlock *rdb;
@@ -686,13 +686,15 @@ amiga_partition(struct gendisk *hd, unsigned int dev, unsigned long first_sector
for (blk = 0; blk < RDB_ALLOCATION_LIMIT; blk++) {
if(!(bh = bread(dev,blk,512))) {
- printk("Dev %d: unable to read RDB block %d\n",dev,blk);
+ printk("Dev %s: unable to read RDB block %d\n",
+ kdevname(dev),blk);
goto rdb_done;
}
- if (*(__u32 *)bh->b_data == htonl(IDNAME_RIGIDDISK)) {
+ if (*(u32 *)bh->b_data == htonl(IDNAME_RIGIDDISK)) {
rdb = (struct RigidDiskBlock *)bh->b_data;
- if (checksum_block((__u32 *)bh->b_data,htonl(rdb->rdb_SummedLongs) & 0x7F)) {
- printk("Dev %d: RDB in block %d has bad checksum\n",dev,blk);
+ if (checksum_block((u32 *)bh->b_data,htonl(rdb->rdb_SummedLongs) & 0x7F)) {
+ printk("Dev %s: RDB in block %d has bad checksum\n",
+ kdevname(dev),blk);
brelse(bh);
continue;
}
@@ -701,14 +703,14 @@ amiga_partition(struct gendisk *hd, unsigned int dev, unsigned long first_sector
brelse(bh);
for (part = 1; blk > 0 && part <= 16; part++) {
if (!(bh = bread(dev,blk,512))) {
- printk("Dev %d: unable to read partition block %d\n",
- dev,blk);
+ printk("Dev %s: unable to read partition block %d\n",
+ kdevname(dev),blk);
goto rdb_done;
}
pb = (struct PartitionBlock *)bh->b_data;
blk = htonl(pb->pb_Next);
if (pb->pb_ID == htonl(IDNAME_PARTITION) && checksum_block(
- (__u32 *)pb,htonl(pb->pb_SummedLongs) & 0x7F) == 0 ) {
+ (u32 *)pb,htonl(pb->pb_SummedLongs) & 0x7F) == 0 ) {
/* Tell Kernel about it */
diff --git a/drivers/block/hd.c b/drivers/block/hd.c
index 9c4d8bb71..62e2f8da3 100644
--- a/drivers/block/hd.c
+++ b/drivers/block/hd.c
@@ -39,6 +39,7 @@
#include <linux/string.h>
#include <linux/ioport.h>
#include <linux/mc146818rtc.h> /* CMOS defines */
+#include <linux/init.h>
#define REALLY_SLOW_IO
#include <asm/system.h>
@@ -110,7 +111,7 @@ unsigned long read_timer(void)
}
#endif
-void hd_setup(char *str, int *ints)
+__initfunc(void hd_setup(char *str, int *ints))
{
int hdind = 0;
@@ -792,7 +793,7 @@ static struct file_operations hd_fops = {
block_fsync /* fsync */
};
-int hd_init(void)
+__initfunc(int hd_init(void))
{
if (register_blkdev(MAJOR_NR,"hd",&hd_fops)) {
printk("hd: unable to get major %d for harddisk\n",MAJOR_NR);
diff --git a/drivers/block/ide-disk.c b/drivers/block/ide-disk.c
index 94073d468..fbf8c3833 100644
--- a/drivers/block/ide-disk.c
+++ b/drivers/block/ide-disk.c
@@ -48,7 +48,6 @@
#include <linux/types.h>
#include <linux/string.h>
#include <linux/kernel.h>
-#include <linux/delay.h>
#include <linux/timer.h>
#include <linux/mm.h>
#include <linux/ioport.h>
@@ -59,6 +58,7 @@
#include <linux/hdreg.h>
#include <linux/genhd.h>
#include <linux/malloc.h>
+#include <linux/delay.h>
#include <asm/byteorder.h>
#include <asm/irq.h>
diff --git a/drivers/block/ide-floppy.c b/drivers/block/ide-floppy.c
index d362dfab4..5a0a603b5 100644
--- a/drivers/block/ide-floppy.c
+++ b/drivers/block/ide-floppy.c
@@ -726,7 +726,7 @@ static void idefloppy_pc_intr (ide_drive_t *drive)
return;
}
#ifdef CONFIG_BLK_DEV_TRITON
- if (clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
+ if (test_and_clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
printk (KERN_ERR "ide-floppy: The floppy wants to issue more interrupts in DMA mode\n");
printk (KERN_ERR "ide-floppy: DMA disabled, reverting to PIO\n");
HWIF(drive)->dmaproc(ide_dma_off, drive);
@@ -842,7 +842,7 @@ static void idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *pc)
bcount.all=pc->request_transfer; /* Request to transfer the entire buffer at once */
#ifdef CONFIG_BLK_DEV_TRITON
- if (clear_bit (PC_DMA_ERROR, &pc->flags)) {
+ if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) {
printk (KERN_WARNING "ide-floppy: DMA disabled, reverting to PIO\n");
HWIF(drive)->dmaproc(ide_dma_off, drive);
}
@@ -1182,7 +1182,7 @@ static int idefloppy_media_change (ide_drive_t *drive)
{
idefloppy_floppy_t *floppy = drive->driver_data;
- return clear_bit (IDEFLOPPY_MEDIA_CHANGED, &floppy->flags);
+ return test_and_clear_bit (IDEFLOPPY_MEDIA_CHANGED, &floppy->flags);
}
/*
diff --git a/drivers/block/ide-probe.c b/drivers/block/ide-probe.c
index 76e10c08f..25b3d54fa 100644
--- a/drivers/block/ide-probe.c
+++ b/drivers/block/ide-probe.c
@@ -47,7 +47,6 @@
#include <linux/types.h>
#include <linux/string.h>
#include <linux/kernel.h>
-#include <linux/delay.h>
#include <linux/timer.h>
#include <linux/mm.h>
#include <linux/ioport.h>
@@ -58,6 +57,7 @@
#include <linux/hdreg.h>
#include <linux/genhd.h>
#include <linux/malloc.h>
+#include <linux/delay.h>
#include <asm/byteorder.h>
#include <asm/irq.h>
diff --git a/drivers/block/ide-tape.c b/drivers/block/ide-tape.c
index 537c5dd82..2fc5f0b9d 100644
--- a/drivers/block/ide-tape.c
+++ b/drivers/block/ide-tape.c
@@ -1777,7 +1777,7 @@ static void idetape_pc_intr (ide_drive_t *drive)
return;
}
#ifdef CONFIG_BLK_DEV_TRITON
- if (clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
+ if (test_and_clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
printk (KERN_ERR "ide-tape: The tape wants to issue more interrupts in DMA mode\n");
printk (KERN_ERR "ide-tape: DMA disabled, reverting to PIO\n");
HWIF(drive)->dmaproc(ide_dma_off, drive);
@@ -1916,7 +1916,7 @@ static void idetape_issue_packet_command (ide_drive_t *drive, idetape_pc_t *pc)
bcount.all=pc->request_transfer; /* Request to transfer the entire buffer at once */
#ifdef CONFIG_BLK_DEV_TRITON
- if (clear_bit (PC_DMA_ERROR, &pc->flags)) {
+ if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) {
printk (KERN_WARNING "ide-tape: DMA disabled, reverting to PIO\n");
HWIF(drive)->dmaproc(ide_dma_off, drive);
}
@@ -2248,7 +2248,7 @@ static void idetape_do_request (ide_drive_t *drive, struct request *rq, unsigned
status.all = GET_STAT();
if (!drive->dsc_overlap && rq->cmd != IDETAPE_PC_RQ2)
set_bit (IDETAPE_IGNORE_DSC, &tape->flags);
- if (!clear_bit (IDETAPE_IGNORE_DSC, &tape->flags) && !status.b.dsc) {
+ if (!test_and_clear_bit (IDETAPE_IGNORE_DSC, &tape->flags) && !status.b.dsc) {
if (postponed_rq == NULL) {
tape->dsc_polling_start = jiffies;
tape->dsc_polling_frequency = tape->best_dsc_rw_frequency;
@@ -2506,7 +2506,7 @@ static int idetape_add_chrdev_write_request (ide_drive_t *drive, int blocks)
if (!idetape_pipeline_active (tape) && tape->nr_stages >= (3 * tape->max_stages) / 4)
idetape_insert_pipeline_into_queue (drive);
- if (clear_bit (IDETAPE_PIPELINE_ERROR, &tape->flags)) /* Return a deferred error */
+ if (test_and_clear_bit (IDETAPE_PIPELINE_ERROR, &tape->flags)) /* Return a deferred error */
return -EIO;
return blocks;
}
@@ -3254,7 +3254,7 @@ static int idetape_chrdev_open (struct inode *inode, struct file *filp)
return -ENXIO;
tape = drive->driver_data;
- if (set_bit (IDETAPE_BUSY, &tape->flags))
+ if (test_and_set_bit (IDETAPE_BUSY, &tape->flags))
return -EBUSY;
MOD_INC_USE_COUNT;
idetape_create_read_position_cmd (&pc);
diff --git a/drivers/block/ide.c b/drivers/block/ide.c
index ca9456479..89759dd32 100644
--- a/drivers/block/ide.c
+++ b/drivers/block/ide.c
@@ -294,7 +294,6 @@
#include <linux/types.h>
#include <linux/string.h>
#include <linux/kernel.h>
-#include <linux/delay.h>
#include <linux/timer.h>
#include <linux/mm.h>
#include <linux/ioport.h>
@@ -307,6 +306,8 @@
#include <linux/malloc.h>
#include <linux/bios32.h>
#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/init.h>
#include <asm/byteorder.h>
#include <asm/irq.h>
@@ -2144,7 +2145,7 @@ void ide_fixstring (byte *s, const int bytecount, const int byteswap)
* stridx() returns the offset of c within s,
* or -1 if c is '\0' or not found within s.
*/
-static int stridx (const char *s, char c)
+__initfunc(static int stridx (const char *s, char c))
{
char *i = strchr(s, c);
return (i && c) ? i - s : -1;
@@ -2162,7 +2163,7 @@ static int stridx (const char *s, char c)
* and base16 is allowed when prefixed with "0x".
* 4. otherwise, zero is returned.
*/
-static int match_parm (char *s, const char *keywords[], int vals[], int max_vals)
+__initfunc(static int match_parm (char *s, const char *keywords[], int vals[], int max_vals))
{
static const char *decimal = "0123456789";
static const char *hex = "0123456789abcdef";
@@ -2261,7 +2262,7 @@ static int match_parm (char *s, const char *keywords[], int vals[], int max_vals
* "ide0=ali14xx" : probe/support ali14xx chipsets (ALI M1439, M1443, M1445)
* "ide0=umc8672" : probe/support umc8672 chipsets
*/
-void ide_setup (char *s)
+__initfunc(void ide_setup (char *s))
{
int i, vals[3];
ide_hwif_t *hwif;
@@ -2558,7 +2559,7 @@ typedef void (ide_pci_init_proc_t)(byte, byte);
* ide_probe_pci() scans PCI for a specific vendor/device function,
* and invokes the supplied init routine for each instance detected.
*/
-static void ide_probe_pci (unsigned short vendor, unsigned short device, ide_pci_init_proc_t *init, int func_adj)
+__initfunc(static void ide_probe_pci (unsigned short vendor, unsigned short device, ide_pci_init_proc_t *init, int func_adj))
{
unsigned long flags;
unsigned index;
@@ -2581,7 +2582,7 @@ static void ide_probe_pci (unsigned short vendor, unsigned short device, ide_pci
* This routine should ideally be using pcibios_find_class() to find all
* PCI IDE interfaces, but that function causes some systems to "go weird".
*/
-static void probe_for_hwifs (void)
+__initfunc(static void probe_for_hwifs (void))
{
#ifdef CONFIG_PCI
/*
@@ -2620,7 +2621,7 @@ static void probe_for_hwifs (void)
#endif
}
-void ide_init_builtin_drivers (void)
+__initfunc(void ide_init_builtin_drivers (void))
{
/*
* Probe for special "known" interface chipsets
@@ -2889,7 +2890,7 @@ EXPORT_SYMBOL(ide_unregister);
/*
* This is gets invoked once during initialization, to set *everything* up
*/
-int ide_init (void)
+__initfunc(int ide_init (void))
{
init_ide_data ();
@@ -2904,7 +2905,7 @@ int ide_init (void)
char *options = NULL;
MODULE_PARM(options,"s");
-static void parse_options (char *line)
+__initfunc(static void parse_options (char *line))
{
char *next = line;
diff --git a/drivers/block/linear.c b/drivers/block/linear.c
index 6fc6960aa..f0f9fec79 100644
--- a/drivers/block/linear.c
+++ b/drivers/block/linear.c
@@ -21,6 +21,7 @@
#include <linux/md.h>
#include <linux/malloc.h>
+#include <linux/init.h>
#include "linear.h"
@@ -180,7 +181,7 @@ static struct md_personality linear_personality=
#ifndef MODULE
-void linear_init (void)
+__initfunc(void linear_init (void))
{
register_md_personality (LINEAR, &linear_personality);
}
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index d6af70d4f..212efece2 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -23,6 +23,7 @@
#include <linux/stat.h>
#include <linux/errno.h>
#include <linux/major.h>
+#include <linux/init.h>
#include <asm/uaccess.h>
@@ -537,8 +538,8 @@ static struct file_operations lo_fops = {
#define loop_init init_module
#endif
-int
-loop_init( void ) {
+__initfunc(int
+loop_init( void )) {
int i;
if (register_blkdev(MAJOR_NR, "loop", &lo_fops)) {
diff --git a/drivers/block/md.c b/drivers/block/md.c
index 7b4ec6313..078e1e1ee 100644
--- a/drivers/block/md.c
+++ b/drivers/block/md.c
@@ -35,6 +35,7 @@
#include <linux/kerneld.h>
#endif
#include <linux/errno.h>
+#include <linux/init.h>
#define MAJOR_NR MD_MAJOR
#define MD_DRIVER
@@ -546,7 +547,7 @@ void raid0_init (void);
void raid1_init (void);
void raid5_init (void);
-int md_init (void)
+__initfunc(int md_init (void))
{
printk ("md driver %s MAX_MD_DEV=%d, MAX_REAL=%d\n", MD_VERSION, MAX_MD_DEV, MAX_REAL);
diff --git a/drivers/block/ps2esdi.c b/drivers/block/ps2esdi.c
index 8e845e8d7..b4d5146de 100644
--- a/drivers/block/ps2esdi.c
+++ b/drivers/block/ps2esdi.c
@@ -43,6 +43,7 @@
#include <linux/ps2esdi.h>
#include <linux/blk.h>
#include <linux/mca.h>
+#include <linux/init.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -176,7 +177,7 @@ static struct gendisk ps2esdi_gendisk =
};
/* initialization routine called by ll_rw_blk.c */
-int ps2esdi_init(void)
+__initfunc(int ps2esdi_init(void))
{
/* register the device - pass the name, major number and operations
@@ -197,7 +198,7 @@ int ps2esdi_init(void)
} /* ps2esdi_init */
/* handles boot time command line parameters */
-void tp720_setup(char *str, int *ints)
+__initfunc(void tp720_setup(char *str, int *ints))
{
/* no params, just sets the tp720esdi flag if it exists */
@@ -205,7 +206,7 @@ void tp720_setup(char *str, int *ints)
tp720esdi = 1;
}
-void ed_setup(char *str, int *ints)
+__initfunc(void ed_setup(char *str, int *ints))
{
int hdind = 0;
@@ -252,10 +253,9 @@ static int ps2esdi_getinfo(char *buf, int slot, void *d)
}
/* ps2 esdi specific initialization - called thru the gendisk chain */
-static void ps2esdi_geninit(struct gendisk *ignored)
+__initfunc(static void ps2esdi_geninit(struct gendisk *ignored))
{
/*
-
The first part contains the initialization code
for the ESDI disk subsystem. All we really do
is search for the POS registers of the controller
@@ -386,7 +386,7 @@ static void ps2esdi_geninit(struct gendisk *ignored)
} /* ps2esdi_geninit */
-static void ps2esdi_get_device_cfg(void)
+__initfunc(static void ps2esdi_get_device_cfg(void))
{
u_short cmd_blk[TYPE_0_CMD_BLK_LENGTH];
diff --git a/drivers/block/rd.c b/drivers/block/rd.c
index 102b19963..4ac6c0c41 100644
--- a/drivers/block/rd.c
+++ b/drivers/block/rd.c
@@ -51,9 +51,11 @@
#include <linux/ioctl.h>
#include <linux/fd.h>
#include <linux/module.h>
+#include <linux/init.h>
#include <asm/system.h>
#include <asm/uaccess.h>
+#include <asm/byteorder.h>
extern void wait_for_keypress(void);
@@ -269,7 +271,7 @@ static struct file_operations fd_fops = {
};
/* This is the registration and initialization section of the ramdisk driver */
-int rd_init(void)
+__initfunc(int rd_init(void))
{
int i;
@@ -334,8 +336,8 @@ void cleanup_module(void)
* romfs
* gzip
*/
-int
-identify_ramdisk_image(kdev_t device, struct file *fp, int start_block)
+__initfunc(int
+identify_ramdisk_image(kdev_t device, struct file *fp, int start_block))
{
const int size = 512;
struct minix_super_block *minixsb;
@@ -440,7 +442,7 @@ done:
/*
* This routine loads in the ramdisk image.
*/
-static void rd_load_image(kdev_t device,int offset)
+__initfunc(static void rd_load_image(kdev_t device,int offset))
{
struct inode inode, out_inode;
struct file infile, outfile;
@@ -527,7 +529,7 @@ done:
}
-void rd_load()
+__initfunc(void rd_load(void))
{
if (rd_doload == 0)
return;
@@ -549,7 +551,7 @@ void rd_load()
#ifdef CONFIG_BLK_DEV_INITRD
-void initrd_load(void)
+__initfunc(void initrd_load(void))
{
rd_load_image(MKDEV(MAJOR_NR, INITRD_MINOR),0);
}
@@ -608,21 +610,21 @@ static void gzip_release(void **);
#include "../../lib/inflate.c"
-static void *malloc(int size)
+__initfunc(static void *malloc(int size))
{
return kmalloc(size, GFP_KERNEL);
}
-static void free(void *where)
+__initfunc(static void free(void *where))
{
kfree(where);
}
-static void gzip_mark(void **ptr)
+__initfunc(static void gzip_mark(void **ptr))
{
}
-static void gzip_release(void **ptr)
+__initfunc(static void gzip_release(void **ptr))
{
}
@@ -631,7 +633,7 @@ static void gzip_release(void **ptr)
* Fill the input buffer. This is called only when the buffer is empty
* and at least one byte is really needed.
*/
-static int fill_inbuf()
+__initfunc(static int fill_inbuf(void))
{
if (exit_code) return -1;
@@ -648,7 +650,7 @@ static int fill_inbuf()
* Write the output window window[0..outcnt-1] and update crc and bytes_out.
* (Used for the decompressed data only.)
*/
-static void flush_window()
+__initfunc(static void flush_window(void))
{
ulg c = crc; /* temporary variable */
unsigned n;
@@ -666,14 +668,14 @@ static void flush_window()
outcnt = 0;
}
-static void error(char *x)
+__initfunc(static void error(char *x))
{
printk(KERN_ERR "%s", x);
exit_code = 1;
}
-static int
-crd_load(struct file * fp, struct file *outfp)
+__initfunc(static int
+crd_load(struct file * fp, struct file *outfp))
{
int result;
diff --git a/drivers/block/xd.c b/drivers/block/xd.c
index 603c4b142..472959603 100644
--- a/drivers/block/xd.c
+++ b/drivers/block/xd.c
@@ -30,6 +30,7 @@
#include <linux/kernel.h>
#include <linux/genhd.h>
#include <linux/hdreg.h>
+#include <linux/init.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -126,7 +127,7 @@ static u_char xd_override = 0, xd_type = 0;
static u_short xd_iobase = 0;
/* xd_init: register the block device number and set up pointer tables */
-int xd_init (void)
+__initfunc(int xd_init (void))
{
if (register_blkdev(MAJOR_NR,"xd",&xd_fops)) {
printk("xd_init: unable to get major number %d\n",MAJOR_NR);
@@ -141,7 +142,7 @@ int xd_init (void)
}
/* xd_detect: scan the possible BIOS ROM locations for the signature strings */
-static u_char xd_detect (u_char *controller, unsigned int *address)
+__initfunc(static u_char xd_detect (u_char *controller, unsigned int *address))
{
u_char i,j,found = 0;
@@ -164,7 +165,7 @@ static u_char xd_detect (u_char *controller, unsigned int *address)
/* xd_geninit: grab the IRQ and DMA channel, initialise the drives */
/* and set up the "raw" device entries in the table */
-static void xd_geninit (struct gendisk *ignored)
+__initfunc(static void xd_geninit (struct gendisk *ignored))
{
u_char i,controller;
unsigned int address;
@@ -527,7 +528,7 @@ static u_int xd_command (u_char *command,u_char mode,u_char *indata,u_char *outd
return (csb & CSB_ERROR);
}
-static u_char xd_initdrives (void (*init_drive)(u_char drive))
+__initfunc(static u_char xd_initdrives (void (*init_drive)(u_char drive)))
{
u_char cmdblk[6],i,count = 0;
@@ -541,7 +542,7 @@ static u_char xd_initdrives (void (*init_drive)(u_char drive))
return (count);
}
-static void xd_dtc_init_controller (unsigned int address)
+__initfunc(static void xd_dtc_init_controller (unsigned int address))
{
switch (address) {
case 0xC8000: xd_iobase = 0x320; break;
@@ -556,7 +557,7 @@ static void xd_dtc_init_controller (unsigned int address)
outb(0,XD_RESET); /* reset the controller */
}
-static void xd_dtc_init_drive (u_char drive)
+__initfunc(static void xd_dtc_init_drive (u_char drive))
{
u_char cmdblk[6],buf[64];
@@ -581,7 +582,7 @@ static void xd_dtc_init_drive (u_char drive)
printk("xd_dtc_init_drive: error reading geometry for drive %d\n",drive);
}
-static void xd_wd_init_controller (unsigned int address)
+__initfunc(static void xd_wd_init_controller (unsigned int address))
{
switch (address) {
case 0xC8000: xd_iobase = 0x320; break;
@@ -600,7 +601,7 @@ static void xd_wd_init_controller (unsigned int address)
/* outb(0,XD_RESET); */ /* reset the controller */
}
-static void xd_wd_init_drive (u_char drive)
+__initfunc(static void xd_wd_init_drive (u_char drive))
{
u_char cmdblk[6],buf[0x200];
@@ -622,7 +623,7 @@ static void xd_wd_init_drive (u_char drive)
printk("xd_wd_init_drive: error reading geometry for drive %d\n",drive);
}
-static void xd_seagate_init_controller (unsigned int address)
+__initfunc(static void xd_seagate_init_controller (unsigned int address))
{
switch (address) {
case 0xC8000: xd_iobase = 0x320; break;
@@ -639,7 +640,7 @@ static void xd_seagate_init_controller (unsigned int address)
outb(0,XD_RESET); /* reset the controller */
}
-static void xd_seagate_init_drive (u_char drive)
+__initfunc(static void xd_seagate_init_drive (u_char drive))
{
u_char cmdblk[6],buf[0x200];
@@ -655,7 +656,7 @@ static void xd_seagate_init_drive (u_char drive)
}
/* Omti support courtesy Dirk Melchers */
-static void xd_omti_init_controller (unsigned int address)
+__initfunc(static void xd_omti_init_controller (unsigned int address))
{
switch (address) {
case 0xC8000: xd_iobase = 0x320; break;
@@ -673,7 +674,7 @@ static void xd_omti_init_controller (unsigned int address)
outb(0,XD_RESET); /* reset the controller */
}
-static void xd_omti_init_drive (u_char drive)
+__initfunc(static void xd_omti_init_drive (u_char drive))
{
/* gets infos from drive */
xd_override_init_drive(drive);
@@ -684,7 +685,7 @@ static void xd_omti_init_drive (u_char drive)
/* xd_override_init_drive: this finds disk geometry in a "binary search" style, narrowing in on the "correct" number of heads
etc. by trying values until it gets the highest successful value. Idea courtesy Salvador Abreu (spa@fct.unl.pt). */
-static void xd_override_init_drive (u_char drive)
+__initfunc(static void xd_override_init_drive (u_char drive))
{
u_short min[] = { 0,0,0 },max[] = { 16,1024,64 },test[] = { 0,0,0 };
u_char cmdblk[6],i;
@@ -707,7 +708,7 @@ static void xd_override_init_drive (u_char drive)
}
/* xd_setup: initialise from command line parameters */
-void xd_setup (char *command,int *integers)
+__initfunc(void xd_setup (char *command,int *integers))
{
xd_override = 1;
@@ -720,7 +721,7 @@ void xd_setup (char *command,int *integers)
}
/* xd_setparam: set the drive characteristics */
-static void xd_setparam (u_char command,u_char drive,u_char heads,u_short cylinders,u_short rwrite,u_short wprecomp,u_char ecc)
+__initfunc(static void xd_setparam (u_char command,u_char drive,u_char heads,u_short cylinders,u_short rwrite,u_short wprecomp,u_char ecc))
{
u_char cmdblk[14];
diff --git a/drivers/block/z2ram.c b/drivers/block/z2ram.c
index 0f556752d..ac13bcff2 100644
--- a/drivers/block/z2ram.c
+++ b/drivers/block/z2ram.c
@@ -28,6 +28,7 @@
#include <linux/major.h>
#include <linux/malloc.h>
#include <linux/blk.h>
+#include <linux/init.h>
#if defined(MODULE)
#include <linux/module.h>
@@ -282,8 +283,8 @@ static struct file_operations z2_fops =
block_fsync /* fsync */
};
-int
-z2_init( void )
+__initfunc(int
+z2_init( void ))
{
if ( !MACH_IS_AMIGA )
diff --git a/drivers/cdrom/aztcd.c b/drivers/cdrom/aztcd.c
index 514a7826d..c97133141 100644
--- a/drivers/cdrom/aztcd.c
+++ b/drivers/cdrom/aztcd.c
@@ -166,6 +166,7 @@
#include <linux/ioport.h>
#include <linux/string.h>
#include <linux/major.h>
+#include <linux/init.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -1049,7 +1050,7 @@ static int aztGetToc(int multi)
Kernel Interface Functions
##########################################################################
*/
-void aztcd_setup(char *str, int *ints)
+__initfunc(void aztcd_setup(char *str, int *ints))
{ if (ints[0] > 0)
azt_port = ints[1];
if (ints[0] > 1)
@@ -1567,7 +1568,7 @@ static int aztcd_release(struct inode * inode, struct file * file)
* Test for presence of drive and initialize it. Called at boot time.
*/
-int aztcd_init(void)
+__initfunc(int aztcd_init(void))
{ long int count, max_count;
unsigned char result[50];
int st;
diff --git a/drivers/cdrom/bpcd.c b/drivers/cdrom/bpcd.c
index 49225ec0c..9f7e8b395 100644
--- a/drivers/cdrom/bpcd.c
+++ b/drivers/cdrom/bpcd.c
@@ -113,6 +113,7 @@
#include <linux/delay.h>
#include <linux/cdrom.h>
#include <linux/ioport.h>
+#include <linux/init.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -201,7 +202,7 @@ static struct file_operations bp_fops = {
nybble value. The following function initialises the table.
*/
-static void init_nyb_map( void )
+__initfunc(static void init_nyb_map( void ))
{ int i, j;
@@ -212,7 +213,7 @@ static void init_nyb_map( void )
}
}
-int bpcd_init (void) /* preliminary initialisation */
+__initfunc(int bpcd_init (void)) /* preliminary initialisation */
{ init_nyb_map();
@@ -327,7 +328,7 @@ void cleanup_module(void)
syntax: bpcd=base[,nybble[,rep]]
*/
-void bpcd_setup(char *str, int *ints)
+__initfunc(void bpcd_setup(char *str, int *ints))
{ if (ints[0] > 0) bp_base = ints[1];
if (ints[0] > 1) bp_nybble = ints[2];
@@ -425,7 +426,7 @@ static void read_data( char * buf, int len )
if (bp_mode == 2) { t2(1); t2(0x20); }
}
-static int probe( int id )
+__initfunc(static int probe( int id ))
{ int l, h, t;
int r = -1;
@@ -588,7 +589,7 @@ static void bp_eject( void)
bp_atapi(ej_cmd,0,"eject");
}
-static int bp_reset( void )
+__initfunc(static int bp_reset( void ))
/* the ATAPI standard actually specifies the contents of all 7 registers
after a reset, but the specification is ambiguous concerning the last
@@ -615,7 +616,7 @@ static int bp_reset( void )
return flg-1;
}
-static int bp_identify( char * id )
+__initfunc(static int bp_identify( char * id ))
{ int k;
char id_cmd[12] = {0x12,0,0,0,36,0,0,0,0,0,0,0};
@@ -627,7 +628,7 @@ static int bp_identify( char * id )
return 0;
}
-static int bp_port_check( void ) /* check for 8-bit port */
+__initfunc(static int bp_port_check( void )) /* check for 8-bit port */
{ int r;
@@ -640,7 +641,7 @@ static int bp_port_check( void ) /* check for 8-bit port */
return 0;
}
-static int bp_locate( void )
+__initfunc(static int bp_locate( void ))
{ int k;
@@ -652,7 +653,7 @@ static int bp_locate( void )
return -1;
}
-static int bp_do_detect( int autop )
+__initfunc(static int bp_do_detect( int autop ))
{ char id[18];
@@ -705,7 +706,7 @@ static int bp_do_detect( int autop )
add it here ....
*/
-static int bp_detect( void )
+__initfunc(static int bp_detect( void ))
{ if (bp_base) return bp_do_detect(0);
if (!bp_do_detect(0x378)) return 0;
diff --git a/drivers/cdrom/cdi.c b/drivers/cdrom/cdi.c
index c45056d2e..ee90de9c6 100644
--- a/drivers/cdrom/cdi.c
+++ b/drivers/cdrom/cdi.c
@@ -28,6 +28,7 @@
#include <linux/config.h>
#include <linux/blk.h> /* where the proto type of cdi_init() is */
+#include <linux/init.h>
#ifdef CONFIG_ISP16_CDI
#include <linux/isp16.h>
#endif CONFIG_ISP16_CDI
@@ -35,8 +36,8 @@
/*
* Cdrom interface configuration.
*/
-int
-cdi_init(void)
+__initfunc(int
+cdi_init(void))
{
int ret_val = -1;
diff --git a/drivers/cdrom/cdu31a.c b/drivers/cdrom/cdu31a.c
index 54c129686..e2c269bcf 100644
--- a/drivers/cdrom/cdu31a.c
+++ b/drivers/cdrom/cdu31a.c
@@ -190,6 +190,7 @@
#include <linux/ioport.h>
#include <linux/string.h>
#include <linux/malloc.h>
+#include <linux/init.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -220,7 +221,7 @@ static struct
unsigned short base; /* I/O Base Address */
short int_num; /* Interrupt Number (-1 means scan for it,
0 means don't use) */
-} cdu31a_addresses[] =
+} cdu31a_addresses[] __initdata =
{
#if 0 /* No autoconfig any more. See Note at beginning
of this file. */
@@ -2963,12 +2964,12 @@ static struct file_operations scd_fops = {
/* The different types of disc loading mechanisms supported */
-static const char *load_mech[] = { "caddy", "tray", "pop-up", "unknown" };
+static const char *load_mech[] __initdata = { "caddy", "tray", "pop-up", "unknown" };
-static void
+__initfunc(static void
get_drive_configuration(unsigned short base_io,
unsigned char res_reg[],
- unsigned int *res_size)
+ unsigned int *res_size))
{
int retry_count;
@@ -3032,9 +3033,9 @@ get_drive_configuration(unsigned short base_io,
/*
* Set up base I/O and interrupts, called from main.c.
*/
-void
+__initfunc(void
cdu31a_setup(char *strings,
- int *ints)
+ int *ints))
{
if (ints[0] > 0)
{
@@ -3063,8 +3064,8 @@ static int cdu31a_block_size;
/*
* Initialize the driver.
*/
-int
-cdu31a_init(void)
+__initfunc(int
+cdu31a_init(void))
{
struct s_sony_drive_config drive_config;
unsigned int res_size;
diff --git a/drivers/cdrom/cm206.c b/drivers/cdrom/cm206.c
index 9411b3f02..fb5533706 100644
--- a/drivers/cdrom/cm206.c
+++ b/drivers/cdrom/cm206.c
@@ -138,6 +138,7 @@ History:
#include <linux/ioport.h>
#include <linux/mm.h>
#include <linux/malloc.h>
+#include <linux/init.h>
#include <linux/ucdrom.h>
@@ -1186,7 +1187,7 @@ void cleanup(int level)
check_region, 15 bits of one port and 6 of another make things
likely enough to accept the region on the first hit...
*/
-int probe_base_port(int base)
+__initfunc(int probe_base_port(int base))
{
int b=0x300, e=0x370; /* this is the range of start addresses */
volatile int fool, i;
@@ -1206,7 +1207,7 @@ int probe_base_port(int base)
#if !defined(MODULE) || defined(AUTO_PROBE_MODULE)
/* Probe for irq# nr. If nr==0, probe for all possible irq's. */
-int probe_irq(int nr) {
+__initfunc(int probe_irq(int nr)) {
int irqs, irq;
outw(dc_normal | READ_AHEAD, r_data_control); /* disable irq-generation */
sti();
@@ -1220,7 +1221,7 @@ int probe_irq(int nr) {
}
#endif
-int cm206_init(void)
+__initfunc(int cm206_init(void))
{
uch e=0;
long int size=sizeof(struct cm206_struct);
@@ -1303,7 +1304,7 @@ int cm206_init(void)
static int cm206[2] = {0,0}; /* for compatible `insmod' parameter passing */
-void parse_options(void)
+__initfunc(void parse_options(void))
{
int i;
for (i=0; i<2; i++) {
@@ -1337,7 +1338,7 @@ void cleanup_module(void)
/* This setup function accepts either `auto' or numbers in the range
* 3--11 (for irq) or 0x300--0x370 (for base port) or both. */
-void cm206_setup(char *s, int *p)
+__initfunc(void cm206_setup(char *s, int *p))
{
int i;
if (!strcmp(s, "auto")) auto_probe=1;
diff --git a/drivers/cdrom/gscd.c b/drivers/cdrom/gscd.c
index c9ad14748..685990a77 100644
--- a/drivers/cdrom/gscd.c
+++ b/drivers/cdrom/gscd.c
@@ -55,6 +55,7 @@
#include <linux/ioport.h>
#include <linux/major.h>
#include <linux/string.h>
+#include <linux/init.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -191,7 +192,7 @@ static int check_gscd_med_chg (kdev_t full_dev)
}
-void gscd_setup (char *str, int *ints)
+__initfunc(void gscd_setup (char *str, int *ints))
{
if (ints[0] > 0)
{
@@ -848,7 +849,7 @@ int i;
return;
}
-int find_drives (void)
+__initfunc(int find_drives (void))
{
int *pdrv;
int drvnum;
@@ -899,7 +900,7 @@ int i;
return drvnum;
}
-void init_cd_drive ( int num )
+__initfunc(void init_cd_drive ( int num ))
{
char resp [50];
int i;
@@ -991,7 +992,7 @@ void cleanup_module (void)
/* Test for presence of drive and initialize it. Called only at boot time. */
-int gscd_init (void)
+__initfunc(int gscd_init (void))
{
return my_gscd_init ();
}
@@ -999,7 +1000,7 @@ int gscd_init (void)
/* This is the common initialisation for the GoldStar drive. */
/* It is called at boot time AND for module init. */
-int my_gscd_init (void)
+__initfunc(int my_gscd_init (void))
{
int i;
int result;
diff --git a/drivers/cdrom/isp16.c b/drivers/cdrom/isp16.c
index c3bb43d24..88c070eba 100644
--- a/drivers/cdrom/isp16.c
+++ b/drivers/cdrom/isp16.c
@@ -48,6 +48,7 @@
#include <linux/string.h>
#include <linux/ioport.h>
#include <linux/isp16.h>
+#include <linux/init.h>
#include <asm/io.h>
static short isp16_detect(void);
@@ -76,8 +77,8 @@ void cleanup_module(void);
#define ISP16_OUT(p,b) (outb(isp16_ctrl,ISP16_CTRL_PORT), outb(b,p))
-void
-isp16_setup(char *str, int *ints)
+__initfunc(void
+isp16_setup(char *str, int *ints))
{
if ( ints[0] > 0 )
isp16_cdrom_base = ints[1];
@@ -93,8 +94,8 @@ isp16_setup(char *str, int *ints)
* ISP16 initialisation.
*
*/
-int
-isp16_init(void)
+__initfunc(int
+isp16_init(void))
{
u_char expected_drive;
@@ -143,8 +144,8 @@ isp16_init(void)
return(0);
}
-static short
-isp16_detect(void)
+__initfunc(static short
+isp16_detect(void))
{
if ( isp16_c929__detect() >= 0 )
@@ -153,8 +154,8 @@ isp16_detect(void)
return(isp16_c928__detect());
}
-static short
-isp16_c928__detect(void)
+__initfunc(static short
+isp16_c928__detect(void))
{
u_char ctrl;
u_char enable_cdrom;
@@ -202,8 +203,8 @@ isp16_c928__detect(void)
return(i);
}
-static short
-isp16_c929__detect(void)
+__initfunc(static short
+isp16_c929__detect(void))
{
u_char ctrl;
u_char tmp;
@@ -229,8 +230,8 @@ isp16_c929__detect(void)
return(2);
}
-static short
-isp16_cdi_config(int base, u_char drive_type, int irq, int dma)
+__initfunc(static short
+isp16_cdi_config(int base, u_char drive_type, int irq, int dma))
{
u_char base_code;
u_char irq_code;
diff --git a/drivers/cdrom/mcd.c b/drivers/cdrom/mcd.c
index aa6f07ec8..e4d1a73f6 100644
--- a/drivers/cdrom/mcd.c
+++ b/drivers/cdrom/mcd.c
@@ -80,6 +80,7 @@
#include <linux/ioport.h>
#include <linux/string.h>
#include <linux/delay.h>
+#include <linux/init.h>
/* #define REALLY_SLOW_IO */
#include <asm/system.h>
@@ -196,7 +197,7 @@ static int GetToc(void);
static int getValue(unsigned char *result);
-void mcd_setup(char *str, int *ints)
+__initfunc(void mcd_setup(char *str, int *ints))
{
if (ints[0] > 0)
mcd_port = ints[1];
@@ -1175,7 +1176,7 @@ static struct file_operations mcd_fops = {
* Test for presence of drive and initialize it. Called at boot time.
*/
-int mcd_init(void)
+__initfunc(int mcd_init(void))
{
int count;
unsigned char result[3];
diff --git a/drivers/cdrom/mcdx.c b/drivers/cdrom/mcdx.c
index 081bd0d53..242508f9d 100644
--- a/drivers/cdrom/mcdx.c
+++ b/drivers/cdrom/mcdx.c
@@ -63,6 +63,7 @@ static const char *mcdx_c_version
#include <linux/ioport.h>
#include <linux/mm.h>
#include <linux/malloc.h>
+#include <linux/init.h>
#include <asm/io.h>
#include <asm/uaccess.h>
@@ -358,6 +359,10 @@ mcdx_ioctl(
msf.cdmsf_sec1 = uint2bcd(msf.cdmsf_sec1);
msf.cdmsf_frame1 = uint2bcd(msf.cdmsf_frame1);
+ stuffp->stop.dt.minute = msf.cdmsf_min1;
+ stuffp->stop.dt.second = msf.cdmsf_sec1;
+ stuffp->stop.dt.frame = msf.cdmsf_frame1;
+
return mcdx_playmsf(stuffp, &msf);
}
@@ -910,7 +915,7 @@ int check_mcdx_media_change(kdev_t full_dev)
return 1;
}
-void mcdx_setup(char *str, int *pi)
+__initfunc(void mcdx_setup(char *str, int *pi))
{
if (pi[0] > 0) mcdx_drive_map[0][0] = pi[1];
if (pi[0] > 1) mcdx_drive_map[0][1] = pi[2];
@@ -1160,7 +1165,7 @@ void cleanup_module(void)
/* Support functions ************************************************/
-int mcdx_init(void)
+__initfunc(int mcdx_init(void))
{
int drive;
diff --git a/drivers/cdrom/optcd.c b/drivers/cdrom/optcd.c
index 8bd4b84f6..417769111 100644
--- a/drivers/cdrom/optcd.c
+++ b/drivers/cdrom/optcd.c
@@ -65,6 +65,7 @@
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/ioport.h>
+#include <linux/init.h>
#include <asm/io.h>
#define MAJOR_NR OPTICS_CDROM_MAJOR
@@ -1961,7 +1962,7 @@ static int opt_media_change(kdev_t dev)
/* Returns 1 if a drive is detected with a version string
starting with "DOLPHIN". Otherwise 0. */
-static int version_ok(void)
+__initfunc(static int version_ok(void))
{
char devname[100];
int count, i, ch, status;
@@ -2016,7 +2017,7 @@ static struct file_operations opt_fops = {
/* Get kernel parameter when used as a kernel driver */
-void optcd_setup(char *str, int *ints)
+__initfunc(void optcd_setup(char *str, int *ints))
{
if (ints[0] > 0)
optcd_port = ints[1];
@@ -2024,7 +2025,7 @@ void optcd_setup(char *str, int *ints)
/* Test for presence of drive and initialize it. Called at boot time
or during module initialisation. */
-int optcd_init(void)
+__initfunc(int optcd_init(void))
{
int status;
diff --git a/drivers/cdrom/sbpcd.c b/drivers/cdrom/sbpcd.c
index 6d27b2248..401dbc657 100644
--- a/drivers/cdrom/sbpcd.c
+++ b/drivers/cdrom/sbpcd.c
@@ -328,6 +328,7 @@
#include <linux/major.h>
#include <linux/string.h>
#include <linux/vmalloc.h>
+#include <linux/init.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -3052,7 +3053,7 @@ static int cc_SubChanInfo(int frame, int count, u_char *buffer)
}
#endif FUTURE
/*==========================================================================*/
-static void check_datarate(void)
+__initfunc(static void check_datarate(void))
{
int i=0;
@@ -3122,7 +3123,7 @@ static int c2_ReadError(int fam)
}
#endif
/*==========================================================================*/
-static void ask_mail(void)
+__initfunc(static void ask_mail(void))
{
int i;
@@ -3141,7 +3142,7 @@ static void ask_mail(void)
msg(DBG_INF,"infobuf =%s\n", msgbuf);
}
/*==========================================================================*/
-static int check_version(void)
+__initfunc(static int check_version(void))
{
int i, j, l;
int teac_possible=0;
@@ -3439,7 +3440,7 @@ static void switch_drive(int i)
/*
* probe for the presence of an interface card
*/
-static int check_card(int port)
+__initfunc(static int check_card(int port))
{
#undef N_RESPO
#define N_RESPO 20
@@ -3543,7 +3544,7 @@ static int check_card(int port)
/*
* probe for the presence of drives on the selected controller
*/
-static int check_drives(void)
+__initfunc(static int check_drives(void))
{
int i, j;
@@ -5285,9 +5286,10 @@ static struct file_operations sbpcd_fops =
*
*/
#if (SBPCD_ISSUE-1)
-static
+__initfunc(static void sbpcd_setup(const char *s, int *p))
+#else
+__initfunc(void sbpcd_setup(const char *s, int *p))
#endif
-void sbpcd_setup(const char *s, int *p)
{
setup_done++;
msg(DBG_INI,"sbpcd_setup called with %04X,%s\n",p[1], s);
@@ -5338,7 +5340,7 @@ void sbpcd_setup(const char *s, int *p)
* port 0x330, we have to use an offset of 8; so, the real CDROM port
* address is 0x338.
*/
-static int config_spea(void)
+__initfunc(static int config_spea(void))
{
/*
* base address offset between configuration port and CDROM port,
@@ -5397,7 +5399,7 @@ static int config_spea(void)
#ifdef MODULE
int init_module(void)
#else
-int SBPCD_INIT(void)
+__initfunc(int SBPCD_INIT(void))
#endif MODULE
{
int i=0, j=0;
diff --git a/drivers/cdrom/sjcd.c b/drivers/cdrom/sjcd.c
index 0ca13dc3d..67d04134d 100644
--- a/drivers/cdrom/sjcd.c
+++ b/drivers/cdrom/sjcd.c
@@ -65,6 +65,7 @@
#include <linux/ioport.h>
#include <linux/string.h>
#include <linux/major.h>
+#include <linux/init.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -159,7 +160,7 @@ static int sjcd_cleanup(void);
* Set up device, i.e., use command line data to set
* base address.
*/
-void sjcd_setup( char *str, int *ints )
+__initfunc(void sjcd_setup( char *str, int *ints ))
{
if (ints[0] > 0)
sjcd_base = ints[1];
@@ -1449,7 +1450,7 @@ static struct {
* Test for presence of drive and initialize it. Called at boot time.
* Probe cdrom, find out version and status.
*/
-int sjcd_init( void ){
+__initfunc(int sjcd_init( void )){
int i;
printk(KERN_INFO "SJCD: Sanyo CDR-H94A cdrom driver version %d.%d.\n", SJCD_VERSION_MAJOR,
diff --git a/drivers/cdrom/sonycd535.c b/drivers/cdrom/sonycd535.c
index 33b4bd42a..b5c257f9b 100644
--- a/drivers/cdrom/sonycd535.c
+++ b/drivers/cdrom/sonycd535.c
@@ -120,6 +120,7 @@
#include <linux/genhd.h>
#include <linux/mm.h>
#include <linux/malloc.h>
+#include <linux/init.h>
#define REALLY_SLOW_IO
#include <asm/system.h>
@@ -1484,8 +1485,8 @@ static struct file_operations cdu_fops =
/*
* Initialize the driver.
*/
-int
-sony535_init(void)
+__initfunc(int
+sony535_init(void))
{
struct s535_sony_drive_config drive_config;
Byte cmd_buff[3];
@@ -1649,8 +1650,8 @@ sony535_init(void)
*
* the address value has to be the existing CDROM port address.
*/
-void
-sonycd535_setup(char *strings, int *ints)
+__initfunc(void
+sonycd535_setup(char *strings, int *ints))
{
/* if IRQ change and default io base desired,
* then call with io base of 0
diff --git a/drivers/char/Config.in b/drivers/char/Config.in
index c32475be7..4216b3154 100644
--- a/drivers/char/Config.in
+++ b/drivers/char/Config.in
@@ -19,7 +19,10 @@ if [ "$CONFIG_SERIAL_EXTENDED" = "y" ]; then
fi
bool 'Non-standard serial port support' CONFIG_SERIAL_NONSTANDARD
if [ "$CONFIG_SERIAL_NONSTANDARD" = "y" ]; then
- tristate 'Digiboard PC/Xx Support' CONFIG_DIGI
+ tristate 'Digiboard Intelligent Async Support' CONFIG_DIGIEPCA
+ if [ "$CONFIG_DIGIEPCA" = "n" ]; then
+ tristate 'Digiboard PC/Xx Support' CONFIG_DIGI
+ fi
tristate 'Cyclades async mux support' CONFIG_CYCLADES
bool 'Stallion multiport serial support' CONFIG_STALDRV
if [ "$CONFIG_STALDRV" = "y" ]; then
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 3e6500f3a..d5a19d343 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -41,7 +41,10 @@ endif
ifndef CONFIG_SUN_KEYBOARD
ifdef CONFIG_VT
-L_OBJS += keyboard.o defkeymap.o
+L_OBJS += keyboard.o
+endif
+ifneq ($(ARCH),m68k)
+L_OBJS += pc_keyb.o defkeymap.o
endif
endif
@@ -63,6 +66,14 @@ else
endif
endif
+ifeq ($(CONFIG_DIGIEPCA),y)
+L_OBJS += epca.o
+else
+ ifeq ($(CONFIG_DIGIEPCA),m)
+ M_OBJS += epca.o
+ endif
+endif
+
ifeq ($(CONFIG_CYCLADES),y)
L_OBJS += cyclades.o
else
diff --git a/drivers/char/README.epca b/drivers/char/README.epca
new file mode 100644
index 000000000..3561608f1
--- /dev/null
+++ b/drivers/char/README.epca
@@ -0,0 +1,506 @@
+user.doc
+Digi International driver package for the PC/Xe, PC/Xi, PC/Xr, PC/Xem as well
+the EISA and PCI variants of these boards where applicable.
+Copyright (C) 1996 Digi International. Written by Ronnie Sanford digilnux@dgii.com
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2 of the License, or (At your
+ option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not write to the Free Software Foundation, Inc.,
+ 675 Mass Ave, Cambridge, MA 02139, USA.
+
+
+This document describes the software used with the Digi/Linux driver package.
+The four user programs listed below are described in this document:
+
+ 1. digiConfig -> Application that configures the Digi driver.
+
+ 2. digiDload -> Application which initializes the Digi hardware.
+
+ 3. buildPCI -> Application which provides the user a method of
+ building device nodes for PCI devices.
+
+ 4. ditty -> Application which provides the user a method of
+ configuring terminal options on Digi hardware.
+
+
+
+--------------------------------------------------------------------------
+1. Configuring driver/kernel for Digi products
+--------------------------------------------------------------------------
+
+ The Digi driver must be configured each time Digi hardware is added
+ or removed. There are two supported methods of doing this. The
+ first method configures the driver dynamically at boot time but requires
+ the user to utilize the lilo loader. This method is the preffered method
+ as it does not require the rebuilding of the kernel. In order to use lilo
+ to configure Digi boards at boot time an appropriate append command should
+ be added to /etc/lilo.conf below the appropriate label decleration.
+ See footer 4. The append commands format is a string of comma seperated
+ identifiers or integers used to configure supported boards. These six
+ values in order are:
+
+ Enable/Disable this card or Override,
+ Type of card: PC/Xe (AccelePort) (0), PC/Xeve (1), PC/Xem or PC/Xr (2),
+ EISA/Xem (3), PC/Xe (64K) (4), PC/Xi (5).
+ Enable/Disable alternate pin arrangement,
+ Number of ports on this card,
+ I/O Port where card is configured (in HEX if using string identifiers),
+ Base of memory window (in HEX if using string identifiers)
+
+ A sample append command is given below which if used would configure and
+ enable a PC/Xe with 8 ports, at i/o address 200, memory address 0xd0000
+ with alt pin turned off. The lilo.conf file should look like this:
+
+ image = /vmlinuz
+ root = /dev/hda2
+ label = vmlinuz
+ append="digiepca=E,PC/Xe,D,8,200,D0000"
+
+ likewise the below will perform the same function:
+
+ image = /vmlinuz
+ root = /dev/hda2
+ label = vmlinuz
+ append="digiepca=1,0,0,8,512,851968"
+
+ Note:
+
+ PCI boards are auto-detected and configured (Hence their codes are
+ not given here). Do not attempt to configure PCI boards with the lilo
+ append command.
+
+ If configuration data has been specified by using digiConfig (Described
+ below), and you wish to override this configuration using lilo without
+ specifying a specific card (Example if there are PCI cards in the system)
+ the following override command will accomplish this:
+
+ -> append="digiepca=2"
+
+ If lilo is not enabled, the second method of configuring Digi hardware
+ will have to be used. digiConfig is an application that can be used
+ to inform the system of any additions, deletions, or modifications
+ involving Digi hardware. To use this method the operator executes
+ digiConfig anytime an EISA or ISA card is added that he wishes to use.
+ This routine is also used to remove cards from the system, and to modify
+ parameters of those cards already present in the system. Upon being
+ executed digiConfig modifies files accessed by the Digi driver. To make
+ these changes permanent; the operating system must be recompiled. After
+ the operating system has been recompiled and booted, the changes made with
+ digiConfig will be introduced to the user. This program MUST be executed
+ every time Digi EISA/ISA hardware configuration changes. Note, it is not
+ necessary to execute digiConfig in order to configure the Digi PCI cards.
+ These cards are self-identifying and will be recognized by the driver.
+ They cannot be displayed using digiConfig nor will digiConfig build the
+ device nodes their device nodes. See footer 1.
+
+ To execute digiConfig; simply type: digiConfig
+
+ The application will query you for the type, memory address, port
+ address, number of ports, alt pin disposition and status of each board
+ that exist on the system. Note, currently this driver only supports
+ PC/Xe, PC/Xeve, PC/Xi, PC/Xr, and PC/Xem as well as their EISA and PCI
+ implementations if applicable. All supported cards (Other than PCI) that
+ are present should be registered via digiConfig. See footer 2.
+
+ After all cards have been configured select exit. The system will then
+ inform you if any changes have been made, and ask you if it is okay to
+ make these changes permanent. If the data entered is correct, select okay.
+ Selecting cancel will prevent the changes from becoming active. digiConfig
+ can then be re-executed to configure the system again.
+
+--------------------------------------------------------------------------
+2. Initializing Digi hardware with digiDload
+--------------------------------------------------------------------------
+
+ digiDload is the application executed after the Digi driver has been
+ loaded. It is responsible for initializing the hardware and leaving
+ it in a state such that the Digi board may be operated by the user.
+ The application may be placed anywhere on the path, but its related
+ support files must be located in /etc/digi. The related files are:
+
+ sxfep.bin
+ sxbios.bin
+ xxfep.bin
+ xxbios.bin
+
+ The format for this command is "digiDload [v]". If given the "v"
+ option turns on verbosity. If not given the application runs in quite
+ mode. To execute the program simply type:
+
+ digiDload
+
+ Upon completion digiDload will generate the below message:
+
+ "digiDload complete: Card initialized"
+
+ At this point the card is configured and ready for normal usage. See
+ technotes.doc for information on how how ports are determined and
+ assigned.
+
+--------------------------------------------------------------------------
+3. Build PCI device nodes with buildPCI
+--------------------------------------------------------------------------
+
+ buildPCI is an application useful for building the necessary device nodes
+ for Digi PCI cards. It is reccomended that this tool be used because the
+ current digiConfig application does not provide this function for PCI cards
+ (Though it does build device nodes for non-PCI cards). To use this program
+ execute the following:first install the driver, and execute digiDload (See above). After digiDload
+ has sucessfully loaded, execute the following:
+
+ buildPCI <arg1> <arg2>
+
+ Where arg1 is the number of ports connected to Digi cards that are not PCI
+ (As shown by the digiConfig utility), and arg2 is the number of ports
+ connected to Digi cards that are PCI.
+
+ Note, buildPCI only has to be ran once to build the necessary device
+ nodes. Though this program may be executed at anytime, we reccomend
+ delaying execution until the first time you install the package and after
+ digiDload has been executed.
+
+--------------------------------------------------------------------------
+4. Setting Terminal Options with ditty
+--------------------------------------------------------------------------
+
+ditty is a utility program that sets and displays the terminal options
+for Digi intelligent serial products. See man ditty for detailed information.
+
+
+Footnotes:
+
+1. The 1.2.x kernel does not provide a method of mapping the high
+ addresses (Normally higher than RAM) associated with PCI. For this
+ reason, this driver disables PCI support while running under the 1.2.x
+ kernels.
+
+2. PCI cards should not and cannot be registered with digiConfig. After
+ the driver has been loaded buildPCI may be executed to construct the
+ necessary device nodes. This step is not necessary for system not
+ having Digi PCI cards.
+
+3. This is because we forsee a time when buildPCI may auto-detect the
+ available Digi PCI cards and this would only work if the program is
+ executed after digiDload.
+
+4. A complete example is given in install.doc.
+
+-------------CHANGES--------------------
+
+All changes should be recorded here. All changes should be explained in
+verbose detail.
+-----------------------------------------------------------------------
+Programmer : Ronnie Sanford
+Date : June 1, 1996
+Description (Verbose) : Initial release of driver package.
+Files affected : all
+Release version : 1.0.0f (BETA)
+-----------------------------------------------------------------------
+-----------------------------------------------------------------------
+Programmer : Ronnie Sanford
+Date : August 7, 1996
+Description (Verbose) : Made several modifications to provide PCI and EISA
+ support:
+
+ 1. We now allocate the termios structures based on
+ the maximum number of channels that COULD be
+ available to the system. We no longer use the
+ number of channels declared in epcaconfig.h
+ (NBDEVS) as the total channel number. This is
+ because this value does not represent channels
+ available to potential PCI cards. This new
+ larger value is also passed back to the os in
+ the num field of tty_driver.
+
+ 2. Added code to copy the previous board structure
+ (Now called static_boards) into a new local
+ copy of the boards structure. This has been
+ done so that PCI cards may be added to this
+ board array and later referenced (And even
+ queried.).
+
+ 3. Added code to pc_init that checks for supported
+ PCI cards. If found this code initializes a new
+ entry into the drivers local board structure
+ with the PCI cards address, and type, etc.. It
+ also bumps the card count (num_cards).
+
+ 4. Modified code in post_fep_init so that when this
+ routine is executed the number of ports supported
+ by a particular PCI card will be determined and
+ loaded into the board structure. It would be
+ much better if this code was placed in pc_init
+ (Because we could then report to the os the true
+ number of ports available; not just the max), but
+ since the card has to be booted to determine the
+ number of ports it supports, we are forced to do it
+ after DIGI_INIT has called post_fep_init. In the
+ future we may attempt to read the num ports
+ attached directly (address 0x1ac).
+
+ 5. Added board types to epca.h in support of various
+ PCI boards (Some of which do not exist yet).
+ Added procedures for these boards throughout the
+ code. Note, windowing is not necessary for PCI
+ boards.
+
+ 6. Added code supporting the EISA/XEM. This included
+ modifying epca.h with the new board type and
+ adding this type into the driver. The EISA/XEM
+ is basically identical to the PC/XEM, other than
+ it's base address does not have to be (And cannot
+ be configured directly).
+
+ 7. Modified digiConfig to prompt for EISA/XEM cards.
+
+Files affected : epca.c, epca.h, digi1.h, digiConfig
+Release version : 1.0.0g (BETA)
+-----------------------------------------------------------------------
+-----------------------------------------------------------------------
+Programmer : Ronnie Sanford
+Date : August 21, 1996
+Description (Verbose) : Made the following modifications:
+
+ 1. A problem affecting hard flow control was found
+ in the termios2digi_h routine. Specifically,
+ when the user activated hard flow control using
+ the CRTSCTS specification, the values used to
+ program hard flow control on the board were
+ incorrect. The solution was to change a line
+ that read "res |= ((ch->m_dtr) | (ch->m_rts));"
+ to "res |= ((ch->m_cts) | (ch->m_rts));" This
+ line only applies if cflag & CRTSCTS. Special
+ thanks to Matt Robinson (matt@mania.com.au) who
+ found and fixed this problem.
+
+ 2. In previous betas the cud device was set to CLOCAL
+ on driver boot up. Likewise the ttyD device was
+ set to ~CLOCAL. This has been fixed in this driver.
+ Now ttyD is CLOCAL and cud is ~CLOCAL. The fix
+ for this can be found in pc_init.
+
+ 3. In ditty.c many changes were made to eliminate bugs
+ and warning messages. Two ioctl calls were eliminated
+ as well a problem involving using the returned baud
+ index to determine the drivers baud rate. Newer
+ Linux kernels support higher baud rates by using
+ 0x1000 bit. When the returned value (ored with
+ 0x1000) was used to reference our fbaud table a
+ serious memory problem occured. This has been fixed.
+
+ 4. Added a request_region call to post_fep_init. This
+ should cause the i/o ports being used to be
+ registered with proc.
+
+ 5. Modified digiConfig to set all cud and ttyD devices
+ to read/write all permission.
+
+ 6. Developed a new apps called buildPCI that provides
+ an easy way to build device nodes for PCI cards.
+
+ 7. Modified user.doc and technotes.doc document the
+ use of buildPCI.
+
+Files affected : epca.c, ditty.c, digiConfig, user.doc, technotes.doc
+Release version : 1.0.0 (Official release)
+-----------------------------------------------------------------------
+Programmer : Ronnie Sanford
+Date : August 21, 1996
+Description (Verbose) : Made the following modifications:
+
+ 1. Removed code from pc_close which closes the
+ drivers line discipline and restores its original
+ line discipline. This is currently unecessary,
+ though future fast cook enhancements may require
+ this.
+
+ 2. Removed code in block_til_ready that set the
+ asyncflags to either ASYNC_CALLOUT_ACTIVE, or
+ ASYNC_NORMAL_ACTIVE. This code was redundant
+ as it already existed in block_til_ready.
+
+ 3. Added code in block_til_ready to cause a return
+ prior to schedule being called if the device
+ was a CALLOUT device. CALLOUT devices never
+ block on CD. (This was a serious bug that
+ prevented the CALLOUT devices (ttyD) from
+ functioning properly in some instances.
+
+ Make a change in the MODEMCHG_IND case of doevent
+ such that it does not require ASYNC_CALLOUT_ACTIVE
+ or ASYNC_NORMAL_ACTIVE to be set in order to
+ unblock an open (Using wait_interruptible).
+
+ Thanks to Mike McLagan (mike.mclagan@linux.org)
+ for diagnosing and fixing this problem.
+
+ 4. Made changes to the disposition of CLOCAL on
+ both SERIAL NORMAL and CALLOUT devices. Both
+ device types now have CLOCAL active at default.
+ This may be changed with a stty command.
+
+ 5. Made changes to digiConfig such that it checks
+ major.h (If valid) for the correct major
+ numbers to use.
+
+Files affected : epca.c, digiConfig
+Release version : 1.0.1a
+
+
+-----------------------------------------------------------------------
+Programmer : Ronnie Sanford
+Date : September 17, 1996
+Description (Verbose) : Made the following modifications:
+
+ 1. Modified pc_open such that it no longer checks
+ the cflag value returned by termios2digi_c for
+ CLOCAL. Digi hardware does not use this value
+ and thus termios2digi_c rightly screens this
+ value out. This driver checks for CLOCAL using
+ the drivers cflag value as known by the Linux OS.
+ (The value passed into termios2digi_c)
+
+ 2. Modified termios2digi_c to screen out the
+ CBAUDEX in CBAUD. This error caused parity to
+ automaticaly be enabled on at higher baud rates.
+
+
+ 3. Added the "disable_bh()" call to the shutdown
+ subroutine. Hopefully this will allow the driver
+ to correctly clean up after itself when used as a
+ module.
+
+ 4. Added support for the PC/XI and 64K PC/XE cards.
+ This involved primarily modifying digiDload to
+ initialize and boot the new cards; however
+ driver modifications were also required to
+ provide the proper windowing for the newly
+ supported cards. (Code was also added to
+ determine the memory segment of the XI card as
+ that card may have more than 64K. Currently
+ digiDload assumes a 64K XI card.)
+
+ 5. Added subroutine called epca_setup that can be
+ called during LILO boot up. This provides the
+ user an easy way to change cards; without
+ running digiConfig and without recompiling the
+ kernel. Added code in pc_init and pc_open to
+ support the epca_setup routine. pc_init checks
+ the liloconfig flag (Which is set by epca_setup)
+ to determine if the driver is using the LILO
+ arguments. If not pc_init loads the board data
+ found in epcaconfig.h; if so it DOESN'T load
+ epcaconfig data depending on epca_setup to handle
+ board configuration. pc_open has been modified
+ such that it checks to insure that no errors
+ occured during the LILO boot process. If a
+ user attempts to boot the driver (via. LILO)
+ with incorrect data, the open will fail.
+
+ 6. Modified the windowing routines pcxe_rxwinon
+ and pcxe_txwinon routines. A bug existed such
+ that those routines checked to see if the rxwin
+ and txwin flags were reset. If so they assumed
+ the board was an XI or 64K XE. Furthermore since
+ these flags were never initialized in our driver
+ sometimes they were 0 and therefore caused a
+ memory fault (Or at least a window overrun). This
+ code has been removed since the pcxe shares
+ nothing in common with the 64K XI and XE.
+
+ 7. Added code in pc_init to set the memory_seg for
+ the various boards. This code was necessary to
+ correct a bug in the PCXE, PCXEVE code where
+ receive and transmit pointers were being calculated
+ from an uninitialized variable (memory_seg).
+
+ 8. Modified digiConfig to allow 64K PC/XI and 64K
+ PC/XE cards to be configured.
+
+ 9. Made changes to support the new 2.1.x development
+ kernel. In particular this required changing all
+ references to vremap to ioremap.
+
+ 10. Modified digiConfig such that it now generates
+ node names corresponding to their internal
+ as opposed to the label on the port itself. Nodes
+ (ttyD?? and cud??) now start at 0. Example:
+ ttyD0 and cud0 represent port 1 on any supported
+ Digi product. A similar change has been made
+ in buildPCI.c.
+
+ 12. At the early portion of post_fep_init if a PCI
+ card is detected a warning message could be given
+ incorrectly if 64 ports were attached to a PCI
+ card. The below line :
+
+ epcaassert(bd->numports > 64,"PCI returned a invalid number of ports");
+
+ was changed to :
+
+ epcaassert(bd->numports <= 64,"PCI returned a invalid number of ports");
+
+ Remember that epcaassert checks for NOT true.
+ Special thanks to Daniel Taylor for fixing this.
+
+ 13. Modified the epcaparam routine. In version 100
+ and 101a there was a line that looked like the
+ below:
+
+ if (ch->omodem != mval)
+
+ The problem with this line was that the first time
+ through omodem was not initialized. Secondly, since
+ many TIOC commands did not alter mval (They use
+ a different variable) changes made by these commands
+ could be lost. This line was changed to:
+
+ mval ^= ch->modemfake & (mval ^ ch->modem);
+
+ if (ch->omodem ^ mval)
+
+ 14. Modified digiConfig in such a way that it checks
+ the version number of the kernel and if it finds
+ a 2.x.x kernel or higher it reads the necessary
+ major numbers for cud and ttyD devices from major.h.
+ This was also done in prior versions but these
+ versions required a #define which identified the
+ kernel as a version which did not have major numbers
+ assigned to Digi systems. This #define is no
+ longer required allowing the same source tree for
+ multiple kernel releases.
+
+ 15. Used macros to replace kernel specific calls such
+ as put_fs_long, get_fs_long, put_user, and get_user
+ the kernel version is now detected and the macro
+ is defined as to correspond with the kernel it
+ is being compiled into. Again this was done to
+ allow one source tree for multiple kernel releases.
+
+ 16. Added support for the new 2.1.x development kernels
+ to digiInstall.
+
+Files affected : epca.c, digiConfig
+Release version : 1.1.0
+-----------------------------------------------------------------------
+Programmer : Daniel Taylor
+Date : April 25, 1997
+Description (Verbose) : Updated driver:
+ 1. Fixed DCD bug. (&tq_scheduler)
+ 2. Removed BH handler code, as it was only handling
+ hangups, and not being called for that.
+ 3. Namespace cleanup (DIGI_TIMER2 => DIGI_TIMER)
+ 4. Updated to 2.1.36, removed #ifdefs for earlier
+ kernel revisions.
+Files affected : epca.c
+Release version : 1.1.1 (BETA)
+-----------------------------------------------------------------------
diff --git a/drivers/char/busmouse.c b/drivers/char/busmouse.c
index d8b267095..3e2ee97bd 100644
--- a/drivers/char/busmouse.c
+++ b/drivers/char/busmouse.c
@@ -56,7 +56,7 @@
static struct mouse_status mouse;
static int mouse_irq = MOUSE_IRQ;
-void bmouse_setup(char *str, int *ints)
+__initfunc(void bmouse_setup(char *str, int *ints))
{
if (ints[0] > 0)
mouse_irq=ints[1];
diff --git a/drivers/char/console.c b/drivers/char/console.c
index 2e5d420fd..56748c068 100644
--- a/drivers/char/console.c
+++ b/drivers/char/console.c
@@ -103,6 +103,7 @@
#include <linux/major.h>
#include <linux/mm.h>
#include <linux/ioport.h>
+#include <linux/init.h>
#ifdef CONFIG_APM
#include <linux/apm_bios.h>
#endif
@@ -2010,7 +2011,7 @@ static void console_bh(void)
* Reads the information preserved by setup.s to determine the current display
* type and sets everything accordingly.
*/
-unsigned long con_init(unsigned long kmem_start)
+__initfunc(unsigned long con_init(unsigned long kmem_start))
{
const char *display_desc = "????";
int currcons = 0;
diff --git a/drivers/char/consolemap.c b/drivers/char/consolemap.c
index c2d1648e6..878ac0d72 100644
--- a/drivers/char/consolemap.c
+++ b/drivers/char/consolemap.c
@@ -11,6 +11,7 @@
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/malloc.h>
+#include <linux/init.h>
#include <asm/uaccess.h>
#include "consolemap.h"
@@ -483,8 +484,8 @@ conv_uni_to_pc(long ucs)
* initialized. It must be possible to call kmalloc(..., GFP_KERNEL)
* from this function, hence the call from sys_setup.
*/
-void
-console_map_init(void)
+__initfunc(void
+console_map_init(void))
{
con_set_default_unimap();
}
diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c
index 0a1825ee8..efa895a69 100644
--- a/drivers/char/cyclades.c
+++ b/drivers/char/cyclades.c
@@ -1,5 +1,7 @@
+#define BLOCKMOVE
static char rcsid[] =
-"$Revision: 1.36.3.9 $$Date: 1996/10/07 19:47:13 $";
+"$Revision: 1.36.4.27 $$Date: 1997/03/26 10:30:00 $";
+
/*
* linux/drivers/char/cyclades.c
*
@@ -22,11 +24,128 @@ static char rcsid[] =
* This module exports the following rs232 io functions:
* int cy_init(void);
* int cy_open(struct tty_struct *tty, struct file *filp);
+ * and the following functions for modularization.
+ * int init_module(void);
+ * void cleanup_module(void);
*
* $Log: cyclades.c,v $
- * Revision 1.36.3.9 1996/10/07 19:47:13 bentson
- * add MOD_DEC_USE_COUNT in one return from cy_close (as
- * noted by Jon Lewis <jlewis@INORGANIC5.FDT.NET>)
+ * Revision 1.36.4.27 1997/03/26 10:30:00 daniel
+ * Changed for suport linux versions 2.1.X.
+ * Backward compatible with linux versions 2.0.X.
+ * Corrected illegal use of filler field in
+ * CH_CTRL struct.
+ * Deleted some debug messages.
+ *
+ * Revision 1.36.4.26 1997/02/27 12:00:00 daniel
+ * Included check for NULL tty pointer in cyz_poll.
+ *
+ * Revision 1.36.4.25 1997/02/26 16:28:30 bentson
+ * Bill Foster at Blarg! Online services noticed that
+ * some of the switch elements of -Z modem control
+ * lacked a closing "break;"
+ *
+ * Revision 1.36.4.24 1997/02/24 11:00:00 daniel
+ * Changed low water threshold for buffer xmit_buf
+ *
+ * Revision 1.36.4.23 1996/12/02 21:50:16 bentson
+ * Marcio provided fix to modem status fetch for -Z
+ *
+ * Revision 1.36.4.22 1996/10/28 22:41:17 bentson
+ * improve mapping of -Z control page (thanks to Steve
+ * Price <stevep@fa.tdktca.com> for help on this)
+ *
+ * Revision 1.36.4.21 1996/09/10 17:00:10 bentson
+ * shift from cpu-bound to memcopy in cyz_polling operation
+ *
+ * Revision 1.36.4.20 1996/09/09 18:30:32 Bentson
+ * Added support to set and report higher speeds.
+ *
+ * Revision 1.36.4.19c 1996/08/09 10:00:00 Marcio Saito
+ * Some fixes in the HW flow control for the BETA release.
+ * Don't try to register the IRQ.
+ *
+ * Revision 1.36.4.19 1996/08/08 16:23:18 Bentson
+ * make sure "cyc" appears in all kernel messages; all soft interrupts
+ * handled by same routine; recognize out-of-band reception; comment
+ * out some diagnostic messages; leave RTS/CTS flow control to hardware;
+ * fix race condition in -Z buffer management; only -Y needs to explictly
+ * flush chars; tidy up some startup messages;
+ *
+ * Revision 1.36.4.18 1996/07/25 18:57:31 bentson
+ * shift MOD_INC_USE_COUNT location to match
+ * serial.c; purge some diagnostic messages;
+ *
+ * Revision 1.36.4.17 1996/07/25 18:01:08 bentson
+ * enable modem status messages and fetch & process them; note
+ * time of last activity type for each port; set_line_char now
+ * supports more than line 0 and treats 0 baud correctly;
+ * get_modem_info senses rs_status;
+ *
+ * Revision 1.36.4.16 1996/07/20 08:43:15 bentson
+ * barely works--now's time to turn on
+ * more features 'til it breaks
+ *
+ * Revision 1.36.4.15 1996/07/19 22:30:06 bentson
+ * check more -Z board status; shorten boot message
+ *
+ * Revision 1.36.4.14 1996/07/19 22:20:37 bentson
+ * fix reference to ch_ctrl in startup; verify return
+ * values from cyz_issue_cmd and cyz_update_channel;
+ * more stuff to get modem control correct;
+ *
+ * Revision 1.36.4.13 1996/07/11 19:53:33 bentson
+ * more -Z stuff folded in; re-order changes to put -Z stuff
+ * after -Y stuff (to make changes clearer)
+ *
+ * Revision 1.36.4.12 1996/07/11 15:40:55 bentson
+ * Add code to poll Cyclom-Z. Add code to get & set RS-232 control.
+ * Add code to send break. Clear firmware ID word at startup (so
+ * that other code won't talk to inactive board).
+ *
+ * Revision 1.36.4.11 1996/07/09 05:28:29 bentson
+ * add code for -Z in set_line_char
+ *
+ * Revision 1.36.4.10 1996/07/08 19:28:37 bentson
+ * fold more -Z stuff (or in some cases, error messages)
+ * into driver; add text to "don't know what to do" messages.
+ *
+ * Revision 1.36.4.9 1996/07/08 18:38:38 bentson
+ * moved compile-time flags near top of file; cosmetic changes
+ * to narrow text (to allow 2-up printing); changed many declarations
+ * to "static" to limit external symbols; shuffled code order to
+ * coalesce -Y and -Z specific code, also to put internal functions
+ * in order of tty_driver structure; added code to recognize -Z
+ * ports (and for moment, do nothing or report error); add cy_startup
+ * to parse boot command line for extra base addresses for ISA probes;
+ *
+ * Revision 1.36.4.8 1996/06/25 17:40:19 bentson
+ * reorder some code, fix types of some vars (int vs. long),
+ * add cy_setup to support user declared ISA addresses
+ *
+ * Revision 1.36.4.7 1996/06/21 23:06:18 bentson
+ * dump ioctl based firmware load (it's now a user level
+ * program); ensure uninitialzed ports cannot be used
+ *
+ * Revision 1.36.4.6 1996/06/20 23:17:19 bentson
+ * rename vars and restructure some code
+ *
+ * Revision 1.36.4.5 1996/06/14 15:09:44 bentson
+ * get right status back after boot load
+ *
+ * Revision 1.36.4.4 1996/06/13 19:51:44 bentson
+ * successfully loads firmware
+ *
+ * Revision 1.36.4.3 1996/06/13 06:08:33 bentson
+ * add more of the code for the boot/load ioctls
+ *
+ * Revision 1.36.4.2 1996/06/11 21:00:51 bentson
+ * start to add Z functionality--starting with ioctl
+ * for loading firmware
+ *
+ * Revision 1.36.4.1 1996/06/10 18:03:02 bentson
+ * added code to recognize Z/PCI card at initialization; report
+ * presence, but card is not initialized (because firmware needs
+ * to be loaded)
*
* Revision 1.36.3.8 1996/06/07 16:29:00 bentson
* starting minor number at zero; added missing verify_area
@@ -38,7 +157,7 @@ static char rcsid[] =
* remove unused diagnostic statements; minor 0 is first;
*
* Revision 1.36.3.6 1996/03/13 13:21:17 marcio
- * The kernel function ioremap (available only in later 1.3.xx kernels)
+ * The kernel function vremap (available only in later 1.3.xx kernels)
* allows the access to memory addresses above the RAM. This revision
* of the driver supports PCI boards below 1Mb (device id 0x100) and
* above 1Mb (device id 0x101).
@@ -261,6 +380,52 @@ static char rcsid[] =
*
*/
+/* If you need to install more boards than NR_CARDS, change the constant
+ in the definition below. No other change is necessary to support up to
+ eight boards. Beyond that you'll have to extend cy_isa_addresses. */
+
+#define NR_CARDS 4
+
+/*
+ If the total number of ports is larger than NR_PORTS, change this
+ constant in the definition below. No other change is necessary to
+ support more boards/ports. */
+
+#define NR_PORTS 64
+
+#define SERIAL_PARANOIA_CHECK
+#undef SERIAL_DEBUG_OPEN
+#undef SERIAL_DEBUG_THROTTLE
+#undef SERIAL_DEBUG_OTHER
+#undef SERIAL_DEBUG_IO
+#undef SERIAL_DEBUG_COUNT
+#undef SERIAL_DEBUG_DTR
+#undef CYCLOM_16Y_HACK
+#undef CYCLOM_ENABLE_MONITORING
+#undef CY_PCI_DEBUG
+
+
+#if 0
+#define PAUSE __asm__("nop");
+#else
+#define PAUSE ;
+#endif
+
+#define cy_min(a,b) (((a)<(b))?(a):(b))
+
+#define CHARS_IN_BUF(buf_ctrl) \
+ ((buf_ctrl->rx_put - \
+ buf_ctrl->rx_get + \
+ buf_ctrl->rx_bufsize) % \
+ buf_ctrl->rx_bufsize)
+
+#define SPACE_IN_BUF(buf_ctrl) \
+ ((buf_ctrl->tx_get - \
+ buf_ctrl->tx_put + \
+ buf_ctrl->tx_bufsize - 1) % \
+ buf_ctrl->tx_bufsize)
+
+
#include <linux/module.h>
#include <linux/errno.h>
@@ -280,7 +445,7 @@ static char rcsid[] =
#include <asm/system.h>
#include <asm/io.h>
-#include <asm/uaccess.h>
+#include <asm/segment.h>
#include <asm/bitops.h>
#include <linux/config.h>
@@ -290,24 +455,34 @@ static char rcsid[] =
#include <linux/pci.h>
#include <linux/init.h>
-#define small_delay(x) for(j=0;j<x;j++)k++;
+#include <linux/version.h>
+#if LINUX_VERSION_CODE >= 131328
-#define SERIAL_PARANOIA_CHECK
-#undef SERIAL_DEBUG_OPEN
-#undef SERIAL_DEBUG_THROTTLE
-#undef SERIAL_DEBUG_OTHER
-#undef SERIAL_DEBUG_IO
-#undef SERIAL_DEBUG_COUNT
-#undef SERIAL_DEBUG_DTR
-#undef CYCLOM_16Y_HACK
-#undef CYCLOM_ENABLE_MONITORING
+#include <asm/uaccess.h>
+
+#define memcpy_fromfs copy_from_user
+#define memcpy_tofs copy_to_user
+#define put_fs_long put_user
+#define vremap ioremap
+
+static unsigned long get_fs_long(unsigned long *addr)
+{
+ unsigned long result = 0;
+ int error = get_user (result, addr);
+ if (error)
+ printk ("cyclades: get_fs_long: error == %d\n", error);
+ return result;
+}
+
+#endif
#ifndef MIN
-#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
#endif
+#define IS_CYC_Z(card) ((card).num_chips == 1)
-#define WAKEUP_CHARS 256
+#define WAKEUP_CHARS (SERIAL_XMIT_SIZE-256)
#define STD_COM_FLAGS (0)
@@ -325,72 +500,39 @@ static int cy_wild_int_mask;
static unsigned char *intr_base_addr;
-/* This is the address lockup table. The driver will probe for Cyclom-Y/ISA
- boards at all addresses in here. If you want the driver to probe addresses
- in a different address, add it to this table.
- If the driver is probing some other board and causing problems, remove the
- address from this table. */
+/* This is the address lookup table. The driver will probe for
+ Cyclom-Y/ISA boards at all addresses in here. If you want the
+ driver to probe addresses at a different address, add it to
+ this table. If the driver is probing some other board and
+ causing problems, remove the offending address from this table.
+ The cy_setup function extracts additional addresses from the
+ boot options line. The form is "cyclades=address,address..."
+*/
static unsigned char *cy_isa_addresses[] = {
- (unsigned char *) 0xD0000,
- (unsigned char *) 0xD2000,
- (unsigned char *) 0xD4000,
- (unsigned char *) 0xD6000,
- (unsigned char *) 0xD8000,
- (unsigned char *) 0xDA000,
- (unsigned char *) 0xDC000,
- (unsigned char *) 0xDE000,
+ (unsigned char *) 0xD0000,
+ (unsigned char *) 0xD2000,
+ (unsigned char *) 0xD4000,
+ (unsigned char *) 0xD6000,
+ (unsigned char *) 0xD8000,
+ (unsigned char *) 0xDA000,
+ (unsigned char *) 0xDC000,
+ (unsigned char *) 0xDE000,
+ 0,0,0,0,0,0,0,0
};
-#define NR_ISA_ADDRESSES (sizeof(cy_isa_addresses)/sizeof(unsigned char *))
+#define NR_ISA_ADDRS (sizeof(cy_isa_addresses)/sizeof(unsigned char*))
/* This is the per-card data structure containing address, irq, number of
- channels, etc. This driver supports a maximum of NR_CARDS cards. If
- you need to install more boards, change this constant in the definition
- below. No other change is necessary to support more boards. */
-
-#define NR_CARDS 4
-
+ channels, etc. This driver supports a maximum of NR_CARDS cards.
+*/
static struct cyclades_card cy_card[NR_CARDS];
/* This is the per-channel data structure containing pointers, flags
- and variables for the port. This driver supports a maximum of NR_PORTS.
- If the total number of ports is larger than NR_PORTS, change this
- constant in the definition below. No other change is necessary to
- support more boards/ports. */
-
-#define NR_PORTS 64
-
+ and variables for the port. This driver supports a maximum of NR_PORTS.
+*/
static struct cyclades_port cy_port[NR_PORTS];
-/* The Cyclom-Ye has placed the sequential chips in non-sequential
- * address order. This look-up table overcomes that problem.
- */
-static int cy_chip_offset [] =
- { 0x0000,
- 0x0400,
- 0x0800,
- 0x0C00,
- 0x0200,
- 0x0600,
- 0x0A00,
- 0x0E00
- };
-
-/* PCI related definitions */
-
-static unsigned short cy_pci_nboard = 0;
-static unsigned short cy_isa_nboard = 0;
-static unsigned short cy_nboard = 0;
-static unsigned short cy_pci_dev_id[] = {
- PCI_DEVICE_ID_CYCLOM_Y_Lo,/* PCI below 1Mb */
- PCI_DEVICE_ID_CYCLOM_Y_Hi,/* PCI above 1Mb */
- 0 /* end of table */
- };
-
-int cy_detect_isa(void);
-int cy_detect_pci(void);
-
-static int cy_next_channel = 0; /* next minor available */
+static int cy_next_channel = 0; /* next minor available */
static int serial_refcount;
@@ -401,17 +543,18 @@ static struct termios *serial_termios_locked[NR_PORTS];
/* This is the per-irq data structure,
it maps an irq to the corresponding card */
-struct cyclades_card *IRQ_cards[16];
+static struct cyclades_card *IRQ_cards[16];
/*
* tmp_buf is used as a temporary buffer by serial_write. We need to
- * lock it in case the copy_from_user blocks while swapping in a page,
+ * lock it in case the memcpy_fromfs blocks while swapping in a page,
* and some other program tries to do a serial write at the same time.
* Since the lock will only come under contention when the system is
* swapping and available memory is low, it makes sense to share one
* buffer across all the serial ports, since it significantly saves
- * memory if large numbers of serial ports are open.
+ * memory if large numbers of serial ports are open. This buffer is
+ * allocated when the first cy_open occurs.
*/
static unsigned char *tmp_buf = 0;
static struct semaphore tmp_buf_sem = MUTEX;
@@ -420,83 +563,127 @@ static struct semaphore tmp_buf_sem = MUTEX;
* This is used to look up the divisor speeds and the timeouts
* We're normally limited to 15 distinct baud rates. The extra
* are accessed via settings in info->flags.
- * 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
- * 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
- * HI VHI
+ * 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ * 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
+ * HI VHI
*/
static int baud_table[] = {
- 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200,
- 1800, 2400, 4800, 9600, 19200, 38400, 57600, 76800,115200,150000,
- 0};
+ 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200,
+ 1800, 2400, 4800, 9600, 19200, 38400, 57600, 76800,115200,150000,
+ 0};
static char baud_co[] = { /* 25 MHz clock option table */
- /* value => 00 01 02 03 04 */
- /* divide by 8 32 128 512 2048 */
- 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x02,
- 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ /* value => 00 01 02 03 04 */
+ /* divide by 8 32 128 512 2048 */
+ 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x02,
+ 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
static char baud_bpr[] = { /* 25 MHz baud rate period table */
- 0x00, 0xf5, 0xa3, 0x6f, 0x5c, 0x51, 0xf5, 0xa3, 0x51, 0xa3,
- 0x6d, 0x51, 0xa3, 0x51, 0xa3, 0x51, 0x36, 0x29, 0x1b, 0x15};
+ 0x00, 0xf5, 0xa3, 0x6f, 0x5c, 0x51, 0xf5, 0xa3, 0x51, 0xa3,
+ 0x6d, 0x51, 0xa3, 0x51, 0xa3, 0x51, 0x36, 0x29, 0x1b, 0x15};
static char baud_cor3[] = { /* receive threshold */
- 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
- 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x07};
+ 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+ 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x07};
+/* The Cyclom-Ye has placed the sequential chips in non-sequential
+ * address order. This look-up table overcomes that problem.
+ */
+static int cy_chip_offset [] =
+ { 0x0000,
+ 0x0400,
+ 0x0800,
+ 0x0C00,
+ 0x0200,
+ 0x0600,
+ 0x0A00,
+ 0x0E00
+ };
+
+/* PCI related definitions */
-static void shutdown(struct cyclades_port *);
-static int startup (struct cyclades_port *);
-static void cy_throttle(struct tty_struct *);
-static void cy_unthrottle(struct tty_struct *);
-static void config_setup(struct cyclades_port *);
+static unsigned short cy_pci_nboard = 0;
+static unsigned short cy_isa_nboard = 0;
+static unsigned short cy_nboard = 0;
+static unsigned short cy_pci_dev_id[] = {
+ PCI_DEVICE_ID_CYCLOM_Y_Lo,/* PCI below 1Mb */
+ PCI_DEVICE_ID_CYCLOM_Y_Hi,/* PCI above 1Mb */
+ PCI_DEVICE_ID_CYCLOM_Z_Lo,/* PCI below 1Mb */
+ PCI_DEVICE_ID_CYCLOM_Z_Hi,/* PCI above 1Mb */
+ 0 /* end of table */
+ };
+
+
+static void cy_start(struct tty_struct *);
+static void set_line_char(struct cyclades_port *);
+static void cy_probe(int, void *, struct pt_regs *);
+static void cyz_poll(unsigned long);
#ifdef CYCLOM_SHOW_STATUS
static void show_status(int);
#endif
+static int cyz_timeron = 0;
+static struct timer_list
+cyz_timerlist = {
+ NULL, NULL, 0, 0, cyz_poll
+};
+
+
+/**************************************************
+error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned long));
+memcpy_tofs (to, from, count);
+***************************************************************
+error = verify_area(VERIFY_READ, (void *) arg, sizeof(unsigned long *));
+memcpy_fromfs(to, from, count);
+**************************************************/
+
+
static inline int
serial_paranoia_check(struct cyclades_port *info,
- kdev_t device, const char *routine)
+ kdev_t device, const char *routine)
{
#ifdef SERIAL_PARANOIA_CHECK
static const char *badmagic =
- "Warning: bad magic number for serial struct (%s) in %s\n";
+ "cyc Warning: bad magic number for serial struct (%s) in %s\n";
static const char *badinfo =
- "Warning: null cyclades_port for (%s) in %s\n";
+ "cyc Warning: null cyclades_port for (%s) in %s\n";
static const char *badrange =
- "Warning: cyclades_port out of range for (%s) in %s\n";
+ "cyc Warning: cyclades_port out of range for (%s) in %s\n";
if (!info) {
- printk(badinfo, kdevname(device), routine);
- return 1;
+ printk(badinfo, kdevname(device), routine);
+ return 1;
}
if( (long)info < (long)(&cy_port[0])
|| (long)(&cy_port[NR_PORTS]) < (long)info ){
- printk(badrange, kdevname(device), routine);
- return 1;
+ printk(badrange, kdevname(device), routine);
+ return 1;
}
if (info->magic != CYCLADES_MAGIC) {
- printk(badmagic, kdevname(device), routine);
- return 1;
+ printk(badmagic, kdevname(device), routine);
+ return 1;
}
#endif
- return 0;
+ return 0;
} /* serial_paranoia_check */
+
/* The following diagnostic routines allow the driver to spew
information on the screen, even (especially!) during interrupts.
*/
-void
+static void
SP(char *data){
unsigned long flags;
save_flags(flags); cli();
console_print(data);
restore_flags(flags);
-}
-void
+}/* SP */
+
+static void
CP(char data){
unsigned long flags;
char scrn[2];
@@ -507,128 +694,278 @@ CP(char data){
restore_flags(flags);
}/* CP */
-void CP1(int data) { (data<10)? CP(data+'0'): CP(data+'A'-10); }/* CP1 */
-void CP2(int data) { CP1((data>>4) & 0x0f); CP1( data & 0x0f); }/* CP2 */
-void CP4(int data) { CP2((data>>8) & 0xff); CP2(data & 0xff); }/* CP4 */
-void CP8(long data) { CP4((data>>16) & 0xffff); CP4(data & 0xffff); }/* CP8 */
+static void CP4(int data)
+ { (data<10)? CP(data+'0'): CP(data+'A'-10); }/* CP4 */
+static void CP8(int data)
+ { CP4((data>>4) & 0x0f); CP4( data & 0x0f); }/* CP8 */
+static void CP16(int data)
+ { CP8((data>>8) & 0xff); CP8(data & 0xff); }/* CP16 */
+static void CP32(long data)
+ { CP16((data>>16) & 0xffff); CP16(data & 0xffff); }/* CP32 */
+
+
+/*
+ * This routine is used by the interrupt handler to schedule
+ * processing in the software interrupt portion of the driver
+ * (also known as the "bottom half"). This can be called any
+ * number of times for any channel without harm.
+ */
+static inline void
+cy_sched_event(struct cyclades_port *info, int event)
+{
+ info->event |= 1 << event; /* remember what kind of event and who */
+ queue_task(&info->tqueue, &tq_cyclades); /* it belongs to */
+ mark_bh(CYCLADES_BH); /* then trigger event */
+} /* cy_sched_event */
+
+
+/*
+ * This routine is used to handle the "bottom half" processing for the
+ * serial driver, known also the "software interrupt" processing.
+ * This processing is done at the kernel interrupt level, after the
+ * cy#/_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON. This
+ * is where time-consuming activities which can not be done in the
+ * interrupt driver proper are done; the interrupt driver schedules
+ * them using cy_sched_event(), and they get done here.
+ *
+ * This is done through one level of indirection--the task queue.
+ * When a hardware interrupt service routine wants service by the
+ * driver's bottom half, it enqueues the appropriate tq_struct (one
+ * per port) to the tq_cyclades work queue and sets a request flag
+ * via mark_bh for processing that queue. When the time is right,
+ * do_cyclades_bh is called (because of the mark_bh) and it requests
+ * that the work queue be processed.
+ *
+ * Although this may seem unwieldy, it gives the system a way to
+ * pass an argument (in this case the pointer to the cyclades_port
+ * structure) to the bottom half of the driver. Previous kernels
+ * had to poll every port to see if that port needed servicing.
+ */
+static void
+do_cyclades_bh(void)
+{
+ run_task_queue(&tq_cyclades);
+} /* do_cyclades_bh */
+
+
+static void
+do_softint(void *private_)
+{
+ struct cyclades_port *info = (struct cyclades_port *) private_;
+ struct tty_struct *tty;
+
+ tty = info->tty;
+ if (!tty)
+ return;
+
+ if (test_and_clear_bit(Cy_EVENT_HANGUP, &info->event)) {
+ tty_hangup(info->tty);
+ wake_up_interruptible(&info->open_wait);
+ info->flags &= ~(ASYNC_NORMAL_ACTIVE|
+ ASYNC_CALLOUT_ACTIVE);
+ }
+ if (test_and_clear_bit(Cy_EVENT_OPEN_WAKEUP, &info->event)) {
+ wake_up_interruptible(&info->open_wait);
+ }
+ if (test_and_clear_bit(Cy_EVENT_WRITE_WAKEUP, &info->event)) {
+ if((tty->flags & (1<< TTY_DO_WRITE_WAKEUP))
+ && tty->ldisc.write_wakeup){
+ (tty->ldisc.write_wakeup)(tty);
+ }
+ wake_up_interruptible(&tty->write_wait);
+ }
+} /* do_softint */
+
+
+/***********************************************************/
+/********* Start of block of Cyclom-Y specific code ********/
/* This routine waits up to 1000 micro-seconds for the previous
command to the Cirrus chip to complete and then issues the
new command. An error is returned if the previous command
didn't finish within the time limit.
*/
-u_short
-write_cy_cmd(u_char *base_addr, u_char cmd, int index)
+static int
+cyy_issue_cmd(u_char *base_addr, u_char cmd, int index)
{
unsigned long flags;
volatile int i;
save_flags(flags); cli();
- /* Check to see that the previous command has completed */
- for(i = 0 ; i < 100 ; i++){
- if (base_addr[CyCCR<<index] == 0){
- break;
- }
- udelay(10L);
- }
- /* if the CCR never cleared, the previous command
- didn't finish within the "reasonable time" */
- if ( i == 100 ) {
- restore_flags(flags);
- return (-1);
- }
+ /* Check to see that the previous command has completed */
+ for(i = 0 ; i < 100 ; i++){
+ if (base_addr[CyCCR<<index] == 0){
+ break;
+ }
+ udelay(10L);
+ }
+ /* if the CCR never cleared, the previous command
+ didn't finish within the "reasonable time" */
+ if ( i == 100 ) {
+ restore_flags(flags);
+ return (-1);
+ }
- /* Issue the new command */
- base_addr[CyCCR<<index] = cmd;
+ /* Issue the new command */
+ base_addr[CyCCR<<index] = cmd;
restore_flags(flags);
return(0);
-} /* write_cy_cmd */
+} /* cyy_issue_cmd */
+static int probe_ready;
-/* cy_start and cy_stop provide software output flow control as a
- function of XON/XOFF, software CTS, and other such stuff. */
+/*
+ * Grab all interrupts in preparation for doing an automatic irq
+ * detection. dontgrab is a mask of irq's _not_ to grab. Returns a
+ * mask of irq's which were grabbed and should therefore be freed
+ * using free_all_interrupts().
+ */
+static int
+grab_all_interrupts(int dontgrab)
+{
+ int irq_lines = 0;
+ int i, mask;
+
+ for (i = 0, mask = 1; i < 16; i++, mask <<= 1) {
+ if (!(mask & dontgrab)
+ && !request_irq(i, cy_probe,
+ SA_INTERRUPT, "serial probe", NULL)) {
+ irq_lines |= mask;
+ }
+ }
+ return irq_lines;
+} /* grab_all_interrupts */
+/*
+ * Release all interrupts grabbed by grab_all_interrupts
+ */
static void
-cy_stop(struct tty_struct *tty)
+free_all_interrupts(int irq_lines)
{
- struct cyclades_card *cinfo;
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
- unsigned char *base_addr;
- int chip,channel,index;
- unsigned long flags;
-
-#ifdef SERIAL_DEBUG_OTHER
- printk("cy_stop ttyC%d\n", info->line); /* */
-#endif
+ int i;
+
+ for (i = 0; i < 16; i++) {
+ if (irq_lines & (1 << i))
+ free_irq(i,NULL);
+ }
+} /* free_all_interrupts */
- if (serial_paranoia_check(info, tty->device, "cy_stop"))
- return;
-
- cinfo = &cy_card[info->card];
- index = cinfo->bus_index;
- channel = info->line - cinfo->first_line;
- chip = channel>>2;
- channel &= 0x03;
- base_addr = (unsigned char*)
- (cy_card[info->card].base_addr + (cy_chip_offset[chip]<<index));
+/*
+ * This routine returns a bitfield of "wild interrupts". Basically,
+ * any unclaimed interrupts which is flapping around.
+ */
+static int
+check_wild_interrupts(void)
+{
+ int i, mask;
+ int wild_interrupts = 0;
+ int irq_lines;
+ unsigned long timeout;
+ unsigned long flags;
+
+ /*Turn on interrupts (they may be off) */
+ save_flags(flags); sti();
- save_flags(flags); cli();
- base_addr[CyCAR<<index] = (u_char)(channel & 0x0003); /* index channel */
- base_addr[CySRER<<index] &= ~CyTxMpty;
+ irq_lines = grab_all_interrupts(0);
+
+ /*
+ * Delay for 0.1 seconds -- we use a busy loop since this may
+ * occur during the bootup sequence
+ */
+ timeout = jiffies+10;
+ while (timeout >= jiffies)
+ ;
+
+ cy_triggered = 0; /* Reset after letting things settle */
+
+ timeout = jiffies+10;
+ while (timeout >= jiffies)
+ ;
+
+ for (i = 0, mask = 1; i < 16; i++, mask <<= 1) {
+ if ((cy_triggered & (1 << i)) &&
+ (irq_lines & (1 << i))) {
+ wild_interrupts |= mask;
+ }
+ }
+ free_all_interrupts(irq_lines);
restore_flags(flags);
+ return wild_interrupts;
+} /* check_wild_interrupts */
- return;
-} /* cy_stop */
-
-static void
-cy_start(struct tty_struct *tty)
+/*
+ * This routine is called by do_auto_irq(); it attempts to determine
+ * which interrupt a serial port is configured to use. It is not
+ * fool-proof, but it works a large part of the time.
+ */
+static int
+get_auto_irq(unsigned char *address)
{
- struct cyclades_card *cinfo;
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ unsigned long timeout;
unsigned char *base_addr;
- int chip,channel,index;
- unsigned long flags;
-
-#ifdef SERIAL_DEBUG_OTHER
- printk("cy_start ttyC%d\n", info->line); /* */
-#endif
-
- if (serial_paranoia_check(info, tty->device, "cy_start"))
- return;
-
- cinfo = &cy_card[info->card];
- index = cinfo->bus_index;
- channel = info->line - cinfo->first_line;
- chip = channel>>2;
- channel &= 0x03;
- base_addr = (unsigned char*)
- (cy_card[info->card].base_addr + (cy_chip_offset[chip]<<index));
+ int index;
- save_flags(flags); cli();
- base_addr[CyCAR<<index] = (u_char)(channel & 0x0003);
+ index = 0; /* IRQ probing is only for ISA */
+ base_addr = address;
+ intr_base_addr = address;
+
+ /*
+ * Enable interrupts and see who answers
+ */
+ cy_irq_triggered = 0;
+ cli();
+ base_addr[CyCAR<<index] = 0;
+ cyy_issue_cmd(base_addr,CyCHAN_CTL|CyENB_XMTR,index);
base_addr[CySRER<<index] |= CyTxMpty;
- restore_flags(flags);
-
- return;
-} /* cy_start */
-
+ probe_ready = 1;
+ sti();
+
+ timeout = jiffies+2;
+ while (timeout >= jiffies) {
+ if (cy_irq_triggered)
+ break;
+ }
+ probe_ready = 0;
+ return(cy_irq_triggered);
+} /* get_auto_irq */
/*
- * This routine is used by the interrupt handler to schedule
- * processing in the software interrupt portion of the driver
- * (also known as the "bottom half"). This can be called any
- * number of times for any channel without harm.
+ * Calls get_auto_irq() multiple times, to make sure we don't get
+ * faked out by random interrupts
*/
-static inline void
-cy_sched_event(struct cyclades_port *info, int event)
+static int
+do_auto_irq(unsigned char *address)
{
- info->event |= 1 << event; /* remember what kind of event and who */
- queue_task_irq_off(&info->tqueue, &tq_cyclades); /* it belongs to */
- mark_bh(CYCLADES_BH); /* then trigger event */
-} /* cy_sched_event */
+ int irq_lines = 0;
+ int irq_try_1 = 0, irq_try_2 = 0;
+ int retries;
+ unsigned long flags;
+ /* Turn on interrupts (they may be off) */
+ save_flags(flags); sti();
+
+ probe_ready = 0;
+
+ cy_wild_int_mask = check_wild_interrupts();
+
+ irq_lines = grab_all_interrupts(cy_wild_int_mask);
+
+ for (retries = 0; retries < 5; retries++) {
+ if (!irq_try_1)
+ irq_try_1 = get_auto_irq(address);
+ if (!irq_try_2)
+ irq_try_2 = get_auto_irq(address);
+ if (irq_try_1 && irq_try_2) {
+ if (irq_try_1 == irq_try_2)
+ break;
+ irq_try_1 = irq_try_2 = 0;
+ }
+ }
+ restore_flags(flags);
+ free_all_interrupts(irq_lines);
+ return (irq_try_1 == irq_try_2) ? irq_try_1 : 0;
+} /* do_auto_irq */
-static int probe_ready;
/*
* This interrupt routine is used
@@ -638,30 +975,31 @@ static void
cy_probe(int irq, void *dev_id, struct pt_regs *regs)
{
int save_xir, save_car;
- int index = 0; /* probing interrupts is only for ISA */
+ int index = 0; /* probing interrupts is only for ISA */
if (!probe_ready) {
- *(intr_base_addr + (Cy_ClrIntr<<index)) = 0;
+ *(intr_base_addr + (Cy_ClrIntr<<index)) = 0;
return;
}
cy_irq_triggered = irq;
cy_triggered |= 1 << irq;
- if(intr_base_addr[CySVRR<<index] != 0) {
- save_xir = (u_char) intr_base_addr[CyTIR<<index];
- save_car = intr_base_addr[CyCAR<<index];
- if ((save_xir & 0x3) != 0){
- SP("channel ");
- CP2(save_xir);
- SP(" requesting unexpected interrupt\n");
- }
- intr_base_addr[CyCAR<<index] = (save_xir & 0x3);
- intr_base_addr[CySRER<<index] &= ~CyTxMpty;
- intr_base_addr[CyTIR<<index] = (save_xir & 0x3f);
- intr_base_addr[CyCAR<<index] = (save_car);
- }
- *(intr_base_addr + (Cy_ClrIntr<<index)) = 0; /* Cy_ClrIntr is 0x1800 */
+ if(intr_base_addr[CySVRR<<index] != 0) {
+ save_xir = (u_char) intr_base_addr[CyTIR<<index];
+ save_car = intr_base_addr[CyCAR<<index];
+ if ((save_xir & 0x3) != 0){
+ SP("channel ");
+ CP8(save_xir);
+ SP(" requesting unexpected interrupt\n");
+ }
+ intr_base_addr[CyCAR<<index] = (save_xir & 0x3);
+ intr_base_addr[CySRER<<index] &= ~CyTxMpty;
+ intr_base_addr[CyTIR<<index] = (save_xir & 0x3f);
+ intr_base_addr[CyCAR<<index] = (save_car);
+ }
+ *(intr_base_addr + (Cy_ClrIntr<<index)) = 0;
+ /* Cy_ClrIntr is 0x1800 */
return;
} /* cy_probe */
@@ -670,7 +1008,7 @@ cy_probe(int irq, void *dev_id, struct pt_regs *regs)
received, out buffer empty, modem change, etc.
*/
static void
-cy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+cyy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
struct tty_struct *tty;
int status;
@@ -703,8 +1041,8 @@ cy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
do{
had_work = 0;
for ( chip = 0 ; chip < cinfo->num_chips ; chip ++) {
- base_addr = (unsigned char *)
- (cinfo->base_addr + (cy_chip_offset[chip]<<index));
+ base_addr = (unsigned char *)
+ (cinfo->base_addr + (cy_chip_offset[chip]<<index));
too_many = 0;
while ( (status = base_addr[CySVRR<<index]) != 0x00) {
had_work++;
@@ -712,12 +1050,12 @@ cy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
no chip can monopolize the driver. This forces the
chips to be checked in a round-robin fashion (after
draining each of a bunch (1000) of characters).
- */
+ */
if(1000<too_many++){
break;
}
- if (status & CySRReceive) { /* reception interrupt */
- /* determine the channel and change to that context */
+ if (status & CySRReceive) { /* reception interrupt */
+ /* determine the channel & change to that context */
save_xir = (u_char) base_addr[CyRIR<<index];
channel = (u_short ) (save_xir & CyIRChannel);
i = channel + chip * 4 + cinfo->first_line;
@@ -746,82 +1084,84 @@ cy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
continue;
}
if (tty->flip.count < TTY_FLIPBUF_SIZE){
- tty->flip.count++;
- if (data & info->read_status_mask){
- if(data & CyBREAK){
- *tty->flip.flag_buf_ptr++ =
- TTY_BREAK;
- *tty->flip.char_buf_ptr++ =
- base_addr[CyRDSR<<index];
- if (info->flags & ASYNC_SAK){
- do_SAK(tty);
- }
- }else if(data & CyFRAME){
- *tty->flip.flag_buf_ptr++ =
- TTY_FRAME;
- *tty->flip.char_buf_ptr++ =
- base_addr[CyRDSR<<index];
- }else if(data & CyPARITY){
- *tty->flip.flag_buf_ptr++ =
- TTY_PARITY;
- *tty->flip.char_buf_ptr++ =
- base_addr[CyRDSR<<index];
- }else if(data & CyOVERRUN){
- *tty->flip.flag_buf_ptr++ =
- TTY_OVERRUN;
- *tty->flip.char_buf_ptr++ = 0;
- /* If the flip buffer itself is
- overflowing, we still loose
- the next incoming character.
- */
- if(tty->flip.count < TTY_FLIPBUF_SIZE){
- tty->flip.count++;
- *tty->flip.flag_buf_ptr++ =
- TTY_NORMAL;
- *tty->flip.char_buf_ptr++ =
- base_addr[CyRDSR<<index];
- }
- /* These two conditions may imply */
- /* a normal read should be done. */
- /* }else if(data & CyTIMEOUT){ */
- /* }else if(data & CySPECHAR){ */
- }else{
- *tty->flip.flag_buf_ptr++ = 0;
- *tty->flip.char_buf_ptr++ = 0;
- }
- }else{
- *tty->flip.flag_buf_ptr++ = 0;
- *tty->flip.char_buf_ptr++ = 0;
- }
+ tty->flip.count++;
+ if (data & info->read_status_mask){
+ if(data & CyBREAK){
+ *tty->flip.flag_buf_ptr++ =
+ TTY_BREAK;
+ *tty->flip.char_buf_ptr++ =
+ base_addr[CyRDSR<<index];
+ if (info->flags & ASYNC_SAK){
+ do_SAK(tty);
+ }
+ }else if(data & CyFRAME){
+ *tty->flip.flag_buf_ptr++ =
+ TTY_FRAME;
+ *tty->flip.char_buf_ptr++ =
+ base_addr[CyRDSR<<index];
+ }else if(data & CyPARITY){
+ *tty->flip.flag_buf_ptr++ =
+ TTY_PARITY;
+ *tty->flip.char_buf_ptr++ =
+ base_addr[CyRDSR<<index];
+ }else if(data & CyOVERRUN){
+ *tty->flip.flag_buf_ptr++ =
+ TTY_OVERRUN;
+ *tty->flip.char_buf_ptr++ = 0;
+ /* If the flip buffer itself is
+ overflowing, we still loose
+ the next incoming character.
+ */
+ if(tty->flip.count
+ < TTY_FLIPBUF_SIZE){
+ tty->flip.count++;
+ *tty->flip.flag_buf_ptr++ =
+ TTY_NORMAL;
+ *tty->flip.char_buf_ptr++ =
+ base_addr[CyRDSR<<index];
+ }
+ /* These two conditions may imply */
+ /* a normal read should be done. */
+ /* }else if(data & CyTIMEOUT){ */
+ /* }else if(data & CySPECHAR){ */
+ }else{
+ *tty->flip.flag_buf_ptr++ = 0;
+ *tty->flip.char_buf_ptr++ = 0;
+ }
+ }else{
+ *tty->flip.flag_buf_ptr++ = 0;
+ *tty->flip.char_buf_ptr++ = 0;
+ }
}else{
- /* there was a software buffer overrun
- and nothing could be done about it!!! */
+ /* there was a software buffer
+ overrun and nothing could be
+ done about it!!! */
}
} else { /* normal character reception */
- /* load # characters available from the chip */
+ /* load # chars available from the chip */
char_count = base_addr[CyRDCR<<index];
#ifdef CYCLOM_ENABLE_MONITORING
- ++info->mon.int_count;
- info->mon.char_count += char_count;
- if (char_count > info->mon.char_max)
- info->mon.char_max = char_count;
- info->mon.char_last = char_count;
+ ++info->mon.int_count;
+ info->mon.char_count += char_count;
+ if (char_count > info->mon.char_max)
+ info->mon.char_max = char_count;
+ info->mon.char_last = char_count;
#endif
while(char_count--){
- if (tty->flip.count >= TTY_FLIPBUF_SIZE){
+ if (tty->flip.count >= TTY_FLIPBUF_SIZE){
break;
}
- tty->flip.count++;
+ tty->flip.count++;
data = base_addr[CyRDSR<<index];
- *tty->flip.flag_buf_ptr++ = TTY_NORMAL;
- *tty->flip.char_buf_ptr++ = data;
+ *tty->flip.flag_buf_ptr++ = TTY_NORMAL;
+ *tty->flip.char_buf_ptr++ = data;
#ifdef CYCLOM_16Y_HACK
- udelay(10L);
+ udelay(10L);
#endif
}
}
- queue_task_irq_off(&tty->flip.tqueue, &tq_timer);
+ queue_task(&tty->flip.tqueue, &tq_timer);
}
/* end of service */
base_addr[CyRIR<<index] = (save_xir & 0x3f);
@@ -829,18 +1169,19 @@ cy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
}
- if (status & CySRTransmit) { /* transmission interrupt */
- /* Since we only get here when the transmit buffer is empty,
- we know we can always stuff a dozen characters. */
+ if (status & CySRTransmit) { /* transmission interrupt */
+ /* Since we only get here when the transmit buffer
+ is empty, we know we can always stuff a dozen
+ characters. */
- /* determine the channel and change to that context */
+ /* determine the channel & change to that context */
save_xir = (u_char) base_addr[CyTIR<<index];
channel = (u_short ) (save_xir & CyIRChannel);
i = channel + chip * 4 + cinfo->first_line;
save_car = base_addr[CyCAR<<index];
base_addr[CyCAR<<index] = save_xir;
- /* validate the port number (as configured and open) */
+ /* validate the port# (as configured and open) */
if( (i < 0) || (NR_PORTS <= i) ){
base_addr[CySRER<<index] &= ~CyTxMpty;
goto txend;
@@ -852,7 +1193,7 @@ cy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
goto txdone;
}
- /* load the on-chip space available for outbound data */
+ /* load the on-chip space for outbound data */
char_count = info->xmit_fifo_size;
@@ -863,64 +1204,65 @@ cy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
info->x_char = 0;
}
- if (info->x_break){
- /* The Cirrus chip requires the "Embedded Transmit
- Commands" of start break, delay, and end break
- sequences to be sent. The duration of the
- break is given in TICs, which runs at HZ
- (typically 100) and the PPR runs at 200 Hz,
- so the delay is duration * 200/HZ, and thus a
- break can run from 1/100 sec to about 5/4 sec.
- */
- base_addr[CyTDR<<index] = 0; /* start break */
- base_addr[CyTDR<<index] = 0x81;
- base_addr[CyTDR<<index] = 0; /* delay a bit */
- base_addr[CyTDR<<index] = 0x82;
- base_addr[CyTDR<<index] = info->x_break*200/HZ;
- base_addr[CyTDR<<index] = 0; /* terminate break */
- base_addr[CyTDR<<index] = 0x83;
- char_count -= 7;
- info->x_break = 0;
- }
+ if (info->x_break){
+ /* The Cirrus chip requires the "Embedded
+ Transmit Commands" of start break, delay,
+ and end break sequences to be sent. The
+ duration of the break is given in TICs,
+ which runs at HZ (typically 100) and the
+ PPR runs at 200 Hz, so the delay is
+ duration * 200/HZ, and thus a break can
+ run from 1/100 sec to about 5/4 sec.
+ */
+ base_addr[CyTDR<<index] = 0; /* start break */
+ base_addr[CyTDR<<index] = 0x81;
+ base_addr[CyTDR<<index] = 0; /* delay a bit */
+ base_addr[CyTDR<<index] = 0x82;
+ base_addr[CyTDR<<index] = info->x_break*200/HZ;
+ base_addr[CyTDR<<index] = 0; /* finish break */
+ base_addr[CyTDR<<index] = 0x83;
+ char_count -= 7;
+ info->x_break = 0;
+ }
while (char_count-- > 0){
if (!info->xmit_cnt){
- base_addr[CySRER<<index] &= ~CyTxMpty;
- goto txdone;
+ base_addr[CySRER<<index] &= ~CyTxMpty;
+ goto txdone;
}
- if (info->xmit_buf == 0){
- base_addr[CySRER<<index] &= ~CyTxMpty;
- goto txdone;
- }
- if (info->tty->stopped || info->tty->hw_stopped){
- base_addr[CySRER<<index] &= ~CyTxMpty;
- goto txdone;
- }
- /* Because the Embedded Transmit Commands have been
- enabled, we must check to see if the escape
- character, NULL, is being sent. If it is, we
- must ensure that there is room for it to be
- doubled in the output stream. Therefore we
- no longer advance the pointer when the character
- is fetched, but rather wait until after the check
- for a NULL output character. (This is necessary
- because there may not be room for the two chars
- needed to send a NULL.
- */
+ if (info->xmit_buf == 0){
+ base_addr[CySRER<<index] &= ~CyTxMpty;
+ goto txdone;
+ }
+ if (info->tty->stopped || info->tty->hw_stopped){
+ base_addr[CySRER<<index] &= ~CyTxMpty;
+ goto txdone;
+ }
+ /* Because the Embedded Transmit Commands have
+ been enabled, we must check to see if the
+ escape character, NULL, is being sent. If it
+ is, we must ensure that there is room for it
+ to be doubled in the output stream. Therefore
+ we no longer advance the pointer when the
+ character is fetched, but rather wait until
+ after the check for a NULL output character.
+ This is necessary because there may not be
+ room for the two chars needed to send a NULL.)
+ */
outch = info->xmit_buf[info->xmit_tail];
if( outch ){
- info->xmit_cnt--;
- info->xmit_tail = (info->xmit_tail + 1)
- & (PAGE_SIZE - 1);
- base_addr[CyTDR<<index] = outch;
+ info->xmit_cnt--;
+ info->xmit_tail = (info->xmit_tail + 1)
+ & (PAGE_SIZE - 1);
+ base_addr[CyTDR<<index] = outch;
}else{
if(char_count > 1){
- info->xmit_cnt--;
- info->xmit_tail = (info->xmit_tail + 1)
- & (PAGE_SIZE - 1);
- base_addr[CyTDR<<index] = outch;
- base_addr[CyTDR<<index] = 0;
- char_count--;
+ info->xmit_cnt--;
+ info->xmit_tail = (info->xmit_tail + 1)
+ & (PAGE_SIZE - 1);
+ base_addr[CyTDR<<index] = outch;
+ base_addr[CyTDR<<index] = 0;
+ char_count--;
}else{
}
}
@@ -939,10 +1281,11 @@ cy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
if (status & CySRModem) { /* modem interrupt */
- /* determine the channel and change to that context */
+ /* determine the channel & change to that context */
save_xir = (u_char) base_addr[CyMIR<<index];
channel = (u_short ) (save_xir & CyIRChannel);
- info = &cy_port[channel + chip * 4 + cinfo->first_line];
+ info = &cy_port[channel + chip * 4
+ + cinfo->first_line];
info->last_active = jiffies;
save_car = base_addr[CyCAR<<index];
base_addr[CyCAR<<index] = save_xir;
@@ -950,32 +1293,40 @@ cy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
mdm_change = base_addr[CyMISR<<index];
mdm_status = base_addr[CyMSVR1<<index];
- if(info->tty == 0){ /* nowhere to put the data, ignore it */
+ if(info->tty == 0){/* no place for data, ignore it*/
;
}else{
if((mdm_change & CyDCD)
&& (info->flags & ASYNC_CHECK_CD)){
if(mdm_status & CyDCD){
- cy_sched_event(info, Cy_EVENT_OPEN_WAKEUP);
- }else if(!((info->flags & ASYNC_CALLOUT_ACTIVE)
- &&(info->flags & ASYNC_CALLOUT_NOHUP))){
- cy_sched_event(info, Cy_EVENT_HANGUP);
+ cy_sched_event(info,
+ Cy_EVENT_OPEN_WAKEUP);
+ }else if(!((info->flags
+ & ASYNC_CALLOUT_ACTIVE)
+ &&(info->flags
+ & ASYNC_CALLOUT_NOHUP))){
+ cy_sched_event(info,
+ Cy_EVENT_HANGUP);
}
}
if((mdm_change & CyCTS)
&& (info->flags & ASYNC_CTS_FLOW)){
if(info->tty->hw_stopped){
if(mdm_status & CyCTS){
- /* !!! cy_start isn't used because... */
+ /* cy_start isn't used
+ because... !!! */
info->tty->hw_stopped = 0;
- base_addr[CySRER<<index] |= CyTxMpty;
- cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP);
+ base_addr[CySRER<<index] |= CyTxMpty;
+ cy_sched_event(info,
+ Cy_EVENT_WRITE_WAKEUP);
}
}else{
if(!(mdm_status & CyCTS)){
- /* !!! cy_stop isn't used because... */
+ /* cy_stop isn't used
+ because ... !!! */
info->tty->hw_stopped = 1;
- base_addr[CySRER<<index] &= ~CyTxMpty;
+ base_addr[CySRER<<index] &=
+ ~CyTxMpty;
}
}
}
@@ -993,217 +1344,373 @@ cy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
} while(had_work);
/* clear interrupts */
- *(card_base_addr + (Cy_ClrIntr<<index)) = 0; /* Cy_ClrIntr is 0x1800 */
+ *(card_base_addr + (Cy_ClrIntr<<index)) = 0;
+ /* Cy_ClrIntr is 0x1800 */
-} /* cy_interrupt */
+} /* cyy_interrupt */
-/*
- * This routine is used to handle the "bottom half" processing for the
- * serial driver, known also the "software interrupt" processing.
- * This processing is done at the kernel interrupt level, after the
- * cy_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON. This
- * is where time-consuming activities which can not be done in the
- * interrupt driver proper are done; the interrupt driver schedules
- * them using cy_sched_event(), and they get done here.
- *
- * This is done through one level of indirection--the task queue.
- * When a hardware interrupt service routine wants service by the
- * driver's bottom half, it enqueues the appropriate tq_struct (one
- * per port) to the tq_cyclades work queue and sets a request flag
- * via mark_bh for processing that queue. When the time is right,
- * do_cyclades_bh is called (because of the mark_bh) and it requests
- * that the work queue be processed.
- *
- * Although this may seem unwieldy, it gives the system a way to
- * pass an argument (in this case the pointer to the cyclades_port
- * structure) to the bottom half of the driver. Previous kernels
- * had to poll every port to see if that port needed servicing.
- */
-static void
-do_cyclades_bh(void)
-{
- run_task_queue(&tq_cyclades);
-} /* do_cyclades_bh */
+/***********************************************************/
+/********* End of block of Cyclom-Y specific code **********/
+/******** Start of block of Cyclom-Z specific code *********/
+/***********************************************************/
-static void
-do_softint(void *private_)
+
+static int
+cyz_fetch_msg( struct cyclades_card *cinfo,
+ u_long *channel, u_char *cmd, u_long **param)
{
- struct cyclades_port *info = (struct cyclades_port *) private_;
- struct tty_struct *tty;
+ struct FIRM_ID *firm_id;
+ struct ZFW_CTRL *zfw_ctrl;
+ struct BOARD_CTRL *board_ctrl;
+ unsigned long loc_doorbell;
+
+ firm_id = (struct FIRM_ID *)(cinfo->base_addr + ID_ADDRESS);
+ if (firm_id->signature != ZFIRM_ID){
+ return (-1);
+ }
+ zfw_ctrl = (struct ZFW_CTRL *)
+ (cinfo->base_addr + firm_id->zfwctrl_addr);
+ board_ctrl = &zfw_ctrl->board_ctrl;
+
+ loc_doorbell = ((struct RUNTIME_9060 *)
+ (cinfo->ctl_addr))->loc_doorbell;
+ if (loc_doorbell){
+ *cmd = (char)(0xff & loc_doorbell);
+ *channel = board_ctrl->fwcmd_channel;
+ *param = board_ctrl->fwcmd_param;
+ ((struct RUNTIME_9060 *)
+ (cinfo->ctl_addr))->loc_doorbell = 0xffffffff;
+ return 1;
+ }
+ return 0;
+} /* cyz_fetch_msg */
- tty = info->tty;
- if (!tty)
- return;
- if (clear_bit(Cy_EVENT_HANGUP, &info->event)) {
- tty_hangup(info->tty);
- wake_up_interruptible(&info->open_wait);
- info->flags &= ~(ASYNC_NORMAL_ACTIVE|
- ASYNC_CALLOUT_ACTIVE);
- }
- if (clear_bit(Cy_EVENT_OPEN_WAKEUP, &info->event)) {
- wake_up_interruptible(&info->open_wait);
+static int
+cyz_issue_cmd( struct cyclades_card *cinfo,
+ u_long channel, u_char cmd, u_long *param)
+{
+ struct FIRM_ID *firm_id;
+ struct ZFW_CTRL *zfw_ctrl;
+ struct BOARD_CTRL *board_ctrl;
+ volatile unsigned long *pci_doorbell;
+ int index;
+
+ firm_id = (struct FIRM_ID *)(cinfo->base_addr + ID_ADDRESS);
+ if (firm_id->signature != ZFIRM_ID){
+ return (-1);
}
- if (clear_bit(Cy_EVENT_WRITE_WAKEUP, &info->event)) {
- if((tty->flags & (1<< TTY_DO_WRITE_WAKEUP))
- && tty->ldisc.write_wakeup){
- (tty->ldisc.write_wakeup)(tty);
- }
- wake_up_interruptible(&tty->write_wait);
+ zfw_ctrl = (struct ZFW_CTRL *)
+ (cinfo->base_addr + firm_id->zfwctrl_addr);
+ board_ctrl = &zfw_ctrl->board_ctrl;
+
+ index = 0;
+ pci_doorbell = &((struct RUNTIME_9060 *)
+ (cinfo->ctl_addr))->pci_doorbell;
+ while( (*pci_doorbell & 0xff) != 0){
+ if (index++ == 100){
+ return(-1);
+ }
+ udelay(50L);
}
-} /* do_softint */
+ board_ctrl->hcmd_channel = channel;
+ board_ctrl->hcmd_param = param;
+ *pci_doorbell = (long)cmd;
+
+ return(0);
+} /* cyz_issue_cmd */
-/*
- * Grab all interrupts in preparation for doing an automatic irq
- * detection. dontgrab is a mask of irq's _not_ to grab. Returns a
- * mask of irq's which were grabbed and should therefore be freed
- * using free_all_interrupts().
- */
static int
-grab_all_interrupts(int dontgrab)
-{
- int irq_lines = 0;
- int i, mask;
-
- for (i = 0, mask = 1; i < 16; i++, mask <<= 1) {
- if (!(mask & dontgrab)
- && !request_irq(i, cy_probe, SA_INTERRUPT, "serial probe", NULL)) {
- irq_lines |= mask;
- }
+cyz_update_channel( struct cyclades_card *cinfo,
+ u_long channel, u_char mode, u_char cmd)
+{
+ struct FIRM_ID *firm_id =
+ (struct FIRM_ID *)(cinfo->base_addr + ID_ADDRESS);
+ struct ZFW_CTRL *zfw_ctrl;
+ struct CH_CTRL *ch_ctrl;
+
+ if (firm_id->signature != ZFIRM_ID){
+ return (-1);
}
- return irq_lines;
-} /* grab_all_interrupts */
+ zfw_ctrl =
+ (struct ZFW_CTRL *)(cinfo->base_addr + firm_id->zfwctrl_addr);
+ ch_ctrl = zfw_ctrl->ch_ctrl;
+
+ ch_ctrl[channel].op_mode = (long)mode;
+
+ return cyz_issue_cmd(cinfo, channel, cmd, 0L);
+
+} /* cyz_update_channel */
+
-/*
- * Release all interrupts grabbed by grab_all_interrupts
- */
static void
-free_all_interrupts(int irq_lines)
+cyz_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
- int i;
-
- for (i = 0; i < 16; i++) {
- if (irq_lines & (1 << i))
- free_irq(i,NULL);
- }
-} /* free_all_interrupts */
+} /* cyz_interrupt */
-/*
- * This routine returns a bitfield of "wild interrupts". Basically,
- * any unclaimed interrupts which is flapping around.
- */
-static int
-check_wild_interrupts(void)
+
+static void
+cyz_poll(unsigned long arg)
{
- int i, mask;
- int wild_interrupts = 0;
- int irq_lines;
- unsigned long timeout;
- unsigned long flags;
-
- /*Turn on interrupts (they may be off) */
- save_flags(flags); sti();
+ struct FIRM_ID *firm_id;
+ struct ZFW_CTRL *zfw_ctrl;
+ struct BOARD_CTRL *board_ctrl;
+ struct CH_CTRL *ch_ctrl;
+ struct BUF_CTRL *buf_ctrl;
+ struct cyclades_card *cinfo;
+ struct cyclades_port *info;
+ struct tty_struct *tty;
+ int card, port;
+ int char_count, small_count;
+ char data;
+ u_long channel;
+ u_char cmd;
+ u_long *param;
- irq_lines = grab_all_interrupts(0);
-
- /*
- * Delay for 0.1 seconds -- we use a busy loop since this may
- * occur during the bootup sequence
- */
- timeout = jiffies+10;
- while (timeout >= jiffies)
- ;
-
- cy_triggered = 0; /* Reset after letting things settle */
-
- timeout = jiffies+10;
- while (timeout >= jiffies)
- ;
-
- for (i = 0, mask = 1; i < 16; i++, mask <<= 1) {
- if ((cy_triggered & (1 << i)) &&
- (irq_lines & (1 << i))) {
- wild_interrupts |= mask;
- }
- }
- free_all_interrupts(irq_lines);
- restore_flags(flags);
- return wild_interrupts;
-} /* check_wild_interrupts */
+ cyz_timerlist.expires = jiffies + 100;
-/*
- * This routine is called by do_auto_irq(); it attempts to determine
- * which interrupt a serial port is configured to use. It is not
- * fool-proof, but it works a large part of the time.
- */
-static int
-get_auto_irq(unsigned char *address)
-{
- unsigned long timeout;
- unsigned char *base_addr;
- int index;
+ for (card = 0 ; card < NR_CARDS ; card++){
+ cinfo = &cy_card[card];
+ if (!IS_CYC_Z(*cinfo)) continue;
- index = 0; /* IRQ probing is only for ISA */
- base_addr = address;
- intr_base_addr = address;
-
- /*
- * Enable interrupts and see who answers
- */
- cy_irq_triggered = 0;
- cli();
- base_addr[CyCAR<<index] = 0;
- write_cy_cmd(base_addr,CyCHAN_CTL|CyENB_XMTR,index);
- base_addr[CySRER<<index] |= CyTxMpty;
- probe_ready = 1;
- sti();
-
- timeout = jiffies+2;
- while (timeout >= jiffies) {
- if (cy_irq_triggered)
- break;
- }
- probe_ready = 0;
- return(cy_irq_triggered);
-} /* get_auto_irq */
+ firm_id = (struct FIRM_ID *)
+ (cinfo->base_addr + ID_ADDRESS);
+ if (firm_id->signature != ZFIRM_ID){
+ continue;
+ }
-/*
- * Calls get_auto_irq() multiple times, to make sure we don't get
- * faked out by random interrupts
- */
-static int
-do_auto_irq(unsigned char *address)
-{
- int irq_lines = 0;
- int irq_try_1 = 0, irq_try_2 = 0;
- int retries;
- unsigned long flags;
+ zfw_ctrl =
+ (struct ZFW_CTRL *)
+ (cinfo->base_addr + firm_id->zfwctrl_addr);
+ board_ctrl = &zfw_ctrl->board_ctrl;
+
+ while( cyz_fetch_msg( cinfo, &channel, &cmd, &param) == 1){
+ char_count = 0;
+ info = &cy_port[ channel + cinfo->first_line ];
+ if((tty = info->tty) == 0) continue;
+ ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]);
+ buf_ctrl = &(zfw_ctrl->buf_ctrl[channel]);
+ info->jiffies[0] = jiffies;
+
+ switch(cmd){
+ case C_CM_PR_ERROR:
+ tty->flip.count++;
+ *tty->flip.flag_buf_ptr++ = TTY_PARITY;
+ *tty->flip.char_buf_ptr++ = 0;
+ char_count++;
+ break;
+ case C_CM_FR_ERROR:
+ tty->flip.count++;
+ *tty->flip.flag_buf_ptr++ = TTY_FRAME;
+ *tty->flip.char_buf_ptr++ = 0;
+ char_count++;
+ break;
+ case C_CM_RXBRK:
+ tty->flip.count++;
+ *tty->flip.flag_buf_ptr++ = TTY_BREAK;
+ *tty->flip.char_buf_ptr++ = 0;
+ char_count++;
+ break;
+ case C_CM_MDCD:
+ if (info->flags & ASYNC_CHECK_CD){
+ if( ch_ctrl[channel].rs_status & C_RS_DCD){
+ /* SP("Open Wakeup\n"); */
+ cy_sched_event(info,
+ Cy_EVENT_OPEN_WAKEUP);
+ }else if(!((info->flags
+ & ASYNC_CALLOUT_ACTIVE)
+ &&(info->flags
+ & ASYNC_CALLOUT_NOHUP))){
+ /* SP("Hangup\n"); */
+ cy_sched_event(info,
+ Cy_EVENT_HANGUP);
+ }
+ }
+ break;
+ case C_CM_MCTS:
+ if (info->flags & ASYNC_CTS_FLOW) {
+ if(info->tty->hw_stopped){
+ if( ch_ctrl[channel].rs_status & C_RS_DCD){
+ /* cy_start isn't used because...
+ HW flow is handled by the board */
+ /* SP("Write Wakeup\n"); */
+ cy_sched_event(info,
+ Cy_EVENT_WRITE_WAKEUP);
+ }
+ }else{
+ if(!(ch_ctrl[channel].rs_status & C_RS_CTS)){
+ /* cy_stop isn't used because
+ HW flow is handled by the board */
+ /* SP("Write stop\n"); */
+ }
+ }
+ }
+ break;
+ case C_CM_MRI:
+ break;
+ case C_CM_MDSR:
+ break;
+ case C_CM_FATAL:
+ /* should do something with this !!! */
+ break;
+ }
+ if(char_count){
+ queue_task(&tty->flip.tqueue, &tq_timer);
+ }
+ }
- /* Turn on interrupts (they may be off) */
- save_flags(flags); sti();
+ for (port = 0; port < board_ctrl->n_channel; port++){
+ info = &cy_port[ port + cinfo->first_line ];
+ tty = info->tty;
+ ch_ctrl = &(zfw_ctrl->ch_ctrl[port]);
+ buf_ctrl = &(zfw_ctrl->buf_ctrl[port]);
- probe_ready = 0;
+ if ((char_count = CHARS_IN_BUF(buf_ctrl))){
+ info->last_active = jiffies;
+ info->jiffies[1] = jiffies;
- cy_wild_int_mask = check_wild_interrupts();
+#ifdef CYCLOM_ENABLE_MONITORING
+ info->mon.int_count++;
+ info->mon.char_count += char_count;
+ if (char_count > info->mon.char_max)
+ info->mon.char_max = char_count;
+ info->mon.char_last = char_count;
+#endif
+ if( tty == 0){
+ /* flush received characters */
+ buf_ctrl->rx_get =
+ (buf_ctrl->rx_get + char_count)
+ % buf_ctrl->rx_bufsize;
+ /* SP("-"); */
+ info->rflush_count++;
+ }else{
+#ifdef BLOCKMOVE
+ /* we'd like to use memcpy(t, f, n) and memset(s, c, count)
+ for performance, but because of buffer boundaries, there
+ may be several steps to the operation */
+ while(0 < (small_count
+ = cy_min( (buf_ctrl->rx_bufsize - buf_ctrl->rx_get),
+ cy_min( (TTY_FLIPBUF_SIZE - tty->flip.count),
+ char_count)))){
+ memcpy(tty->flip.char_buf_ptr,
+ (char *)(cinfo->base_addr
+ + buf_ctrl->rx_bufaddr
+ + buf_ctrl->rx_get),
+ small_count);
+ tty->flip.char_buf_ptr += small_count;
+ memset(tty->flip.flag_buf_ptr,
+ TTY_NORMAL,
+ small_count);
+ tty->flip.flag_buf_ptr += small_count;
+ buf_ctrl->rx_get =
+ (buf_ctrl->rx_get + small_count)
+ % buf_ctrl->rx_bufsize;
+ char_count -= small_count;
+ tty->flip.count += small_count;
+ }
+#else
+ while(char_count--){
+ if (tty->flip.count >= TTY_FLIPBUF_SIZE){
+ break;
+ }
+ data = *(char *) (cinfo->base_addr +
+ buf_ctrl->rx_bufaddr +
+ buf_ctrl->rx_get);
+ buf_ctrl->rx_get =
+ (buf_ctrl->rx_get + 1)
+ % buf_ctrl->rx_bufsize;
+
+ tty->flip.count++;
+ *tty->flip.flag_buf_ptr++ = TTY_NORMAL;
+ *tty->flip.char_buf_ptr++ = data;
+ }
+#endif
+ queue_task(&tty->flip.tqueue, &tq_timer);
+ }
+ }
- irq_lines = grab_all_interrupts(cy_wild_int_mask);
-
- for (retries = 0; retries < 5; retries++) {
- if (!irq_try_1)
- irq_try_1 = get_auto_irq(address);
- if (!irq_try_2)
- irq_try_2 = get_auto_irq(address);
- if (irq_try_1 && irq_try_2) {
- if (irq_try_1 == irq_try_2)
- break;
- irq_try_1 = irq_try_2 = 0;
+ if ((char_count = SPACE_IN_BUF(buf_ctrl))){
+ if( tty == 0){
+ goto ztxdone;
+ }
+
+ if(info->x_char) { /* send special char */
+ data = info->x_char;
+
+ *(char *) (cinfo->base_addr +
+ buf_ctrl->tx_bufaddr +
+ buf_ctrl->tx_put) = data;
+ buf_ctrl->tx_put =
+ (buf_ctrl->tx_put + 1)
+ % buf_ctrl->tx_bufsize;
+ info->x_char = 0;
+ char_count--;
+ info->last_active = jiffies;
+ info->jiffies[2] = jiffies;
+ }
+ if (info->x_break){
+ printk("cyc cyz_poll shouldn't see x_break\n");
+ info->x_break = 0;
+ info->last_active = jiffies;
+ info->jiffies[2] = jiffies;
+ }
+#ifdef BLOCKMOVE
+ while(0 < (small_count
+ = cy_min( (buf_ctrl->tx_bufsize - buf_ctrl->tx_put),
+ cy_min ( (PAGE_SIZE - info->xmit_tail),
+ cy_min( info->xmit_cnt, char_count))))){
+ memcpy((char *)(cinfo->base_addr
+ + buf_ctrl->tx_bufaddr
+ + buf_ctrl->tx_put),
+ &info->xmit_buf[info->xmit_tail],
+ small_count);
+ buf_ctrl->tx_put =
+ (buf_ctrl->tx_put + small_count)
+ % buf_ctrl->tx_bufsize;
+ char_count -= small_count;
+ info->xmit_cnt -= small_count;
+ info->xmit_tail =
+ (info->xmit_tail + small_count) & (PAGE_SIZE - 1);
+ info->last_active = jiffies;
+ info->jiffies[2] = jiffies;
+ }
+#else
+ while (info->xmit_cnt && char_count){
+ data = info->xmit_buf[info->xmit_tail];
+ info->xmit_cnt--;
+ info->xmit_tail =
+ (info->xmit_tail + 1) & (PAGE_SIZE - 1);
+
+ *(char *) (cinfo->base_addr +
+ buf_ctrl->tx_bufaddr +
+ buf_ctrl->tx_put) = data;
+ buf_ctrl->tx_put =
+ (buf_ctrl->tx_put + 1)
+ % buf_ctrl->tx_bufsize;
+ char_count--;
+ info->last_active = jiffies;
+ info->jiffies[2] = jiffies;
+ }
+#endif
+ ztxdone:
+ if (info->xmit_cnt < WAKEUP_CHARS) {
+ cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP);
+ }
}
}
- restore_flags(flags);
- free_all_interrupts(irq_lines);
- return (irq_try_1 == irq_try_2) ? irq_try_1 : 0;
-} /* do_auto_irq */
+
+ /* poll every 40 ms */
+ cyz_timerlist.expires = jiffies + 4;
+ }
+ add_timer(&cyz_timerlist);
+
+ return;
+} /* cyz_poll */
+
+
+/********** End of block of Cyclom-Z specific code *********/
+/***********************************************************/
/* This is called whenever a port becomes active;
@@ -1217,72 +1724,130 @@ startup(struct cyclades_port * info)
int card,chip,channel,index;
if (info->flags & ASYNC_INITIALIZED){
- return 0;
+ return 0;
}
if (!info->type){
- if (info->tty){
- set_bit(TTY_IO_ERROR, &info->tty->flags);
- }
- return 0;
+ if (info->tty){
+ set_bit(TTY_IO_ERROR, &info->tty->flags);
+ }
+ return 0;
}
if (!info->xmit_buf){
- info->xmit_buf = (unsigned char *) get_free_page (GFP_KERNEL);
- if (!info->xmit_buf){
- return -ENOMEM;
- }
+ info->xmit_buf = (unsigned char *) get_free_page (GFP_KERNEL);
+ if (!info->xmit_buf){
+ return -ENOMEM;
+ }
}
- config_setup(info);
+ set_line_char(info);
card = info->card;
channel = (info->line) - (cy_card[card].first_line);
- chip = channel>>2;
- channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr = (unsigned char*)
+ if (!IS_CYC_Z(cy_card[card])) {
+ chip = channel>>2;
+ channel &= 0x03;
+ index = cy_card[card].bus_index;
+ base_addr = (unsigned char*)
(cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
#ifdef SERIAL_DEBUG_OPEN
- printk("startup card %d, chip %d, channel %d, base_addr %lx",
- card, chip, channel, (long)base_addr);/**/
+ printk("cyc startup card %d, chip %d, channel %d, base_addr %lx\n",
+ card, chip, channel, (long)base_addr);/**/
#endif
- save_flags(flags); cli();
- base_addr[CyCAR<<index] = (u_char)channel;
+ save_flags(flags); cli();
+ base_addr[CyCAR<<index] = (u_char)channel;
- base_addr[CyRTPR<<index] = (info->default_timeout
- ? info->default_timeout
- : 0x02); /* 10ms rx timeout */
+ base_addr[CyRTPR<<index] = (info->default_timeout
+ ? info->default_timeout
+ : 0x02); /* 10ms rx timeout */
- write_cy_cmd(base_addr,CyCHAN_CTL|CyENB_RCVR|CyENB_XMTR,index);
+ cyy_issue_cmd(base_addr,CyCHAN_CTL|CyENB_RCVR|CyENB_XMTR,index);
- base_addr[CyCAR<<index] = (u_char)channel; /* !!! Is this needed? */
- base_addr[CyMSVR1<<index] = CyRTS;
- base_addr[CyMSVR2<<index] = CyDTR;
+ base_addr[CyCAR<<index] =
+ (u_char)channel; /* !!! Is this needed? */
+ base_addr[CyMSVR1<<index] = CyRTS;
+ base_addr[CyMSVR2<<index] = CyDTR;
#ifdef SERIAL_DEBUG_DTR
- printk("cyc: %d: raising DTR\n", __LINE__);
- printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1<<index], base_addr[CyMSVR2<<index]);
+ printk("cyc:startup raising DTR\n");
+ printk(" status: 0x%x, 0x%x\n",
+ base_addr[CyMSVR1<<index], base_addr[CyMSVR2<<index]);
#endif
- base_addr[CySRER<<index] |= CyRxData;
- info->flags |= ASYNC_INITIALIZED;
+ base_addr[CySRER<<index] |= CyRxData;
+ info->flags |= ASYNC_INITIALIZED;
+ if (info->tty){
+ clear_bit(TTY_IO_ERROR, &info->tty->flags);
+ }
+ info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+ restore_flags(flags);
+ } else {
+ struct FIRM_ID *firm_id;
+ struct ZFW_CTRL *zfw_ctrl;
+ struct BOARD_CTRL *board_ctrl;
+ struct CH_CTRL *ch_ctrl;
+ int retval;
+
+ base_addr = (unsigned char*) (cy_card[card].base_addr);
+
+ firm_id = (struct FIRM_ID *) (base_addr + ID_ADDRESS);
+ if (firm_id->signature != ZFIRM_ID){
+ return -ENODEV;
+ }
+
+ zfw_ctrl =
+ (struct ZFW_CTRL *)
+ (cy_card[card].base_addr + firm_id->zfwctrl_addr);
+ board_ctrl = &zfw_ctrl->board_ctrl;
+ ch_ctrl = zfw_ctrl->ch_ctrl;
+
+#ifdef SERIAL_DEBUG_OPEN
+ printk("cyc startup Z card %d, channel %d, base_addr %lx\n",
+ card, channel, (long)base_addr);/**/
+#endif
+
+ ch_ctrl[channel].op_mode = C_CH_ENABLE;
+ ch_ctrl[channel].intr_enable = C_IN_MDCD|C_IN_MCTS;
+ retval = cyz_issue_cmd( &cy_card[card],
+ channel, C_CM_IOCTL, 0L); /* was C_CM_RESET */
+ if (retval != 0){
+ printk("cyc:startup(1) retval was %x\n", retval);
+ }
+
+ /* set timeout !!! */
+ /* set RTS and DTR !!! */
+ ch_ctrl[channel].rs_control |=
+ C_RS_RTS | C_RS_DTR ;
+ retval = cyz_issue_cmd(&cy_card[info->card],
+ channel, C_CM_IOCTLM, 0L);
+ if (retval != 0){
+ printk("cyc:startup(2) retval was %x\n", retval);
+ }
+#ifdef SERIAL_DEBUG_DTR
+ printk("cyc:startup raising Z DTR\n");
+#endif
+
+ /* enable send, recv, modem !!! */
+
+ info->flags |= ASYNC_INITIALIZED;
if (info->tty){
clear_bit(TTY_IO_ERROR, &info->tty->flags);
}
info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
- restore_flags(flags);
+ }
#ifdef SERIAL_DEBUG_OPEN
- printk(" done\n");
+ printk(" cyc startup done\n");
#endif
- return 0;
+ return 0;
} /* startup */
-void
+
+static void
start_xmit( struct cyclades_port *info )
{
unsigned long flags;
@@ -1291,18 +1856,24 @@ start_xmit( struct cyclades_port *info )
card = info->card;
channel = (info->line) - (cy_card[card].first_line);
- chip = channel>>2;
- channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr = (unsigned char*)
- (cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
+ if (!IS_CYC_Z(cy_card[card])) {
+ chip = channel>>2;
+ channel &= 0x03;
+ index = cy_card[card].bus_index;
+ base_addr = (unsigned char*)
+ (cy_card[card].base_addr
+ + (cy_chip_offset[chip]<<index));
- save_flags(flags); cli();
- base_addr[CyCAR<<index] = channel;
- base_addr[CySRER<<index] |= CyTxMpty;
- restore_flags(flags);
+ save_flags(flags); cli();
+ base_addr[CyCAR<<index] = channel;
+ base_addr[CySRER<<index] |= CyTxMpty;
+ restore_flags(flags);
+ } else {
+ /* Don't have to do anything at this time */
+ }
} /* start_xmit */
+
/*
* This routine shuts down a serial port; interrupts are disabled,
* and DTR is dropped if the hangup on close termio flag is on.
@@ -1315,326 +1886,535 @@ shutdown(struct cyclades_port * info)
int card,chip,channel,index;
if (!(info->flags & ASYNC_INITIALIZED)){
- return;
+ return;
}
card = info->card;
channel = info->line - cy_card[card].first_line;
- chip = channel>>2;
- channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr = (unsigned char*)
- (cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
+ if (!IS_CYC_Z(cy_card[card])) {
+ chip = channel>>2;
+ channel &= 0x03;
+ index = cy_card[card].bus_index;
+ base_addr = (unsigned char*)
+ (cy_card[card].base_addr
+ + (cy_chip_offset[chip]<<index));
#ifdef SERIAL_DEBUG_OPEN
- printk("shutdown card %d, chip %d, channel %d, base_addr %lx\n",
- card, chip, channel, (long)base_addr);
+ printk("cyc shutdown Y card %d, chip %d, channel %d, base_addr %lx\n",
+ card, chip, channel, (long)base_addr);
#endif
- /* !!! REALLY MUST WAIT FOR LAST CHARACTER TO BE
- SENT BEFORE DROPPING THE LINE !!! (Perhaps
- set some flag that is read when XMTY happens.)
- Other choices are to delay some fixed interval
- or schedule some later processing.
- */
- save_flags(flags); cli();
- if (info->xmit_buf){
- unsigned char * temp;
- temp = info->xmit_buf;
- info->xmit_buf = 0;
- free_page((unsigned long) temp);
- }
+ /* REALLY SHOULD WAIT FOR LAST CHARACTER TO BE
+ SENT BEFORE DROPPING THE LINE !!! (Perhaps
+ set some flag that is read when XMTY happens.)
+ Other choices are to delay some fixed interval
+ or schedule some later processing.
+ */
+ save_flags(flags); cli();
+ if (info->xmit_buf){
+ unsigned char * temp;
+ temp = info->xmit_buf;
+ info->xmit_buf = 0;
+ free_page((unsigned long) temp);
+ }
- base_addr[CyCAR<<index] = (u_char)channel;
- if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
- base_addr[CyMSVR1<<index] = ~CyRTS;
- base_addr[CyMSVR2<<index] = ~CyDTR;
+ base_addr[CyCAR<<index] = (u_char)channel;
+ if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
+ base_addr[CyMSVR1<<index] = ~CyRTS;
+ base_addr[CyMSVR2<<index] = ~CyDTR;
#ifdef SERIAL_DEBUG_DTR
- printk("cyc: %d: dropping DTR\n", __LINE__);
- printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1<<index], base_addr[CyMSVR2<<index]);
+ printk("cyc shutdown dropping DTR\n");
+ printk(" status: 0x%x, 0x%x\n",
+ base_addr[CyMSVR1<<index], base_addr[CyMSVR2<<index]);
#endif
- }
- write_cy_cmd(base_addr,CyCHAN_CTL|CyDIS_RCVR,index);
- /* it may be appropriate to clear _XMIT at
- some later date (after testing)!!! */
+ }
+ cyy_issue_cmd(base_addr,CyCHAN_CTL|CyDIS_RCVR,index);
+ /* it may be appropriate to clear _XMIT at
+ some later date (after testing)!!! */
- if (info->tty){
- set_bit(TTY_IO_ERROR, &info->tty->flags);
+ if (info->tty){
+ set_bit(TTY_IO_ERROR, &info->tty->flags);
+ }
+ info->flags &= ~ASYNC_INITIALIZED;
+ restore_flags(flags);
+ } else {
+ struct FIRM_ID *firm_id;
+ struct ZFW_CTRL *zfw_ctrl;
+ struct BOARD_CTRL *board_ctrl;
+ struct CH_CTRL *ch_ctrl;
+ int retval;
+
+ base_addr = (unsigned char*) (cy_card[card].base_addr);
+#ifdef SERIAL_DEBUG_OPEN
+ printk("cyc shutdown Z card %d, channel %d, base_addr %lx\n",
+ card, channel, (long)base_addr);
+#endif
+
+ firm_id = (struct FIRM_ID *) (base_addr + ID_ADDRESS);
+ if (firm_id->signature != ZFIRM_ID){
+ return;
}
- info->flags &= ~ASYNC_INITIALIZED;
- restore_flags(flags);
+
+ zfw_ctrl =
+ (struct ZFW_CTRL *)
+ (cy_card[card].base_addr + firm_id->zfwctrl_addr);
+ board_ctrl = &zfw_ctrl->board_ctrl;
+ ch_ctrl = zfw_ctrl->ch_ctrl;
+
+ save_flags(flags); cli();
+ if (info->xmit_buf){
+ unsigned char * temp;
+ temp = info->xmit_buf;
+ info->xmit_buf = 0;
+ free_page((unsigned long) temp);
+ }
+ if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
+ ch_ctrl[channel].rs_control &=
+ ~(C_RS_RTS | C_RS_DTR );
+ retval = cyz_issue_cmd(&cy_card[info->card],
+ channel, C_CM_IOCTLM, 0L);
+ if (retval != 0){
+ printk("cyc:shutdown retval was %x\n",
+ retval);
+ }
+#ifdef SERIAL_DEBUG_DTR
+ printk("cyc:shutdown dropping Z DTR\n");
+#endif
+ }
+
+ if (info->tty){
+ set_bit(TTY_IO_ERROR, &info->tty->flags);
+ }
+ info->flags &= ~ASYNC_INITIALIZED;
+
+ restore_flags(flags);
+ }
#ifdef SERIAL_DEBUG_OPEN
- printk(" done\n");
+ printk(" cyc shutdown done\n");
#endif
return;
} /* shutdown */
+
/*
- * This routine finds or computes the various line characteristics.
+ * ------------------------------------------------------------
+ * cy_open() and friends
+ * ------------------------------------------------------------
*/
-static void
-config_setup(struct cyclades_port * info)
+
+static int
+block_til_ready(struct tty_struct *tty, struct file * filp,
+ struct cyclades_port *info)
{
+ struct wait_queue wait = { current, NULL };
+ struct cyclades_card *cinfo;
unsigned long flags;
- unsigned char *base_addr;
- int card,chip,channel,index;
- unsigned cflag;
- int i;
-
- if (!info->tty || !info->tty->termios){
- return;
- }
- if (info->line == -1){
- return;
- }
- cflag = info->tty->termios->c_cflag;
+ int chip, channel,index;
+ int retval;
+ char *base_addr;
- /* baud rate */
- i = cflag & CBAUD;
-#ifdef CBAUDEX
-/* Starting with kernel 1.1.65, there is direct support for
- higher baud rates. The following code supports those
- changes. The conditional aspect allows this driver to be
- used for earlier as well as later kernel versions. (The
- mapping is slightly different from serial.c because there
- is still the possibility of supporting 75 kbit/sec with
- the Cyclades board.)
- */
- if (i & CBAUDEX) {
- if (i == B57600)
- i = 16;
- else if(i == B115200)
- i = 18;
-#ifdef B78600
- else if(i == B78600)
- i = 17;
-#endif
- else
- info->tty->termios->c_cflag &= ~CBAUDEX;
- }
-#endif
- if (i == 15) {
- if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
- i += 1;
- if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
- i += 3;
- }
- info->tbpr = baud_bpr[i]; /* Tx BPR */
- info->tco = baud_co[i]; /* Tx CO */
- info->rbpr = baud_bpr[i]; /* Rx BPR */
- info->rco = baud_co[i]; /* Rx CO */
- if (baud_table[i] == 134) {
- info->timeout = (info->xmit_fifo_size*HZ*30/269) + 2;
- /* get it right for 134.5 baud */
- } else if (baud_table[i]) {
- info->timeout = (info->xmit_fifo_size*HZ*15/baud_table[i]) + 2;
- /* this needs to be propagated into the card info */
- } else {
- info->timeout = 0;
- }
- /* By tradition (is it a standard?) a baud rate of zero
- implies the line should be/has been closed. A bit
- later in this routine such a test is performed. */
-
- /* byte size and parity */
- info->cor5 = 0;
- info->cor4 = 0;
- info->cor3 = (info->default_threshold
- ? info->default_threshold
- : baud_cor3[i]); /* receive threshold */
- info->cor2 = CyETC;
- switch(cflag & CSIZE){
- case CS5:
- info->cor1 = Cy_5_BITS;
- break;
- case CS6:
- info->cor1 = Cy_6_BITS;
- break;
- case CS7:
- info->cor1 = Cy_7_BITS;
- break;
- case CS8:
- info->cor1 = Cy_8_BITS;
- break;
- }
- if(cflag & CSTOPB){
- info->cor1 |= Cy_2_STOP;
- }
- if (cflag & PARENB){
- if (cflag & PARODD){
- info->cor1 |= CyPARITY_O;
+ /*
+ * If the device is in the middle of being closed, then block
+ * until it's done, and then try again.
+ */
+ if (info->flags & ASYNC_CLOSING) {
+ interruptible_sleep_on(&info->close_wait);
+ if (info->flags & ASYNC_HUP_NOTIFY){
+ return -EAGAIN;
}else{
- info->cor1 |= CyPARITY_E;
+ return -ERESTARTSYS;
}
- }else{
- info->cor1 |= CyPARITY_NONE;
}
-
- /* CTS flow control flag */
- if (cflag & CRTSCTS){
- info->flags |= ASYNC_CTS_FLOW;
- info->cor2 |= CyCtsAE;
- }else{
- info->flags &= ~ASYNC_CTS_FLOW;
- info->cor2 &= ~CyCtsAE;
- }
- if (cflag & CLOCAL)
- info->flags &= ~ASYNC_CHECK_CD;
- else
- info->flags |= ASYNC_CHECK_CD;
-
- /***********************************************
- The hardware option, CyRtsAO, presents RTS when
- the chip has characters to send. Since most modems
- use RTS as reverse (inbound) flow control, this
- option is not used. If inbound flow control is
- necessary, DTR can be programmed to provide the
- appropriate signals for use with a non-standard
- cable. Contact Marcio Saito for details.
- ***********************************************/
- card = info->card;
- channel = (info->line) - (cy_card[card].first_line);
- chip = channel>>2;
- channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr = (unsigned char*)
- (cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
-
- save_flags(flags); cli();
- base_addr[CyCAR<<index] = (u_char)channel;
-
- /* tx and rx baud rate */
-
- base_addr[CyTCOR<<index] = info->tco;
- base_addr[CyTBPR<<index] = info->tbpr;
- base_addr[CyRCOR<<index] = info->rco;
- base_addr[CyRBPR<<index] = info->rbpr;
-
- /* set line characteristics according configuration */
-
- base_addr[CySCHR1<<index] = START_CHAR(info->tty);
- base_addr[CySCHR2<<index] = STOP_CHAR(info->tty);
- base_addr[CyCOR1<<index] = info->cor1;
- base_addr[CyCOR2<<index] = info->cor2;
- base_addr[CyCOR3<<index] = info->cor3;
- base_addr[CyCOR4<<index] = info->cor4;
- base_addr[CyCOR5<<index] = info->cor5;
-
- write_cy_cmd(base_addr,CyCOR_CHANGE|CyCOR1ch|CyCOR2ch|CyCOR3ch,index);
-
- base_addr[CyCAR<<index] = (u_char)channel; /* !!! Is this needed? */
+ /*
+ * If this is a callout device, then just make sure the normal
+ * device isn't being used.
+ */
+ if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
+ if (info->flags & ASYNC_NORMAL_ACTIVE){
+ return -EBUSY;
+ }
+ if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+ (info->flags & ASYNC_SESSION_LOCKOUT) &&
+ (info->session != current->session)){
+ return -EBUSY;
+ }
+ if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+ (info->flags & ASYNC_PGRP_LOCKOUT) &&
+ (info->pgrp != current->pgrp)){
+ return -EBUSY;
+ }
+ info->flags |= ASYNC_CALLOUT_ACTIVE;
+ return 0;
+ }
- base_addr[CyRTPR<<index] = (info->default_timeout
- ? info->default_timeout
- : 0x02); /* 10ms rx timeout */
+ /*
+ * If non-blocking mode is set, then make the check up front
+ * and then exit.
+ */
+ if (filp->f_flags & O_NONBLOCK) {
+ if (info->flags & ASYNC_CALLOUT_ACTIVE){
+ return -EBUSY;
+ }
+ info->flags |= ASYNC_NORMAL_ACTIVE;
+ return 0;
+ }
- if (C_CLOCAL(info->tty)) {
- base_addr[CySRER<<index] |= CyMdmCh; /* without modem intr */
- /* act on 1->0 modem transitions */
- base_addr[CyMCOR1<<index] = CyCTS;
- /* act on 0->1 modem transitions */
- base_addr[CyMCOR2<<index] = CyCTS;
- } else {
- base_addr[CySRER<<index] |= CyMdmCh; /* with modem intr */
- /* act on 1->0 modem transitions */
- base_addr[CyMCOR1<<index] = CyDSR|CyCTS|CyRI|CyDCD;
- /* act on 0->1 modem transitions */
- base_addr[CyMCOR2<<index] = CyDSR|CyCTS|CyRI|CyDCD;
- }
+ /*
+ * Block waiting for the carrier detect and the line to become
+ * free (i.e., not in use by the callout). While we are in
+ * this loop, info->count is dropped by one, so that
+ * cy_close() knows when to free things. We restore it upon
+ * exit, either normal or abnormal.
+ */
+ retval = 0;
+ add_wait_queue(&info->open_wait, &wait);
+#ifdef SERIAL_DEBUG_OPEN
+ printk("cyc block_til_ready before block: ttyC%d, count = %d\n",
+ info->line, info->count);/**/
+#endif
+ info->count--;
+#ifdef SERIAL_DEBUG_COUNT
+ printk("cyc block_til_ready: (%d): decrementing count to %d\n",
+ current->pid, info->count);
+#endif
+ info->blocked_open++;
- if(i == 0){ /* baud rate is zero, turn off line */
- base_addr[CyMSVR2<<index] = ~CyDTR;
+ cinfo = &cy_card[info->card];
+ channel = info->line - cinfo->first_line;
+ if (!IS_CYC_Z(*cinfo)) {
+ chip = channel>>2;
+ channel &= 0x03;
+ index = cinfo->bus_index;
+ base_addr = (char *)(cinfo->base_addr
+ + (cy_chip_offset[chip]<<index));
+
+ while (1) {
+ save_flags(flags); cli();
+ if (!(info->flags & ASYNC_CALLOUT_ACTIVE)){
+ base_addr[CyCAR<<index] = (u_char)channel;
+ base_addr[CyMSVR1<<index] = CyRTS;
+ base_addr[CyMSVR2<<index] = CyDTR;
#ifdef SERIAL_DEBUG_DTR
- printk("cyc: %d: dropping DTR\n", __LINE__);
- printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1<<index], base_addr[CyMSVR2<<index]);
+ printk("cyc:block_til_ready raising DTR\n");
+ printk(" status: 0x%x, 0x%x\n",
+ base_addr[CyMSVR1<<index], base_addr[CyMSVR2<<index]);
#endif
- }else{
- base_addr[CyMSVR2<<index] = CyDTR;
-#ifdef SERIAL_DEBUG_DTR
- printk("cyc: %d: raising DTR\n", __LINE__);
- printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1<<index], base_addr[CyMSVR2<<index]);
+ }
+ restore_flags(flags);
+ current->state = TASK_INTERRUPTIBLE;
+ if (tty_hung_up_p(filp)
+ || !(info->flags & ASYNC_INITIALIZED) ){
+ if (info->flags & ASYNC_HUP_NOTIFY) {
+ retval = -EAGAIN;
+ }else{
+ retval = -ERESTARTSYS;
+ }
+ break;
+ }
+ save_flags(flags); cli();
+ base_addr[CyCAR<<index] = (u_char)channel;
+ if (!(info->flags & ASYNC_CALLOUT_ACTIVE)
+ && !(info->flags & ASYNC_CLOSING)
+ && (C_CLOCAL(tty)
+ || (base_addr[CyMSVR1<<index] & CyDCD))) {
+ restore_flags(flags);
+ break;
+ }
+ restore_flags(flags);
+ if (current->signal & ~current->blocked) {
+ retval = -ERESTARTSYS;
+ break;
+ }
+#ifdef SERIAL_DEBUG_OPEN
+ printk("cyc block_til_ready blocking: ttyC%d, count = %d\n",
+ info->line, info->count);/**/
#endif
+ schedule();
}
-
- if (info->tty){
- clear_bit(TTY_IO_ERROR, &info->tty->flags);
+ } else {
+ struct FIRM_ID *firm_id;
+ struct ZFW_CTRL *zfw_ctrl;
+ struct BOARD_CTRL *board_ctrl;
+ struct CH_CTRL *ch_ctrl;
+ int retval;
+
+ base_addr = (char *)(cinfo->base_addr);
+ firm_id = (struct FIRM_ID *)
+ (base_addr + ID_ADDRESS);
+ if (firm_id->signature != ZFIRM_ID){
+ return -EINVAL;
}
- restore_flags(flags);
+ zfw_ctrl =
+ (struct ZFW_CTRL *)
+ (base_addr + firm_id->zfwctrl_addr);
+ board_ctrl = &zfw_ctrl->board_ctrl;
+ ch_ctrl = zfw_ctrl->ch_ctrl;
+
+ while (1) {
+ ch_ctrl[channel].rs_control |=
+ C_RS_RTS | C_RS_DTR ;
+ retval = cyz_issue_cmd(&cy_card[info->card],
+ channel, C_CM_IOCTLM, 0L);
+ if (retval != 0){
+ printk("cyc:block_til_ready retval was %x\n", retval);
+ }
+#ifdef SERIAL_DEBUG_DTR
+ printk("cyc:block_til_ready raising Z DTR\n");
+#endif
-} /* config_setup */
+ current->state = TASK_INTERRUPTIBLE;
+ if (tty_hung_up_p(filp)
+ || !(info->flags & ASYNC_INITIALIZED) ){
+ if (info->flags & ASYNC_HUP_NOTIFY) {
+ retval = -EAGAIN;
+ }else{
+ retval = -ERESTARTSYS;
+ }
+ break;
+ }
+ if (!(info->flags & ASYNC_CALLOUT_ACTIVE)
+ && !(info->flags & ASYNC_CLOSING)
+ && (C_CLOCAL(tty)
+ || (ch_ctrl[channel].rs_status & C_RS_DCD))) {
+ break;
+ }
+ if (current->signal & ~current->blocked) {
+ retval = -ERESTARTSYS;
+ break;
+ }
+#ifdef SERIAL_DEBUG_OPEN
+ printk("cyc block_til_ready blocking: ttyC%d, count = %d\n",
+ info->line, info->count);/**/
+#endif
+ schedule();
+ }
+ }
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&info->open_wait, &wait);
+ if (!tty_hung_up_p(filp)){
+ info->count++;
+#ifdef SERIAL_DEBUG_COUNT
+ printk("cyc:block_til_ready (%d): incrementing count to %d\n",
+ current->pid, info->count);
+#endif
+ }
+ info->blocked_open--;
+#ifdef SERIAL_DEBUG_OPEN
+ printk("cyc:block_til_ready after blocking: ttyC%d, count = %d\n",
+ info->line, info->count);/**/
+#endif
+ if (retval)
+ return retval;
+ info->flags |= ASYNC_NORMAL_ACTIVE;
+ return 0;
+} /* block_til_ready */
-static void
-cy_put_char(struct tty_struct *tty, unsigned char ch)
+/*
+ * This routine is called whenever a serial port is opened. It
+ * performs the serial-specific initialization for the tty structure.
+ */
+int
+cy_open(struct tty_struct *tty, struct file * filp)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
- unsigned long flags;
+ struct cyclades_port *info;
+ int retval, line;
-#ifdef SERIAL_DEBUG_IO
- printk("cy_put_char ttyC%d\n", info->line);
+ line = MINOR(tty->device) - tty->driver.minor_start;
+ if ((line < 0) || (NR_PORTS <= line)){
+ return -ENODEV;
+ }
+ info = &cy_port[line];
+ if (info->line < 0){
+ return -ENODEV;
+ }
+
+ /* If the card's firmware hasn't been loaded,
+ treat it as absent from the system. This
+ will make the user pay attention.
+ */
+ if (IS_CYC_Z(cy_card[info->card])) {
+ struct FIRM_ID *firm_id =
+ (struct FIRM_ID *)
+ (cy_card[info->card].base_addr + ID_ADDRESS);
+ if (firm_id->signature != ZFIRM_ID){
+ printk("Cyclom-Z firmware not yet loaded\n");
+ return -ENODEV;
+ }
+ }
+#ifdef SERIAL_DEBUG_OTHER
+ printk("cyc:cy_open ttyC%d\n", info->line); /* */
+#endif
+ if (serial_paranoia_check(info, tty->device, "cy_open")){
+ return -ENODEV;
+ }
+#ifdef SERIAL_DEBUG_OPEN
+ printk("cyc:cy_open ttyC%d, count = %d\n",
+ info->line, info->count);/**/
+#endif
+ info->count++;
+#ifdef SERIAL_DEBUG_COUNT
+ printk("cyc:cy_open (%d): incrementing count to %d\n",
+ current->pid, info->count);
#endif
+ tty->driver_data = info;
+ info->tty = tty;
- if (serial_paranoia_check(info, tty->device, "cy_put_char"))
- return;
+ /* Some drivers have (incorrect/incomplete) code to test
+ against a race condition. Should add good code here!!! */
+ if (!tmp_buf) {
+ tmp_buf = (unsigned char *) get_free_page(GFP_KERNEL);
+ if (!tmp_buf){
+ return -ENOMEM;
+ }
+ }
- if (!tty || !info->xmit_buf)
- return;
+ if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) {
+ if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
+ *tty->termios = info->normal_termios;
+ else
+ *tty->termios = info->callout_termios;
+ }
+ /*
+ * Start up serial port
+ */
+ retval = startup(info);
+ if (retval){
+ return retval;
+ }
- save_flags(flags); cli();
- if (info->xmit_cnt >= PAGE_SIZE - 1) {
- restore_flags(flags);
- return;
- }
+ MOD_INC_USE_COUNT;
- info->xmit_buf[info->xmit_head++] = ch;
- info->xmit_head &= PAGE_SIZE - 1;
- info->xmit_cnt++;
- restore_flags(flags);
-} /* cy_put_char */
+ retval = block_til_ready(tty, filp, info);
+ if (retval) {
+#ifdef SERIAL_DEBUG_OPEN
+ printk("cyc:cy_open returning after block_til_ready with %d\n",
+ retval);
+#endif
+ return retval;
+ }
+
+ info->session = current->session;
+ info->pgrp = current->pgrp;
+
+#ifdef SERIAL_DEBUG_OPEN
+ printk(" cyc:cy_open done\n");/**/
+#endif
+ return 0;
+} /* cy_open */
+/*
+ * This routine is called when a particular tty device is closed.
+ */
static void
-cy_flush_chars(struct tty_struct *tty)
+cy_close(struct tty_struct * tty, struct file * filp)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ struct cyclades_port * info = (struct cyclades_port *)tty->driver_data;
unsigned long flags;
- unsigned char *base_addr;
- int card,chip,channel,index;
-
-#ifdef SERIAL_DEBUG_IO
- printk("cy_flush_chars ttyC%d\n", info->line); /* */
+
+#ifdef SERIAL_DEBUG_OTHER
+ printk("cyc:cy_close ttyC%d\n", info->line);
#endif
- if (serial_paranoia_check(info, tty->device, "cy_flush_chars"))
- return;
+ if (!info
+ || serial_paranoia_check(info, tty->device, "cy_close")){
+ return;
+ }
+#ifdef SERIAL_DEBUG_OPEN
+ printk("cyc:cy_close ttyC%d, count = %d\n", info->line, info->count);
+#endif
- if (info->xmit_cnt <= 0 || tty->stopped
- || tty->hw_stopped || !info->xmit_buf)
- return;
+ save_flags(flags); cli();
- card = info->card;
- channel = info->line - cy_card[card].first_line;
- chip = channel>>2;
- channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr = (unsigned char*)
- (cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
+ /* If the TTY is being hung up, nothing to do */
+ if (tty_hung_up_p(filp)) {
+ restore_flags(flags);
+ return;
+ }
+
+ if ((tty->count == 1) && (info->count != 1)) {
+ /*
+ * Uh, oh. tty->count is 1, which means that the tty
+ * structure will be freed. Info->count should always
+ * be one in these conditions. If it's greater than
+ * one, we've got real problems, since it means the
+ * serial port won't be shutdown.
+ */
+ printk("cyc:cy_close: bad serial port count; tty->count is 1, "
+ "info->count is %d\n", info->count);
+ info->count = 1;
+ }
+#ifdef SERIAL_DEBUG_COUNT
+ printk("cyc:cy_close at (%d): decrementing count to %d\n",
+ current->pid, info->count - 1);
+#endif
+ if (--info->count < 0) {
+#ifdef SERIAL_DEBUG_COUNT
+ printk("cyc:cyc_close setting count to 0\n");
+#endif
+ info->count = 0;
+ }
+ if (info->count) {
+ MOD_DEC_USE_COUNT;
+ restore_flags(flags);
+ return;
+ }
+ info->flags |= ASYNC_CLOSING;
+ /*
+ * Save the termios structure, since this port may have
+ * separate termios for callout and dialin.
+ */
+ if (info->flags & ASYNC_NORMAL_ACTIVE)
+ info->normal_termios = *tty->termios;
+ if (info->flags & ASYNC_CALLOUT_ACTIVE)
+ info->callout_termios = *tty->termios;
+ if (info->flags & ASYNC_INITIALIZED)
+ tty_wait_until_sent(tty, 5*HZ); /* 5 seconds timeout */
+ shutdown(info);
+ if (tty->driver.flush_buffer)
+ tty->driver.flush_buffer(tty);
+ if (tty->ldisc.flush_buffer)
+ tty->ldisc.flush_buffer(tty);
+ info->event = 0;
+ info->tty = 0;
+ if (info->blocked_open) {
+ if (info->close_delay) {
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + info->close_delay;
+ schedule();
+ }
+ wake_up_interruptible(&info->open_wait);
+ }
+ info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
+ ASYNC_CLOSING);
+ wake_up_interruptible(&info->close_wait);
- save_flags(flags); cli();
- base_addr[CyCAR<<index] = channel;
- base_addr[CySRER<<index] |= CyTxMpty;
+#ifdef SERIAL_DEBUG_OTHER
+ printk(" cyc:cy_close done\n");
+#endif
+
+ MOD_DEC_USE_COUNT;
restore_flags(flags);
-} /* cy_flush_chars */
+ return;
+} /* cy_close */
/* This routine gets called when tty_write has put something into
- the write_queue. If the port is not already transmitting stuff,
- start it off by enabling interrupts. The interrupt service
- routine will then ensure that the characters are sent. If the
- port is already active, there is no need to kick it.
+ * the write_queue. The characters may come from user space or
+ * kernel space.
+ *
+ * This routine will return the number of characters actually
+ * accepted for writing.
+ *
+ * If the port is not already transmitting stuff, start it off by
+ * enabling interrupts. The interrupt service routine will then
+ * ensure that the characters are sent.
+ * If the port is already active, there is no need to kick it.
+ *
*/
static int
cy_write(struct tty_struct * tty, int from_user,
@@ -1645,42 +2425,49 @@ cy_write(struct tty_struct * tty, int from_user,
int c, total = 0;
#ifdef SERIAL_DEBUG_IO
- printk("cy_write ttyC%d\n", info->line); /* */
+ printk("cyc:cy_write ttyC%d\n", info->line); /* */
#endif
if (serial_paranoia_check(info, tty->device, "cy_write")){
- return 0;
+ return 0;
}
-
+
if (!tty || !info->xmit_buf || !tmp_buf){
return 0;
}
+ if (from_user)
+ down(&tmp_buf_sem);
while (1) {
- save_flags(flags); cli();
- c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
- SERIAL_XMIT_SIZE - info->xmit_head));
- if (c <= 0){
- restore_flags(flags);
- break;
- }
+ save_flags(flags); cli();
+ c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+ SERIAL_XMIT_SIZE - info->xmit_head));
+ if (c <= 0){
+ restore_flags(flags);
+ break;
+ }
- if (from_user) {
- down(&tmp_buf_sem);
- copy_from_user(tmp_buf, buf, c);
- c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
- SERIAL_XMIT_SIZE - info->xmit_head));
- memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
- up(&tmp_buf_sem);
- } else
- memcpy(info->xmit_buf + info->xmit_head, buf, c);
- info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
- info->xmit_cnt += c;
- restore_flags(flags);
- buf += c;
- count -= c;
- total += c;
+ if (from_user) {
+ memcpy_fromfs(tmp_buf, buf, c);
+ c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+ SERIAL_XMIT_SIZE - info->xmit_head));
+ memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
+ } else
+ memcpy(info->xmit_buf + info->xmit_head, buf, c);
+ info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
+ info->xmit_cnt += c;
+ restore_flags(flags);
+ buf += c;
+ count -= c;
+ total += c;
+#if 0
+ SP("CW");
+ CP16(c);
+ SP(" ");
+#endif
}
+ if (from_user)
+ up(&tmp_buf_sem);
if (info->xmit_cnt
@@ -1692,21 +2479,110 @@ cy_write(struct tty_struct * tty, int from_user,
} /* cy_write */
+/*
+ * This routine is called by the kernel to write a single
+ * character to the tty device. If the kernel uses this routine,
+ * it must call the flush_chars() routine (if defined) when it is
+ * done stuffing characters into the driver. If there is no room
+ * in the queue, the character is ignored.
+ */
+static void
+cy_put_char(struct tty_struct *tty, unsigned char ch)
+{
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ unsigned long flags;
+
+#ifdef SERIAL_DEBUG_IO
+ printk("cyc:cy_put_char ttyC%d\n", info->line);
+#endif
+
+ if (serial_paranoia_check(info, tty->device, "cy_put_char"))
+ return;
+
+ if (!tty || !info->xmit_buf)
+ return;
+
+ save_flags(flags); cli();
+ if (info->xmit_cnt >= PAGE_SIZE - 1) {
+ restore_flags(flags);
+ return;
+ }
+
+ info->xmit_buf[info->xmit_head++] = ch;
+ info->xmit_head &= PAGE_SIZE - 1;
+ info->xmit_cnt++;
+ restore_flags(flags);
+#if 0
+ SP("+");
+#endif
+} /* cy_put_char */
+
+
+/*
+ * This routine is called by the kernel after it has written a
+ * series of characters to the tty device using put_char().
+ */
+static void
+cy_flush_chars(struct tty_struct *tty)
+{
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ unsigned long flags;
+ unsigned char *base_addr;
+ int card,chip,channel,index;
+
+#ifdef SERIAL_DEBUG_IO
+ printk("cyc:cy_flush_chars ttyC%d\n", info->line); /* */
+#endif
+
+ if (serial_paranoia_check(info, tty->device, "cy_flush_chars"))
+ return;
+
+ if (info->xmit_cnt <= 0 || tty->stopped
+ || tty->hw_stopped || !info->xmit_buf)
+ return;
+
+ card = info->card;
+ channel = info->line - cy_card[card].first_line;
+ if (!IS_CYC_Z(cy_card[card])) {
+ chip = channel>>2;
+ channel &= 0x03;
+ index = cy_card[card].bus_index;
+ base_addr = (unsigned char*)
+ (cy_card[card].base_addr
+ + (cy_chip_offset[chip]<<index));
+
+ save_flags(flags); cli();
+ base_addr[CyCAR<<index] = channel;
+ base_addr[CySRER<<index] |= CyTxMpty;
+ restore_flags(flags);
+ } else {
+ /* Since polling is already in place,
+ nothing further need be done. */
+ }
+} /* cy_flush_chars */
+
+
+/*
+ * This routine returns the numbers of characters the tty driver
+ * will accept for queuing to be written. This number is subject
+ * to change as output buffers get emptied, or if the output flow
+ * control is activated.
+ */
static int
cy_write_room(struct tty_struct *tty)
{
struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
- int ret;
-
+ int ret;
+
#ifdef SERIAL_DEBUG_IO
- printk("cy_write_room ttyC%d\n", info->line); /* */
+ printk("cyc:cy_write_room ttyC%d\n", info->line); /* */
#endif
if (serial_paranoia_check(info, tty->device, "cy_write_room"))
- return 0;
+ return 0;
ret = PAGE_SIZE - info->xmit_cnt - 1;
if (ret < 0)
- ret = 0;
+ ret = 0;
return ret;
} /* cy_write_room */
@@ -1715,126 +2591,351 @@ static int
cy_chars_in_buffer(struct tty_struct *tty)
{
struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
-
+
#ifdef SERIAL_DEBUG_IO
- printk("cy_chars_in_buffer ttyC%d %d\n", info->line, info->xmit_cnt); /* */
+ printk("cyc:cy_chars_in_buffer ttyC%d %d\n",
+ info->line, info->xmit_cnt); /* */
#endif
if (serial_paranoia_check(info, tty->device, "cy_chars_in_buffer"))
- return 0;
+ return 0;
return info->xmit_cnt;
} /* cy_chars_in_buffer */
-static void
-cy_flush_buffer(struct tty_struct *tty)
-{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
- unsigned long flags;
-
-#ifdef SERIAL_DEBUG_IO
- printk("cy_flush_buffer ttyC%d\n", info->line); /* */
-#endif
-
- if (serial_paranoia_check(info, tty->device, "cy_flush_buffer"))
- return;
- save_flags(flags); cli();
- info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
- restore_flags(flags);
- wake_up_interruptible(&tty->write_wait);
- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP))
- && tty->ldisc.write_wakeup)
- (tty->ldisc.write_wakeup)(tty);
-} /* cy_flush_buffer */
+/*
+ * ------------------------------------------------------------
+ * cy_ioctl() and friends
+ * ------------------------------------------------------------
+ */
-/* This routine is called by the upper-layer tty layer to signal
- that incoming characters should be throttled or that the
- throttle should be released.
+/*
+ * This routine finds or computes the various line characteristics.
+ * It used to be called config_setup
*/
static void
-cy_throttle(struct tty_struct * tty)
+set_line_char(struct cyclades_port * info)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
unsigned long flags;
unsigned char *base_addr;
int card,chip,channel,index;
+ unsigned cflag;
+ int i;
-#ifdef SERIAL_DEBUG_THROTTLE
- char buf[64];
-
- printk("throttle %s: %d....\n", _tty_name(tty, buf),
- tty->ldisc.chars_in_buffer(tty));
- printk("cy_throttle ttyC%d\n", info->line);
-#endif
-
- if (serial_paranoia_check(info, tty->device, "cy_nthrottle")){
- return;
+ if (!info->tty || !info->tty->termios){
+ return;
}
-
- if (I_IXOFF(tty)) {
- info->x_char = STOP_CHAR(tty);
- /* Should use the "Send Special Character" feature!!! */
+ if (info->line == -1){
+ return;
}
+ cflag = info->tty->termios->c_cflag;
card = info->card;
- channel = info->line - cy_card[card].first_line;
- chip = channel>>2;
- channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr = (unsigned char*)
- (cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
+ channel = (info->line) - (cy_card[card].first_line);
- save_flags(flags); cli();
- base_addr[CyCAR<<index] = (u_char)channel;
- base_addr[CyMSVR1<<index] = ~CyRTS;
- restore_flags(flags);
+ if (!IS_CYC_Z(cy_card[card])) {
+ /* baud rate */
+ i = cflag & CBAUD;
+
+ if (i & CBAUDEX) {
+ if (i == B57600)
+ i = 16;
+ else if(i == B115200)
+ i = 18;
+#ifdef B76800
+ else if(i == B76800)
+ i = 17;
+#endif
+ else
+ info->tty->termios->c_cflag &= ~CBAUDEX;
+ }
- return;
-} /* cy_throttle */
+ if (i == 15) {
+ if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+ i += 1;
+ if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+ i += 3;
+ }
+ info->tbpr = baud_bpr[i]; /* Tx BPR */
+ info->tco = baud_co[i]; /* Tx CO */
+ info->rbpr = baud_bpr[i]; /* Rx BPR */
+ info->rco = baud_co[i]; /* Rx CO */
+ if (baud_table[i] == 134) {
+ info->timeout = (info->xmit_fifo_size*HZ*30/269) + 2;
+ /* get it right for 134.5 baud */
+ } else if (baud_table[i]) {
+ info->timeout = (info->xmit_fifo_size*HZ*15/baud_table[i]) + 2;
+ /* this needs to be propagated into the card info */
+ } else {
+ info->timeout = 0;
+ }
+ /* By tradition (is it a standard?) a baud rate of zero
+ implies the line should be/has been closed. A bit
+ later in this routine such a test is performed. */
+
+ /* byte size and parity */
+ info->cor5 = 0;
+ info->cor4 = 0;
+ info->cor3 = (info->default_threshold
+ ? info->default_threshold
+ : baud_cor3[i]); /* receive threshold */
+ info->cor2 = CyETC;
+ switch(cflag & CSIZE){
+ case CS5:
+ info->cor1 = Cy_5_BITS;
+ break;
+ case CS6:
+ info->cor1 = Cy_6_BITS;
+ break;
+ case CS7:
+ info->cor1 = Cy_7_BITS;
+ break;
+ case CS8:
+ info->cor1 = Cy_8_BITS;
+ break;
+ }
+ if(cflag & CSTOPB){
+ info->cor1 |= Cy_2_STOP;
+ }
+ if (cflag & PARENB){
+ if (cflag & PARODD){
+ info->cor1 |= CyPARITY_O;
+ }else{
+ info->cor1 |= CyPARITY_E;
+ }
+ }else{
+ info->cor1 |= CyPARITY_NONE;
+ }
+
+ /* CTS flow control flag */
+ if (cflag & CRTSCTS){
+ info->flags |= ASYNC_CTS_FLOW;
+ info->cor2 |= CyCtsAE;
+ }else{
+ info->flags &= ~ASYNC_CTS_FLOW;
+ info->cor2 &= ~CyCtsAE;
+ }
+ if (cflag & CLOCAL)
+ info->flags &= ~ASYNC_CHECK_CD;
+ else
+ info->flags |= ASYNC_CHECK_CD;
+
+ /***********************************************
+ The hardware option, CyRtsAO, presents RTS when
+ the chip has characters to send. Since most modems
+ use RTS as reverse (inbound) flow control, this
+ option is not used. If inbound flow control is
+ necessary, DTR can be programmed to provide the
+ appropriate signals for use with a non-standard
+ cable. Contact Marcio Saito for details.
+ ***********************************************/
+
+ chip = channel>>2;
+ channel &= 0x03;
+ index = cy_card[card].bus_index;
+ base_addr = (unsigned char*)
+ (cy_card[card].base_addr
+ + (cy_chip_offset[chip]<<index));
+ save_flags(flags); cli();
+ base_addr[CyCAR<<index] = (u_char)channel;
-static void
-cy_unthrottle(struct tty_struct * tty)
-{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
- unsigned long flags;
- unsigned char *base_addr;
- int card,chip,channel,index;
+ /* tx and rx baud rate */
+
+ base_addr[CyTCOR<<index] = info->tco;
+ base_addr[CyTBPR<<index] = info->tbpr;
+ base_addr[CyRCOR<<index] = info->rco;
+ base_addr[CyRBPR<<index] = info->rbpr;
+
+ /* set line characteristics according configuration */
+
+ base_addr[CySCHR1<<index] = START_CHAR(info->tty);
+ base_addr[CySCHR2<<index] = STOP_CHAR(info->tty);
+ base_addr[CyCOR1<<index] = info->cor1;
+ base_addr[CyCOR2<<index] = info->cor2;
+ base_addr[CyCOR3<<index] = info->cor3;
+ base_addr[CyCOR4<<index] = info->cor4;
+ base_addr[CyCOR5<<index] = info->cor5;
+
+ cyy_issue_cmd(base_addr,
+ CyCOR_CHANGE|CyCOR1ch|CyCOR2ch|CyCOR3ch,index);
+
+ base_addr[CyCAR<<index] =
+ (u_char)channel; /* !!! Is this needed? */
+
+ base_addr[CyRTPR<<index] = (info->default_timeout
+ ? info->default_timeout
+ : 0x02); /* 10ms rx timeout */
+
+ if (C_CLOCAL(info->tty)) {
+ base_addr[CySRER<<index] |= CyMdmCh; /* without modem intr */
+ /* act on 1->0 modem transitions */
+ base_addr[CyMCOR1<<index] = CyCTS;
+ /* act on 0->1 modem transitions */
+ base_addr[CyMCOR2<<index] = CyCTS;
+ } else {
+ base_addr[CySRER<<index] |= CyMdmCh; /* with modem intr */
+ /* act on 1->0 modem transitions */
+ base_addr[CyMCOR1<<index] = CyDSR|CyCTS|CyRI|CyDCD;
+ /* act on 0->1 modem transitions */
+ base_addr[CyMCOR2<<index] = CyDSR|CyCTS|CyRI|CyDCD;
+ }
-#ifdef SERIAL_DEBUG_THROTTLE
- char buf[64];
-
- printk("throttle %s: %d....\n", _tty_name(tty, buf),
- tty->ldisc.chars_in_buffer(tty));
- printk("cy_unthrottle ttyC%d\n", info->line);
+ if(i == 0){ /* baud rate is zero, turn off line */
+ base_addr[CyMSVR2<<index] = ~CyDTR;
+#ifdef SERIAL_DEBUG_DTR
+ printk("cyc:set_line_char dropping DTR\n");
+ printk(" status: 0x%x,
+ 0x%x\n", base_addr[CyMSVR1<<index],
+ base_addr[CyMSVR2<<index]);
+#endif
+ }else{
+ base_addr[CyMSVR2<<index] = CyDTR;
+#ifdef SERIAL_DEBUG_DTR
+ printk("cyc:set_line_char raising DTR\n");
+ printk(" status: 0x%x, 0x%x\n",
+ base_addr[CyMSVR1<<index],
+ base_addr[CyMSVR2<<index]);
#endif
+ }
- if (serial_paranoia_check(info, tty->device, "cy_nthrottle")){
+ if (info->tty){
+ clear_bit(TTY_IO_ERROR, &info->tty->flags);
+ }
+
+ restore_flags(flags);
+ } else {
+ struct FIRM_ID *firm_id;
+ struct ZFW_CTRL *zfw_ctrl;
+ struct BOARD_CTRL *board_ctrl;
+ struct CH_CTRL *ch_ctrl;
+ struct BUF_CTRL *buf_ctrl;
+ int retval;
+
+ firm_id = (struct FIRM_ID *)
+ (cy_card[card].base_addr + ID_ADDRESS);
+ if (firm_id->signature != ZFIRM_ID){
return;
- }
+ }
- if (I_IXOFF(tty)) {
- info->x_char = START_CHAR(tty);
- /* Should use the "Send Special Character" feature!!! */
- }
+ zfw_ctrl =
+ (struct ZFW_CTRL *)
+ (cy_card[card].base_addr + firm_id->zfwctrl_addr);
+ board_ctrl = &zfw_ctrl->board_ctrl;
+ ch_ctrl = &zfw_ctrl->ch_ctrl[channel];
+ buf_ctrl = &zfw_ctrl->buf_ctrl[channel];
- card = info->card;
- channel = info->line - cy_card[card].first_line;
- chip = channel>>2;
- channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr = (unsigned char*)
- (cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
+ /* baud rate */
+ switch(i = cflag & CBAUD){
+ /*
+ case B0: ch_ctrl->comm_baud = 0; break;
+ */
+ case B50: ch_ctrl->comm_baud = 50; break;
+ case B75: ch_ctrl->comm_baud = 75; break;
+ case B110: ch_ctrl->comm_baud = 110; break;
+ case B134: ch_ctrl->comm_baud = 134; break;
+ case B150: ch_ctrl->comm_baud = 150; break;
+ case B200: ch_ctrl->comm_baud = 200; break;
+ case B300: ch_ctrl->comm_baud = 300; break;
+ case B600: ch_ctrl->comm_baud = 600; break;
+ case B1200: ch_ctrl->comm_baud = 1200; break;
+ case B1800: ch_ctrl->comm_baud = 1800; break;
+ case B2400: ch_ctrl->comm_baud = 2400; break;
+ case B4800: ch_ctrl->comm_baud = 4800; break;
+ case B9600: ch_ctrl->comm_baud = 9600; break;
+ case B19200: ch_ctrl->comm_baud = 19200; break;
+ case B38400:
+ if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI){
+ ch_ctrl->comm_baud = 57600;
+ }else if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI){
+ ch_ctrl->comm_baud = 115200;
+ }else{
+ ch_ctrl->comm_baud = 38400;
+ }
+ break;
+ case B57600: ch_ctrl->comm_baud = 57600; break;
+#ifdef B76800
+ case B76800: ch_ctrl->comm_baud = 76800; break;
+#endif
+ case B115200: ch_ctrl->comm_baud = 115200; break;
+ case B230400: ch_ctrl->comm_baud = 230400; break;
+ case B460800: ch_ctrl->comm_baud = 460800; break;
+ }
+ if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST){
+ ch_ctrl->comm_baud = info->baud;
+ }
- save_flags(flags); cli();
- base_addr[CyCAR<<index] = (u_char)channel;
- base_addr[CyMSVR1<<index] = CyRTS;
- restore_flags(flags);
+ /* byte size and parity */
+ switch(cflag & CSIZE){
+ case CS5: ch_ctrl->comm_data_l = C_DL_CS5; break;
+ case CS6: ch_ctrl->comm_data_l = C_DL_CS6; break;
+ case CS7: ch_ctrl->comm_data_l = C_DL_CS7; break;
+ case CS8: ch_ctrl->comm_data_l = C_DL_CS8; break;
+ }
+ if(cflag & CSTOPB){
+ ch_ctrl->comm_data_l |= C_DL_2STOP;
+ }else{
+ ch_ctrl->comm_data_l |= C_DL_1STOP;
+ }
+ if (cflag & PARENB){
+ if (cflag & PARODD){
+ ch_ctrl->comm_parity = C_PR_ODD;
+ }else{
+ ch_ctrl->comm_parity = C_PR_EVEN;
+ }
+ }else{
+ ch_ctrl->comm_parity = C_PR_NONE;
+ }
+
+ /* CTS flow control flag */
+ if (cflag & CRTSCTS){
+ info->flags |= ASYNC_CTS_FLOW;
+ ch_ctrl->hw_flow |= C_RS_CTS | C_RS_RTS;
+ }else{
+ info->flags &= ~ASYNC_CTS_FLOW;
+ ch_ctrl->hw_flow &= ~(C_RS_CTS | C_RS_RTS);
+ }
+
+ retval = cyz_issue_cmd( &cy_card[card], channel, C_CM_IOCTL, 0L);
+ if (retval != 0){
+ printk("cyc:set_line_char retval at %d was %x\n",
+ __LINE__, retval);
+ }
+
+ /* CD sensitivity */
+ if (cflag & CLOCAL){
+ info->flags &= ~ASYNC_CHECK_CD;
+ }else{
+ info->flags |= ASYNC_CHECK_CD;
+ }
+
+ if(i == 0){ /* baud rate is zero, turn off line */
+ ch_ctrl->rs_control &= ~C_RS_DTR;
+#ifdef SERIAL_DEBUG_DTR
+ printk("cyc:set_line_char dropping Z DTR\n");
+#endif
+ }else{
+ ch_ctrl->rs_control |= C_RS_DTR;
+#ifdef SERIAL_DEBUG_DTR
+ printk("cyc:set_line_char raising Z DTR\n");
+#endif
+ }
+
+ retval = cyz_issue_cmd( &cy_card[card], channel, C_CM_IOCTLM, 0L);
+ if (retval != 0){
+ printk("cyc:set_line_char retval at %d was %x\n",
+ __LINE__, retval);
+ }
+
+ if (info->tty){
+ clear_bit(TTY_IO_ERROR, &info->tty->flags);
+ }
+ }
+
+} /* set_line_char */
- return;
-} /* cy_unthrottle */
static int
get_serial_info(struct cyclades_port * info,
@@ -1851,14 +2952,15 @@ get_serial_info(struct cyclades_port * info,
tmp.port = info->card * 0x100 + info->line - cinfo->first_line;
tmp.irq = cinfo->irq;
tmp.flags = info->flags;
- tmp.baud_base = 0; /*!!!*/
tmp.close_delay = info->close_delay;
+ tmp.baud_base = info->baud;
tmp.custom_divisor = 0; /*!!!*/
tmp.hub6 = 0; /*!!!*/
- copy_to_user(retinfo,&tmp,sizeof(*retinfo));
+ memcpy_tofs(retinfo,&tmp,sizeof(*retinfo));
return 0;
} /* get_serial_info */
+
static int
set_serial_info(struct cyclades_port * info,
struct serial_struct * new_info)
@@ -1867,18 +2969,19 @@ set_serial_info(struct cyclades_port * info,
struct cyclades_port old_info;
if (!new_info)
- return -EFAULT;
- copy_from_user(&new_serial,new_info,sizeof(new_serial));
+ return -EFAULT;
+ memcpy_fromfs(&new_serial,new_info,sizeof(new_serial));
old_info = *info;
if (!suser()) {
- if ((new_serial.close_delay != info->close_delay) ||
- ((new_serial.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK) !=
- (info->flags & ASYNC_FLAGS & ~ASYNC_USR_MASK)))
- return -EPERM;
- info->flags = ((info->flags & ~ASYNC_USR_MASK) |
- (new_serial.flags & ASYNC_USR_MASK));
- goto check_and_exit;
+ if ((new_serial.close_delay != info->close_delay) ||
+ ((new_serial.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK) !=
+ (info->flags & ASYNC_FLAGS & ~ASYNC_USR_MASK)))
+ return -EPERM;
+ info->flags = ((info->flags & ~ASYNC_USR_MASK) |
+ (new_serial.flags & ASYNC_USR_MASK));
+ info->baud = new_serial.baud_base;
+ goto check_and_exit;
}
@@ -1888,19 +2991,21 @@ set_serial_info(struct cyclades_port * info,
*/
info->flags = ((info->flags & ~ASYNC_FLAGS) |
- (new_serial.flags & ASYNC_FLAGS));
+ (new_serial.flags & ASYNC_FLAGS));
+ info->baud = new_serial.baud_base;
info->close_delay = new_serial.close_delay;
check_and_exit:
if (info->flags & ASYNC_INITIALIZED){
- config_setup(info);
- return 0;
+ set_line_char(info);
+ return 0;
}else{
return startup(info);
}
} /* set_serial_info */
+
static int
get_modem_info(struct cyclades_port * info, unsigned int *value)
{
@@ -1908,259 +3013,423 @@ get_modem_info(struct cyclades_port * info, unsigned int *value)
unsigned char *base_addr;
unsigned long flags;
unsigned char status;
+ unsigned long lstatus;
unsigned int result;
+ struct FIRM_ID *firm_id;
+ struct ZFW_CTRL *zfw_ctrl;
+ struct BOARD_CTRL *board_ctrl;
+ struct CH_CTRL *ch_ctrl;
card = info->card;
channel = (info->line) - (cy_card[card].first_line);
- chip = channel>>2;
- channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr = (unsigned char*)
- (cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
+ if (!IS_CYC_Z(cy_card[card])) {
+ chip = channel>>2;
+ channel &= 0x03;
+ index = cy_card[card].bus_index;
+ base_addr = (unsigned char*)
+ (cy_card[card].base_addr
+ + (cy_chip_offset[chip]<<index));
- save_flags(flags); cli();
- base_addr[CyCAR<<index] = (u_char)channel;
- status = base_addr[CyMSVR1<<index];
- status |= base_addr[CyMSVR2<<index];
- restore_flags(flags);
+ save_flags(flags); cli();
+ base_addr[CyCAR<<index] = (u_char)channel;
+ status = base_addr[CyMSVR1<<index];
+ status |= base_addr[CyMSVR2<<index];
+ restore_flags(flags);
+
+ result = ((status & CyRTS) ? TIOCM_RTS : 0)
+ | ((status & CyDTR) ? TIOCM_DTR : 0)
+ | ((status & CyDCD) ? TIOCM_CAR : 0)
+ | ((status & CyRI) ? TIOCM_RNG : 0)
+ | ((status & CyDSR) ? TIOCM_DSR : 0)
+ | ((status & CyCTS) ? TIOCM_CTS : 0);
+ } else {
+ base_addr = (unsigned char*) (cy_card[card].base_addr);
+
+ if (cy_card[card].num_chips != 1){
+ return -EINVAL;
+ }
- result = ((status & CyRTS) ? TIOCM_RTS : 0)
- | ((status & CyDTR) ? TIOCM_DTR : 0)
- | ((status & CyDCD) ? TIOCM_CAR : 0)
- | ((status & CyRI) ? TIOCM_RNG : 0)
- | ((status & CyDSR) ? TIOCM_DSR : 0)
- | ((status & CyCTS) ? TIOCM_CTS : 0);
- put_user(result,(unsigned int *) value);
+ firm_id = (struct FIRM_ID *)
+ (cy_card[card].base_addr + ID_ADDRESS);
+ if (firm_id->signature == ZFIRM_ID){
+ zfw_ctrl =
+ (struct ZFW_CTRL *)
+ (cy_card[card].base_addr + firm_id->zfwctrl_addr);
+ board_ctrl = &zfw_ctrl->board_ctrl;
+ ch_ctrl = zfw_ctrl->ch_ctrl;
+ lstatus = ch_ctrl[channel].rs_status;
+ result = ((lstatus & C_RS_RTS) ? TIOCM_RTS : 0)
+ | ((lstatus & C_RS_DTR) ? TIOCM_DTR : 0)
+ | ((lstatus & C_RS_DCD) ? TIOCM_CAR : 0)
+ | ((lstatus & C_RS_RI) ? TIOCM_RNG : 0)
+ | ((lstatus & C_RS_DSR) ? TIOCM_DSR : 0)
+ | ((lstatus & C_RS_CTS) ? TIOCM_CTS : 0);
+ }else{
+ result = 0;
+ return -ENODEV;
+ }
+
+ }
+ put_fs_long(result,(unsigned long *) value);
return 0;
} /* get_modem_info */
+
static int
set_modem_info(struct cyclades_port * info, unsigned int cmd,
unsigned int *value)
{
- int card,chip,channel,index;
- unsigned char *base_addr;
- unsigned long flags;
- unsigned int arg;
- int error;
-
- error = get_user(arg, value);
- if (error)
- return error;
+ int card,chip,channel,index;
+ unsigned char *base_addr;
+ unsigned long flags;
+ unsigned int arg = get_fs_long((unsigned long *) value);
+ struct FIRM_ID *firm_id;
+ struct ZFW_CTRL *zfw_ctrl;
+ struct BOARD_CTRL *board_ctrl;
+ struct CH_CTRL *ch_ctrl;
+ int retval;
card = info->card;
channel = (info->line) - (cy_card[card].first_line);
- chip = channel>>2;
- channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr = (unsigned char*)
- (cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
-
- switch (cmd) {
- case TIOCMBIS:
- if (arg & TIOCM_RTS){
- save_flags(flags); cli();
+ if (!IS_CYC_Z(cy_card[card])) {
+ chip = channel>>2;
+ channel &= 0x03;
+ index = cy_card[card].bus_index;
+ base_addr = (unsigned char*)
+ (cy_card[card].base_addr
+ + (cy_chip_offset[chip]<<index));
+
+ switch (cmd) {
+ case TIOCMBIS:
+ if (arg & TIOCM_RTS){
+ save_flags(flags); cli();
+ base_addr[CyCAR<<index] = (u_char)channel;
+ base_addr[CyMSVR1<<index] = CyRTS;
+ restore_flags(flags);
+ }
+ if (arg & TIOCM_DTR){
+ save_flags(flags); cli();
base_addr[CyCAR<<index] = (u_char)channel;
- base_addr[CyMSVR1<<index] = CyRTS;
- restore_flags(flags);
- }
- if (arg & TIOCM_DTR){
- save_flags(flags); cli();
- base_addr[CyCAR<<index] = (u_char)channel;
- base_addr[CyMSVR2<<index] = CyDTR;
+ base_addr[CyMSVR2<<index] = CyDTR;
#ifdef SERIAL_DEBUG_DTR
- printk("cyc: %d: raising DTR\n", __LINE__);
- printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1<<index], base_addr[CyMSVR2<<index]);
+ printk("cyc:set_modem_info raising DTR\n");
+ printk(" status: 0x%x, 0x%x\n",
+ base_addr[CyMSVR1<<index], base_addr[CyMSVR2<<index]);
#endif
- restore_flags(flags);
- }
- break;
- case TIOCMBIC:
- if (arg & TIOCM_RTS){
- save_flags(flags); cli();
+ restore_flags(flags);
+ }
+ break;
+ case TIOCMBIC:
+ if (arg & TIOCM_RTS){
+ save_flags(flags); cli();
+ base_addr[CyCAR<<index] = (u_char)channel;
+ base_addr[CyMSVR1<<index] = ~CyRTS;
+ restore_flags(flags);
+ }
+ if (arg & TIOCM_DTR){
+ save_flags(flags); cli();
base_addr[CyCAR<<index] = (u_char)channel;
- base_addr[CyMSVR1<<index] = ~CyRTS;
- restore_flags(flags);
- }
- if (arg & TIOCM_DTR){
- save_flags(flags); cli();
- base_addr[CyCAR<<index] = (u_char)channel;
- base_addr[CyMSVR2<<index] = ~CyDTR;
+ base_addr[CyMSVR2<<index] = ~CyDTR;
#ifdef SERIAL_DEBUG_DTR
- printk("cyc: %d: dropping DTR\n", __LINE__);
- printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1<<index], base_addr[CyMSVR2<<index]);
+ printk("cyc:set_modem_info dropping DTR\n");
+ printk(" status: 0x%x, 0x%x\n",
+ base_addr[CyMSVR1<<index], base_addr[CyMSVR2<<index]);
#endif
- restore_flags(flags);
- }
- break;
- case TIOCMSET:
- if (arg & TIOCM_RTS){
- save_flags(flags); cli();
+ restore_flags(flags);
+ }
+ break;
+ case TIOCMSET:
+ if (arg & TIOCM_RTS){
+ save_flags(flags); cli();
+ base_addr[CyCAR<<index] = (u_char)channel;
+ base_addr[CyMSVR1<<index] = CyRTS;
+ restore_flags(flags);
+ }else{
+ save_flags(flags); cli();
+ base_addr[CyCAR<<index] = (u_char)channel;
+ base_addr[CyMSVR1<<index] = ~CyRTS;
+ restore_flags(flags);
+ }
+ if (arg & TIOCM_DTR){
+ save_flags(flags); cli();
base_addr[CyCAR<<index] = (u_char)channel;
- base_addr[CyMSVR1<<index] = CyRTS;
- restore_flags(flags);
- }else{
- save_flags(flags); cli();
+ base_addr[CyMSVR2<<index] = CyDTR;
+#ifdef SERIAL_DEBUG_DTR
+ printk("cyc:set_modem_info raising DTR\n");
+ printk(" status: 0x%x, 0x%x\n",
+ base_addr[CyMSVR1<<index], base_addr[CyMSVR2<<index]);
+#endif
+ restore_flags(flags);
+ }else{
+ save_flags(flags); cli();
base_addr[CyCAR<<index] = (u_char)channel;
- base_addr[CyMSVR1<<index] = ~CyRTS;
- restore_flags(flags);
+ base_addr[CyMSVR2<<index] = ~CyDTR;
+#ifdef SERIAL_DEBUG_DTR
+ printk("cyc:set_modem_info dropping DTR\n");
+ printk(" status: 0x%x, 0x%x\n",
+ base_addr[CyMSVR1<<index], base_addr[CyMSVR2<<index]);
+#endif
+ restore_flags(flags);
+ }
+ break;
+ default:
+ return -EINVAL;
}
- if (arg & TIOCM_DTR){
- save_flags(flags); cli();
- base_addr[CyCAR<<index] = (u_char)channel;
- base_addr[CyMSVR2<<index] = CyDTR;
+ } else {
+ base_addr = (unsigned char*) (cy_card[card].base_addr);
+
+ firm_id = (struct FIRM_ID *)
+ (cy_card[card].base_addr + ID_ADDRESS);
+ if (firm_id->signature == ZFIRM_ID){
+ zfw_ctrl =
+ (struct ZFW_CTRL *)
+ (cy_card[card].base_addr + firm_id->zfwctrl_addr);
+ board_ctrl = &zfw_ctrl->board_ctrl;
+ ch_ctrl = zfw_ctrl->ch_ctrl;
+
+ switch (cmd) {
+ case TIOCMBIS:
+ if (arg & TIOCM_RTS){
+ ch_ctrl[channel].rs_control |= C_RS_RTS;
+ }
+ if (arg & TIOCM_DTR){
+ ch_ctrl[channel].rs_control |= C_RS_DTR;
#ifdef SERIAL_DEBUG_DTR
- printk("cyc: %d: raising DTR\n", __LINE__);
- printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1<<index], base_addr[CyMSVR2<<index]);
+ printk("cyc:set_modem_info raising Z DTR\n");
#endif
- restore_flags(flags);
- }else{
- save_flags(flags); cli();
- base_addr[CyCAR<<index] = (u_char)channel;
- base_addr[CyMSVR2<<index] = ~CyDTR;
+ }
+ break;
+ case TIOCMBIC:
+ if (arg & TIOCM_RTS){
+ ch_ctrl[channel].rs_control &= ~C_RS_RTS;
+ }
+ if (arg & TIOCM_DTR){
+ ch_ctrl[channel].rs_control &= ~C_RS_DTR;
#ifdef SERIAL_DEBUG_DTR
- printk("cyc: %d: dropping DTR\n", __LINE__);
- printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1<<index], base_addr[CyMSVR2<<index]);
+ printk("cyc:set_modem_info clearing Z DTR\n");
#endif
- restore_flags(flags);
- }
- break;
- default:
+ }
+ break;
+ case TIOCMSET:
+ if (arg & TIOCM_RTS){
+ ch_ctrl[channel].rs_control |= C_RS_RTS;
+ }else{
+ ch_ctrl[channel].rs_control &= ~C_RS_RTS;
+ }
+ if (arg & TIOCM_DTR){
+ ch_ctrl[channel].rs_control |= C_RS_DTR;
+#ifdef SERIAL_DEBUG_DTR
+ printk("cyc:set_modem_info raising Z DTR\n");
+#endif
+ }else{
+ ch_ctrl[channel].rs_control &= ~C_RS_DTR;
+#ifdef SERIAL_DEBUG_DTR
+ printk("cyc:set_modem_info clearing Z DTR\n");
+#endif
+ }
+ break;
+ default:
return -EINVAL;
- }
+ }
+ }else{
+ return -ENODEV;
+ }
+ retval = cyz_issue_cmd(&cy_card[info->card],
+ channel, C_CM_IOCTLM,0L);
+ if (retval != 0){
+ printk("cyc:set_modem_info retval at %d was %x\n",
+ __LINE__, retval);
+ }
+ }
return 0;
} /* set_modem_info */
+
static void
send_break( struct cyclades_port * info, int duration)
-{ /* Let the transmit ISR take care of this (since it
- requires stuffing characters into the output stream).
- */
- info->x_break = duration;
- if (!info->xmit_cnt ) {
- start_xmit(info);
+{
+
+ if (!IS_CYC_Z(cy_card[info->card])) {
+ /* Let the transmit ISR take care of this (since it
+ requires stuffing characters into the output stream).
+ */
+ info->x_break = duration;
+ if (!info->xmit_cnt ) {
+ start_xmit(info);
+ }
+ } else {
+ /* For the moment we ignore the duration parameter!!!
+ A better implementation will use C_CM_SET_BREAK
+ and C_CM_CLR_BREAK with the appropriate delay.
+ */
+#if 0
+this appears to wedge the output data stream
+int retval;
+ retval = cyz_issue_cmd(&cy_card[info->card],
+ (info->line) - (cy_card[info->card].first_line),
+ C_CM_SENDBRK, 0L);
+ if (retval != 0){
+ printk("cyc:send_break retval at %d was %x\n",
+ __LINE__, retval);
+ }
+#endif
}
} /* send_break */
+
static int
get_mon_info(struct cyclades_port * info, struct cyclades_monitor * mon)
{
- copy_to_user(mon, &info->mon, sizeof(struct cyclades_monitor));
- info->mon.int_count = 0;
- info->mon.char_count = 0;
- info->mon.char_max = 0;
- info->mon.char_last = 0;
- return 0;
-}
+ memcpy_tofs(mon, &info->mon, sizeof(struct cyclades_monitor));
+ info->mon.int_count = 0;
+ info->mon.char_count = 0;
+ info->mon.char_max = 0;
+ info->mon.char_last = 0;
+ return 0;
+}/* get_mon_info */
+
static int
set_threshold(struct cyclades_port * info, unsigned long value)
{
- unsigned char *base_addr;
- int card,channel,chip,index;
+ unsigned char *base_addr;
+ int card,channel,chip,index;
- card = info->card;
- channel = info->line - cy_card[card].first_line;
- chip = channel>>2;
- channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr = (unsigned char*)
- (cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
+ card = info->card;
+ channel = info->line - cy_card[card].first_line;
+ if (!IS_CYC_Z(cy_card[card])) {
+ chip = channel>>2;
+ channel &= 0x03;
+ index = cy_card[card].bus_index;
+ base_addr = (unsigned char*)
+ (cy_card[card].base_addr
+ + (cy_chip_offset[chip]<<index));
+
+ info->cor3 &= ~CyREC_FIFO;
+ info->cor3 |= value & CyREC_FIFO;
+ base_addr[CyCOR3<<index] = info->cor3;
+ cyy_issue_cmd(base_addr,CyCOR_CHANGE|CyCOR3ch,index);
+ } else {
+ // Nothing to do!
+ }
+ return 0;
+}/* set_threshold */
- info->cor3 &= ~CyREC_FIFO;
- info->cor3 |= value & CyREC_FIFO;
- base_addr[CyCOR3<<index] = info->cor3;
- write_cy_cmd(base_addr,CyCOR_CHANGE|CyCOR3ch,index);
- return 0;
-}
static int
get_threshold(struct cyclades_port * info, unsigned long *value)
{
- unsigned char *base_addr;
- int card,channel,chip,index;
- unsigned long tmp;
+ unsigned char *base_addr;
+ int card,channel,chip,index;
+ unsigned long tmp;
- card = info->card;
- channel = info->line - cy_card[card].first_line;
- chip = channel>>2;
- channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr = (unsigned char*)
- (cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
+ card = info->card;
+ channel = info->line - cy_card[card].first_line;
+ if (!IS_CYC_Z(cy_card[card])) {
+ chip = channel>>2;
+ channel &= 0x03;
+ index = cy_card[card].bus_index;
+ base_addr = (unsigned char*)
+ (cy_card[card].base_addr
+ + (cy_chip_offset[chip]<<index));
+
+ tmp = base_addr[CyCOR3<<index] & CyREC_FIFO;
+ put_fs_long(tmp,value);
+ } else {
+ // Nothing to do!
+ }
+ return 0;
+}/* get_threshold */
- tmp = base_addr[CyCOR3<<index] & CyREC_FIFO;
- put_user(tmp,value);
- return 0;
-}
static int
set_default_threshold(struct cyclades_port * info, unsigned long value)
{
- info->default_threshold = value & 0x0f;
- return 0;
-}
+ info->default_threshold = value & 0x0f;
+ return 0;
+}/* set_default_threshold */
+
static int
get_default_threshold(struct cyclades_port * info, unsigned long *value)
{
- put_user(info->default_threshold,value);
- return 0;
-}
+ put_fs_long(info->default_threshold,value);
+ return 0;
+}/* get_default_threshold */
+
static int
set_timeout(struct cyclades_port * info, unsigned long value)
{
- unsigned char *base_addr;
- int card,channel,chip,index;
+ unsigned char *base_addr;
+ int card,channel,chip,index;
- card = info->card;
- channel = info->line - cy_card[card].first_line;
- chip = channel>>2;
- channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr = (unsigned char*)
- (cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
+ card = info->card;
+ channel = info->line - cy_card[card].first_line;
+ if (!IS_CYC_Z(cy_card[card])) {
+ chip = channel>>2;
+ channel &= 0x03;
+ index = cy_card[card].bus_index;
+ base_addr = (unsigned char*)
+ (cy_card[card].base_addr
+ + (cy_chip_offset[chip]<<index));
+
+ base_addr[CyRTPR<<index] = value & 0xff;
+ } else {
+ // Nothing to do!
+ }
+ return 0;
+}/* set_timeout */
- base_addr[CyRTPR<<index] = value & 0xff;
- return 0;
-}
static int
get_timeout(struct cyclades_port * info, unsigned long *value)
{
- unsigned char *base_addr;
- int card,channel,chip,index;
- unsigned long tmp;
+ unsigned char *base_addr;
+ int card,channel,chip,index;
+ unsigned long tmp;
- card = info->card;
- channel = info->line - cy_card[card].first_line;
- chip = channel>>2;
- channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr = (unsigned char*)
- (cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
+ card = info->card;
+ channel = info->line - cy_card[card].first_line;
+ if (!IS_CYC_Z(cy_card[card])) {
+ chip = channel>>2;
+ channel &= 0x03;
+ index = cy_card[card].bus_index;
+ base_addr = (unsigned char*)
+ (cy_card[card].base_addr
+ + (cy_chip_offset[chip]<<index));
+
+ tmp = base_addr[CyRTPR<<index];
+ put_fs_long(tmp,value);
+ } else {
+ // Nothing to do!
+ }
+ return 0;
+}/* get_timeout */
- tmp = base_addr[CyRTPR<<index];
- put_user(tmp,value);
- return 0;
-}
static int
set_default_timeout(struct cyclades_port * info, unsigned long value)
{
- info->default_timeout = value & 0xff;
- return 0;
-}
+ info->default_timeout = value & 0xff;
+ return 0;
+}/* set_default_timeout */
+
static int
get_default_timeout(struct cyclades_port * info, unsigned long *value)
{
- put_user(info->default_timeout,value);
- return 0;
-}
+ put_fs_long(info->default_timeout,value);
+ return 0;
+}/* get_default_timeout */
+
+/*
+ * This routine allows the tty driver to implement device-
+ * specific ioctl's. If the ioctl number passed in cmd is
+ * not recognized by the driver, it should return ENOIOCTLCMD.
+ */
static int
cy_ioctl(struct tty_struct *tty, struct file * file,
unsigned int cmd, unsigned long arg)
@@ -2170,7 +3439,8 @@ cy_ioctl(struct tty_struct *tty, struct file * file,
int ret_val = 0;
#ifdef SERIAL_DEBUG_OTHER
- printk("cy_ioctl ttyC%d, cmd = %x arg = %lx\n", info->line, cmd, arg); /* */
+ printk("cyc:cy_ioctl ttyC%d, cmd = %x arg = %lx\n",
+ info->line, cmd, arg); /* */
#endif
switch (cmd) {
@@ -2182,7 +3452,7 @@ cy_ioctl(struct tty_struct *tty, struct file * file,
break;
}
ret_val = get_mon_info(info, (struct cyclades_monitor *)arg);
- break;
+ break;
case CYGETTHRESH:
error = verify_area(VERIFY_WRITE, (void *) arg
,sizeof(unsigned long));
@@ -2190,11 +3460,11 @@ cy_ioctl(struct tty_struct *tty, struct file * file,
ret_val = error;
break;
}
- ret_val = get_threshold(info, (unsigned long *)arg);
- break;
+ ret_val = get_threshold(info, (unsigned long *)arg);
+ break;
case CYSETTHRESH:
ret_val = set_threshold(info, (unsigned long)arg);
- break;
+ break;
case CYGETDEFTHRESH:
error = verify_area(VERIFY_WRITE, (void *) arg
,sizeof(unsigned long));
@@ -2202,11 +3472,11 @@ cy_ioctl(struct tty_struct *tty, struct file * file,
ret_val = error;
break;
}
- ret_val = get_default_threshold(info, (unsigned long *)arg);
- break;
+ ret_val = get_default_threshold(info, (unsigned long *)arg);
+ break;
case CYSETDEFTHRESH:
ret_val = set_default_threshold(info, (unsigned long)arg);
- break;
+ break;
case CYGETTIMEOUT:
error = verify_area(VERIFY_WRITE, (void *) arg
,sizeof(unsigned long));
@@ -2214,11 +3484,11 @@ cy_ioctl(struct tty_struct *tty, struct file * file,
ret_val = error;
break;
}
- ret_val = get_timeout(info, (unsigned long *)arg);
- break;
+ ret_val = get_timeout(info, (unsigned long *)arg);
+ break;
case CYSETTIMEOUT:
ret_val = set_timeout(info, (unsigned long)arg);
- break;
+ break;
case CYGETDEFTIMEOUT:
error = verify_area(VERIFY_WRITE, (void *) arg
,sizeof(unsigned long));
@@ -2226,23 +3496,23 @@ cy_ioctl(struct tty_struct *tty, struct file * file,
ret_val = error;
break;
}
- ret_val = get_default_timeout(info, (unsigned long *)arg);
- break;
+ ret_val = get_default_timeout(info, (unsigned long *)arg);
+ break;
case CYSETDEFTIMEOUT:
ret_val = set_default_timeout(info, (unsigned long)arg);
- break;
+ break;
case TCSBRK: /* SVID version: non-zero arg --> no break */
- ret_val = tty_check_change(tty);
- if (ret_val)
- return ret_val;
+ ret_val = tty_check_change(tty);
+ if (ret_val)
+ return ret_val;
tty_wait_until_sent(tty,0);
if (!arg)
send_break(info, HZ/4); /* 1/4 second */
break;
case TCSBRKP: /* support for POSIX tcsendbreak() */
- ret_val = tty_check_change(tty);
- if (ret_val)
- return ret_val;
+ ret_val = tty_check_change(tty);
+ if (ret_val)
+ return ret_val;
tty_wait_until_sent(tty,0);
send_break(info, arg ? arg*(HZ/10) : HZ/4);
break;
@@ -2254,19 +3524,31 @@ cy_ioctl(struct tty_struct *tty, struct file * file,
/* The following commands are incompletely implemented!!! */
case TIOCGSOFTCAR:
- ret_val = put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned int *) arg);
- break;
+ error = verify_area(VERIFY_WRITE, (void *) arg
+ ,sizeof(unsigned int *));
+ if (error){
+ ret_val = error;
+ break;
+ }
+ put_fs_long(C_CLOCAL(tty) ? 1 : 0,
+ (unsigned long *) arg);
+ break;
case TIOCSSOFTCAR:
- ret_val = get_user(arg,(unsigned int *) arg);
- if (ret_val)
- break;
+ error = verify_area(VERIFY_READ, (void *) arg
+ ,sizeof(unsigned long *));
+ if (error) {
+ ret_val = error;
+ break;
+ }
+
+ arg = get_fs_long((unsigned long *) arg);
tty->termios->c_cflag =
((tty->termios->c_cflag & ~CLOCAL) |
(arg ? CLOCAL : 0));
break;
case TIOCMGET:
error = verify_area(VERIFY_WRITE, (void *) arg
- ,sizeof(unsigned int));
+ ,sizeof(unsigned int *));
if (error){
ret_val = error;
break;
@@ -2294,31 +3576,35 @@ cy_ioctl(struct tty_struct *tty, struct file * file,
(struct serial_struct *) arg);
break;
default:
- ret_val = -ENOIOCTLCMD;
+ ret_val = -ENOIOCTLCMD;
}
#ifdef SERIAL_DEBUG_OTHER
- printk("cy_ioctl done\n");
+ printk(" cyc:cy_ioctl done\n");
#endif
return ret_val;
} /* cy_ioctl */
-
-
+/*
+ * This routine allows the tty driver to be notified when
+ * device's termios settings have changed. Note that a
+ * well-designed tty driver should be prepared to accept the case
+ * where old == NULL, and try to do something rational.
+ */
static void
cy_set_termios(struct tty_struct *tty, struct termios * old_termios)
{
struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
#ifdef SERIAL_DEBUG_OTHER
- printk("cy_set_termios ttyC%d\n", info->line);
+ printk("cyc:cy_set_termios ttyC%d\n", info->line);
#endif
if (tty->termios->c_cflag == old_termios->c_cflag)
return;
- config_setup(info);
+ set_line_char(info);
if ((old_termios->c_cflag & CRTSCTS) &&
!(tty->termios->c_cflag & CRTSCTS)) {
@@ -2335,353 +3621,243 @@ cy_set_termios(struct tty_struct *tty, struct termios * old_termios)
} /* cy_set_termios */
+/*
+ * void (*set_ldisc)(struct tty_struct *tty);
+ *
+ * This routine allows the tty driver to be notified when the
+ * device's termios settings have changed.
+ *
+ */
+
+
+/* This routine is called by the upper-layer tty layer to signal
+ that incoming characters should be throttled because the input
+ buffers are close to full.
+ */
static void
-cy_close(struct tty_struct * tty, struct file * filp)
+cy_throttle(struct tty_struct * tty)
{
- struct cyclades_port * info = (struct cyclades_port *)tty->driver_data;
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
unsigned long flags;
+ unsigned char *base_addr;
+ int card,chip,channel,index;
-#ifdef SERIAL_DEBUG_OTHER
- printk("cy_close ttyC%d\n", info->line);
+#ifdef SERIAL_DEBUG_THROTTLE
+ char buf[64];
+
+ printk("cyc:throttle %s: %d....ttyC%d\n", _tty_name(tty, buf),
+ tty->ldisc.chars_in_buffer(tty), info->line);
#endif
- if (!info
- || serial_paranoia_check(info, tty->device, "cy_close")){
- return;
+ if (serial_paranoia_check(info, tty->device, "cy_nthrottle")){
+ return;
}
-#ifdef SERIAL_DEBUG_OPEN
- printk("cy_close ttyC%d, count = %d\n", info->line, info->count);
-#endif
-
- save_flags(flags); cli();
- /* If the TTY is being hung up, nothing to do */
- if (tty_hung_up_p(filp)) {
- MOD_DEC_USE_COUNT;
- restore_flags(flags);
- return;
- }
-
- if ((tty->count == 1) && (info->count != 1)) {
- /*
- * Uh, oh. tty->count is 1, which means that the tty
- * structure will be freed. Info->count should always
- * be one in these conditions. If it's greater than
- * one, we've got real problems, since it means the
- * serial port won't be shutdown.
- */
- printk("cy_close: bad serial port count; tty->count is 1, "
- "info->count is %d\n", info->count);
- info->count = 1;
- }
-#ifdef SERIAL_DEBUG_COUNT
- printk("cyc: %d(%d): decrementing count to %d\n", __LINE__, current->pid, info->count - 1);
-#endif
- if (--info->count < 0) {
-#ifdef SERIAL_DEBUG_COUNT
- printk("cyc: %d: setting count to 0\n", __LINE__);
-#endif
- info->count = 0;
+ if (I_IXOFF(tty)) {
+ info->x_char = STOP_CHAR(tty);
+ /* Should use the "Send Special Character" feature!!! */
}
- if (info->count)
- {
- MOD_DEC_USE_COUNT;
+
+ card = info->card;
+ channel = info->line - cy_card[card].first_line;
+ if (!IS_CYC_Z(cy_card[card])) {
+ chip = channel>>2;
+ channel &= 0x03;
+ index = cy_card[card].bus_index;
+ base_addr = (unsigned char*)
+ (cy_card[card].base_addr
+ + (cy_chip_offset[chip]<<index));
+
+ save_flags(flags); cli();
+ base_addr[CyCAR<<index] = (u_char)channel;
+ base_addr[CyMSVR1<<index] = ~CyRTS;
restore_flags(flags);
- return;
- }
- info->flags |= ASYNC_CLOSING;
- /*
- * Save the termios structure, since this port may have
- * separate termios for callout and dialin.
- */
- if (info->flags & ASYNC_NORMAL_ACTIVE)
- info->normal_termios = *tty->termios;
- if (info->flags & ASYNC_CALLOUT_ACTIVE)
- info->callout_termios = *tty->termios;
- if (info->flags & ASYNC_INITIALIZED)
- tty_wait_until_sent(tty, 30*HZ); /* 30 seconds timeout */
- shutdown(info);
- if (tty->driver.flush_buffer)
- tty->driver.flush_buffer(tty);
- if (tty->ldisc.flush_buffer)
- tty->ldisc.flush_buffer(tty);
- info->event = 0;
- info->tty = 0;
- if (info->blocked_open) {
- if (info->close_delay) {
- current->state = TASK_INTERRUPTIBLE;
- current->timeout = jiffies + info->close_delay;
- schedule();
- }
- wake_up_interruptible(&info->open_wait);
+ } else {
+ // Nothing to do!
}
- info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
- ASYNC_CLOSING);
- wake_up_interruptible(&info->close_wait);
-#ifdef SERIAL_DEBUG_OTHER
- printk("cy_close done\n");
-#endif
-
- MOD_DEC_USE_COUNT;
- restore_flags(flags);
return;
-} /* cy_close */
+} /* cy_throttle */
+
/*
- * cy_hangup() --- called by tty_hangup() when a hangup is signaled.
+ * This routine notifies the tty driver that it should signal
+ * that characters can now be sent to the tty without fear of
+ * overrunning the input buffers of the line disciplines.
*/
-void
-cy_hangup(struct tty_struct *tty)
+static void
+cy_unthrottle(struct tty_struct * tty)
{
- struct cyclades_port * info = (struct cyclades_port *)tty->driver_data;
-
-#ifdef SERIAL_DEBUG_OTHER
- printk("cy_hangup ttyC%d\n", info->line); /* */
-#endif
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ unsigned long flags;
+ unsigned char *base_addr;
+ int card,chip,channel,index;
- if (serial_paranoia_check(info, tty->device, "cy_hangup"))
- return;
-
- shutdown(info);
- info->event = 0;
- info->count = 0;
-#ifdef SERIAL_DEBUG_COUNT
- printk("cyc: %d(%d): setting count to 0\n", __LINE__, current->pid);
+#ifdef SERIAL_DEBUG_THROTTLE
+ char buf[64];
+
+ printk("cyc:throttle %s: %d....ttyC%d\n", _tty_name(tty, buf),
+ tty->ldisc.chars_in_buffer(tty), info->line);
#endif
- info->tty = 0;
- info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
- wake_up_interruptible(&info->open_wait);
-} /* cy_hangup */
+ if (serial_paranoia_check(info, tty->device, "cy_nthrottle")){
+ return;
+ }
+ if (I_IXOFF(tty)) {
+ info->x_char = START_CHAR(tty);
+ /* Should use the "Send Special Character" feature!!! */
+ }
-/*
- * ------------------------------------------------------------
- * cy_open() and friends
- * ------------------------------------------------------------
- */
+ card = info->card;
+ channel = info->line - cy_card[card].first_line;
+ if (!IS_CYC_Z(cy_card[card])) {
+ chip = channel>>2;
+ channel &= 0x03;
+ index = cy_card[card].bus_index;
+ base_addr = (unsigned char*)
+ (cy_card[card].base_addr
+ + (cy_chip_offset[chip]<<index));
-static int
-block_til_ready(struct tty_struct *tty, struct file * filp,
- struct cyclades_port *info)
+ save_flags(flags); cli();
+ base_addr[CyCAR<<index] = (u_char)channel;
+ base_addr[CyMSVR1<<index] = CyRTS;
+ restore_flags(flags);
+ }else{
+ // Nothing to do!
+ }
+
+ return;
+} /* cy_unthrottle */
+
+
+/* cy_start and cy_stop provide software output flow control as a
+ function of XON/XOFF, software CTS, and other such stuff.
+*/
+static void
+cy_stop(struct tty_struct *tty)
{
- struct wait_queue wait = { current, NULL };
struct cyclades_card *cinfo;
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ unsigned char *base_addr;
+ int chip,channel,index;
unsigned long flags;
- int chip, channel,index;
- int retval;
- char *base_addr;
- /*
- * If the device is in the middle of being closed, then block
- * until it's done, and then try again.
- */
- if (info->flags & ASYNC_CLOSING) {
- interruptible_sleep_on(&info->close_wait);
- if (info->flags & ASYNC_HUP_NOTIFY){
- return -EAGAIN;
- }else{
- return -ERESTARTSYS;
- }
- }
+#ifdef SERIAL_DEBUG_OTHER
+ printk("cyc:cy_stop ttyC%d\n", info->line); /* */
+#endif
- /*
- * If this is a callout device, then just make sure the normal
- * device isn't being used.
- */
- if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
- if (info->flags & ASYNC_NORMAL_ACTIVE){
- return -EBUSY;
- }
- if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
- (info->flags & ASYNC_SESSION_LOCKOUT) &&
- (info->session != current->session)){
- return -EBUSY;
- }
- if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
- (info->flags & ASYNC_PGRP_LOCKOUT) &&
- (info->pgrp != current->pgrp)){
- return -EBUSY;
- }
- info->flags |= ASYNC_CALLOUT_ACTIVE;
- return 0;
+ if (serial_paranoia_check(info, tty->device, "cy_stop"))
+ return;
+
+ cinfo = &cy_card[info->card];
+ channel = info->line - cinfo->first_line;
+ if (!IS_CYC_Z(*cinfo)) {
+ index = cinfo->bus_index;
+ chip = channel>>2;
+ channel &= 0x03;
+ base_addr = (unsigned char*)
+ (cy_card[info->card].base_addr
+ + (cy_chip_offset[chip]<<index));
+
+ save_flags(flags); cli();
+ base_addr[CyCAR<<index] =
+ (u_char)(channel & 0x0003); /* index channel */
+ base_addr[CySRER<<index] &= ~CyTxMpty;
+ restore_flags(flags);
+ } else {
+ // Nothing to do!
}
- /*
- * If non-blocking mode is set, then make the check up front
- * and then exit.
- */
- if (filp->f_flags & O_NONBLOCK) {
- if (info->flags & ASYNC_CALLOUT_ACTIVE){
- return -EBUSY;
- }
- info->flags |= ASYNC_NORMAL_ACTIVE;
- return 0;
- }
+ return;
+} /* cy_stop */
- /*
- * Block waiting for the carrier detect and the line to become
- * free (i.e., not in use by the callout). While we are in
- * this loop, info->count is dropped by one, so that
- * cy_close() knows when to free things. We restore it upon
- * exit, either normal or abnormal.
- */
- retval = 0;
- add_wait_queue(&info->open_wait, &wait);
-#ifdef SERIAL_DEBUG_OPEN
- printk("block_til_ready before block: ttyC%d, count = %d\n",
- info->line, info->count);/**/
-#endif
- info->count--;
-#ifdef SERIAL_DEBUG_COUNT
- printk("cyc: %d(%d): decrementing count to %d\n", __LINE__, current->pid, info->count);
+
+static void
+cy_start(struct tty_struct *tty)
+{
+ struct cyclades_card *cinfo;
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ unsigned char *base_addr;
+ int chip,channel,index;
+ unsigned long flags;
+
+#ifdef SERIAL_DEBUG_OTHER
+ printk("cyc:cy_start ttyC%d\n", info->line); /* */
#endif
- info->blocked_open++;
+ if (serial_paranoia_check(info, tty->device, "cy_start"))
+ return;
+
cinfo = &cy_card[info->card];
channel = info->line - cinfo->first_line;
- chip = channel>>2;
- channel &= 0x03;
index = cinfo->bus_index;
- base_addr = (char *) (cinfo->base_addr + (cy_chip_offset[chip]<<index));
-
- while (1) {
- save_flags(flags); cli();
- if (!(info->flags & ASYNC_CALLOUT_ACTIVE)){
- base_addr[CyCAR<<index] = (u_char)channel;
- base_addr[CyMSVR1<<index] = CyRTS;
- base_addr[CyMSVR2<<index] = CyDTR;
-#ifdef SERIAL_DEBUG_DTR
- printk("cyc: %d: raising DTR\n", __LINE__);
- printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1<<index], base_addr[CyMSVR2<<index]);
-#endif
- }
- restore_flags(flags);
- current->state = TASK_INTERRUPTIBLE;
- if (tty_hung_up_p(filp)
- || !(info->flags & ASYNC_INITIALIZED) ){
- if (info->flags & ASYNC_HUP_NOTIFY) {
- retval = -EAGAIN;
- }else{
- retval = -ERESTARTSYS;
- }
- break;
- }
- save_flags(flags); cli();
- base_addr[CyCAR<<index] = (u_char)channel;
- if (!(info->flags & ASYNC_CALLOUT_ACTIVE)
- && !(info->flags & ASYNC_CLOSING)
- && (C_CLOCAL(tty)
- || (base_addr[CyMSVR1<<index] & CyDCD))) {
- restore_flags(flags);
- break;
- }
- restore_flags(flags);
- if (current->signal & ~current->blocked) {
- retval = -ERESTARTSYS;
- break;
- }
-#ifdef SERIAL_DEBUG_OPEN
- printk("block_til_ready blocking: ttyC%d, count = %d\n",
- info->line, info->count);/**/
-#endif
- schedule();
- }
- current->state = TASK_RUNNING;
- remove_wait_queue(&info->open_wait, &wait);
- if (!tty_hung_up_p(filp)){
- info->count++;
-#ifdef SERIAL_DEBUG_COUNT
- printk("cyc: %d(%d): incrementing count to %d\n", __LINE__, current->pid, info->count);
-#endif
+ if (!IS_CYC_Z(*cinfo)) {
+ chip = channel>>2;
+ channel &= 0x03;
+ base_addr = (unsigned char*)
+ (cy_card[info->card].base_addr
+ + (cy_chip_offset[chip]<<index));
+
+ save_flags(flags); cli();
+ base_addr[CyCAR<<index] = (u_char)(channel & 0x0003);
+ base_addr[CySRER<<index] |= CyTxMpty;
+ restore_flags(flags);
+ } else {
+ // Nothing to do!
}
- info->blocked_open--;
-#ifdef SERIAL_DEBUG_OPEN
- printk("block_til_ready after blocking: ttyC%d, count = %d\n",
- info->line, info->count);/**/
-#endif
- if (retval)
- return retval;
- info->flags |= ASYNC_NORMAL_ACTIVE;
- return 0;
-} /* block_til_ready */
+
+ return;
+} /* cy_start */
+
/*
- * This routine is called whenever a serial port is opened. It
- * performs the serial-specific initialization for the tty structure.
+ * cy_hangup() --- called by tty_hangup() when a hangup is signaled.
*/
-int
-cy_open(struct tty_struct *tty, struct file * filp)
+static void
+cy_hangup(struct tty_struct *tty)
{
- struct cyclades_port *info;
- int retval, line;
-
- line = MINOR(tty->device) - tty->driver.minor_start;
- if ((line < 0) || (NR_PORTS <= line)){
- return -ENODEV;
- }
- info = &cy_port[line];
- if (info->line < 0){
- return -ENODEV;
- }
+ struct cyclades_port * info = (struct cyclades_port *)tty->driver_data;
+
#ifdef SERIAL_DEBUG_OTHER
- printk("cy_open ttyC%d\n", info->line); /* */
-#endif
- if (serial_paranoia_check(info, tty->device, "cy_open")){
- return -ENODEV;
- }
-#ifdef SERIAL_DEBUG_OPEN
- printk("cy_open ttyC%d, count = %d\n", info->line, info->count);/**/
+ printk("cyc:cy_hangup ttyC%d\n", info->line); /* */
#endif
- info->count++;
-#ifdef SERIAL_DEBUG_COUNT
- printk("cyc: %d(%d): incrementing count to %d\n", __LINE__, current->pid, info->count);
-#endif
- tty->driver_data = info;
- info->tty = tty;
- if (!tmp_buf) {
- tmp_buf = (unsigned char *) get_free_page(GFP_KERNEL);
- if (!tmp_buf){
- return -ENOMEM;
- }
- }
-
- if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) {
- if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
- *tty->termios = info->normal_termios;
- else
- *tty->termios = info->callout_termios;
- }
- /*
- * Start up serial port
- */
- retval = startup(info);
- if (retval){
- return retval;
- }
-
- MOD_INC_USE_COUNT;
-
- retval = block_til_ready(tty, filp, info);
- if (retval) {
-#ifdef SERIAL_DEBUG_OPEN
- printk("cy_open returning after block_til_ready with %d\n",
- retval);
+ if (serial_paranoia_check(info, tty->device, "cy_hangup"))
+ return;
+
+ shutdown(info);
+ info->event = 0;
+ info->count = 0;
+#ifdef SERIAL_DEBUG_COUNT
+ printk("cyc:cy_hangup (%d): setting count to 0\n", current->pid);
#endif
- return retval;
- }
+ info->tty = 0;
+ info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
+ wake_up_interruptible(&info->open_wait);
+} /* cy_hangup */
- info->session = current->session;
- info->pgrp = current->pgrp;
-#ifdef SERIAL_DEBUG_OPEN
- printk("cy_open done\n");/**/
+static void
+cy_flush_buffer(struct tty_struct *tty)
+{
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ unsigned long flags;
+
+#ifdef SERIAL_DEBUG_IO
+ printk("cyc:cy_flush_buffer ttyC%d\n", info->line); /* */
#endif
- return 0;
-} /* cy_open */
+ if (serial_paranoia_check(info, tty->device, "cy_flush_buffer"))
+ return;
+ save_flags(flags); cli();
+ info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+ restore_flags(flags);
+ wake_up_interruptible(&tty->write_wait);
+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP))
+ && tty->ldisc.write_wakeup)
+ (tty->ldisc.write_wakeup)(tty);
+} /* cy_flush_buffer */
/*
@@ -2692,21 +3868,11 @@ cy_open(struct tty_struct *tty, struct file * filp)
* ---------------------------------------------------------------------
*/
-/*
- * This routine prints out the appropriate serial driver version
- * number, and identifies which options were configured into this
- * driver.
- */
-static inline void
-show_version(void)
-{
- printk("Cyclom driver %s\n",rcsid);
-} /* show_version */
-/* initialize chips on card -- return number of valid
+/* initialize chips on Cyclom-Y card -- return number of valid
chips (which is number of ports/4) */
__initfunc(static int
-cy_init_card(unsigned char *true_base_addr,int index))
+cyy_init_card(unsigned char *true_base_addr,int index))
{
unsigned int chip_number;
unsigned char* base_addr;
@@ -2716,7 +3882,8 @@ cy_init_card(unsigned char *true_base_addr,int index))
udelay(500L);
for(chip_number=0; chip_number<CyMaxChipsPerCard; chip_number++){
- base_addr = true_base_addr + (cy_chip_offset[chip_number]<<index);
+ base_addr = true_base_addr
+ + (cy_chip_offset[chip_number]<<index);
udelay(1000L);
if(base_addr[CyCCR<<index] != 0x00){
/*************
@@ -2736,39 +3903,396 @@ cy_init_card(unsigned char *true_base_addr,int index))
and this must be a Cyclom-16Y, not a Cyclom-32Ye.
*/
if (chip_number == 4
- && *(true_base_addr + (cy_chip_offset[0]<<index) + (CyGFRCR<<index)) == 0){
- return chip_number;
+ && *(true_base_addr
+ + (cy_chip_offset[0]<<index)
+ + (CyGFRCR<<index)) == 0){
+ return chip_number;
}
base_addr[CyCCR<<index] = CyCHIP_RESET;
udelay(1000L);
if(base_addr[CyGFRCR<<index] == 0x00){
- /*
- printk(" chip #%d at %#6lx is not responding (GFRCR stayed 0)\n",
+ /*
+ printk(" chip #%d at %#6lx is not responding ",
chip_number, (unsigned long)base_addr);
- */
+ printk("(GFRCR stayed 0)\n",
+ */
return chip_number;
}
if((0xf0 & base_addr[CyGFRCR<<index]) != 0x40){
- /*
+ /*
printk(" chip #%d at %#6lx is not valid (GFRCR == %#2x)\n",
- chip_number, (unsigned long)base_addr, base_addr[CyGFRCR<<index]);
- */
+ chip_number, (unsigned long)base_addr,
+ base_addr[CyGFRCR<<index]);
+ */
return chip_number;
}
base_addr[CyGCR<<index] = CyCH0_SERIAL;
- base_addr[CyPPR<<index] = 244; /* better value than CyCLOCK_25_1MS * 5
- to run clock at 200 Hz */
+ base_addr[CyPPR<<index] = 244;
+ /* better value than CyCLOCK_25_1MS * 5
+ to run clock at 200 Hz */
- /*
+ /*
printk(" chip #%d at %#6lx is rev 0x%2x\n",
- chip_number, (unsigned long)base_addr, base_addr[CyGFRCR<<index]);
- */
+ chip_number, (unsigned long)base_addr,
+ base_addr[CyGFRCR<<index]);
+ */
}
return chip_number;
-} /* cy_init_card */
+} /* cyy_init_card */
+
+
+/*
+ * ---------------------------------------------------------------------
+ * cy_detect_isa() - Probe for Cyclom-Y/ISA boards.
+ * sets global variables and return the number of ISA boards found.
+ * ---------------------------------------------------------------------
+ */
+__initfunc(static int
+cy_detect_isa(void))
+{
+ unsigned int cy_isa_irq,nboard;
+ unsigned char *cy_isa_address;
+ unsigned short i,j,cy_isa_nchan;
+
+ nboard = 0;
+
+ /* scan the address table probing for Cyclom-Y/ISA boards */
+ for (i = 0 ; i < NR_ISA_ADDRS ; i++) {
+ cy_isa_address = cy_isa_addresses[i];
+ if (cy_isa_address == 0x0000) {
+ return(nboard);
+ }
+
+ /* probe for CD1400... */
+#if LINUX_VERSION_CODE >= 131328
+ cy_isa_address = vremap((unsigned int)cy_isa_address,0x2000);
+#endif
+ cy_isa_nchan = 4 * cyy_init_card(cy_isa_address,0);
+ if (cy_isa_nchan == 0) {
+ continue;
+ }
+
+ /* find out the board's irq by probing */
+ cy_isa_irq = do_auto_irq(cy_isa_address);
+ if (cy_isa_irq == 0) {
+ printk("Cyclom-Y/ISA found at 0x%x ",
+ (unsigned int) cy_isa_address);
+ printk("but the IRQ could not be detected.\n");
+ continue;
+ }
+
+ if((cy_next_channel+cy_isa_nchan) > NR_PORTS) {
+ printk("Cyclom-Y/ISA found at 0x%x ",
+ (unsigned int) cy_isa_address);
+ printk("but no more channels are available.\n");
+ return(nboard);
+ }
+ /* fill the next cy_card structure available */
+ for (j = 0 ; j < NR_CARDS ; j++) {
+ if (cy_card[j].base_addr == 0) break;
+ }
+ if (j == NR_CARDS) { /* no more cy_cards available */
+ printk("Cyclom-Y/ISA found at 0x%x ",
+ (unsigned int) cy_isa_address);
+ printk("but no more cards can be used .\n");
+ return(nboard);
+ }
+
+ /* allocate IRQ */
+ if(request_irq(cy_isa_irq, cyy_interrupt,
+ SA_INTERRUPT, "cyclomY", NULL))
+ {
+ printk("Cyclom-Y/ISA found at 0x%x ",
+ (unsigned int) cy_isa_address);
+ printk("but could not allocate IRQ#%d.\n",
+ cy_isa_irq);
+ return(nboard);
+ }
+
+ /* set cy_card */
+ cy_card[j].base_addr = (int) cy_isa_address;
+ cy_card[j].ctl_addr = 0;
+ cy_card[j].irq = (int) cy_isa_irq;
+ cy_card[j].bus_index = 0;
+ cy_card[j].first_line = cy_next_channel;
+ cy_card[j].num_chips = cy_isa_nchan/4;
+ IRQ_cards[cy_isa_irq] = &cy_card[j];
+ nboard++;
+
+ /* print message */
+ printk("Cyclom-Y/ISA #%d: 0x%x-0x%x, IRQ%d, ",
+ j+1, (unsigned int) cy_isa_address,
+ (unsigned int)(cy_isa_address + 0x1fff),
+ cy_isa_irq);
+ printk("%d channels starting from port %d.\n",
+ cy_isa_nchan, cy_next_channel);
+ cy_next_channel += cy_isa_nchan;
+ }
+ return(nboard);
+
+} /* cy_detect_isa */
+
+/*
+ * ---------------------------------------------------------------------
+ * cy_detect_pci() - Test PCI bus presence and Cyclom-Ye/PCI.
+ * sets global variables and return the number of PCI boards found.
+ * ---------------------------------------------------------------------
+ */
+__initfunc(static int
+cy_detect_pci(void))
+{
+#ifdef CONFIG_PCI
+ unsigned char cyy_bus, cyy_dev_fn, cyy_rev_id;
+ unsigned long pci_intr_ctrl;
+ unsigned char cy_pci_irq;
+ unsigned int cy_pci_addr0, cy_pci_addr1, cy_pci_addr2;
+ unsigned short i,j,cy_pci_nchan;
+ unsigned short device_id,dev_index = 0,board_index = 0;
+
+ if(pcibios_present() == 0) { /* PCI bus not present */
+ return(0);
+ }
+ for (i = 0; i < NR_CARDS; i++) {
+ /* look for a Cyclades card by vendor and device id */
+ while((device_id = cy_pci_dev_id[dev_index]) != 0) {
+ if(pcibios_find_device(PCI_VENDOR_ID_CYCLADES,
+ device_id,board_index,
+ &cyy_bus, &cyy_dev_fn) != 0)
+ {
+ dev_index++; /* try next device id */
+ board_index = 0;
+ } else {
+ board_index++;
+ break; /* found a board */
+ }
+ }
+
+ /* read PCI configuration area */
+ pcibios_read_config_byte(cyy_bus, cyy_dev_fn,
+ PCI_INTERRUPT_LINE, &cy_pci_irq);
+ pcibios_read_config_dword(cyy_bus, cyy_dev_fn,
+ PCI_BASE_ADDRESS_0, &cy_pci_addr0);
+ pcibios_read_config_dword(cyy_bus, cyy_dev_fn,
+ PCI_BASE_ADDRESS_1, &cy_pci_addr1);
+ pcibios_read_config_dword(cyy_bus, cyy_dev_fn,
+ PCI_BASE_ADDRESS_2, &cy_pci_addr2);
+ pcibios_read_config_byte(cyy_bus, cyy_dev_fn,
+ PCI_REVISION_ID, &cyy_rev_id);
+ if (device_id == 0){
+ break;
+ }else if ((device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo)
+ || (device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi)){
+#ifdef CY_PCI_DEBUG
+ printk("Cyclom-Y/PCI (bus=0x0%x, pci_id=0x%x, ",
+ cyy_bus, cyy_dev_fn);
+ printk("rev_id=%d) IRQ%d\n",
+ cyy_rev_id, (int)cy_pci_irq);
+ printk("Cyclom-Y/PCI:found winaddr=0x%x ioaddr=0x%x\n",
+ cy_pci_addr2, cy_pci_addr1);
+#endif
+ cy_pci_addr1 &= 0xfffffffc;
+ cy_pci_addr2 &= 0xfffffff0;
+
+#if LINUX_VERSION_CODE < 131328
+ if ((ulong)cy_pci_addr2 >= 0x100000) /* above 1M? */
+#endif
+ cy_pci_addr2 =
+ (unsigned int) vremap(cy_pci_addr2,CyPCI_Ywin);
+
+#ifdef CY_PCI_DEBUG
+ printk("Cyclom-Y/PCI: relocate winaddr=0x%x ioaddr=0x%x\n",
+ cy_pci_addr2, cy_pci_addr1);
+#endif
+ cy_pci_nchan = 4 * cyy_init_card((unsigned char *)
+ cy_pci_addr2,1);
+ if(cy_pci_nchan == 0) {
+ printk("Cyclom-Y PCI host card with ");
+ printk("no Serial-Modules at 0x%x.\n",
+ (unsigned int) cy_pci_addr2);
+ continue;
+ }
+ if((cy_next_channel+cy_pci_nchan) > NR_PORTS) {
+ printk("Cyclom-Y/PCI found at 0x%x ",
+ (unsigned int) cy_pci_addr2);
+ printk("but no channels are available.\n");
+ return(i);
+ }
+ /* fill the next cy_card structure available */
+ for (j = 0 ; j < NR_CARDS ; j++) {
+ if (cy_card[j].base_addr == 0) break;
+ }
+ if (j == NR_CARDS) { /* no more cy_cards available */
+ printk("Cyclom-Y/PCI found at 0x%x ",
+ (unsigned int) cy_pci_addr2);
+ printk("but no more cards can be used.\n");
+ return(i);
+ }
+
+ /* allocate IRQ */
+ if(request_irq(cy_pci_irq, cyy_interrupt,
+ SA_INTERRUPT, "cyclomY", NULL))
+ {
+ printk("Cyclom-Y/PCI found at 0x%x ",
+ (unsigned int) cy_pci_addr2);
+ printk("but could not allocate IRQ%d.\n",
+ cy_pci_irq);
+ return(i);
+ }
+
+ /* set cy_card */
+ cy_card[j].base_addr = (int) cy_pci_addr2;
+ cy_card[j].ctl_addr = 0;
+ cy_card[j].irq = (int) cy_pci_irq;
+ cy_card[j].bus_index = 1;
+ cy_card[j].first_line = cy_next_channel;
+ cy_card[j].num_chips = cy_pci_nchan/4;
+ IRQ_cards[cy_pci_irq] = &cy_card[j];
+
+ /* enable interrupts in the PCI interface */
+ outw(inw(cy_pci_addr1+0x68)|0x0900,cy_pci_addr1+0x68);
+ pci_intr_ctrl = (unsigned long)
+ (inw(cy_pci_addr1+0x68)
+ | inw(cy_pci_addr1+0x6a)<<16);
+
+ /* print message */
+ printk("Cyclom-Y/PCI #%d: 0x%x-0x%x, IRQ%d, ",
+ j+1, cy_pci_addr2, (cy_pci_addr2 + CyPCI_Ywin - 1),
+ (int)cy_pci_irq);
+ printk("%d channels starting from port %d.\n",
+ cy_pci_nchan, cy_next_channel);
+
+ cy_next_channel += cy_pci_nchan;
+ }else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Lo){
+ /* print message */
+ printk("Cyclom-Z/PCI (bus=0x0%x, pci_id=0x%x, ",
+ cyy_bus, cyy_dev_fn);
+ printk("rev_id=%d) IRQ%d\n",
+ cyy_rev_id, (int)cy_pci_irq);
+ printk("Cyclom-Z/PCI: found winaddr=0x%x ctladdr=0x%x\n",
+ cy_pci_addr2, cy_pci_addr0);
+ printk("Cyclom-Z/PCI not supported for low addresses\n");
+ break;
+ }else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi){
+#ifdef CY_PCI_DEBUG
+ printk("Cyclom-Z/PCI (bus=0x0%x, pci_id=0x%x, ",
+ cyy_bus, cyy_dev_fn);
+ printk("rev_id=%d) IRQ%d\n",
+ cyy_rev_id, (int)cy_pci_irq);
+ printk("Cyclom-Z/PCI: found winaddr=0x%x ctladdr=0x%x\n",
+ cy_pci_addr2, cy_pci_addr0);
+#endif
+ cy_pci_addr2 &= 0xfffffff0;
+ cy_pci_addr2 = (unsigned int) vremap(
+ cy_pci_addr2 & PAGE_MASK,
+ PAGE_ALIGN(CyPCI_Zwin))
+ + (cy_pci_addr2 & (PAGE_SIZE-1));
+ cy_pci_addr0 &= 0xfffffff0;
+ cy_pci_addr0 = (unsigned int) vremap(
+ cy_pci_addr0 & PAGE_MASK,
+ PAGE_ALIGN(CyPCI_Zctl))
+ + (cy_pci_addr0 & (PAGE_SIZE-1));
+#ifdef CY_PCI_DEBUG
+ printk("Cyclom-Z/PCI: relocate winaddr=0x%x ctladdr=0x%x\n",
+ cy_pci_addr2, cy_pci_addr0);
+ ((struct RUNTIME_9060 *)(cy_pci_addr0))
+ ->loc_addr_base = WIN_CREG;
+ PAUSE
+ printk("Cyclom-Z/PCI: FPGA id %lx, ver %lx\n",
+ 0xff & ((struct CUSTOM_REG *)(cy_pci_addr2))->fpga_id,
+ 0xff & ((struct CUSTOM_REG *)(cy_pci_addr2))->fpga_version);
+ ((struct RUNTIME_9060 *)(cy_pci_addr0))
+ ->loc_addr_base = WIN_RAM;
+#endif
+ /* The following clears the firmware id word. This ensures
+ that the driver will not attempt to talk to the board
+ until it has been properly initialized.
+ */
+ PAUSE
+ *(unsigned long *)(cy_pci_addr2+ID_ADDRESS) = 0L;
+
+ /* This must be a Cyclom-8Zo/PCI. The extendable
+ version will have a different device_id and will
+ be allocated its maximum number of ports. */
+ cy_pci_nchan = 8;
+
+ /* fill the next cy_card structure available */
+ for (j = 0 ; j < NR_CARDS ; j++) {
+ if (cy_card[j].base_addr == 0) break;
+ }
+ if (j == NR_CARDS) { /* no more cy_cards available */
+ printk("Cyclom-Z/PCI found at 0x%x ",
+ (unsigned int) cy_pci_addr2);
+ printk("but no more cards can be used.\n");
+ return(i);
+ }
+
+ /* allocate IRQ only if board has an IRQ */
+ if( (1 < cy_pci_irq) && (cy_pci_irq < 15) ) {
+ if(request_irq(cy_pci_irq,cyz_interrupt,
+ SA_INTERRUPT,"cyclomZ",NULL))
+ {
+ printk("Could not allocate IRQ%d ",
+ (unsigned int) cy_pci_addr2);
+ printk("for Cyclom-Z/PCI at 0x%x.\n",
+ cy_pci_irq);
+ return(i);
+ }
+ }
+
+ /* set cy_card */
+ cy_card[j].base_addr = cy_pci_addr2;
+ cy_card[j].ctl_addr = cy_pci_addr0;
+ cy_card[j].irq = (int) cy_pci_irq;
+ cy_card[j].bus_index = 1;
+ cy_card[j].first_line = cy_next_channel;
+ cy_card[j].num_chips = 1;
+ IRQ_cards[cy_pci_irq] = &cy_card[j];
+
+ /* print message */
+ /* don't report IRQ if board is no IRQ */
+ if( (cy_pci_irq < 15) && (cy_pci_irq > 1) ) {
+ printk("Cyclom-Z/PCI #%d: 0x%x-0x%x, IRQ%d, ",
+ j+1,cy_pci_addr2,
+ (cy_pci_addr2 + CyPCI_Zwin - 1),
+ (int)cy_pci_irq);
+ }else{
+ printk("Cyclom-Z/PCI #%d: 0x%x-0x%x, ",
+ j+1,cy_pci_addr2,
+ (cy_pci_addr2 + CyPCI_Zwin - 1));
+ }
+ printk("%d channels starting from port %d.\n",
+ cy_pci_nchan,cy_next_channel);
+ cy_next_channel += cy_pci_nchan;
+ }
+ }
+ return(i);
+#else
+ return(0);
+#endif /* ifdef CONFIG_PCI */
+} /* cy_detect_pci */
+
+
+/*
+ * This routine prints out the appropriate serial driver version number
+ * and identifies which options were configured into this driver.
+ */
+static inline void
+show_version(void)
+{
+ char *rcsvers, *rcsdate, *tmp;
+ rcsvers = strchr(rcsid, ' '); rcsvers++;
+ tmp = strchr(rcsvers, ' '); *tmp++ = '\0';
+ rcsdate = strchr(tmp, ' '); rcsdate++;
+ tmp = strrchr(rcsdate, ' '); *tmp = '\0';
+ printk("Cyclom driver %s %s\n",
+ rcsvers, rcsdate);
+ printk("\tbuilt %s %s\n",
+ __DATE__, __TIME__);
+} /* show_version */
+
/* The serial driver boot-time initialization code!
Hardware I/O ports are mapped to character special devices on a
@@ -2783,15 +4307,18 @@ cy_init_card(unsigned char *true_base_addr,int index))
device driver because the Cyclom is more properly a multiplexer,
not just an aggregation of serial ports on one card.
- If there are more cards with more ports than have been statically
- allocated above, a warning is printed and the extra ports are ignored.
+ If there are more cards with more ports than have been
+ statically allocated above, a warning is printed and the
+ extra ports are ignored.
*/
+
__initfunc(int
cy_init(void))
{
- struct cyclades_port *info;
+ struct cyclades_port *info;
struct cyclades_card *cinfo;
- int board,port,i;
+ int number_z_boards = 0;
+ int board,port,i;
show_version();
@@ -2807,7 +4334,7 @@ cy_init(void))
cy_serial_driver.subtype = SERIAL_TYPE_NORMAL;
cy_serial_driver.init_termios = tty_std_termios;
cy_serial_driver.init_termios.c_cflag =
- B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ B9600 | CS8 | CREAD | HUPCL | CLOCAL;
cy_serial_driver.flags = TTY_DRIVER_REAL_RAW;
cy_serial_driver.refcount = &serial_refcount;
cy_serial_driver.table = serial_table;
@@ -2839,27 +4366,27 @@ cy_init(void))
cy_callout_driver.subtype = SERIAL_TYPE_CALLOUT;
if (tty_register_driver(&cy_serial_driver))
- panic("Couldn't register Cyclom serial driver\n");
+ panic("Couldn't register Cyclom serial driver\n");
if (tty_register_driver(&cy_callout_driver))
- panic("Couldn't register Cyclom callout driver\n");
+ panic("Couldn't register Cyclom callout driver\n");
init_bh(CYCLADES_BH, do_cyclades_bh);
for (i = 0; i < 16; i++) {
- IRQ_cards[i] = 0;
+ IRQ_cards[i] = 0;
}
for (i = 0; i < NR_CARDS; i++) {
- /* base_addr=0 indicates board not found */
- cy_card[i].base_addr = 0;
+ /* base_addr=0 indicates board not found */
+ cy_card[i].base_addr = 0;
}
/* the code below is responsible to find the boards. Each different
type of board has its own detection routine. If a board is found,
the next cy_card structure available is set by the detection
- routine. These functions are responsible for checking the availability
- of cy_card and cy_port data structures and updating the
- cy_next_channel. */
+ routine. These functions are responsible for checking the
+ availability of cy_card and cy_port data structures and updating
+ the cy_next_channel. */
/* look for isa boards */
cy_isa_nboard = cy_detect_isa();
@@ -2871,289 +4398,195 @@ cy_init(void))
/* invalidate remaining cy_card structures */
for (i = 0 ; i < NR_CARDS ; i++) {
- if (cy_card[i].base_addr == 0) {
- cy_card[i].first_line = -1;
- }
+ if (cy_card[i].base_addr == 0) {
+ cy_card[i].first_line = -1;
+ cy_card[i].ctl_addr = 0;
+ cy_card[i].irq = 0;
+ cy_card[i].bus_index = 0;
+ cy_card[i].first_line = 0;
+ cy_card[i].num_chips = 0;
+ }
}
/* invalidate remaining cy_port structures */
for (i = cy_next_channel ; i < NR_PORTS ; i++) {
- cy_port[i].line = -1;
- cy_port[i].magic = -1;
+ cy_port[i].line = -1;
+ cy_port[i].magic = -1;
}
/* initialize per-port data structures for each valid board found */
for (board = 0 ; board < cy_nboard ; board++) {
- cinfo = &cy_card[board];
- for (port = cinfo->first_line ;
- port < cinfo->first_line + 4*cinfo->num_chips ;
- port++)
- {
- info = &cy_port[port];
- info->magic = CYCLADES_MAGIC;
- info->type = PORT_CIRRUS;
- info->card = board;
- info->line = port;
- info->flags = STD_COM_FLAGS;
- info->tty = 0;
- info->xmit_fifo_size = 12;
- info->cor1 = CyPARITY_NONE|Cy_1_STOP|Cy_8_BITS;
- info->cor2 = CyETC;
- info->cor3 = 0x08; /* _very_ small receive threshold */
- info->cor4 = 0;
- info->cor5 = 0;
- info->tbpr = baud_bpr[13]; /* Tx BPR */
- info->tco = baud_co[13]; /* Tx CO */
- info->rbpr = baud_bpr[13]; /* Rx BPR */
- info->rco = baud_co[13]; /* Rx CO */
- info->close_delay = 0;
- info->x_char = 0;
- info->event = 0;
- info->count = 0;
+ cinfo = &cy_card[board];
+ if (cinfo->num_chips == 1){ /* Cyclom-8Zo/PCI */
+ number_z_boards++;
+ for (port = cinfo->first_line ;
+ port < cinfo->first_line + 8;
+ port++)
+ {
+ info = &cy_port[port];
+ info->magic = CYCLADES_MAGIC;
+ info->type = PORT_STARTECH;
+ info->card = board;
+ info->line = port;
+ info->flags = STD_COM_FLAGS;
+ info->tty = 0;
+ info->xmit_fifo_size = 0;
+ info->cor1 = 0;
+ info->cor2 = 0;
+ info->cor3 = 0;
+ info->cor4 = 0;
+ info->cor5 = 0;
+ info->tbpr = 0;
+ info->tco = 0;
+ info->rbpr = 0;
+ info->rco = 0;
+ info->close_delay = 0;
+ info->x_char = 0;
+ info->event = 0;
+ info->count = 0;
#ifdef SERIAL_DEBUG_COUNT
- printk("cyc: %d: setting count to 0\n", __LINE__);
-#endif
- info->blocked_open = 0;
- info->default_threshold = 0;
- info->default_timeout = 0;
- info->tqueue.routine = do_softint;
- info->tqueue.data = info;
- info->callout_termios =cy_callout_driver.init_termios;
- info->normal_termios = cy_serial_driver.init_termios;
- info->open_wait = 0;
- info->close_wait = 0;
- /* info->session */
- /* info->pgrp */
- info->read_status_mask = CyTIMEOUT| CySPECHAR| CyBREAK
- | CyPARITY| CyFRAME| CyOVERRUN;
- /* info->timeout */
- }
+ printk("cyc:cy_init(1) setting Z count to 0\n");
+#endif
+ info->blocked_open = 0;
+ info->default_threshold = 0;
+ info->default_timeout = 0;
+ info->tqueue.routine = do_softint;
+ info->tqueue.data = info;
+ info->callout_termios =
+ cy_callout_driver.init_termios;
+ info->normal_termios =
+ cy_serial_driver.init_termios;
+ info->open_wait = 0;
+ info->close_wait = 0;
+ /* info->session */
+ /* info->pgrp */
+ info->read_status_mask = 0;
+ /* info->timeout */
+ /* Bentson's vars */
+ info->jiffies[0] = 0;
+ info->jiffies[1] = 0;
+ info->jiffies[2] = 0;
+ info->rflush_count = 0;
+ }
+ continue;
+ }else{ /* Cyclom-Y of some kind*/
+ for (port = cinfo->first_line ;
+ port < cinfo->first_line + 4*cinfo->num_chips ;
+ port++)
+ {
+ info = &cy_port[port];
+ info->magic = CYCLADES_MAGIC;
+ info->type = PORT_CIRRUS;
+ info->card = board;
+ info->line = port;
+ info->flags = STD_COM_FLAGS;
+ info->tty = 0;
+ info->xmit_fifo_size = 12;
+ info->cor1 = CyPARITY_NONE|Cy_1_STOP|Cy_8_BITS;
+ info->cor2 = CyETC;
+ info->cor3 = 0x08; /* _very_ small rcv threshold */
+ info->cor4 = 0;
+ info->cor5 = 0;
+ info->tbpr = baud_bpr[13]; /* Tx BPR */
+ info->tco = baud_co[13]; /* Tx CO */
+ info->rbpr = baud_bpr[13]; /* Rx BPR */
+ info->rco = baud_co[13]; /* Rx CO */
+ info->close_delay = 0;
+ info->x_char = 0;
+ info->event = 0;
+ info->count = 0;
+#ifdef SERIAL_DEBUG_COUNT
+ printk("cyc:cy_init(2) setting Y count to 0\n");
+#endif
+ info->blocked_open = 0;
+ info->default_threshold = 0;
+ info->default_timeout = 0;
+ info->tqueue.routine = do_softint;
+ info->tqueue.data = info;
+ info->callout_termios =
+ cy_callout_driver.init_termios;
+ info->normal_termios =
+ cy_serial_driver.init_termios;
+ info->open_wait = 0;
+ info->close_wait = 0;
+ /* info->session */
+ /* info->pgrp */
+ info->read_status_mask =
+ CyTIMEOUT| CySPECHAR| CyBREAK
+ | CyPARITY| CyFRAME| CyOVERRUN;
+ /* info->timeout */
+ }
+ }
+ }
+
+ if ( number_z_boards && !cyz_timeron){
+ cyz_timeron++;
+ cyz_timerlist.expires = jiffies + 1;
+ add_timer(&cyz_timerlist);
+#ifdef CY_PCI_DEBUG
+ printk("Cyclom-Z polling initialized\n");
+#endif
}
+
return 0;
} /* cy_init */
#ifdef MODULE
+/* See linux/drivers/char/riscom.c for ideas on how to
+ pass additional base addresses to the driver!!! */
int
init_module(void)
{
return(cy_init());
-}
+} /* init_module */
void
cleanup_module(void)
{
- unsigned long flags;
int i;
+ unsigned long flags;
+
+
+ if (cyz_timeron){
+ cyz_timeron = 0;
+ del_timer(&cyz_timerlist);
+ }
save_flags(flags);
cli();
- remove_bh(CYCLADES_BH);
+ remove_bh(CYCLADES_BH);
if (tty_unregister_driver(&cy_callout_driver))
- printk("Couldn't unregister Cyclom callout driver\n");
+ printk("Couldn't unregister Cyclom callout driver\n");
if (tty_unregister_driver(&cy_serial_driver))
- printk("Couldn't unregister Cyclom serial driver\n");
+ printk("Couldn't unregister Cyclom serial driver\n");
restore_flags(flags);
for (i = 0; i < NR_CARDS; i++) {
- if (cy_card[i].base_addr != 0)
- {
- free_irq(cy_card[i].irq,NULL);
- }
+ if (cy_card[i].base_addr != 0
+ && cy_card[i].irq)
+ {
+ free_irq(cy_card[i].irq,NULL);
+ }
}
-}
-#endif
-
-/*
- * ---------------------------------------------------------------------
- * cy_detect_isa() - Probe for Cyclom-Y/ISA boards.
- * sets global variables and return the number of ISA boards found.
- * ---------------------------------------------------------------------
- */
-__initfunc(int
-cy_detect_isa())
-{
- unsigned int cy_isa_irq,nboard;
- unsigned char *cy_isa_address;
- unsigned short i,j,cy_isa_nchan;
-
- nboard = 0;
-
- /* scan the address table probing for Cyclom-Y/ISA boards */
- for (i = 0 ; i < NR_ISA_ADDRESSES ; i++) {
- cy_isa_address = cy_isa_addresses[i];
- if (cy_isa_address == 0x0000) {
- return(nboard);
- }
-
- /* probe for CD1400... */
- cy_isa_nchan = 4 * cy_init_card(cy_isa_address,0);
- if (cy_isa_nchan == 0) {
- continue;
- }
-
- /* find out the board's irq by probing */
- cy_isa_irq = do_auto_irq(cy_isa_address);
- if (cy_isa_irq == 0) {
- printk("Cyclom-Y/ISA found at 0x%x but the IRQ could not be detected.\n",
- (unsigned int) cy_isa_address);
- continue;
- }
-
- if((cy_next_channel+cy_isa_nchan) > NR_PORTS) {
- printk("Cyclom-Y/ISA found at 0x%x but no more channel structures are available.\n",
- (unsigned int) cy_isa_address);
- return(nboard);
- }
- /* fill the next cy_card structure available */
- for (j = 0 ; j < NR_CARDS ; j++) {
- if (cy_card[j].base_addr == 0) break;
- }
- if (j == NR_CARDS) { /* no more cy_cards available */
- printk("Cyclom-Y/ISA found at 0x%x but no more card structures are available.\n",
- (unsigned int) cy_isa_address);
- return(nboard);
- }
-
- /* allocate IRQ */
- if(request_irq(cy_isa_irq,cy_interrupt,SA_INTERRUPT,"cyclades",NULL))
- {
- printk("Cyclom-Y/ISA found at 0x%x but could not allocate interrupt IRQ#%d.\n",
- (unsigned int) cy_isa_address,cy_isa_irq);
- return(nboard);
- }
-
- /* set cy_card */
- cy_card[j].base_addr = (int) cy_isa_address;
- cy_card[j].irq = (int) cy_isa_irq;
- cy_card[j].bus_index = 0;
- cy_card[j].first_line = cy_next_channel;
- cy_card[j].num_chips = cy_isa_nchan/4;
- IRQ_cards[cy_isa_irq] = &cy_card[j];
- nboard++;
-
- /* print message */
- printk("Cyclom-Y/ISA #%d: 0x%x-0x%x, IRQ%d, %d channels starting from port %d.\n",
- j+1,(unsigned int) cy_isa_address,
- (unsigned int)(cy_isa_address + 0x1fff),
- cy_isa_irq,cy_isa_nchan,cy_next_channel);
- cy_next_channel += cy_isa_nchan;
- }
- return(nboard);
-
-}
-
-/*
- * ---------------------------------------------------------------------
- * cy_detect_pci() - Test PCI bus presence and Cyclom-Ye/PCI.
- * sets global variables and return the number of PCI boards found.
- * ---------------------------------------------------------------------
- */
-__initfunc(int
-cy_detect_pci())
+} /* cleanup_module */
+#else
+/* called by linux/init/main.c to parse command line options */
+void
+cy_setup(char *str, int *ints)
{
-#ifdef CONFIG_PCI
- unsigned char cyy_bus, cyy_dev_fn, cyy_rev_id;
- unsigned long pci_intr_ctrl;
- unsigned char cy_pci_irq;
- unsigned int cy_pci_address, cy_pci_io;
- unsigned short i,j,cy_pci_nchan;
- unsigned short device_id,dev_index = 0,board_index = 0;
-
- if(pcibios_present() == 0) { /* PCI bus not present */
- return(0);
- }
- for (i = 0; i < NR_CARDS; i++) {
- /* look for a Cyclom-Y card by vendor and device id */
- while((device_id = cy_pci_dev_id[dev_index]) != 0) {
- if(pcibios_find_device(PCI_VENDOR_ID_CYCLADES,
- device_id,board_index,
- &cyy_bus, &cyy_dev_fn) != 0)
- {
- dev_index++; /* try next device id */
- board_index = 0;
- } else {
- board_index++;
- break; /* found a board */
- }
- }
- if (device_id == 0) break;
-
- /* read PCI configuration area */
- pcibios_read_config_byte(cyy_bus, cyy_dev_fn,
- PCI_INTERRUPT_LINE, &cy_pci_irq);
- pcibios_read_config_dword(cyy_bus, cyy_dev_fn,
- PCI_BASE_ADDRESS_1, &cy_pci_io);
- pcibios_read_config_dword(cyy_bus, cyy_dev_fn,
- PCI_BASE_ADDRESS_2, &cy_pci_address);
- pcibios_read_config_byte(cyy_bus, cyy_dev_fn,
- PCI_REVISION_ID, &cyy_rev_id);
- cy_pci_address &= 0xfffffff0;
- if ((ulong)cy_pci_address >= 0x100000) { /* above 1M? */
- cy_pci_address =
- (unsigned int) ioremap(cy_pci_address,0x4000);
- }
- cy_pci_io &= 0xfffffffc;
- cy_pci_nchan = 4 * cy_init_card((unsigned char *)
- cy_pci_address,1);
- if(cy_pci_nchan == 0) {
- printk("Cyclom-Y PCI host card with no Serial-Modules at 0x%x.\n",
- (unsigned int) cy_pci_address);
- continue;
- }
- if((cy_next_channel+cy_pci_nchan) > NR_PORTS) {
- printk("Cyclom-Y/PCI found at 0x%x but no more channel structures are available.\n",
- (unsigned int) cy_pci_address);
- return(i);
- }
-#ifdef CY_PCI_DEBUG
- printk("Cyclom-Ye/PCI #%d (bus=0x0%x, pci_id=0x%x, rev_id=%d).\n",
- i+1,cyy_bus,cyy_dev_fn,cyy_rev_id);
- printk("Cyclom-Ye/PCI: found at 0x%x, IRQ%d, ioaddr = 0x%lx.\n",
- cy_pci_address,(int)cy_pci_irq,cy_pci_io);
-#endif
- /* fill the next cy_card structure available */
- for (j = 0 ; j < NR_CARDS ; j++) {
- if (cy_card[j].base_addr == 0) break;
- }
- if (j == NR_CARDS) { /* no more cy_cards available */
- printk("Cyclom-Y/PCI found at 0x%x but no more card structures are available.\n",
- (unsigned int) cy_pci_address);
- return(i);
- }
+ int i, j;
- /* allocate IRQ */
- if(request_irq(cy_pci_irq,cy_interrupt,SA_INTERRUPT,"cyclades",NULL))
- {
- printk("Cyclom-Y/PCI found at 0x%x but could not allocate interrupt IRQ%d.\n",
- (unsigned int) cy_pci_address,cy_pci_irq);
- return(i);
- }
+ for (i = 0 ; i < NR_ISA_ADDRS ; i++) {
+ if (cy_isa_addresses[i] == 0) break;
+ }
+ for (j = 1; j <= ints[0]; j++){
+ if ( i < NR_ISA_ADDRS ){
+ cy_isa_addresses[i++] = (unsigned char *)(ints[j]);
+ }
+ }
- /* set cy_card */
- cy_card[j].base_addr = (int) cy_pci_address;
- cy_card[j].irq = (int) cy_pci_irq;
- cy_card[j].bus_index = 1;
- cy_card[j].first_line = cy_next_channel;
- cy_card[j].num_chips = cy_pci_nchan/4;
- IRQ_cards[cy_pci_irq] = &cy_card[j];
-
- /* enable interrupts in the PCI interface */
- outw(inw(cy_pci_io+0x68)|0x0900,cy_pci_io+0x68);
- pci_intr_ctrl = (unsigned long)(inw(cy_pci_io+0x68) | inw(cy_pci_io+0x6a)<<16);
-
- /* print message */
- printk("Cyclom-Y/PCI #%d: 0x%x-0x%x, IRQ%d, %d channels starting from port %d.\n",
- j+1,(unsigned int) cy_pci_address,
- (unsigned int)(cy_pci_address + 0x3fff),
- (int)cy_pci_irq,cy_pci_nchan,cy_next_channel);
-
- cy_next_channel += cy_pci_nchan;
- }
- return(i);
-#else
- return(0);
-#endif /* ifdef CONFIG_PCI */
-}
+} /* cy_setup */
+#endif
#ifdef CYCLOM_SHOW_STATUS
@@ -3181,7 +4614,8 @@ show_status(int line_num)
printk(" cy_port\n");
printk(" card line flags = %d %d %x\n",
info->card, info->line, info->flags);
- printk(" *tty read_status_mask timeout xmit_fifo_size = %lx %x %x %x\n",
+ printk(" *tty read_status_mask timeout xmit_fifo_size ",
+ printk("= %lx %x %x %x\n",
(long)info->tty, info->read_status_mask,
info->timeout, info->xmit_fifo_size);
printk(" cor1,cor2,cor3,cor4,cor5 = %x %x %x %x %x\n",
@@ -3198,59 +4632,60 @@ show_status(int line_num)
save_flags(flags); cli();
- base_addr = (unsigned char*)
- (cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
+ base_addr = (unsigned char*)
+ (cy_card[card].base_addr
+ + (cy_chip_offset[chip]<<index));
/* Global Registers */
- printk(" CyGFRCR %x\n", base_addr[CyGFRCR<<index]);
- printk(" CyCAR %x\n", base_addr[CyCAR<<index]);
- printk(" CyGCR %x\n", base_addr[CyGCR<<index]);
- printk(" CySVRR %x\n", base_addr[CySVRR<<index]);
- printk(" CyRICR %x\n", base_addr[CyRICR<<index]);
- printk(" CyTICR %x\n", base_addr[CyTICR<<index]);
- printk(" CyMICR %x\n", base_addr[CyMICR<<index]);
- printk(" CyRIR %x\n", base_addr[CyRIR<<index]);
- printk(" CyTIR %x\n", base_addr[CyTIR<<index]);
- printk(" CyMIR %x\n", base_addr[CyMIR<<index]);
- printk(" CyPPR %x\n", base_addr[CyPPR<<index]);
+ printk(" CyGFRCR %x\n", base_addr[CyGFRCR<<index]);
+ printk(" CyCAR %x\n", base_addr[CyCAR<<index]);
+ printk(" CyGCR %x\n", base_addr[CyGCR<<index]);
+ printk(" CySVRR %x\n", base_addr[CySVRR<<index]);
+ printk(" CyRICR %x\n", base_addr[CyRICR<<index]);
+ printk(" CyTICR %x\n", base_addr[CyTICR<<index]);
+ printk(" CyMICR %x\n", base_addr[CyMICR<<index]);
+ printk(" CyRIR %x\n", base_addr[CyRIR<<index]);
+ printk(" CyTIR %x\n", base_addr[CyTIR<<index]);
+ printk(" CyMIR %x\n", base_addr[CyMIR<<index]);
+ printk(" CyPPR %x\n", base_addr[CyPPR<<index]);
- base_addr[CyCAR<<index] = (u_char)channel;
+ base_addr[CyCAR<<index] = (u_char)channel;
/* Virtual Registers */
- printk(" CyRIVR %x\n", base_addr[CyRIVR<<index]);
- printk(" CyTIVR %x\n", base_addr[CyTIVR<<index]);
- printk(" CyMIVR %x\n", base_addr[CyMIVR<<index]);
- printk(" CyMISR %x\n", base_addr[CyMISR<<index]);
+ printk(" CyRIVR %x\n", base_addr[CyRIVR<<index]);
+ printk(" CyTIVR %x\n", base_addr[CyTIVR<<index]);
+ printk(" CyMIVR %x\n", base_addr[CyMIVR<<index]);
+ printk(" CyMISR %x\n", base_addr[CyMISR<<index]);
/* Channel Registers */
- printk(" CyCCR %x\n", base_addr[CyCCR<<index]);
- printk(" CySRER %x\n", base_addr[CySRER<<index]);
- printk(" CyCOR1 %x\n", base_addr[CyCOR1<<index]);
- printk(" CyCOR2 %x\n", base_addr[CyCOR2<<index]);
- printk(" CyCOR3 %x\n", base_addr[CyCOR3<<index]);
- printk(" CyCOR4 %x\n", base_addr[CyCOR4<<index]);
- printk(" CyCOR5 %x\n", base_addr[CyCOR5<<index]);
- printk(" CyCCSR %x\n", base_addr[CyCCSR<<index]);
- printk(" CyRDCR %x\n", base_addr[CyRDCR<<index]);
- printk(" CySCHR1 %x\n", base_addr[CySCHR1<<index]);
- printk(" CySCHR2 %x\n", base_addr[CySCHR2<<index]);
- printk(" CySCHR3 %x\n", base_addr[CySCHR3<<index]);
- printk(" CySCHR4 %x\n", base_addr[CySCHR4<<index]);
- printk(" CySCRL %x\n", base_addr[CySCRL<<index]);
- printk(" CySCRH %x\n", base_addr[CySCRH<<index]);
- printk(" CyLNC %x\n", base_addr[CyLNC<<index]);
- printk(" CyMCOR1 %x\n", base_addr[CyMCOR1<<index]);
- printk(" CyMCOR2 %x\n", base_addr[CyMCOR2<<index]);
- printk(" CyRTPR %x\n", base_addr[CyRTPR<<index]);
- printk(" CyMSVR1 %x\n", base_addr[CyMSVR1<<index]);
- printk(" CyMSVR2 %x\n", base_addr[CyMSVR2<<index]);
- printk(" CyRBPR %x\n", base_addr[CyRBPR<<index]);
- printk(" CyRCOR %x\n", base_addr[CyRCOR<<index]);
- printk(" CyTBPR %x\n", base_addr[CyTBPR<<index]);
- printk(" CyTCOR %x\n", base_addr[CyTCOR<<index]);
+ printk(" CyCCR %x\n", base_addr[CyCCR<<index]);
+ printk(" CySRER %x\n", base_addr[CySRER<<index]);
+ printk(" CyCOR1 %x\n", base_addr[CyCOR1<<index]);
+ printk(" CyCOR2 %x\n", base_addr[CyCOR2<<index]);
+ printk(" CyCOR3 %x\n", base_addr[CyCOR3<<index]);
+ printk(" CyCOR4 %x\n", base_addr[CyCOR4<<index]);
+ printk(" CyCOR5 %x\n", base_addr[CyCOR5<<index]);
+ printk(" CyCCSR %x\n", base_addr[CyCCSR<<index]);
+ printk(" CyRDCR %x\n", base_addr[CyRDCR<<index]);
+ printk(" CySCHR1 %x\n", base_addr[CySCHR1<<index]);
+ printk(" CySCHR2 %x\n", base_addr[CySCHR2<<index]);
+ printk(" CySCHR3 %x\n", base_addr[CySCHR3<<index]);
+ printk(" CySCHR4 %x\n", base_addr[CySCHR4<<index]);
+ printk(" CySCRL %x\n", base_addr[CySCRL<<index]);
+ printk(" CySCRH %x\n", base_addr[CySCRH<<index]);
+ printk(" CyLNC %x\n", base_addr[CyLNC<<index]);
+ printk(" CyMCOR1 %x\n", base_addr[CyMCOR1<<index]);
+ printk(" CyMCOR2 %x\n", base_addr[CyMCOR2<<index]);
+ printk(" CyRTPR %x\n", base_addr[CyRTPR<<index]);
+ printk(" CyMSVR1 %x\n", base_addr[CyMSVR1<<index]);
+ printk(" CyMSVR2 %x\n", base_addr[CyMSVR2<<index]);
+ printk(" CyRBPR %x\n", base_addr[CyRBPR<<index]);
+ printk(" CyRCOR %x\n", base_addr[CyRCOR<<index]);
+ printk(" CyTBPR %x\n", base_addr[CyTBPR<<index]);
+ printk(" CyTCOR %x\n", base_addr[CyTCOR<<index]);
restore_flags(flags);
} /* show_status */
diff --git a/drivers/char/dsp56k.c b/drivers/char/dsp56k.c
index dd035d58c..ef97f7255 100644
--- a/drivers/char/dsp56k.c
+++ b/drivers/char/dsp56k.c
@@ -34,6 +34,7 @@
#include <linux/delay.h> /* guess what */
#include <linux/fs.h>
#include <linux/mm.h>
+#include <linux/init.h>
#include <asm/segment.h>
#include <asm/atarihw.h>
@@ -529,582 +530,7 @@ static struct file_operations dsp56k_fops = {
static int init_error = 0;
-void dsp56k_init(void)
-{
- if(!ATARIHW_PRESENT(DSP56K)) {
- init_error = 1;
- printk("DSP56k driver: Hardware not present\n");
- return;
- }
-
-#ifndef MODULE
- if(register_chrdev(DSP56K_MAJOR, "dsp56k", &dsp56k_fops)) {
- printk("DSP56k driver: Unable to register driver\n");
- return;
- }
-#endif /* !MODULE */
-
- dsp56k.in_use = 0;
-
- printk("DSP56k driver installed\n");
-}
-
-#ifdef MODULE
-int init_module(void)
-{
- int r;
-
- init_error = 0;
- dsp56k_init();
- if(init_error)
- return -EPERM;
-
- r = register_chrdev(DSP56K_MAJOR, "dsp56k", &dsp56k_fops);
- if(r) {
- printk("DSP56k driver: Unable to register driver\n");
- return r;
- }
-
- return 0;
-}
-
-void cleanup_module(void)
-{
- unregister_chrdev(DSP56K_MAJOR, "dsp56k");
-}
-#endif /* MODULE */
-/*
- * The DSP56001 Device Driver, saviour of the Free World(tm)
- *
- * Authors: Fredrik Noring <noring@lysator.liu.se>
- * lars brinkhoff <f93labr@dd.chalmers.se>
- * Tomas Berndtsson <tobe@lysator.liu.se>
- *
- * First version May 1996
- *
- * History:
- * 97-01-29 Tomas Berndtsson,
- * Integrated with Linux 2.1.21 kernel sources.
- * 97-02-15 Tomas Berndtsson,
- * Fixed for kernel 2.1.26
- *
- * BUGS:
- * Hmm... there must be something here :)
- *
- * Copyright (C) 1996,1997 Fredrik Noring, lars brinkhoff & Tomas Berndtsson
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/version.h>
-#include <linux/malloc.h> /* for kmalloc() and kfree() */
-#include <linux/sched.h> /* for struct wait_queue etc */
-#include <linux/major.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/delay.h> /* guess what */
-#include <linux/fs.h>
-#include <linux/mm.h>
-
-#include <asm/segment.h>
-#include <asm/atarihw.h>
-#include <asm/traps.h>
-#include <asm/uaccess.h> /* For put_user and get_user */
-
-#include <asm/dsp56k.h>
-
-/* minor devices */
-#define DSP56K_DEV_56001 0 /* The only device so far */
-
-#define TIMEOUT 10 /* Host port timeout in number of tries */
-#define MAXIO 2048 /* Maximum number of words before sleep */
-#define DSP56K_MAX_BINARY_LENGTH (3*64*1024)
-
-#define DSP56K_TX_INT_ON dsp56k_host_interface.icr |= DSP56K_ICR_TREQ
-#define DSP56K_RX_INT_ON dsp56k_host_interface.icr |= DSP56K_ICR_RREQ
-#define DSP56K_TX_INT_OFF dsp56k_host_interface.icr &= ~DSP56K_ICR_TREQ
-#define DSP56K_RX_INT_OFF dsp56k_host_interface.icr &= ~DSP56K_ICR_RREQ
-
-#define DSP56K_TRANSMIT (dsp56k_host_interface.isr & DSP56K_ISR_TXDE)
-#define DSP56K_RECEIVE (dsp56k_host_interface.isr & DSP56K_ISR_RXDF)
-
-#define max(a,b) ((a) > (b) ? (a) : (b))
-#define min(a,b) ((a) < (b) ? (a) : (b))
-
-#define wait_some(n) \
-{ \
- current->state = TASK_INTERRUPTIBLE; \
- current->timeout = jiffies + n; \
- schedule(); \
-}
-
-#define handshake(count, maxio, timeout, ENABLE, f) \
-{ \
- long i, t, m; \
- while (count > 0) { \
- m = min(count, maxio); \
- for (i = 0; i < m; i++) { \
- for (t = 0; t < timeout && !ENABLE; t++) \
- wait_some(2); \
- if(!ENABLE) \
- return -EIO; \
- f; \
- } \
- count -= m; \
- if (m == maxio) wait_some(2); \
- } \
-}
-
-#define tx_wait(n) \
-{ \
- int t; \
- for(t = 0; t < n && !DSP56K_TRANSMIT; t++) \
- wait_some(1); \
- if(!DSP56K_TRANSMIT) { \
- return -EIO; \
- } \
-}
-
-#define rx_wait(n) \
-{ \
- int t; \
- for(t = 0; t < n && !DSP56K_RECEIVE; t++) \
- wait_some(1); \
- if(!DSP56K_RECEIVE) { \
- return -EIO; \
- } \
-}
-
-/* DSP56001 bootstrap code */
-static char bootstrap[] = {
- 0x0c, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x60, 0xf4, 0x00, 0x00, 0x00, 0x4f, 0x61, 0xf4,
- 0x00, 0x00, 0x7e, 0xa9, 0x06, 0x2e, 0x80, 0x00, 0x00, 0x47,
- 0x07, 0xd8, 0x84, 0x07, 0x59, 0x84, 0x08, 0xf4, 0xa8, 0x00,
- 0x00, 0x04, 0x08, 0xf4, 0xbf, 0x00, 0x0c, 0x00, 0x00, 0xfe,
- 0xb8, 0x0a, 0xf0, 0x80, 0x00, 0x7e, 0xa9, 0x08, 0xf4, 0xa0,
- 0x00, 0x00, 0x01, 0x08, 0xf4, 0xbe, 0x00, 0x00, 0x00, 0x0a,
- 0xa9, 0x80, 0x00, 0x7e, 0xad, 0x08, 0x4e, 0x2b, 0x44, 0xf4,
- 0x00, 0x00, 0x00, 0x03, 0x44, 0xf4, 0x45, 0x00, 0x00, 0x01,
- 0x0e, 0xa0, 0x00, 0x0a, 0xa9, 0x80, 0x00, 0x7e, 0xb5, 0x08,
- 0x50, 0x2b, 0x0a, 0xa9, 0x80, 0x00, 0x7e, 0xb8, 0x08, 0x46,
- 0x2b, 0x44, 0xf4, 0x45, 0x00, 0x00, 0x02, 0x0a, 0xf0, 0xaa,
- 0x00, 0x7e, 0xc9, 0x20, 0x00, 0x45, 0x0a, 0xf0, 0xaa, 0x00,
- 0x7e, 0xd0, 0x06, 0xc6, 0x00, 0x00, 0x7e, 0xc6, 0x0a, 0xa9,
- 0x80, 0x00, 0x7e, 0xc4, 0x08, 0x58, 0x6b, 0x0a, 0xf0, 0x80,
- 0x00, 0x7e, 0xad, 0x06, 0xc6, 0x00, 0x00, 0x7e, 0xcd, 0x0a,
- 0xa9, 0x80, 0x00, 0x7e, 0xcb, 0x08, 0x58, 0xab, 0x0a, 0xf0,
- 0x80, 0x00, 0x7e, 0xad, 0x06, 0xc6, 0x00, 0x00, 0x7e, 0xd4,
- 0x0a, 0xa9, 0x80, 0x00, 0x7e, 0xd2, 0x08, 0x58, 0xeb, 0x0a,
- 0xf0, 0x80, 0x00, 0x7e, 0xad};
-static int sizeof_bootstrap = 375;
-
-
-static struct dsp56k_device {
- int in_use;
- long maxio, timeout;
- int tx_wsize, rx_wsize;
-} dsp56k;
-
-static int dsp56k_reset(void)
-{
- u_char status;
-
- /* Power down the DSP */
- sound_ym.rd_data_reg_sel = 14;
- status = sound_ym.rd_data_reg_sel & 0xef;
- sound_ym.wd_data = status;
- sound_ym.wd_data = status | 0x10;
-
- udelay(10);
-
- /* Power up the DSP */
- sound_ym.rd_data_reg_sel = 14;
- sound_ym.wd_data = sound_ym.rd_data_reg_sel & 0xef;
-
- return 0;
-}
-
-static int dsp56k_upload(u_char *bin, int len)
-{
- int i;
- u_char *p;
-
- dsp56k_reset();
-
- p = bootstrap;
- for (i = 0; i < sizeof_bootstrap/3; i++) {
- /* tx_wait(10); */
- dsp56k_host_interface.data.b[1] = *p++;
- dsp56k_host_interface.data.b[2] = *p++;
- dsp56k_host_interface.data.b[3] = *p++;
- }
- for (; i < 512; i++) {
- /* tx_wait(10); */
- dsp56k_host_interface.data.b[1] = 0;
- dsp56k_host_interface.data.b[2] = 0;
- dsp56k_host_interface.data.b[3] = 0;
- }
-
- for (i = 0; i < len; i++) {
- tx_wait(10);
- get_user(dsp56k_host_interface.data.b[1], bin++);
- get_user(dsp56k_host_interface.data.b[2], bin++);
- get_user(dsp56k_host_interface.data.b[3], bin++);
- }
-
- tx_wait(10);
- dsp56k_host_interface.data.l = 3; /* Magic execute */
-
- return 0;
-}
-
-static long dsp56k_read(struct inode *inode, struct file *file,
- char *buf, unsigned long count)
-{
- int dev = MINOR(inode->i_rdev) & 0x0f;
-
- switch(dev)
- {
- case DSP56K_DEV_56001:
- {
-
- long n;
-
- /* Don't do anything if nothing is to be done */
- if (!count) return 0;
-
- n = 0;
- switch (dsp56k.rx_wsize) {
- case 1: /* 8 bit */
- {
- handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE,
- put_user(dsp56k_host_interface.data.b[3], buf+n++));
- return n;
- }
- case 2: /* 16 bit */
- {
- short *data;
-
- count /= 2;
- data = (short*) buf;
- handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE,
- put_user(dsp56k_host_interface.data.w[1], data+n++));
- return 2*n;
- }
- case 3: /* 24 bit */
- {
- count /= 3;
- handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE,
- put_user(dsp56k_host_interface.data.b[1], buf+n++);
- put_user(dsp56k_host_interface.data.b[2], buf+n++);
- put_user(dsp56k_host_interface.data.b[3], buf+n++));
- return 3*n;
- }
- case 4: /* 32 bit */
- {
- long *data;
-
- count /= 4;
- data = (long*) buf;
- handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE,
- put_user(dsp56k_host_interface.data.l, data+n++));
- return 4*n;
- }
- }
- return -EFAULT;
- }
-
- default:
- printk("DSP56k driver: Unknown minor device: %d\n", dev);
- return -ENXIO;
- }
-}
-
-static long dsp56k_write(struct inode *inode, struct file *file,
- const char *buf, unsigned long count)
-{
- int dev = MINOR(inode->i_rdev) & 0x0f;
-
- switch(dev)
- {
- case DSP56K_DEV_56001:
- {
- long n;
-
- /* Don't do anything if nothing is to be done */
- if (!count) return 0;
-
- n = 0;
- switch (dsp56k.tx_wsize) {
- case 1: /* 8 bit */
- {
- handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT,
- get_user(dsp56k_host_interface.data.b[3], buf+n++));
- return n;
- }
- case 2: /* 16 bit */
- {
- short *data;
-
- count /= 2;
- data = (short*) buf;
- handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT,
- get_user(dsp56k_host_interface.data.w[1], data+n++));
- return 2*n;
- }
- case 3: /* 24 bit */
- {
- count /= 3;
- handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT,
- get_user(dsp56k_host_interface.data.b[1], buf+n++);
- get_user(dsp56k_host_interface.data.b[2], buf+n++);
- get_user(dsp56k_host_interface.data.b[3], buf+n++));
- return 3*n;
- }
- case 4: /* 32 bit */
- {
- long *data;
-
- count /= 4;
- data = (long*) buf;
- handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT,
- get_user(dsp56k_host_interface.data.l, data+n++));
- return 4*n;
- }
- }
-
- return -EFAULT;
- }
- default:
- printk("DSP56k driver: Unknown minor device: %d\n", dev);
- return -ENXIO;
- }
-}
-
-static int dsp56k_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- int dev = MINOR(inode->i_rdev) & 0x0f;
-
- switch(dev)
- {
- case DSP56K_DEV_56001:
-
- switch(cmd) {
- case DSP56K_UPLOAD:
- {
- char *bin;
- int r, len;
- struct dsp56k_upload *binary = (struct dsp56k_upload *) arg;
-
- if(get_user(len, &binary->len) < 0)
- return -EFAULT;
- if(get_user(bin, &binary->bin) < 0)
- return -EFAULT;
-
- if (len == 0) {
- return -EINVAL; /* nothing to upload?!? */
- }
- if (len > DSP56K_MAX_BINARY_LENGTH) {
- return -EINVAL;
- }
-
- r = dsp56k_upload(bin, len);
- if (r < 0) {
- return r;
- }
-
- break;
- }
- case DSP56K_SET_TX_WSIZE:
- if (arg > 4 || arg < 1)
- return -EINVAL;
- dsp56k.tx_wsize = (int) arg;
- break;
- case DSP56K_SET_RX_WSIZE:
- if (arg > 4 || arg < 1)
- return -EINVAL;
- dsp56k.rx_wsize = (int) arg;
- break;
- case DSP56K_HOST_FLAGS:
- {
- int dir, out, status;
- struct dsp56k_host_flags *hf = (struct dsp56k_host_flags*) arg;
-
- if(get_user(dir, &hf->dir) < 0)
- return -EFAULT;
- if(get_user(out, &hf->out) < 0)
- return -EFAULT;
-
- if ((dir & 0x1) && (out & 0x1))
- dsp56k_host_interface.icr |= DSP56K_ICR_HF0;
- else if (dir & 0x1)
- dsp56k_host_interface.icr &= ~DSP56K_ICR_HF0;
- if ((dir & 0x2) && (out & 0x2))
- dsp56k_host_interface.icr |= DSP56K_ICR_HF1;
- else if (dir & 0x2)
- dsp56k_host_interface.icr &= ~DSP56K_ICR_HF1;
-
- status = 0;
- if (dsp56k_host_interface.icr & DSP56K_ICR_HF0) status |= 0x1;
- if (dsp56k_host_interface.icr & DSP56K_ICR_HF1) status |= 0x2;
- if (dsp56k_host_interface.isr & DSP56K_ISR_HF2) status |= 0x4;
- if (dsp56k_host_interface.isr & DSP56K_ISR_HF3) status |= 0x8;
-
- if(put_user(status, &hf->status) < 0)
- return -EFAULT;
- break;
- }
- case DSP56K_HOST_CMD:
- if (arg > 31 || arg < 0)
- return -EINVAL;
- dsp56k_host_interface.cvr = (u_char)((arg & DSP56K_CVR_HV_MASK) |
- DSP56K_CVR_HC);
- break;
- default:
- return -EINVAL;
- }
- return 0;
-
- default:
- printk("DSP56k driver: Unknown minor device: %d\n", dev);
- return -ENXIO;
- }
-}
-
-/* As of 2.1.26 this should be dsp56k_poll,
- * but how do I then check device minor number?
- * Do I need this function at all???
- */
-#ifdef 0
-static int dsp56k_select(struct inode *inode, struct file *file, int sel_type,
- select_table *wait)
-{
- int dev = MINOR(inode->i_rdev) & 0x0f;
-
- switch(dev)
- {
- case DSP56K_DEV_56001:
-
- switch(sel_type) {
- case SEL_IN: /* read */
- return 1;
- case SEL_OUT: /* write */
- return 1;
- default:
- return 1;
- }
-
- default:
- printk("DSP56k driver: Unknown minor device: %d\n", dev);
- return -ENXIO;
- }
-}
-#endif
-
-static int dsp56k_open(struct inode *inode, struct file *file)
-{
- int dev = MINOR(inode->i_rdev) & 0x0f;
-
- switch(dev)
- {
- case DSP56K_DEV_56001:
-
- if (dsp56k.in_use)
- return -EBUSY;
-
- dsp56k.in_use = 1;
- dsp56k.timeout = TIMEOUT;
- dsp56k.maxio = MAXIO;
- dsp56k.rx_wsize = dsp56k.tx_wsize = 4;
-
- DSP56K_TX_INT_OFF;
- DSP56K_RX_INT_OFF;
-
- /* Zero host flags */
- dsp56k_host_interface.icr &= ~DSP56K_ICR_HF0;
- dsp56k_host_interface.icr &= ~DSP56K_ICR_HF1;
-
- break;
-
- default:
- printk("DSP56k driver: Unknown minor device: %d\n", dev);
- return -ENXIO;
- }
-
-#ifdef MODULE
- MOD_INC_USE_COUNT;
-#endif /* MODULE */
-
- return 0;
-}
-
-static void dsp56k_release(struct inode *inode, struct file *file)
-{
- int dev = MINOR(inode->i_rdev) & 0x0f;
-
- switch(dev)
- {
- case DSP56K_DEV_56001:
-
- dsp56k.in_use = 0;
-
- break;
- default:
- printk("DSP56k driver: Unknown minor device: %d\n", dev);
- return;
- }
-
-#ifdef MODULE
- MOD_DEC_USE_COUNT;
-#endif /* MODULE */
-}
-
-static struct file_operations dsp56k_fops = {
- NULL, /* no special dsp56k_lseek */
- dsp56k_read,
- dsp56k_write,
- NULL, /* no special dsp56k_readdir */
- NULL, /* dsp56k_poll? */
- dsp56k_ioctl,
- NULL, /* no special dsp56k_mmap */
- dsp56k_open,
- dsp56k_release,
- NULL, /* no special dsp56k_fsync */
- NULL, /* no special dsp56k_fasync */
- NULL, /* no special dsp56k_check_media_change */
- NULL /* no special dsp56k_revalidate */
-};
-
-
-/****** Init and module functions ******/
-
-static int init_error = 0;
-
-void dsp56k_init(void)
+__initfunc(void dsp56k_init(void))
{
if(!ATARIHW_PRESENT(DSP56K)) {
init_error = 1;
diff --git a/drivers/char/epca.c b/drivers/char/epca.c
new file mode 100644
index 000000000..63da8b5cb
--- /dev/null
+++ b/drivers/char/epca.c
@@ -0,0 +1,4313 @@
+/*
+
+
+ Copyright (C) 1996 Digi International.
+
+ For technical support please email digiLinux@dgii.com or
+ call Digi tech support at (612) 912-3456
+
+ Much of this design and code came from epca.c which was
+ copyright (C) 1994, 1995 Troy De Jongh, and subsquently
+ modified by David Nugent, Christoph Lameter, Mike McLagan.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+--------------------------------------------------------------------------- */
+/* See README.epca for change history --DAT*/
+
+
+#ifdef MODVERSIONS
+#define MODULE
+#endif
+
+/* -----------------------------------------------------------------------
+ This way modules should work regardless if they defined MODULE or
+ MODVERSIONS. (MODVERSIONS is for the newer kernels ...
+-------------------------------------------------------------------------- */
+
+#ifdef MODULE
+#include <linux/config.h>
+#endif /* MODULE */
+
+#include <linux/version.h>
+
+#define NEW_MODULES
+
+#ifdef NEW_MODULES
+#ifdef MODVERSIONS
+#include <linux/modversions.h>
+#endif /* MODVERSIONS */
+#endif /* NEW_MODULES */
+
+#ifdef MODULE
+#include <linux/module.h>
+#endif /* MODULE */
+
+
+#include <linux/errno.h>
+#include <linux/major.h>
+#include <linux/delay.h>
+#include <linux/tty.h>
+#include <linux/serial.h>
+#include <linux/tty_driver.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+#include <linux/ctype.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/segment.h>
+
+
+#include <asm/bitops.h>
+
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty_flip.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/major.h>
+#include <linux/ioport.h>
+
+#ifdef MODULE
+#ifndef NEW_MODULES
+char kernel_version[]=UTS_RELEASE;
+#endif /* NEW_MODULE */
+#endif /* MODULE */
+
+
+#ifdef CONFIG_PCI
+#define ENABLE_PCI
+#endif /* CONFIG_PCI */
+
+
+
+#include <asm/uaccess.h>
+#define putUser(arg1, arg2) put_user(arg1, (unsigned long *)arg2)
+#define getUser(arg1, arg2) get_user(arg1, (unsigned int *)arg2)
+
+
+
+#ifdef ENABLE_PCI
+#include <linux/bios32.h>
+#include <linux/pci.h>
+#include <linux/digiPCI.h>
+#endif /* ENABLE_PCI */
+
+#include <linux/digi1.h>
+#include <linux/digiFep1.h>
+#include <linux/epca.h>
+#include <linux/epcaconfig.h>
+
+/* ---------------------- Begin defines ------------------------ */
+
+#define VERSION "1.1.0"
+
+/* This major needs to be submitted to Linux to join the majors list */
+
+#define DIGIINFOMAJOR 35 /* For Digi specific ioctl */
+
+
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#define MAXCARDS 7
+#define epcaassert(x, msg) if (!(x)) epca_error(__LINE__, msg)
+
+/* ----------------- Begin global definitions ------------------- */
+
+static char mesg[100];
+static int pc_refcount, nbdevs = 0, num_cards = 0, liloconfig = 0;
+static int digi_poller_inhibited = 1 ;
+
+static int setup_error_code = 0;
+static int invalid_lilo_config = 0;
+
+/* -----------------------------------------------------------------------
+ MAXBOARDS is typically 12, but ISA and EISA cards are restricted to
+ 7 below.
+--------------------------------------------------------------------------*/
+static struct board_info boards[7];
+
+
+/* ------------- Begin structures used for driver registeration ---------- */
+
+struct tty_driver pc_driver;
+struct tty_driver pc_callout;
+struct tty_driver pc_info;
+
+/* The below structures are used to initialize the tty_driver structures. */
+
+/* -------------------------------------------------------------------------
+ Note : MAX_ALLOC is currently limited to 0x100. This restriction is
+ placed on us by Linux not Digi.
+----------------------------------------------------------------------------*/
+static struct tty_struct *pc_table[MAX_ALLOC];
+static struct termios *pc_termios[MAX_ALLOC];
+static struct termios *pc_termios_locked[MAX_ALLOC];
+
+
+/* ------------------ Begin Digi specific structures -------------------- */
+
+/* ------------------------------------------------------------------------
+ digi_channels represents an array of structures that keep track of
+ each channel of the Digi product. Information such as transmit and
+ receive pointers, termio data, and signal definitions (DTR, CTS, etc ...)
+ are stored here. This structure is NOT used to overlay the cards
+ physical channel structure.
+-------------------------------------------------------------------------- */
+
+static struct channel digi_channels[MAX_ALLOC];
+
+/* ------------------------------------------------------------------------
+ card_ptr is an array used to hold the address of the
+ first channel structure of each card. This array will hold
+ the addresses of various channels located in digi_channels.
+-------------------------------------------------------------------------- */
+static struct channel *card_ptr[MAXCARDS];
+
+/* ---------------------- Begin function prototypes --------------------- */
+
+/* ----------------------------------------------------------------------
+ Begin generic memory functions. These functions will be alias
+ (point at) more specific functions dependant on the board being
+ configured.
+----------------------------------------------------------------------- */
+
+
+#ifdef MODULE
+int init_module(void);
+void cleanup_module(void);
+#endif /* MODULE */
+
+static inline void memwinon(struct board_info *b, unsigned int win);
+static inline void memwinoff(struct board_info *b, unsigned int win);
+static inline void globalwinon(struct channel *ch);
+static inline void rxwinon(struct channel *ch);
+static inline void txwinon(struct channel *ch);
+static inline void memoff(struct channel *ch);
+static inline void assertgwinon(struct channel *ch);
+static inline void assertmemoff(struct channel *ch);
+
+/* ---- Begin more 'specific' memory functions for cx_like products --- */
+
+static inline void pcxem_memwinon(struct board_info *b, unsigned int win);
+static inline void pcxem_memwinoff(struct board_info *b, unsigned int win);
+static inline void pcxem_globalwinon(struct channel *ch);
+static inline void pcxem_rxwinon(struct channel *ch);
+static inline void pcxem_txwinon(struct channel *ch);
+static inline void pcxem_memoff(struct channel *ch);
+
+/* ------ Begin more 'specific' memory functions for the pcxe ------- */
+
+static inline void pcxe_memwinon(struct board_info *b, unsigned int win);
+static inline void pcxe_memwinoff(struct board_info *b, unsigned int win);
+static inline void pcxe_globalwinon(struct channel *ch);
+static inline void pcxe_rxwinon(struct channel *ch);
+static inline void pcxe_txwinon(struct channel *ch);
+static inline void pcxe_memoff(struct channel *ch);
+
+/* ---- Begin more 'specific' memory functions for the pc64xe and pcxi ---- */
+/* Note : pc64xe and pcxi share the same windowing routines */
+
+static inline void pcxi_memwinon(struct board_info *b, unsigned int win);
+static inline void pcxi_memwinoff(struct board_info *b, unsigned int win);
+static inline void pcxi_globalwinon(struct channel *ch);
+static inline void pcxi_rxwinon(struct channel *ch);
+static inline void pcxi_txwinon(struct channel *ch);
+static inline void pcxi_memoff(struct channel *ch);
+
+/* - Begin 'specific' do nothing memory functions needed for some cards - */
+
+static inline void dummy_memwinon(struct board_info *b, unsigned int win);
+static inline void dummy_memwinoff(struct board_info *b, unsigned int win);
+static inline void dummy_globalwinon(struct channel *ch);
+static inline void dummy_rxwinon(struct channel *ch);
+static inline void dummy_txwinon(struct channel *ch);
+static inline void dummy_memoff(struct channel *ch);
+static inline void dummy_assertgwinon(struct channel *ch);
+static inline void dummy_assertmemoff(struct channel *ch);
+
+/* ------------------- Begin declare functions ----------------------- */
+
+static inline struct channel *verifyChannel(register struct tty_struct *);
+static inline void pc_sched_event(struct channel *, int);
+static void epca_error(int, char *);
+static void pc_close(struct tty_struct *, struct file *);
+static void shutdown(struct channel *);
+static void pc_hangup(struct tty_struct *);
+static void pc_put_char(struct tty_struct *, unsigned char);
+static int pc_write_room(struct tty_struct *);
+static int pc_chars_in_buffer(struct tty_struct *);
+static void pc_flush_buffer(struct tty_struct *);
+static void pc_flush_chars(struct tty_struct *);
+static int block_til_ready(struct tty_struct *, struct file *,
+ struct channel *);
+static int pc_open(struct tty_struct *, struct file *);
+static void post_fep_init(unsigned int crd);
+static void epcapoll(unsigned long);
+static void doevent(int);
+static void fepcmd(struct channel *, int, int, int, int, int);
+static unsigned termios2digi_h(struct channel *ch, unsigned);
+static unsigned termios2digi_i(struct channel *ch, unsigned);
+static unsigned termios2digi_c(struct channel *ch, unsigned);
+static void epcaparam(struct tty_struct *, struct channel *);
+static void receive_data(struct channel *);
+static int pc_ioctl(struct tty_struct *, struct file *,
+ unsigned int, unsigned long);
+static void pc_set_termios(struct tty_struct *, struct termios *);
+static void do_softint(void *);
+static void pc_stop(struct tty_struct *);
+static void pc_start(struct tty_struct *);
+static void pc_throttle(struct tty_struct * tty);
+static void pc_unthrottle(struct tty_struct *tty);
+static void digi_send_break(struct channel *ch, int msec);
+static void setup_empty_event(struct tty_struct *tty, struct channel *ch);
+void epca_setup(char *, int *);
+void console_print(const char *);
+
+static int get_termio(struct tty_struct *, struct termio *);
+static int pc_write(struct tty_struct *, int, const unsigned char *, int);
+int pc_init(void);
+
+#ifdef ENABLE_PCI
+static int init_PCI(int);
+static int get_PCI_configuration(char, char, unsigned int *, unsigned int *,
+ unsigned int *, unsigned int *,
+ unsigned int *, unsigned int *);
+#endif /* ENABLE_PCI */
+
+
+/* ------------------------------------------------------------------
+ Table of functions for each board to handle memory. Mantaining
+ parallelism is a *very* good idea here. The idea is for the
+ runtime code to blindly call these functions, not knowing/caring
+ about the underlying hardware. This stuff should contain no
+ conditionals; if more functionality is needed a different entry
+ should be established. These calls are the interface calls and
+ are the only functions that should be accessed. Anyone caught
+ making direct calls deserves what they get.
+-------------------------------------------------------------------- */
+
+static inline void memwinon(struct board_info *b, unsigned int win)
+{
+ (b->memwinon)(b, win);
+}
+
+static inline void memwinoff(struct board_info *b, unsigned int win)
+{
+ (b->memwinoff)(b, win);
+}
+
+static inline void globalwinon(struct channel *ch)
+{
+ (ch->board->globalwinon)(ch);
+}
+
+static inline void rxwinon(struct channel *ch)
+{
+ (ch->board->rxwinon)(ch);
+}
+
+static inline void txwinon(struct channel *ch)
+{
+ (ch->board->txwinon)(ch);
+}
+
+static inline void memoff(struct channel *ch)
+{
+ (ch->board->memoff)(ch);
+}
+static inline void assertgwinon(struct channel *ch)
+{
+ (ch->board->assertgwinon)(ch);
+}
+
+static inline void assertmemoff(struct channel *ch)
+{
+ (ch->board->assertmemoff)(ch);
+}
+
+/* ---------------------------------------------------------
+ PCXEM windowing is the same as that used in the PCXR
+ and CX series cards.
+------------------------------------------------------------ */
+
+static inline void pcxem_memwinon(struct board_info *b, unsigned int win)
+{
+ outb_p(FEPWIN|win, (int)b->port + 1);
+}
+
+static inline void pcxem_memwinoff(struct board_info *b, unsigned int win)
+{
+ outb_p(0, (int)b->port + 1);
+}
+
+static inline void pcxem_globalwinon(struct channel *ch)
+{
+ outb_p( FEPWIN, (int)ch->board->port + 1);
+}
+
+static inline void pcxem_rxwinon(struct channel *ch)
+{
+ outb_p(ch->rxwin, (int)ch->board->port + 1);
+}
+
+static inline void pcxem_txwinon(struct channel *ch)
+{
+ outb_p(ch->txwin, (int)ch->board->port + 1);
+}
+
+static inline void pcxem_memoff(struct channel *ch)
+{
+ outb_p(0, (int)ch->board->port + 1);
+}
+
+/* ----------------- Begin pcxe memory window stuff ------------------ */
+
+static inline void pcxe_memwinon(struct board_info *b, unsigned int win)
+{
+ outb_p(FEPWIN | win, (int)b->port + 1);
+}
+
+static inline void pcxe_memwinoff(struct board_info *b, unsigned int win)
+{
+ outb_p(inb((int)b->port) & ~FEPMEM,
+ (int)b->port + 1);
+ outb_p(0, (int)b->port + 1);
+}
+
+static inline void pcxe_globalwinon(struct channel *ch)
+{
+ outb_p( FEPWIN, (int)ch->board->port + 1);
+}
+
+static inline void pcxe_rxwinon(struct channel *ch)
+{
+ outb_p(ch->rxwin, (int)ch->board->port + 1);
+}
+
+static inline void pcxe_txwinon(struct channel *ch)
+{
+ outb_p(ch->txwin, (int)ch->board->port + 1);
+}
+
+static inline void pcxe_memoff(struct channel *ch)
+{
+ outb_p(0, (int)ch->board->port);
+ outb_p(0, (int)ch->board->port + 1);
+}
+
+/* ------------- Begin pc64xe and pcxi memory window stuff -------------- */
+
+static inline void pcxi_memwinon(struct board_info *b, unsigned int win)
+{
+ outb_p(inb((int)b->port) | FEPMEM, (int)b->port);
+}
+
+static inline void pcxi_memwinoff(struct board_info *b, unsigned int win)
+{
+ outb_p(inb((int)b->port) & ~FEPMEM, (int)b->port);
+}
+
+static inline void pcxi_globalwinon(struct channel *ch)
+{
+ outb_p(FEPMEM, (int)ch->board->port);
+}
+
+static inline void pcxi_rxwinon(struct channel *ch)
+{
+ outb_p(FEPMEM, (int)ch->board->port);
+}
+
+static inline void pcxi_txwinon(struct channel *ch)
+{
+ outb_p(FEPMEM, (int)ch->board->port);
+}
+
+static inline void pcxi_memoff(struct channel *ch)
+{
+ outb_p(0, (int)ch->board->port);
+}
+
+static inline void pcxi_assertgwinon(struct channel *ch)
+{
+ epcaassert(inb((int)ch->board->port) & FEPMEM, "Global memory off");
+}
+
+static inline void pcxi_assertmemoff(struct channel *ch)
+{
+ epcaassert(!(inb((int)ch->board->port) & FEPMEM), "Memory on");
+}
+
+
+/* ----------------------------------------------------------------------
+ Not all of the cards need specific memory windowing routines. Some
+ cards (Such as PCI) needs no windowing routines at all. We provide
+ these do nothing routines so that the same code base can be used.
+ The driver will ALWAYS call a windowing routine if it thinks it needs
+ to; regardless of the card. However, dependant on the card the routine
+ may or may not do anything.
+---------------------------------------------------------------------------*/
+
+static inline void dummy_memwinon(struct board_info *b, unsigned int win)
+{
+}
+
+static inline void dummy_memwinoff(struct board_info *b, unsigned int win)
+{
+}
+
+static inline void dummy_globalwinon(struct channel *ch)
+{
+}
+
+static inline void dummy_rxwinon(struct channel *ch)
+{
+}
+
+static inline void dummy_txwinon(struct channel *ch)
+{
+}
+
+static inline void dummy_memoff(struct channel *ch)
+{
+}
+
+static inline void dummy_assertgwinon(struct channel *ch)
+{
+}
+
+static inline void dummy_assertmemoff(struct channel *ch)
+{
+}
+
+/* ----------------- Begin verifyChannel function ----------------------- */
+static inline struct channel *verifyChannel(register struct tty_struct *tty)
+{ /* Begin verifyChannel */
+
+ /* --------------------------------------------------------------------
+ This routine basically provides a sanity check. It insures that
+ the channel returned is within the proper range of addresses as
+ well as properly initialized. If some bogus info gets passed in
+ through tty->driver_data this should catch it.
+ --------------------------------------------------------------------- */
+
+ if (tty)
+ { /* Begin if tty */
+
+ register struct channel *ch = (struct channel *)tty->driver_data;
+
+ if ((ch >= &digi_channels[0]) && (ch < &digi_channels[nbdevs]))
+ {
+ if (ch->magic == EPCA_MAGIC)
+ return ch;
+ }
+
+ } /* End if tty */
+
+ /* Else return a NULL for invalid */
+ return NULL;
+
+} /* End verifyChannel */
+
+/* ------------------ Begin pc_sched_event ------------------------- */
+
+static inline void pc_sched_event(struct channel *ch, int event)
+{ /* Begin pc_sched_event */
+
+
+ /* ----------------------------------------------------------------------
+ We call this to schedule interrupt processing on some event. The
+ kernel sees our request and calls the related routine in OUR driver.
+ -------------------------------------------------------------------------*/
+
+ ch->event |= 1 << event;
+ queue_task(&ch->tqueue, &tq_scheduler);
+
+
+} /* End pc_sched_event */
+
+/* ------------------ Begin epca_error ------------------------- */
+
+static void epca_error(int line, char *msg)
+{ /* Begin epca_error */
+
+ printk(KERN_ERR "epca_error (Digi): line = %d %s\n",line,msg);
+ return;
+
+} /* End epca_error */
+
+/* ------------------ Begin pc_close ------------------------- */
+static void pc_close(struct tty_struct * tty, struct file * filp)
+{ /* Begin pc_close */
+
+ struct channel *ch;
+ unsigned long flags;
+
+ if (tty->driver.subtype == SERIAL_TYPE_INFO)
+ {
+ return;
+ }
+
+
+ /* ---------------------------------------------------------
+ verifyChannel returns the channel from the tty struct
+ if it is valid. This serves as a sanity check.
+ ------------------------------------------------------------- */
+
+ if ((ch = verifyChannel(tty)) != NULL)
+ { /* Begin if ch != NULL */
+
+ save_flags(flags);
+ cli();
+
+ if (tty_hung_up_p(filp))
+ {
+ restore_flags(flags);
+ return;
+ }
+
+ /* Check to see if the channel is open more than once */
+ if (ch->count-- > 1)
+ { /* Begin channel is open more than once */
+
+ /* -------------------------------------------------------------
+ Return without doing anything. Someone might still be using
+ the channel.
+ ---------------------------------------------------------------- */
+
+ restore_flags(flags);
+ return;
+ } /* End channel is open more than once */
+
+ /* Port open only once go ahead with shutdown & reset */
+
+ if (ch->count < 0)
+ {
+ ch->count = 0;
+ }
+
+ /* ---------------------------------------------------------------
+ Let the rest of the driver know the channel is being closed.
+ This becomes important if an open is attempted before close
+ is finished.
+ ------------------------------------------------------------------ */
+
+ ch->asyncflags |= ASYNC_CLOSING;
+
+ /* -------------------------------------------------------------
+ Save the termios structure, since this port may have
+ separate termios for callout and dialin.
+ --------------------------------------------------------------- */
+
+ if (ch->asyncflags & ASYNC_NORMAL_ACTIVE)
+ ch->normal_termios = *tty->termios;
+
+ if (ch->asyncflags & ASYNC_CALLOUT_ACTIVE)
+ ch->callout_termios = *tty->termios;
+
+ tty->closing = 1;
+
+ if (ch->asyncflags & ASYNC_INITIALIZED)
+ {
+ /* Setup an event to indicate when the transmit buffer empties */
+ setup_empty_event(tty, ch);
+ tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */
+ }
+
+ if (tty->driver.flush_buffer)
+ tty->driver.flush_buffer(tty);
+
+ if (tty->ldisc.flush_buffer)
+ tty->ldisc.flush_buffer(tty);
+
+ shutdown(ch);
+ tty->closing = 0;
+ ch->event = 0;
+ ch->tty = NULL;
+
+ if (ch->blocked_open)
+ { /* Begin if blocked_open */
+
+ if (ch->close_delay)
+ {
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + ch->close_delay;
+ schedule();
+ }
+
+ wake_up_interruptible(&ch->open_wait);
+
+ } /* End if blocked_open */
+
+ ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED |
+ ASYNC_CALLOUT_ACTIVE | ASYNC_CLOSING);
+ wake_up_interruptible(&ch->close_wait);
+
+#ifdef MODULE
+ MOD_DEC_USE_COUNT;
+#endif
+
+ restore_flags(flags);
+
+ } /* End if ch != NULL */
+
+} /* End pc_close */
+
+/* ------------------ Begin shutdown ------------------------- */
+
+static void shutdown(struct channel *ch)
+{ /* Begin shutdown */
+
+ unsigned long flags;
+ struct tty_struct *tty;
+ volatile struct board_chan *bc;
+
+ if (!(ch->asyncflags & ASYNC_INITIALIZED))
+ return;
+
+ save_flags(flags);
+ cli();
+ globalwinon(ch);
+
+ bc = ch->brdchan;
+
+ /* ------------------------------------------------------------------
+ In order for an event to be generated on the receipt of data the
+ idata flag must be set. Since we are shutting down, this is not
+ necessary clear this flag.
+ --------------------------------------------------------------------- */
+
+ if (bc)
+ bc->idata = 0;
+
+ tty = ch->tty;
+
+ /* ----------------------------------------------------------------
+ If we're a modem control device and HUPCL is on, drop RTS & DTR.
+ ------------------------------------------------------------------ */
+
+ if (tty->termios->c_cflag & HUPCL)
+ {
+ ch->omodem &= ~(ch->m_rts | ch->m_dtr);
+ fepcmd(ch, SETMODEM, 0, ch->m_dtr | ch->m_rts, 10, 1);
+ }
+
+ memoff(ch);
+
+ /* ------------------------------------------------------------------
+ The channel has officialy been closed. The next time it is opened
+ it will have to reinitialized. Set a flag to indicate this.
+ ---------------------------------------------------------------------- */
+
+ /* Prevent future Digi programmed interrupts from coming active */
+
+ ch->asyncflags &= ~ASYNC_INITIALIZED;
+ restore_flags(flags);
+
+} /* End shutdown */
+
+/* ------------------ Begin pc_hangup ------------------------- */
+
+static void pc_hangup(struct tty_struct *tty)
+{ /* Begin pc_hangup */
+
+ struct channel *ch;
+
+ /* ---------------------------------------------------------
+ verifyChannel returns the channel from the tty struct
+ if it is valid. This serves as a sanity check.
+ ------------------------------------------------------------- */
+
+ if ((ch = verifyChannel(tty)) != NULL)
+ { /* Begin if ch != NULL */
+
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ if (tty->driver.flush_buffer)
+ tty->driver.flush_buffer(tty);
+
+ if (tty->ldisc.flush_buffer)
+ tty->ldisc.flush_buffer(tty);
+
+ shutdown(ch);
+
+#ifdef MODULE
+ if (ch->count)
+ MOD_DEC_USE_COUNT;
+#endif /* MODULE */
+
+
+ ch->tty = NULL;
+ ch->event = 0;
+ ch->count = 0;
+ restore_flags(flags);
+ ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED | ASYNC_CALLOUT_ACTIVE);
+ wake_up_interruptible(&ch->open_wait);
+
+ } /* End if ch != NULL */
+
+} /* End pc_hangup */
+
+/* ------------------ Begin pc_write ------------------------- */
+
+static int pc_write(struct tty_struct * tty, int from_user,
+ const unsigned char *buf, int bytesAvailable)
+{ /* Begin pc_write */
+
+ register unsigned int head, tail;
+ register int dataLen;
+ register int size;
+ register int amountCopied;
+
+
+ struct channel *ch;
+ unsigned long flags;
+ int remain;
+ volatile struct board_chan *bc;
+
+
+ /* ----------------------------------------------------------------
+ pc_write is primarily called directly by the kernel routine
+ tty_write (Though it can also be called by put_char) found in
+ tty_io.c. pc_write is passed a line discipline buffer where
+ the data to be written out is stored. The line discipline
+ implementation itself is done at the kernel level and is not
+ brought into the driver.
+ ------------------------------------------------------------------- */
+
+ /* Stop users from hurting themselves on control minor */
+
+ if (tty->driver.subtype == SERIAL_TYPE_INFO)
+ {
+ return (0) ;
+ }
+
+ /* ---------------------------------------------------------
+ verifyChannel returns the channel from the tty struct
+ if it is valid. This serves as a sanity check.
+ ------------------------------------------------------------- */
+
+ if ((ch = verifyChannel(tty)) == NULL)
+ return 0;
+
+ /* Make a pointer to the channel data structure found on the board. */
+
+ bc = ch->brdchan;
+ size = ch->txbufsize;
+
+ if (from_user)
+ { /* Begin from_user */
+
+ save_flags(flags);
+ cli();
+
+ globalwinon(ch);
+
+ /* -----------------------------------------------------------------
+ Anding against size will wrap the pointer back to its begining
+ position if it is necessary. This will only work if size is
+ a power of 2 which should always be the case. Size is determined
+ by the cards on board FEP/OS.
+ -------------------------------------------------------------------- */
+
+ /* head refers to the next empty location in which data may be stored */
+
+ head = bc->tin & (size - 1);
+
+ /* tail refers to the next data byte to be transmitted */
+
+ tail = bc->tout;
+
+ /* Consider changing this to a do statement to make sure */
+
+ if (tail != bc->tout)
+ tail = bc->tout;
+
+ /* ------------------------------------------------------------------
+ Anding against size will wrap the pointer back to its begining
+ position if it is necessary. This will only work if size is
+ a power of 2 which should always be the case. Size is determined
+ by the cards on board FEP/OS.
+ --------------------------------------------------------------------- */
+
+ tail &= (size - 1);
+
+ /* -----------------------------------------------------------------
+ Two situations can affect how space in the transmit buffer
+ is calculated. You can have a situation where the transmit
+ in pointer (tin) head has wrapped around and actually has a
+ lower address than the transmit out pointer (tout) tail; or
+ the transmit in pointer (tin) head will not be wrapped around
+ yet, and have a higher address than the transmit out pointer
+ (tout) tail. Obviously space available in the transmit buffer
+ is calculated differently for each case.
+
+ Example 1:
+
+ Consider a 10 byte buffer where head is a pointer to the next
+ empty location in the buffer and tail is a pointer to the next
+ byte to transmit. In this example head will not have wrapped
+ around and therefore head > tail.
+
+ 0 1 2 3 4 5 6 7 8 9
+ tail head
+
+ The above diagram shows that buffer locations 2,3,4,5 and 6 have
+ data to be transmited, while head points at the next empty
+ location. To calculate how much space is available first we have
+ to determine if the head pointer (tin) has wrapped. To do this
+ compare the head pointer to the tail pointer, If head is equal
+ or greater than tail; then it has not wrapped; and the space may
+ be calculated by subtracting tail from head and then subtracting
+ that value from the buffers size. A one is subtracted from the
+ new value to indicate how much space is available between the
+ head pointer and end of buffer; as well as the space between the
+ begining of the buffer and the tail. If the head is not greater
+ or equal to the tail this indicates that the head has wrapped
+ around to the begining of the buffer. To calculate the space
+ available in this case simply subtract head from tail. This new
+ value minus one represents the space available betwwen the head
+ and tail pointers. In this example head (7) is greater than tail (2)
+ and therefore has not wrapped around. We find the space by first
+ subtracting tail from head (7-2=5). We then subtract this value
+ from the buffer size of ten and subtract one (10-5-1=4). The space
+ remaining is 4 bytes.
+
+ Example 2:
+
+ Consider a 10 byte buffer where head is a pointer to the next
+ empty location in the buffer and tail is a pointer to the next
+ byte to transmit. In this example head will wrapped around and
+ therefore head < tail.
+
+ 0 1 2 3 4 5 6 7 8 9
+ head tail
+
+ The above diagram shows that buffer locations 7,8,9,0 and 1 have
+ data to be transmited, while head points at the next empty
+ location. To find the space available we compare head to tail. If
+ head is not equal to, or greater than tail this indicates that head
+ has wrapped around. In this case head (2) is not equal to, or
+ greater than tail (7) and therefore has already wrapped around. To
+ calculate the available space between the two pointers we subtract
+ head from tail (7-2=5). We then subtract one from this new value
+ (5-1=4). We have 5 bytes empty remaining in the buffer. Unlike the
+ previous example these five bytes are located between the head and
+ tail pointers.
+
+ ----------------------------------------------------------------------- */
+
+ dataLen = (head >= tail) ? (size - (head - tail) - 1) : (tail - head - 1);
+
+ /* ----------------------------------------------------------------------
+ In this case bytesAvailable has been passed into pc_write and
+ represents the amount of data that needs to be written. dataLen
+ represents the amount of space available on the card. Whichever
+ value is smaller will be the amount actually written.
+ bytesAvailable will then take on this newly calculated value.
+ ---------------------------------------------------------------------- */
+
+ bytesAvailable = MIN(dataLen, bytesAvailable);
+
+ /* First we read the data in from the file system into a temp buffer */
+
+ if (bytesAvailable)
+ { /* Begin bytesAvailable */
+
+ /* Can the user buffer be accessed at the moment ? */
+ if (verify_area(VERIFY_READ, (char*)buf, bytesAvailable))
+ bytesAvailable = 0; /* Can't do; try again later */
+ else /* Evidently it can, began transmission */
+ { /* Begin if area verified */
+ /* ---------------------------------------------------------------
+ The below function reads data from user memory. This routine
+ can not be used in an interrupt routine. (Because it may
+ generate a page fault) It can only be called while we can the
+ user context is accessible.
+
+ The prototype is :
+ inline void copy_from_user(void * to, const void * from,
+ unsigned long count);
+
+ You must include <asm/segment.h>
+ I also think (Check hackers guide) that optimization must
+ be turned ON. (Which sounds strange to me...)
+
+ Remember copy_from_user WILL generate a page fault if the
+ user memory being accessed has been swapped out. This can
+ cause this routine to temporarily sleep while this page
+ fault is occuring.
+
+ ----------------------------------------------------------------- */
+
+ copy_from_user(ch->tmp_buf, buf, bytesAvailable);
+
+ } /* End if area verified */
+
+ } /* End bytesAvailable */
+
+ /* ------------------------------------------------------------------
+ Set buf to this address for the moment. tmp_buf was allocated in
+ post_fep_init.
+ --------------------------------------------------------------------- */
+ buf = ch->tmp_buf;
+ memoff(ch);
+ restore_flags(flags);
+
+ } /* End from_user */
+
+ /* All data is now local */
+
+ amountCopied = 0;
+ save_flags(flags);
+ cli();
+
+ globalwinon(ch);
+
+ head = bc->tin & (size - 1);
+ tail = bc->tout;
+
+ if (tail != bc->tout)
+ tail = bc->tout;
+ tail &= (size - 1);
+
+ /* If head >= tail, head has not wrapped around. */
+ if (head >= tail)
+ { /* Begin head has not wrapped */
+
+ /* ---------------------------------------------------------------
+ remain (much like dataLen above) represents the total amount of
+ space available on the card for data. Here dataLen represents
+ the space existing between the head pointer and the end of
+ buffer. This is important because a memcpy cannot be told to
+ automatically wrap around when it hits the buffer end.
+ ------------------------------------------------------------------ */
+
+ dataLen = size - head;
+ remain = size - (head - tail) - 1;
+
+ } /* End head has not wrapped */
+ else
+ { /* Begin head has wrapped around */
+
+ remain = tail - head - 1;
+ dataLen = remain;
+
+ } /* End head has wrapped around */
+
+ /* -------------------------------------------------------------------
+ Check the space on the card. If we have more data than
+ space; reduce the amount of data to fit the space.
+ ---------------------------------------------------------------------- */
+
+ bytesAvailable = MIN(remain, bytesAvailable);
+
+ txwinon(ch);
+ while (bytesAvailable > 0)
+ { /* Begin while there is data to copy onto card */
+
+ /* -----------------------------------------------------------------
+ If head is not wrapped, the below will make sure the first
+ data copy fills to the end of card buffer.
+ ------------------------------------------------------------------- */
+
+ dataLen = MIN(bytesAvailable, dataLen);
+ memcpy(ch->txptr + head, buf, dataLen);
+ buf += dataLen;
+ head += dataLen;
+ amountCopied += dataLen;
+ bytesAvailable -= dataLen;
+
+ if (head >= size)
+ {
+ head = 0;
+ dataLen = tail;
+ }
+
+ } /* End while there is data to copy onto card */
+
+ ch->statusflags |= TXBUSY;
+ globalwinon(ch);
+ bc->tin = head;
+
+ if ((ch->statusflags & LOWWAIT) == 0)
+ {
+ ch->statusflags |= LOWWAIT;
+ bc->ilow = 1;
+ }
+ memoff(ch);
+ restore_flags(flags);
+
+ return(amountCopied);
+
+} /* End pc_write */
+
+/* ------------------ Begin pc_put_char ------------------------- */
+
+static void pc_put_char(struct tty_struct *tty, unsigned char c)
+{ /* Begin pc_put_char */
+
+
+ pc_write(tty, 0, &c, 1);
+ return;
+
+} /* End pc_put_char */
+
+/* ------------------ Begin pc_write_room ------------------------- */
+
+static int pc_write_room(struct tty_struct *tty)
+{ /* Begin pc_write_room */
+
+ int remain;
+ struct channel *ch;
+ unsigned long flags;
+ unsigned int head, tail;
+ volatile struct board_chan *bc;
+
+ remain = 0;
+
+ /* ---------------------------------------------------------
+ verifyChannel returns the channel from the tty struct
+ if it is valid. This serves as a sanity check.
+ ------------------------------------------------------------- */
+
+ if ((ch = verifyChannel(tty)) != NULL)
+ {
+ save_flags(flags);
+ cli();
+ globalwinon(ch);
+
+ bc = ch->brdchan;
+ head = bc->tin & (ch->txbufsize - 1);
+ tail = bc->tout;
+
+ if (tail != bc->tout)
+ tail = bc->tout;
+ /* Wrap tail if necessary */
+ tail &= (ch->txbufsize - 1);
+
+ if ((remain = tail - head - 1) < 0 )
+ remain += ch->txbufsize;
+
+ if (remain && (ch->statusflags & LOWWAIT) == 0)
+ {
+ ch->statusflags |= LOWWAIT;
+ bc->ilow = 1;
+ }
+ memoff(ch);
+ restore_flags(flags);
+ }
+
+ /* Return how much room is left on card */
+ return remain;
+
+} /* End pc_write_room */
+
+/* ------------------ Begin pc_chars_in_buffer ---------------------- */
+
+static int pc_chars_in_buffer(struct tty_struct *tty)
+{ /* Begin pc_chars_in_buffer */
+
+ int chars;
+ unsigned int ctail, head, tail;
+ int remain;
+ unsigned long flags;
+ struct channel *ch;
+ volatile struct board_chan *bc;
+
+
+ /* ---------------------------------------------------------
+ verifyChannel returns the channel from the tty struct
+ if it is valid. This serves as a sanity check.
+ ------------------------------------------------------------- */
+
+ if ((ch = verifyChannel(tty)) == NULL)
+ return(0);
+
+ save_flags(flags);
+ cli();
+ globalwinon(ch);
+
+ bc = ch->brdchan;
+ tail = bc->tout;
+ head = bc->tin;
+ ctail = ch->mailbox->cout;
+
+ if (tail == head && ch->mailbox->cin == ctail && bc->tbusy == 0)
+ chars = 0;
+ else
+ { /* Begin if some space on the card has been used */
+
+ head = bc->tin & (ch->txbufsize - 1);
+ tail &= (ch->txbufsize - 1);
+
+ /* --------------------------------------------------------------
+ The logic here is basically opposite of the above pc_write_room
+ here we are finding the amount of bytes in the buffer filled.
+ Not the amount of bytes empty.
+ ------------------------------------------------------------------- */
+
+ if ((remain = tail - head - 1) < 0 )
+ remain += ch->txbufsize;
+
+ chars = (int)(ch->txbufsize - remain);
+
+ /* -------------------------------------------------------------
+ Make it possible to wakeup anything waiting for output
+ in tty_ioctl.c, etc.
+
+ If not already set. Setup an event to indicate when the
+ transmit buffer empties
+ ----------------------------------------------------------------- */
+
+ if (!(ch->statusflags & EMPTYWAIT))
+ setup_empty_event(tty,ch);
+
+ } /* End if some space on the card has been used */
+
+ memoff(ch);
+ restore_flags(flags);
+
+ /* Return number of characters residing on card. */
+ return(chars);
+
+} /* End pc_chars_in_buffer */
+
+/* ------------------ Begin pc_flush_buffer ---------------------- */
+
+static void pc_flush_buffer(struct tty_struct *tty)
+{ /* Begin pc_flush_buffer */
+
+ unsigned int tail;
+ unsigned long flags;
+ struct channel *ch;
+ volatile struct board_chan *bc;
+
+
+ /* ---------------------------------------------------------
+ verifyChannel returns the channel from the tty struct
+ if it is valid. This serves as a sanity check.
+ ------------------------------------------------------------- */
+
+ if ((ch = verifyChannel(tty)) == NULL)
+ return;
+
+ save_flags(flags);
+ cli();
+
+ globalwinon(ch);
+
+ bc = ch->brdchan;
+ tail = bc->tout;
+
+ /* Have FEP move tout pointer; effectively flushing transmit buffer */
+
+ fepcmd(ch, STOUT, (unsigned) tail, 0, 0, 0);
+
+ memoff(ch);
+ restore_flags(flags);
+
+ wake_up_interruptible(&tty->write_wait);
+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
+ (tty->ldisc.write_wakeup)(tty);
+
+} /* End pc_flush_buffer */
+
+/* ------------------ Begin pc_flush_chars ---------------------- */
+
+static void pc_flush_chars(struct tty_struct *tty)
+{ /* Begin pc_flush_chars */
+
+ struct channel * ch;
+
+ /* ---------------------------------------------------------
+ verifyChannel returns the channel from the tty struct
+ if it is valid. This serves as a sanity check.
+ ------------------------------------------------------------- */
+
+ if ((ch = verifyChannel(tty)) != NULL)
+ {
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+
+ /* ----------------------------------------------------------------
+ If not already set and the transmitter is busy setup an event
+ to indicate when the transmit empties.
+ ------------------------------------------------------------------- */
+
+ if ((ch->statusflags & TXBUSY) && !(ch->statusflags & EMPTYWAIT))
+ setup_empty_event(tty,ch);
+
+ restore_flags(flags);
+ }
+
+} /* End pc_flush_chars */
+
+/* ------------------ Begin block_til_ready ---------------------- */
+
+static int block_til_ready(struct tty_struct *tty,
+ struct file *filp, struct channel *ch)
+{ /* Begin block_til_ready */
+
+ struct wait_queue wait = {current, NULL};
+ int retval, do_clocal = 0;
+ unsigned long flags;
+
+
+ if (tty_hung_up_p(filp))
+ {
+ if (ch->asyncflags & ASYNC_HUP_NOTIFY)
+ retval = -EAGAIN;
+ else
+ retval = -ERESTARTSYS;
+ return(retval);
+ }
+
+ /* -----------------------------------------------------------------
+ If the device is in the middle of being closed, then block
+ until it's done, and then try again.
+ -------------------------------------------------------------------- */
+ if (ch->asyncflags & ASYNC_CLOSING)
+ {
+ interruptible_sleep_on(&ch->close_wait);
+
+ if (ch->asyncflags & ASYNC_HUP_NOTIFY)
+ return -EAGAIN;
+ else
+ return -ERESTARTSYS;
+ }
+
+ /* -----------------------------------------------------------------
+ If this is a callout device, then just make sure the normal
+ device isn't being used.
+ -------------------------------------------------------------------- */
+
+ if (tty->driver.subtype == SERIAL_TYPE_CALLOUT)
+ { /* A cud device has been opened */
+ if (ch->asyncflags & ASYNC_NORMAL_ACTIVE)
+ return -EBUSY;
+
+ if ((ch->asyncflags & ASYNC_CALLOUT_ACTIVE) &&
+ (ch->asyncflags & ASYNC_SESSION_LOCKOUT) &&
+ (ch->session != current->session))
+ return -EBUSY;
+
+ if ((ch->asyncflags & ASYNC_CALLOUT_ACTIVE) &&
+ (ch->asyncflags & ASYNC_PGRP_LOCKOUT) &&
+ (ch->pgrp != current->pgrp))
+ return -EBUSY;
+
+ ch->asyncflags |= ASYNC_CALLOUT_ACTIVE;
+
+ return 0;
+ } /* End a cud device has been opened */
+
+ if (filp->f_flags & O_NONBLOCK)
+ {
+ /* -----------------------------------------------------------------
+ If non-blocking mode is set, then make the check up front
+ and then exit.
+ -------------------------------------------------------------------- */
+
+ if (ch->asyncflags & ASYNC_CALLOUT_ACTIVE)
+ return -EBUSY;
+
+ ch->asyncflags |= ASYNC_NORMAL_ACTIVE;
+
+ return 0;
+ }
+
+
+ if (ch->asyncflags & ASYNC_CALLOUT_ACTIVE)
+ {
+ if (ch->normal_termios.c_cflag & CLOCAL)
+ do_clocal = 1;
+ }
+ else
+ {
+ if (tty->termios->c_cflag & CLOCAL)
+ do_clocal = 1;
+ }
+
+ /* Block waiting for the carrier detect and the line to become free */
+
+ retval = 0;
+ add_wait_queue(&ch->open_wait, &wait);
+ save_flags(flags);
+ cli();
+
+
+ /* We dec count so that pc_close will know when to free things */
+ if (!tty_hung_up_p(filp))
+ ch->count--;
+
+ restore_flags(flags);
+
+ ch->blocked_open++;
+
+ while(1)
+ { /* Begin forever while */
+
+ current->state = TASK_INTERRUPTIBLE;
+
+ if (tty_hung_up_p(filp) ||
+ !(ch->asyncflags & ASYNC_INITIALIZED))
+ {
+ if (ch->asyncflags & ASYNC_HUP_NOTIFY)
+ retval = -EAGAIN;
+ else
+ retval = -ERESTARTSYS;
+ break;
+ }
+
+ if (!(ch->asyncflags & ASYNC_CLOSING) &&
+ !(ch->asyncflags & ASYNC_CALLOUT_ACTIVE) &&
+ (do_clocal || (ch->imodem & ch->dcd)))
+ break;
+
+ if (current->signal & ~current->blocked)
+ {
+ retval = -ERESTARTSYS;
+ break;
+ }
+
+ /* ---------------------------------------------------------------
+ Allow someone else to be scheduled. We will occasionaly go
+ through this loop until one of the above conditions change.
+ The below schedule call will allow other processes to enter and
+ prevent this loop from hogging the cpu.
+ ------------------------------------------------------------------ */
+ schedule();
+
+ } /* End forever while */
+
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&ch->open_wait, &wait);
+ cli();
+ if (!tty_hung_up_p(filp))
+ ch->count++;
+ restore_flags(flags);
+
+ ch->blocked_open--;
+
+ if (retval)
+ return retval;
+
+ ch->asyncflags |= ASYNC_NORMAL_ACTIVE;
+
+ return 0;
+
+} /* End block_til_ready */
+
+/* ------------------ Begin pc_open ---------------------- */
+
+static int pc_open(struct tty_struct *tty, struct file * filp)
+{ /* Begin pc_open */
+
+ struct channel *ch;
+ unsigned long flags;
+ int line, retval, boardnum;
+ volatile struct board_chan *bc;
+ volatile unsigned int head;
+
+ /* Nothing "real" happens in open of control device */
+
+ if (tty->driver.subtype == SERIAL_TYPE_INFO)
+ {
+ return (0) ;
+ }
+
+ line = MINOR(tty->device) - tty->driver.minor_start;
+ if (line < 0 || line >= nbdevs)
+ {
+ printk(KERN_ERR "<Error> - pc_open : line out of range in pc_open\n");
+ tty->driver_data = NULL;
+ return(-ENODEV);
+ }
+
+#ifdef MODULE
+
+ MOD_INC_USE_COUNT;
+
+#endif
+
+ ch = &digi_channels[line];
+ boardnum = ch->boardnum;
+
+ /* Check status of board configured in system. */
+
+ /* -----------------------------------------------------------------
+ I check to see if the epca_setup routine detected an user error.
+ It might be better to put this in pc_init, but for the moment it
+ goes here.
+ ---------------------------------------------------------------------- */
+
+ if (invalid_lilo_config)
+ {
+ if (setup_error_code & INVALID_BOARD_TYPE)
+ printk(KERN_ERR "<Error> - pc_open: Invalid board type specified in LILO command\n");
+
+ if (setup_error_code & INVALID_NUM_PORTS)
+ printk(KERN_ERR "<Error> - pc_open: Invalid number of ports specified in LILO command\n");
+
+ if (setup_error_code & INVALID_MEM_BASE)
+ printk(KERN_ERR "<Error> - pc_open: Invalid board memory address specified in LILO command\n");
+
+ if (setup_error_code & INVALID_PORT_BASE)
+ printk(KERN_ERR "<Error> - pc_open: Invalid board port address specified in LILO command\n");
+
+ if (setup_error_code & INVALID_BOARD_STATUS)
+ printk(KERN_ERR "<Error> - pc_open: Invalid board status specified in LILO command\n");
+
+ if (setup_error_code & INVALID_ALTPIN)
+ printk(KERN_ERR "<Error> - pc_open: Invalid board altpin specified in LILO command\n");
+
+ tty->driver_data = NULL; /* Mark this device as 'down' */
+ return(-ENODEV);
+ }
+
+ if ((boardnum >= num_cards) || (boards[boardnum].status == DISABLED))
+ {
+ tty->driver_data = NULL; /* Mark this device as 'down' */
+ return(-ENODEV);
+ }
+
+ if (( bc = ch->brdchan) == 0)
+ {
+ tty->driver_data = NULL;
+ return(-ENODEV);
+ }
+
+ /* ------------------------------------------------------------------
+ Every time a channel is opened, increment a counter. This is
+ necessary because we do not wish to flush and shutdown the channel
+ until the last app holding the channel open, closes it.
+ --------------------------------------------------------------------- */
+
+ ch->count++;
+
+ /* ----------------------------------------------------------------
+ Set a kernel structures pointer to our local channel
+ structure. This way we can get to it when passed only
+ a tty struct.
+ ------------------------------------------------------------------ */
+
+ tty->driver_data = ch;
+
+ /* ----------------------------------------------------------------
+ If this is the first time the channel has been opened, initialize
+ the tty->termios struct otherwise let pc_close handle it.
+ -------------------------------------------------------------------- */
+
+ /* Should this be here except for SPLIT termios ? */
+ if (ch->count == 1)
+ {
+ if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
+ *tty->termios = ch->normal_termios;
+ else
+ *tty->termios = ch->callout_termios;
+ }
+
+ ch->session = current->session;
+ ch->pgrp = current->pgrp;
+
+ save_flags(flags);
+ cli();
+
+ globalwinon(ch);
+ ch->statusflags = 0;
+
+ /* Save boards current modem status */
+ ch->imodem = bc->mstat;
+
+ /* ----------------------------------------------------------------
+ Set receive head and tail ptrs to each other. This indicates
+ no data available to read.
+ ----------------------------------------------------------------- */
+ head = bc->rin;
+ bc->rout = head;
+
+ /* Set the channels associated tty structure */
+ ch->tty = tty;
+
+ /* -----------------------------------------------------------------
+ The below routine generally sets up parity, baud, flow control
+ issues, etc.... It effect both control flags and input flags.
+ -------------------------------------------------------------------- */
+ epcaparam(tty,ch);
+
+ ch->asyncflags |= ASYNC_INITIALIZED;
+ memoff(ch);
+
+ restore_flags(flags);
+
+ retval = block_til_ready(tty, filp, ch);
+ if (retval)
+ {
+ return retval;
+ }
+
+ /* -------------------------------------------------------------
+ Set this again in case a hangup set it to zero while this
+ open() was waiting for the line...
+ --------------------------------------------------------------- */
+ ch->tty = tty;
+
+ save_flags(flags);
+ cli();
+ globalwinon(ch);
+
+ /* Enable Digi Data events */
+ bc->idata = 1;
+
+ memoff(ch);
+ restore_flags(flags);
+
+ return 0;
+
+} /* End pc_open */
+
+#ifdef MODULE
+/* -------------------- Begin init_module ---------------------- */
+int init_module()
+{ /* Begin init_module */
+
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+
+ pc_init();
+
+ restore_flags(flags);
+
+ return(0);
+} /* End init_module */
+
+#endif
+#ifdef MODULE
+/* -------------------- Begin cleanup_module ---------------------- */
+void cleanup_module()
+{ /* Begin cleanup_module */
+
+ int count, crd;
+ struct board_info *bd;
+ struct channel *ch;
+ unsigned long flags;
+
+
+ save_flags(flags);
+ cli();
+
+ timer_table[DIGI_TIMER].fn = 0;
+
+ if ((tty_unregister_driver(&pc_driver)) ||
+ (tty_unregister_driver(&pc_callout)))
+ {
+ printk(KERN_WARNING "<Error> - DIGI : cleanup_module failed to un-register tty driver\n");
+ restore_flags(flags);
+ return;
+ }
+
+ for (crd = 0; crd < num_cards; crd++)
+ { /* Begin for each card */
+
+ bd = &boards[crd];
+
+ if (!bd)
+ { /* Begin sanity check */
+ printk(KERN_ERR "<Error> - Digi : cleanup_module failed\n");
+ return;
+ } /* End sanity check */
+
+ ch = card_ptr[crd];
+
+ for (count = 0; count < bd->numports; count++, ch++)
+ { /* Begin for each port */
+
+ if (ch)
+ {
+ if (ch->tty)
+ tty_hangup(ch->tty);
+ kfree_s(ch->tmp_buf, ch->txbufsize);
+ }
+
+ } /* End for each port */
+ } /* End for each card */
+
+
+ restore_flags(flags);
+
+} /* End cleanup_module */
+#endif /* MODULE */
+
+/* ------------------ Begin pc_init ---------------------- */
+
+int pc_init(void)
+{ /* Begin pc_init */
+
+ /* ----------------------------------------------------------------
+ pc_init is called by the operating system during boot up prior to
+ any open calls being made. In the older versions of Linux (Prior
+ to 2.0.0) an entry is made into tty_io.c. A pointer to the last
+ memory location (from kernel space) used (kmem_start) is passed
+ to pc_init. It is pc_inits responsibility to modify this value
+ for any memory that the Digi driver might need and then return
+ this value to the operating system. For example if the driver
+ wishes to allocate 1K of kernel memory, pc_init would return
+ (kmem_start + 1024). This memory (Between kmem_start and kmem_start
+ + 1024) would then be available for use exclusively by the driver.
+ In this case our driver does not allocate any of this kernel
+ memory.
+ ------------------------------------------------------------------*/
+
+ ulong flags, save_loops_per_sec;
+ int crd;
+ struct board_info *bd;
+ unsigned char board_id = 0;
+
+
+#ifdef ENABLE_PCI
+ int pci_boards_found, pci_count;
+
+ pci_count = 0;
+#endif /* ENABLE_PCI */
+
+ /* -----------------------------------------------------------------------
+ If epca_setup has not been ran by LILO set num_cards to defaults; copy
+ board structure defined by digiConfig into drivers board structure.
+ Note : If LILO has ran epca_setup then epca_setup will handle defining
+ num_cards as well as copying the data into the board structure.
+ -------------------------------------------------------------------------- */
+ if (!liloconfig)
+ { /* Begin driver has been configured via. epcaconfig */
+
+ nbdevs = NBDEVS;
+ num_cards = NUMCARDS;
+ memcpy((void *)&boards, (void *)&static_boards,
+ (sizeof(struct board_info) * NUMCARDS));
+ } /* End driver has been configured via. epcaconfig */
+
+ /* -----------------------------------------------------------------
+ Note : If lilo was used to configure the driver and the
+ ignore epcaconfig option was choosen (digiepca=2) then
+ nbdevs and num_cards will equal 0 at this point. This is
+ okay; PCI cards will still be picked up if detected.
+ --------------------------------------------------------------------- */
+
+ /* -----------------------------------------------------------
+ Set up interrupt, we will worry about memory allocation in
+ post_fep_init.
+ --------------------------------------------------------------- */
+
+
+ printk(KERN_INFO "DIGI epca driver version %s loaded.\n",VERSION);
+
+#ifdef ENABLE_PCI
+
+ /* ------------------------------------------------------------------
+ NOTE : This code assumes that the number of ports found in
+ the boards array is correct. This could be wrong if
+ the card in question is PCI (And therefore has no ports
+ entry in the boards structure.) The rest of the
+ information will be valid for PCI because the begining
+ of pc_init scans for PCI and determines i/o and base
+ memory addresses. I am not sure if it is possible to
+ read the number of ports supported by the card prior to
+ it being booted (Since that is the state it is in when
+ pc_init is run). Because it is not possible to query the
+ number of supported ports until after the card has booted;
+ we are required to calculate the card_ptrs as the card is
+ is initialized (Inside post_fep_init). The negative thing
+ about this approach is that digiDload's call to GET_INFO
+ will have a bad port value. (Since this is called prior
+ to post_fep_init.)
+
+ --------------------------------------------------------------------- */
+
+ pci_boards_found = 0;
+ if (pcibios_present())
+ {
+ if(num_cards < MAXBOARDS)
+ pci_boards_found += init_PCI(num_cards);
+ num_cards += pci_boards_found;
+ }
+ else
+ {
+ printk(KERN_ERR "<Error> - No PCI BIOS found\n");
+ }
+
+#endif /* ENABLE_PCI */
+
+ memset(&pc_driver, 0, sizeof(struct tty_driver));
+ memset(&pc_callout, 0, sizeof(struct tty_driver));
+ memset(&pc_info, 0, sizeof(struct tty_driver));
+
+ pc_driver.magic = TTY_DRIVER_MAGIC;
+ pc_driver.name = "ttyD";
+ pc_driver.major = DIGI_MAJOR;
+ pc_driver.minor_start = 0;
+ pc_driver.num = MAX_ALLOC;
+ pc_driver.type = TTY_DRIVER_TYPE_SERIAL;
+ pc_driver.subtype = SERIAL_TYPE_NORMAL;
+ pc_driver.init_termios = tty_std_termios;
+ pc_driver.init_termios.c_iflag = 0;
+ pc_driver.init_termios.c_oflag = 0;
+
+ pc_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL;
+ pc_driver.init_termios.c_lflag = 0;
+ pc_driver.flags = TTY_DRIVER_REAL_RAW;
+ pc_driver.refcount = &pc_refcount;
+ pc_driver.table = pc_table;
+
+ /* pc_termios is an array of pointers pointing at termios structs */
+ /* The below should get the first pointer */
+ pc_driver.termios = pc_termios;
+ pc_driver.termios_locked = pc_termios_locked;
+
+ /* ------------------------------------------------------------------
+ Setup entry points for the driver. These are primarily called by
+ the kernel in tty_io.c and n_tty.c
+ --------------------------------------------------------------------- */
+
+ pc_driver.open = pc_open;
+ pc_driver.close = pc_close;
+ pc_driver.write = pc_write;
+ pc_driver.write_room = pc_write_room;
+ pc_driver.flush_buffer = pc_flush_buffer;
+ pc_driver.chars_in_buffer = pc_chars_in_buffer;
+ pc_driver.flush_chars = pc_flush_chars;
+ pc_driver.put_char = pc_put_char;
+ pc_driver.ioctl = pc_ioctl;
+ pc_driver.set_termios = pc_set_termios;
+ pc_driver.stop = pc_stop;
+ pc_driver.start = pc_start;
+ pc_driver.throttle = pc_throttle;
+ pc_driver.unthrottle = pc_unthrottle;
+ pc_driver.hangup = pc_hangup;
+ pc_callout = pc_driver;
+
+ pc_callout.name = "cud";
+ pc_callout.major = DIGICU_MAJOR;
+ pc_callout.minor_start = 0;
+ pc_callout.init_termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL;
+ pc_callout.subtype = SERIAL_TYPE_CALLOUT;
+
+ pc_info = pc_driver;
+ pc_info.name = "digiCtl";
+ pc_info.major = DIGIINFOMAJOR;
+ pc_info.minor_start = 0;
+ pc_info.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL;
+ pc_info.subtype = SERIAL_TYPE_INFO;
+
+
+ /* ---------------------------------------------------------------------
+ loops_per_sec hasn't been set at this point :-(, so fake it out...
+ I set it, so that I can use the __delay() function.
+ ------------------------------------------------------------------------ */
+ save_loops_per_sec = loops_per_sec;
+ loops_per_sec = 13L * 500000L;
+
+ save_flags(flags);
+ cli();
+
+ for (crd = 0; crd < num_cards; crd++)
+ { /* Begin for each card */
+
+ /* ------------------------------------------------------------------
+ This is where the appropriate memory handlers for the hardware is
+ set. Everything at runtime blindly jumps through these vectors.
+ ---------------------------------------------------------------------- */
+
+ /* defined in epcaconfig.h */
+ bd = &boards[crd];
+
+ switch (bd->type)
+ { /* Begin switch on bd->type {board type} */
+ case PCXEM:
+ case EISAXEM:
+ bd->memwinon = pcxem_memwinon ;
+ bd->memwinoff = pcxem_memwinoff ;
+ bd->globalwinon = pcxem_globalwinon ;
+ bd->txwinon = pcxem_txwinon ;
+ bd->rxwinon = pcxem_rxwinon ;
+ bd->memoff = pcxem_memoff ;
+ bd->assertgwinon = dummy_assertgwinon;
+ bd->assertmemoff = dummy_assertmemoff;
+ break;
+
+ case PCIXEM:
+ case PCIXRJ:
+ case PCIXR:
+ bd->memwinon = dummy_memwinon;
+ bd->memwinoff = dummy_memwinoff;
+ bd->globalwinon = dummy_globalwinon;
+ bd->txwinon = dummy_txwinon;
+ bd->rxwinon = dummy_rxwinon;
+ bd->memoff = dummy_memoff;
+ bd->assertgwinon = dummy_assertgwinon;
+ bd->assertmemoff = dummy_assertmemoff;
+ break;
+
+ case PCXE:
+ case PCXEVE:
+
+ bd->memwinon = pcxe_memwinon;
+ bd->memwinoff = pcxe_memwinoff;
+ bd->globalwinon = pcxe_globalwinon;
+ bd->txwinon = pcxe_txwinon;
+ bd->rxwinon = pcxe_rxwinon;
+ bd->memoff = pcxe_memoff;
+ bd->assertgwinon = dummy_assertgwinon;
+ bd->assertmemoff = dummy_assertmemoff;
+ break;
+
+ case PCXI:
+ case PC64XE:
+
+ bd->memwinon = pcxi_memwinon;
+ bd->memwinoff = pcxi_memwinoff;
+ bd->globalwinon = pcxi_globalwinon;
+ bd->txwinon = pcxi_txwinon;
+ bd->rxwinon = pcxi_rxwinon;
+ bd->memoff = pcxi_memoff;
+ bd->assertgwinon = pcxi_assertgwinon;
+ bd->assertmemoff = pcxi_assertmemoff;
+ break;
+
+ default:
+ break;
+
+ } /* End switch on bd->type */
+
+ /* ---------------------------------------------------------------
+ Some cards need a memory segment to be defined for use in
+ transmit and receive windowing operations. These boards
+ are listed in the below switch. In the case of the XI the
+ amount of memory on the board is variable so the memory_seg
+ is also variable. This code determines what they segment
+ should be.
+ ----------------------------------------------------------------- */
+
+ switch (bd->type)
+ { /* Begin switch on bd->type {board type} */
+
+ case PCXE:
+ case PCXEVE:
+ case PC64XE:
+ bd->memory_seg = 0xf000;
+ break;
+
+ case PCXI:
+ board_id = inb((int)bd->port);
+ if ((board_id & 0x1) == 0x1)
+ { /* Begin its an XI card */
+
+ /* Is it a 64K board */
+ if ((board_id & 0x30) == 0)
+ bd->memory_seg = 0xf000;
+
+ /* Is it a 128K board */
+ if ((board_id & 0x30) == 0x10)
+ bd->memory_seg = 0xe000;
+
+ /* Is is a 256K board */
+ if ((board_id & 0x30) == 0x20)
+ bd->memory_seg = 0xc000;
+
+ /* Is it a 512K board */
+ if ((board_id & 0x30) == 0x30)
+ bd->memory_seg = 0x8000;
+
+ } /* End it is an XI card */
+ else
+ {
+ printk(KERN_ERR "<Error> - Board at 0x%x doesn't appear to be an XI\n",(int)bd->port);
+ }
+ break;
+
+ } /* End switch on bd->type */
+
+ } /* End for each card */
+
+ if (tty_register_driver(&pc_driver))
+ panic("Couldn't register Digi PC/ driver");
+
+ if (tty_register_driver(&pc_callout))
+ panic("Couldn't register Digi PC/ callout");
+
+ if (tty_register_driver(&pc_info))
+ panic("Couldn't register Digi PC/ info ");
+
+ loops_per_sec = save_loops_per_sec; /* reset it to what it should be */
+
+ /* -------------------------------------------------------------------
+ Start up the poller to check for events on all enabled boards
+ ---------------------------------------------------------------------- */
+
+ timer_table[DIGI_TIMER].fn = (void *)epcapoll;
+ timer_table[DIGI_TIMER].expires = 0;
+
+ restore_flags(flags);
+
+ timer_active |= 1 << DIGI_TIMER;
+ return 0;
+
+} /* End pc_init */
+
+/* ------------------ Begin post_fep_init ---------------------- */
+
+static void post_fep_init(unsigned int crd)
+{ /* Begin post_fep_init */
+
+ int i;
+ unchar *memaddr;
+ volatile struct global_data *gd;
+ struct board_info *bd;
+ volatile struct board_chan *bc;
+ struct channel *ch;
+ int shrinkmem = 0, lowwater ;
+
+ /* -------------------------------------------------------------
+ This call is made by the user via. the ioctl call DIGI_INIT.
+ It is resposible for setting up all the card specific stuff.
+ ---------------------------------------------------------------- */
+ bd = &boards[crd];
+
+ /* -----------------------------------------------------------------
+ If this is a PCI board, get the port info. Remember PCI cards
+ do not have entries into the epcaconfig.h file, so we can't get
+ the number of ports from it. Unfortunetly, this means that anyone
+ doing a DIGI_GETINFO before the board has booted will get an invalid
+ number of ports returned (It should return 0). Calls to DIGI_GETINFO
+ after DIGI_INIT has been called will return the proper values.
+ ------------------------------------------------------------------- */
+
+ if (bd->type >= PCIXEM) /* If the board in question is PCI */
+ { /* Begin get PCI number of ports */
+
+ /* --------------------------------------------------------------------
+ Below we use XEMPORTS as a memory offset regardless of which PCI
+ card it is. This is because all of the supported PCI cards have
+ the same memory offset for the channel data. This will have to be
+ changed if we ever develop a PCI/XE card. NOTE : The FEP manual
+ states that the port offset is 0xC22 as opposed to 0xC02. This is
+ only true for PC/XE, and PC/XI cards; not for the XEM, or CX series.
+ On the PCI cards the number of ports is determined by reading a
+ ID PROM located in the box attached to the card. The card can then
+ determine the index the id to determine the number of ports available.
+ (FYI - The id should be located at 0x1ac (And may use up to 4 bytes
+ if the box in question is a XEM or CX)).
+ ------------------------------------------------------------------------ */
+
+ bd->numports = (unsigned short)*(unsigned char *)bus_to_virt((unsigned long)
+ (bd->re_map_membase + XEMPORTS));
+
+
+ epcaassert(bd->numports <= 64,"PCI returned a invalid number of ports");
+ nbdevs += (bd->numports);
+
+ } /* End get PCI number of ports */
+
+ if (crd != 0)
+ card_ptr[crd] = card_ptr[crd-1] + boards[crd-1].numports;
+ else
+ card_ptr[crd] = &digi_channels[crd]; /* <- For card 0 only */
+
+ ch = card_ptr[crd];
+
+
+ epcaassert(ch <= &digi_channels[nbdevs - 1], "ch out of range");
+
+ if (bd->membase < (unsigned char *)0x100000)
+ memaddr = (unchar *) bd->membase;
+ else /* Else get special mapped memory above RAM */
+ memaddr = (unchar *)bd->re_map_membase;
+
+ /*
+ The below command is necessary because newer kernels (2.1.x and
+ up) do not have a 1:1 virtual to physical mapping. The below
+ call adjust for that.
+ */
+
+ memaddr = (unsigned char *)bus_to_virt((unsigned long)memaddr);
+
+ /* -----------------------------------------------------------------
+ The below assignment will set bc to point at the BEGINING of
+ the cards channel structures. For 1 card there will be between
+ 8 and 64 of these structures.
+ -------------------------------------------------------------------- */
+
+ bc = (volatile struct board_chan *)((ulong)memaddr + CHANSTRUCT);
+
+ /* -------------------------------------------------------------------
+ The below assignment will set gd to point at the BEGINING of
+ global memory address 0xc00. The first data in that global
+ memory actually starts at address 0xc1a. The command in
+ pointer begins at 0xd10.
+ ---------------------------------------------------------------------- */
+
+ gd = (volatile struct global_data *)((ulong)memaddr + GLOBAL);
+
+ /* --------------------------------------------------------------------
+ XEPORTS (address 0xc22) points at the number of channels the
+ card supports. (For 64XE, XI, XEM, and XR use 0xc02)
+ ----------------------------------------------------------------------- */
+
+ if (((bd->type == PCXEVE) | (bd->type == PCXE)) &&
+ (*(ushort *)((ulong)memaddr + XEPORTS) < 3))
+ shrinkmem = 1;
+ if (bd->type < PCIXEM)
+ request_region((int)bd->port, 4, board_desc[bd->type]);
+
+ memwinon(bd, 0);
+
+ /* --------------------------------------------------------------------
+ Remember ch is the main drivers channels structure, while bc is
+ the cards channel structure.
+ ------------------------------------------------------------------------ */
+
+ /* For every port on the card do ..... */
+
+ for (i = 0; i < bd->numports; i++, ch++, bc++)
+ { /* Begin for each port */
+
+ ch->brdchan = bc;
+ ch->mailbox = gd;
+ ch->tqueue.routine = do_softint;
+ ch->tqueue.data = ch;
+ ch->board = &boards[crd];
+
+ switch (bd->type)
+ { /* Begin switch bd->type */
+
+ /* ----------------------------------------------------------------
+ Since some of the boards use different bitmaps for their
+ control signals we cannot hard code these values and retain
+ portability. We virtualize this data here.
+ ------------------------------------------------------------------- */
+ case EISAXEM:
+ case PCXEM:
+ case PCIXEM:
+ case PCIXRJ:
+ case PCIXR:
+ ch->m_rts = 0x02 ;
+ ch->m_dcd = 0x80 ;
+ ch->m_dsr = 0x20 ;
+ ch->m_cts = 0x10 ;
+ ch->m_ri = 0x40 ;
+ ch->m_dtr = 0x01 ;
+ break;
+
+ case PCXE:
+ case PCXEVE:
+ case PCXI:
+ case PC64XE:
+ ch->m_rts = 0x02 ;
+ ch->m_dcd = 0x08 ;
+ ch->m_dsr = 0x10 ;
+ ch->m_cts = 0x20 ;
+ ch->m_ri = 0x40 ;
+ ch->m_dtr = 0x80 ;
+ break;
+
+ } /* End switch bd->type */
+
+ if (boards[crd].altpin)
+ {
+ ch->dsr = ch->m_dcd;
+ ch->dcd = ch->m_dsr;
+ ch->digiext.digi_flags |= DIGI_ALTPIN;
+ }
+ else
+ {
+ ch->dcd = ch->m_dcd;
+ ch->dsr = ch->m_dsr;
+ }
+
+ ch->boardnum = crd;
+ ch->channelnum = i;
+ ch->magic = EPCA_MAGIC;
+ ch->tty = 0;
+
+ if (shrinkmem)
+ {
+ fepcmd(ch, SETBUFFER, 32, 0, 0, 0);
+ shrinkmem = 0;
+ }
+
+ switch (bd->type)
+ { /* Begin switch bd->type */
+
+ case PCIXEM:
+ case PCIXRJ:
+ case PCIXR:
+ /* Cover all the 2MEG cards */
+ ch->txptr = memaddr + (((bc->tseg) << 4) & 0x1fffff);
+ ch->rxptr = memaddr + (((bc->rseg) << 4) & 0x1fffff);
+ ch->txwin = FEPWIN | ((bc->tseg) >> 11);
+ ch->rxwin = FEPWIN | ((bc->rseg) >> 11);
+ break;
+
+ case PCXEM:
+ case EISAXEM:
+ /* Cover all the 32K windowed cards */
+ /* Mask equal to window size - 1 */
+ ch->txptr = memaddr + (((bc->tseg) << 4) & 0x7fff);
+ ch->rxptr = memaddr + (((bc->rseg) << 4) & 0x7fff);
+ ch->txwin = FEPWIN | ((bc->tseg) >> 11);
+ ch->rxwin = FEPWIN | ((bc->rseg) >> 11);
+ break;
+
+ case PCXEVE:
+ case PCXE:
+ ch->txptr = memaddr + (((bc->tseg - bd->memory_seg) << 4) & 0x1fff);
+ ch->txwin = FEPWIN | ((bc->tseg - bd->memory_seg) >> 9);
+ ch->rxptr = memaddr + (((bc->rseg - bd->memory_seg) << 4) & 0x1fff);
+ ch->rxwin = FEPWIN | ((bc->rseg - bd->memory_seg) >>9 );
+ break;
+
+ case PCXI:
+ case PC64XE:
+ ch->txptr = memaddr + ((bc->tseg - bd->memory_seg) << 4);
+ ch->rxptr = memaddr + ((bc->rseg - bd->memory_seg) << 4);
+ ch->txwin = ch->rxwin = 0;
+ break;
+
+ } /* End switch bd->type */
+
+ ch->txbufhead = 0;
+ ch->txbufsize = bc->tmax + 1;
+
+ ch->rxbufhead = 0;
+ ch->rxbufsize = bc->rmax + 1;
+
+ lowwater = ch->txbufsize >= 2000 ? 1024 : (ch->txbufsize / 2);
+
+ /* Set transmitter low water mark */
+ fepcmd(ch, STXLWATER, lowwater, 0, 10, 0);
+
+ /* Set receiver low water mark */
+
+ fepcmd(ch, SRXLWATER, (ch->rxbufsize / 4), 0, 10, 0);
+
+ /* Set receiver high water mark */
+
+ fepcmd(ch, SRXHWATER, (3 * ch->rxbufsize / 4), 0, 10, 0);
+
+ bc->edelay = 100;
+ bc->idata = 1;
+
+ ch->startc = bc->startc;
+ ch->stopc = bc->stopc;
+ ch->startca = bc->startca;
+ ch->stopca = bc->stopca;
+
+ ch->fepcflag = 0;
+ ch->fepiflag = 0;
+ ch->fepoflag = 0;
+ ch->fepstartc = 0;
+ ch->fepstopc = 0;
+ ch->fepstartca = 0;
+ ch->fepstopca = 0;
+
+ ch->close_delay = 50;
+ ch->count = 0;
+ ch->blocked_open = 0;
+ ch->callout_termios = pc_callout.init_termios;
+ ch->normal_termios = pc_driver.init_termios;
+ ch->open_wait = 0;
+ ch->close_wait = 0;
+ ch->tmp_buf = kmalloc(ch->txbufsize,GFP_KERNEL);
+ if (!(ch->tmp_buf))
+ {
+ printk(KERN_ERR "POST FEP INIT : kmalloc failed for port 0x%x\n",i);
+
+ }
+ memset((void *)ch->tmp_buf,0,ch->txbufsize);
+ } /* End for each port */
+
+ printk(KERN_INFO
+ "Digi PC/Xx Driver V%s: %s I/O = 0x%lx Mem = 0x%lx Ports = %d\n",
+ VERSION, board_desc[bd->type], (long)bd->port, (long)bd->membase, bd->numports);
+ sprintf(mesg,
+ "Digi PC/Xx Driver V%s: %s I/O = 0x%lx Mem = 0x%lx Ports = %d\n",
+ VERSION, board_desc[bd->type], (long)bd->port, (long)bd->membase, bd->numports);
+ console_print(mesg);
+
+ memwinoff(bd, 0);
+
+} /* End post_fep_init */
+
+/* --------------------- Begin epcapoll ------------------------ */
+
+static void epcapoll(unsigned long ignored)
+{ /* Begin epcapoll */
+
+ unsigned long flags;
+ int crd;
+ volatile unsigned int head, tail;
+ struct channel *ch;
+ struct board_info *bd;
+
+ /* -------------------------------------------------------------------
+ This routine is called upon every timer interrupt. Even though
+ the Digi series cards are capable of generating interupts this
+ method of non-looping polling is more efficient. This routine
+ checks for card generated events (Such as receive data, are transmit
+ buffer empty) and acts on those events.
+ ----------------------------------------------------------------------- */
+
+ save_flags(flags);
+ cli();
+
+ for (crd = 0; crd < num_cards; crd++)
+ { /* Begin for each card */
+
+ bd = &boards[crd];
+ ch = card_ptr[crd];
+
+ if ((bd->status == DISABLED) || digi_poller_inhibited)
+ continue; /* Begin loop next interation */
+
+ /* -----------------------------------------------------------
+ assertmemoff is not needed here; indeed it is an empty subroutine.
+ It is being kept because future boards may need this as well as
+ some legacy boards.
+ ---------------------------------------------------------------- */
+
+ assertmemoff(ch);
+
+ globalwinon(ch);
+
+ /* ---------------------------------------------------------------
+ In this case head and tail actually refer to the event queue not
+ the transmit or receive queue.
+ ------------------------------------------------------------------- */
+
+ head = ch->mailbox->ein;
+ tail = ch->mailbox->eout;
+
+ /* If head isn't equal to tail we have an event */
+
+ if (head != tail)
+ doevent(crd);
+
+ memoff(ch);
+
+ } /* End for each card */
+
+ timer_table[DIGI_TIMER].fn = (void *)epcapoll;
+ timer_table[DIGI_TIMER].expires = jiffies + (HZ / 25);
+ timer_active |= 1 << DIGI_TIMER;
+
+ restore_flags(flags);
+
+} /* End epcapoll */
+
+/* --------------------- Begin doevent ------------------------ */
+
+static void doevent(int crd)
+{ /* Begin doevent */
+
+ volatile unchar *eventbuf;
+ struct channel *ch, *chan0;
+ static struct tty_struct *tty;
+ volatile struct board_info *bd;
+ volatile struct board_chan *bc;
+ register volatile unsigned int tail, head;
+ register int event, channel;
+ register int mstat, lstat;
+
+ /* -------------------------------------------------------------------
+ This subroutine is called by epcapoll when an event is detected
+ in the event queue. This routine responds to those events.
+ --------------------------------------------------------------------- */
+
+ bd = &boards[crd];
+
+ chan0 = card_ptr[crd];
+ epcaassert(chan0 <= &digi_channels[nbdevs - 1], "ch out of range");
+
+ assertgwinon(chan0);
+
+ while ((tail = chan0->mailbox->eout) != (head = chan0->mailbox->ein))
+ { /* Begin while something in event queue */
+
+ assertgwinon(chan0);
+
+ if (bd->membase < (unsigned char *)0x100000)
+ eventbuf = (volatile unchar *)bus_to_virt((ulong)(bd->membase + tail + ISTART));
+ else
+ {
+ eventbuf = (volatile unchar *)bus_to_virt((ulong)(bd->re_map_membase + tail + ISTART));
+ }
+
+ /* Get the channel the event occured on */
+ channel = eventbuf[0];
+
+ /* Get the actual event code that occured */
+ event = eventbuf[1];
+
+ /* ----------------------------------------------------------------
+ The two assignments below get the current modem status (mstat)
+ and the previous modem status (lstat). These are useful becuase
+ an event could signal a change in modem signals itself.
+ ------------------------------------------------------------------- */
+
+ mstat = eventbuf[2];
+ lstat = eventbuf[3];
+
+ ch = chan0 + channel;
+
+ if ((unsigned)channel >= bd->numports || !ch)
+ {
+ if (channel >= bd->numports)
+ ch = chan0;
+ bc = ch->brdchan;
+ goto next;
+ }
+
+ if ((bc = ch->brdchan) == NULL)
+ goto next;
+
+ if (event & DATA_IND)
+ { /* Begin DATA_IND */
+
+ receive_data(ch);
+ assertgwinon(ch);
+
+ } /* End DATA_IND */
+ else
+ if (event & MODEMCHG_IND)
+ { /* Begin MODEMCHG_IND */
+
+ /* A modem signal change has been indicated */
+
+ ch->imodem = mstat;
+
+ if (ch->asyncflags & ASYNC_CHECK_CD)
+ {
+ if (mstat & ch->dcd) /* We are now receiving dcd */
+ wake_up_interruptible(&ch->open_wait);
+ else
+ pc_sched_event(ch, EPCA_EVENT_HANGUP); /* No dcd; hangup */
+ }
+
+ } /* End MODEMCHG_IND */
+
+ tty = ch->tty;
+ if (tty)
+ { /* Begin if valid tty */
+
+ if (event & BREAK_IND)
+ { /* Begin if BREAK_IND */
+
+ /* A break has been indicated */
+
+ tty->flip.count++;
+ *tty->flip.flag_buf_ptr++ = TTY_BREAK;
+
+ *tty->flip.char_buf_ptr++ = 0;
+
+ tty_schedule_flip(tty);
+
+ } /* End if BREAK_IND */
+ else
+ if (event & LOWTX_IND)
+ { /* Begin LOWTX_IND */
+
+ if (ch->statusflags & LOWWAIT)
+ { /* Begin if LOWWAIT */
+
+ ch->statusflags &= ~LOWWAIT;
+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+ tty->ldisc.write_wakeup)
+ (tty->ldisc.write_wakeup)(tty);
+ wake_up_interruptible(&tty->write_wait);
+
+ } /* End if LOWWAIT */
+
+ } /* End LOWTX_IND */
+ else
+ if (event & EMPTYTX_IND)
+ { /* Begin EMPTYTX_IND */
+
+ /* This event is generated by setup_empty_event */
+
+ ch->statusflags &= ~TXBUSY;
+ if (ch->statusflags & EMPTYWAIT)
+ { /* Begin if EMPTYWAIT */
+
+ ch->statusflags &= ~EMPTYWAIT;
+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+ tty->ldisc.write_wakeup)
+ (tty->ldisc.write_wakeup)(tty);
+
+ wake_up_interruptible(&tty->write_wait);
+
+ } /* End if EMPTYWAIT */
+
+ } /* End EMPTYTX_IND */
+
+ } /* End if valid tty */
+
+
+ next:
+ globalwinon(ch);
+
+ if (!bc)
+ printk(KERN_ERR "<Error> - bc == NULL in doevent!\n");
+ else
+ bc->idata = 1;
+
+ chan0->mailbox->eout = (tail + 4) & (IMAX - ISTART - 4);
+ globalwinon(chan0);
+
+ } /* End while something in event queue */
+
+} /* End doevent */
+
+/* --------------------- Begin fepcmd ------------------------ */
+
+static void fepcmd(struct channel *ch, int cmd, int word_or_byte,
+ int byte2, int ncmds, int bytecmd)
+{ /* Begin fepcmd */
+
+ unchar *memaddr;
+ unsigned int head, cmdTail, cmdStart, cmdMax;
+ long count;
+ int n;
+
+ /* This is the routine in which commands may be passed to the card. */
+
+ if (ch->board->status == DISABLED)
+ {
+ return;
+ }
+
+ assertgwinon(ch);
+
+ /* Remember head (As well as max) is just an offset not a base addr */
+ head = ch->mailbox->cin;
+
+ /* cmdStart is a base address */
+ cmdStart = ch->mailbox->cstart;
+
+ /* ------------------------------------------------------------------
+ We do the addition below because we do not want a max pointer
+ relative to cmdStart. We want a max pointer that points at the
+ physical end of the command queue.
+ -------------------------------------------------------------------- */
+
+ cmdMax = (cmdStart + 4 + (ch->mailbox->cmax));
+
+ if (ch->board->membase < (unsigned char *)0x100000)
+ memaddr = ch->board->membase;
+ else
+ memaddr = ch->board->re_map_membase;
+
+ /*
+ The below command is necessary because newer kernels (2.1.x and
+ up) do not have a 1:1 virtual to physical mapping. The below
+ call adjust for that.
+ */
+
+ memaddr = (unsigned char *)bus_to_virt((unsigned long)memaddr);
+
+ if (head >= (cmdMax - cmdStart) || (head & 03))
+ {
+ printk(KERN_ERR "line %d: Out of range, cmd = %x, head = %x\n", __LINE__,
+ cmd, head);
+ printk(KERN_ERR "line %d: Out of range, cmdMax = %x, cmdStart = %x\n", __LINE__,
+ cmdMax, cmdStart);
+ return;
+ }
+
+ if (bytecmd)
+ {
+ *(volatile unchar *)(memaddr + head + cmdStart + 0) = (unchar)cmd;
+
+ *(volatile unchar *)(memaddr + head + cmdStart + 1) = (unchar)ch->channelnum;
+ /* Below word_or_byte is bits to set */
+ *(volatile unchar *)(memaddr + head + cmdStart + 2) = (unchar)word_or_byte;
+ /* Below byte2 is bits to reset */
+ *(volatile unchar *)(memaddr + head + cmdStart + 3) = (unchar)byte2;
+
+ }
+ else
+ {
+ *(volatile unchar *)(memaddr + head + cmdStart + 0) = (unchar)cmd;
+ *(volatile unchar *)(memaddr + head + cmdStart + 1) = (unchar)ch->channelnum;
+ *(volatile ushort*)(memaddr + head + cmdStart + 2) = (ushort)word_or_byte;
+ }
+
+ head = (head + 4) & (cmdMax - cmdStart - 4);
+ ch->mailbox->cin = head;
+
+ count = FEPTIMEOUT;
+
+ for (;;)
+ { /* Begin forever loop */
+
+ count--;
+ if (count == 0)
+ {
+ printk(KERN_ERR "<Error> - Fep not responding in fepcmd()\n");
+ return;
+ }
+
+ head = ch->mailbox->cin;
+ cmdTail = ch->mailbox->cout;
+
+ n = (head - cmdTail) & (cmdMax - cmdStart - 4);
+
+ /* ----------------------------------------------------------
+ Basically this will break when the FEP acknowledges the
+ command by incrementing cmdTail (Making it equal to head).
+ ------------------------------------------------------------- */
+
+ if (n <= ncmds * (sizeof(short) * 4))
+ break; /* Well nearly forever :-) */
+
+ } /* End forever loop */
+
+} /* End fepcmd */
+
+/* ---------------------------------------------------------------------
+ Digi products use fields in their channels structures that are very
+ similar to the c_cflag and c_iflag fields typically found in UNIX
+ termios structures. The below three routines allow mappings
+ between these hardware "flags" and their respective Linux flags.
+------------------------------------------------------------------------- */
+
+/* --------------------- Begin termios2digi_h -------------------- */
+
+static unsigned termios2digi_h(struct channel *ch, unsigned cflag)
+{ /* Begin termios2digi_h */
+
+ unsigned res = 0;
+
+ if (cflag & CRTSCTS)
+ {
+ ch->digiext.digi_flags |= (RTSPACE | CTSPACE);
+ res |= ((ch->m_cts) | (ch->m_rts));
+ }
+
+ if (ch->digiext.digi_flags & RTSPACE)
+ res |= ch->m_rts;
+
+ if (ch->digiext.digi_flags & DTRPACE)
+ res |= ch->m_dtr;
+
+ if (ch->digiext.digi_flags & CTSPACE)
+ res |= ch->m_cts;
+
+ if (ch->digiext.digi_flags & DSRPACE)
+ res |= ch->dsr;
+
+ if (ch->digiext.digi_flags & DCDPACE)
+ res |= ch->dcd;
+
+ if (res & (ch->m_rts))
+ ch->digiext.digi_flags |= RTSPACE;
+
+ if (res & (ch->m_cts))
+ ch->digiext.digi_flags |= CTSPACE;
+
+ return res;
+
+} /* End termios2digi_h */
+
+/* --------------------- Begin termios2digi_i -------------------- */
+static unsigned termios2digi_i(struct channel *ch, unsigned iflag)
+{ /* Begin termios2digi_i */
+
+ unsigned res = iflag & (IGNBRK | BRKINT | IGNPAR | PARMRK |
+ INPCK | ISTRIP|IXON|IXANY|IXOFF);
+
+ if (ch->digiext.digi_flags & DIGI_AIXON)
+ res |= IAIXON;
+ return res;
+
+} /* End termios2digi_i */
+
+/* --------------------- Begin termios2digi_c -------------------- */
+
+static unsigned termios2digi_c(struct channel *ch, unsigned cflag)
+{ /* Begin termios2digi_c */
+
+ unsigned res = 0;
+
+#ifdef SPEED_HACK
+ /* CL: HACK to force 115200 at 38400 and 57600 at 19200 Baud */
+ if ((cflag & CBAUD)== B38400) cflag=cflag - B38400 + B115200;
+ if ((cflag & CBAUD)== B19200) cflag=cflag - B19200 + B57600;
+#endif /* SPEED_HACK */
+
+ if (cflag & CBAUDEX)
+ { /* Begin detected CBAUDEX */
+
+ ch->digiext.digi_flags |= DIGI_FAST;
+
+ /* -------------------------------------------------------------
+ HUPCL bit is used by FEP to indicate fast baud
+ table is to be used.
+ ----------------------------------------------------------------- */
+
+ res |= FEP_HUPCL;
+
+ } /* End detected CBAUDEX */
+ else ch->digiext.digi_flags &= ~DIGI_FAST;
+
+ /* -------------------------------------------------------------------
+ CBAUD has bit position 0x1000 set these days to indicate Linux
+ baud rate remap. Digi hardware can't handle the bit assignment.
+ (We use a different bit assignment for high speed.). Clear this
+ bit out.
+ ---------------------------------------------------------------------- */
+ res |= cflag & ((CBAUD ^ CBAUDEX) | PARODD | PARENB | CSTOPB | CSIZE);
+
+ /* -------------------------------------------------------------
+ This gets a little confusing. The Digi cards have their own
+ representation of c_cflags controling baud rate. For the most
+ part this is identical to the Linux implementation. However;
+ Digi supports one rate (76800) that Linux doesn't. This means
+ that the c_cflag entry that would normally mean 76800 for Digi
+ actually means 115200 under Linux. Without the below mapping,
+ a stty 115200 would only drive the board at 76800. Since
+ the rate 230400 is also found after 76800, the same problem afflicts
+ us when we choose a rate of 230400. Without the below modificiation
+ stty 230400 would actually give us 115200.
+
+ There are two additional differences. The Linux value for CLOCAL
+ (0x800; 0004000) has no meaning to the Digi hardware. Also in
+ later releases of Linux; the CBAUD define has CBAUDEX (0x1000;
+ 0010000) ored into it (CBAUD = 0x100f as opposed to 0xf). CBAUDEX
+ should be checked for a screened out prior to termios2digi_c
+ returning. Since CLOCAL isn't used by the board this can be
+ ignored as long as the returned value is used only by Digi hardware.
+ ----------------------------------------------------------------- */
+
+ if (cflag & CBAUDEX)
+ {
+ /* -------------------------------------------------------------
+ The below code is trying to guarantee that only baud rates
+ 115200 and 230400 are remapped. We use exclusive or because
+ the various baud rates share common bit positions and therefore
+ can't be tested for easily.
+ ----------------------------------------------------------------- */
+
+
+ if ((!((cflag & 0x7) ^ (B115200 & ~CBAUDEX))) ||
+ (!((cflag & 0x7) ^ (B230400 & ~CBAUDEX))))
+ {
+ res += 1;
+ }
+ }
+
+ return res;
+
+} /* End termios2digi_c */
+
+/* --------------------- Begin epcaparam ----------------------- */
+
+static void epcaparam(struct tty_struct *tty, struct channel *ch)
+{ /* Begin epcaparam */
+
+ unsigned int cmdHead;
+ struct termios *ts;
+ volatile struct board_chan *bc;
+ unsigned mval, hflow, cflag, iflag;
+
+ bc = ch->brdchan;
+ epcaassert(bc !=0, "bc out of range");
+
+ assertgwinon(ch);
+
+ ts = tty->termios;
+
+ if ((ts->c_cflag & CBAUD) == 0)
+ { /* Begin CBAUD detected */
+
+ cmdHead = bc->rin;
+ bc->rout = cmdHead;
+ cmdHead = bc->tin;
+
+ /* Changing baud in mid-stream transmission can be wonderful */
+ /* ---------------------------------------------------------------
+ Flush current transmit buffer by setting cmdTail pointer (tout)
+ to cmdHead pointer (tin). Hopefully the transmit buffer is empty.
+ ----------------------------------------------------------------- */
+
+ fepcmd(ch, STOUT, (unsigned) cmdHead, 0, 0, 0);
+ mval = 0;
+
+ } /* End CBAUD detected */
+ else
+ { /* Begin CBAUD not detected */
+
+ /* -------------------------------------------------------------------
+ c_cflags have changed but that change had nothing to do with BAUD.
+ Propagate the change to the card.
+ ---------------------------------------------------------------------- */
+
+ cflag = termios2digi_c(ch, ts->c_cflag);
+
+ if (cflag != ch->fepcflag)
+ {
+ ch->fepcflag = cflag;
+ /* Set baud rate, char size, stop bits, parity */
+ fepcmd(ch, SETCTRLFLAGS, (unsigned) cflag, 0, 0, 0);
+ }
+
+
+ /* ----------------------------------------------------------------
+ If the user has not forced CLOCAL and if the device is not a
+ CALLOUT device (Which is always CLOCAL) we set flags such that
+ the driver will wait on carrier detect.
+ ------------------------------------------------------------------- */
+
+ if ((ts->c_cflag & CLOCAL) || (tty->driver.subtype == SERIAL_TYPE_CALLOUT))
+ { /* Begin it is a cud device or a ttyD device with CLOCAL on */
+ ch->asyncflags &= ~ASYNC_CHECK_CD;
+ } /* End it is a cud device or a ttyD device with CLOCAL on */
+ else
+ { /* Begin it is a ttyD device */
+ ch->asyncflags |= ASYNC_CHECK_CD;
+ } /* End it is a ttyD device */
+
+ mval = ch->m_dtr | ch->m_rts;
+
+ } /* End CBAUD not detected */
+
+ iflag = termios2digi_i(ch, ts->c_iflag);
+
+ /* Check input mode flags */
+
+ if (iflag != ch->fepiflag)
+ {
+ ch->fepiflag = iflag;
+
+ /* ---------------------------------------------------------------
+ Command sets channels iflag structure on the board. Such things
+ as input soft flow control, handeling of parity errors, and
+ break handeling are all set here.
+ ------------------------------------------------------------------- */
+
+ /* break handeling, parity handeling, input stripping, flow control chars */
+ fepcmd(ch, SETIFLAGS, (unsigned int) ch->fepiflag, 0, 0, 0);
+ }
+
+ /* ---------------------------------------------------------------
+ Set the board mint value for this channel. This will cause hardware
+ events to be generated each time the DCD signal (Described in mint)
+ changes.
+ ------------------------------------------------------------------- */
+ bc->mint = ch->dcd;
+
+ if ((ts->c_cflag & CLOCAL) || (ch->digiext.digi_flags & DIGI_FORCEDCD))
+ if (ch->digiext.digi_flags & DIGI_FORCEDCD)
+ bc->mint = 0;
+
+ ch->imodem = bc->mstat;
+
+ hflow = termios2digi_h(ch, ts->c_cflag);
+
+ if (hflow != ch->hflow)
+ {
+ ch->hflow = hflow;
+
+ /* --------------------------------------------------------------
+ Hard flow control has been selected but the board is not
+ using it. Activate hard flow control now.
+ ----------------------------------------------------------------- */
+
+ fepcmd(ch, SETHFLOW, hflow, 0xff, 0, 1);
+ }
+
+
+ mval ^= ch->modemfake & (mval ^ ch->modem);
+
+ if (ch->omodem ^ mval)
+ {
+ ch->omodem = mval;
+
+ /* --------------------------------------------------------------
+ The below command sets the DTR and RTS mstat structure. If
+ hard flow control is NOT active these changes will drive the
+ output of the actual DTR and RTS lines. If hard flow control
+ is active, the changes will be saved in the mstat structure and
+ only asserted when hard flow control is turned off.
+ ----------------------------------------------------------------- */
+
+ /* First reset DTR & RTS; then set them */
+ fepcmd(ch, SETMODEM, 0, ((ch->m_dtr)|(ch->m_rts)), 0, 1);
+ fepcmd(ch, SETMODEM, mval, 0, 0, 1);
+
+ }
+
+ if (ch->startc != ch->fepstartc || ch->stopc != ch->fepstopc)
+ {
+ ch->fepstartc = ch->startc;
+ ch->fepstopc = ch->stopc;
+
+ /* ------------------------------------------------------------
+ The XON / XOFF characters have changed; propogate these
+ changes to the card.
+ --------------------------------------------------------------- */
+
+ fepcmd(ch, SONOFFC, ch->fepstartc, ch->fepstopc, 0, 1);
+ }
+
+ if (ch->startca != ch->fepstartca || ch->stopca != ch->fepstopca)
+ {
+ ch->fepstartca = ch->startca;
+ ch->fepstopca = ch->stopca;
+
+ /* ---------------------------------------------------------------
+ Similar to the above, this time the auxilarly XON / XOFF
+ characters have changed; propogate these changes to the card.
+ ------------------------------------------------------------------ */
+
+ fepcmd(ch, SAUXONOFFC, ch->fepstartca, ch->fepstopca, 0, 1);
+ }
+
+} /* End epcaparam */
+
+/* --------------------- Begin receive_data ----------------------- */
+
+static void receive_data(struct channel *ch)
+{ /* Begin receive_data */
+
+ unchar *rptr;
+ struct termios *ts = 0;
+ struct tty_struct *tty;
+ volatile struct board_chan *bc;
+ register int dataToRead, wrapgap, bytesAvailable;
+ register unsigned int tail, head;
+ unsigned int wrapmask;
+ int rc;
+
+
+ /* ---------------------------------------------------------------
+ This routine is called by doint when a receive data event
+ has taken place.
+ ------------------------------------------------------------------- */
+
+ globalwinon(ch);
+
+ if (ch->statusflags & RXSTOPPED)
+ return;
+
+ tty = ch->tty;
+ if (tty)
+ ts = tty->termios;
+
+ bc = ch->brdchan;
+
+ if (!bc)
+ {
+ printk(KERN_ERR "<Error> - bc is NULL in receive_data!\n");
+ return;
+ }
+
+ wrapmask = ch->rxbufsize - 1;
+
+ /* ---------------------------------------------------------------------
+ Get the head and tail pointers to the receiver queue. Wrap the
+ head pointer if it has reached the end of the buffer.
+ ------------------------------------------------------------------------ */
+
+ head = bc->rin;
+ head &= wrapmask;
+ tail = bc->rout & wrapmask;
+
+ bytesAvailable = (head - tail) & wrapmask;
+
+ if (bytesAvailable == 0)
+ return;
+
+ /* ------------------------------------------------------------------
+ If CREAD bit is off or device not open, set TX tail to head
+ --------------------------------------------------------------------- */
+
+ if (!tty || !ts || !(ts->c_cflag & CREAD))
+ {
+ bc->rout = head;
+ return;
+ }
+
+ if (tty->flip.count == TTY_FLIPBUF_SIZE)
+ return;
+
+ if (bc->orun)
+ {
+ bc->orun = 0;
+ printk(KERN_WARNING "overrun! DigiBoard device minor = %d\n",MINOR(tty->device));
+ }
+
+ rxwinon(ch);
+ rptr = tty->flip.char_buf_ptr;
+ rc = tty->flip.count;
+
+ while (bytesAvailable > 0)
+ { /* Begin while there is data on the card */
+
+ wrapgap = (head >= tail) ? head - tail : ch->rxbufsize - tail;
+
+ /* ---------------------------------------------------------------
+ Even if head has wrapped around only report the amount of
+ data to be equal to the size - tail. Remember memcpy can't
+ automaticly wrap around the receive buffer.
+ ----------------------------------------------------------------- */
+
+ dataToRead = (wrapgap < bytesAvailable) ? wrapgap : bytesAvailable;
+
+ /* --------------------------------------------------------------
+ Make sure we don't overflow the buffer
+ ----------------------------------------------------------------- */
+
+ if ((rc + dataToRead) > TTY_FLIPBUF_SIZE)
+ dataToRead = TTY_FLIPBUF_SIZE - rc;
+
+ if (dataToRead == 0)
+ break;
+
+ /* ---------------------------------------------------------------
+ Move data read from our card into the line disciplines buffer
+ for translation if necessary.
+ ------------------------------------------------------------------ */
+
+ if ((memcpy(rptr, ch->rxptr + tail, dataToRead)) != rptr)
+ printk(KERN_ERR "<Error> - receive_data : memcpy failed\n");
+
+ rc += dataToRead;
+ rptr += dataToRead;
+ tail = (tail + dataToRead) & wrapmask;
+ bytesAvailable -= dataToRead;
+
+ } /* End while there is data on the card */
+
+
+ tty->flip.count = rc;
+ tty->flip.char_buf_ptr = rptr;
+ globalwinon(ch);
+ bc->rout = tail;
+
+ /* Must be called with global data */
+ tty_schedule_flip(ch->tty);
+ return;
+
+} /* End receive_data */
+
+/* --------------------- Begin pc_ioctl ----------------------- */
+
+static int pc_ioctl(struct tty_struct *tty, struct file * file,
+ unsigned int cmd, unsigned long arg)
+{ /* Begin pc_ioctl */
+
+ digiflow_t dflow;
+ int retval, error;
+ unsigned long flags;
+ unsigned int mflag, mstat;
+ unsigned char startc, stopc;
+ volatile struct board_chan *bc;
+ struct channel *ch = (struct channel *) tty->driver_data;
+
+ /* The control device has it's own set of commands */
+ if (tty->driver.subtype == SERIAL_TYPE_INFO)
+ { /* Begin if subtype is the control device */
+
+ switch (cmd)
+ { /* Begin switch cmd */
+
+ case DIGI_GETINFO:
+ { /* Begin case DIGI_GETINFO */
+
+ struct digi_info di ;
+ int brd;
+
+ getUser(brd, (unsigned int *)arg);
+
+ if ((error = verify_area(VERIFY_WRITE, (char*)arg, sizeof(di))))
+ {
+ printk(KERN_ERR "DIGI_GETINFO : verify area size 0x%x failed\n",sizeof(di));
+ return(error);
+ }
+
+ if ((brd < 0) || (brd >= num_cards) || (num_cards == 0))
+ return (-ENODEV);
+
+ memset(&di, 0, sizeof(di));
+
+ di.board = brd ;
+ di.status = boards[brd].status;
+ di.type = boards[brd].type ;
+ di.numports = boards[brd].numports ;
+ di.port = boards[brd].port ;
+ di.membase = boards[brd].membase ;
+
+ copy_to_user((char *)arg, &di, sizeof (di));
+ break;
+
+ } /* End case DIGI_GETINFO */
+
+ case DIGI_POLLER:
+ { /* Begin case DIGI_POLLER */
+
+ int brd = arg & 0xff000000 >> 16 ;
+ unsigned char state = arg & 0xff ;
+
+ if ((brd < 0) || (brd >= num_cards))
+ {
+ printk(KERN_ERR "<Error> - DIGI POLLER : brd not valid!\n");
+ return (-ENODEV);
+ }
+
+ digi_poller_inhibited = state ;
+ break ;
+
+ } /* End case DIGI_POLLER */
+
+ case DIGI_INIT:
+ { /* Begin case DIGI_INIT */
+
+ /* ------------------------------------------------------------
+ This call is made by the apps to complete the initilization
+ of the board(s). This routine is responsible for setting
+ the card to its initial state and setting the drivers control
+ fields to the sutianle settings for the card in question.
+ ---------------------------------------------------------------- */
+
+ int crd ;
+ for (crd = 0; crd < num_cards; crd++)
+ post_fep_init (crd);
+
+ break ;
+
+ } /* End case DIGI_INIT */
+
+
+ default:
+ return -ENOIOCTLCMD;
+
+ } /* End switch cmd */
+ return (0) ;
+
+ } /* End if subtype is the control device */
+
+ if (ch)
+ bc = ch->brdchan;
+ else
+ {
+ printk(KERN_ERR "<Error> - ch is NULL in pc_ioctl!\n");
+ return(-EINVAL);
+ }
+
+ save_flags(flags);
+
+ /* -------------------------------------------------------------------
+ For POSIX compliance we need to add more ioctls. See tty_ioctl.c
+ in /usr/src/linux/drivers/char for a good example. In particular
+ think about adding TCSETAF, TCSETAW, TCSETA, TCSETSF, TCSETSW, TCSETS.
+ ---------------------------------------------------------------------- */
+
+ switch (cmd)
+ { /* Begin switch cmd */
+
+ case TCGETS:
+ retval = verify_area(VERIFY_WRITE, (void *)arg,
+ sizeof(struct termios));
+
+ if (retval)
+ return(retval);
+
+ copy_to_user((struct termios *)arg,
+ tty->termios, sizeof(struct termios));
+ return(0);
+
+ case TCGETA:
+ return get_termio(tty, (struct termio *)arg);
+
+ case TCSBRK: /* SVID version: non-zero arg --> no break */
+
+ retval = tty_check_change(tty);
+ if (retval)
+ return retval;
+
+ /* Setup an event to indicate when the transmit buffer empties */
+
+ setup_empty_event(tty,ch);
+ tty_wait_until_sent(tty, 0);
+ if (!arg)
+ digi_send_break(ch, HZ/4); /* 1/4 second */
+ return 0;
+
+ case TCSBRKP: /* support for POSIX tcsendbreak() */
+
+ retval = tty_check_change(tty);
+ if (retval)
+ return retval;
+
+ /* Setup an event to indicate when the transmit buffer empties */
+
+ setup_empty_event(tty,ch);
+ tty_wait_until_sent(tty, 0);
+ digi_send_break(ch, arg ? arg*(HZ/10) : HZ/4);
+ return 0;
+
+ case TIOCGSOFTCAR:
+
+ error = verify_area(VERIFY_WRITE, (void *) arg,sizeof(long));
+ if (error)
+ return error;
+
+ putUser(C_CLOCAL(tty) ? 1 : 0,
+ (unsigned long *) arg);
+ return 0;
+
+ case TIOCSSOFTCAR:
+ /*RONNIE PUT VERIFY_READ (See above) check here */
+ {
+ unsigned int value;
+
+ getUser(value, (unsigned int *)arg);
+ tty->termios->c_cflag =
+ ((tty->termios->c_cflag & ~CLOCAL) |
+ (value ? CLOCAL : 0));
+ return 0;
+ }
+
+ case TIOCMODG:
+ case TIOCMGET:
+
+ mflag = 0;
+
+ cli();
+ globalwinon(ch);
+ mstat = bc->mstat;
+ memoff(ch);
+ restore_flags(flags);
+
+ if (mstat & ch->m_dtr)
+ mflag |= TIOCM_DTR;
+
+ if (mstat & ch->m_rts)
+ mflag |= TIOCM_RTS;
+
+ if (mstat & ch->m_cts)
+ mflag |= TIOCM_CTS;
+
+ if (mstat & ch->dsr)
+ mflag |= TIOCM_DSR;
+
+ if (mstat & ch->m_ri)
+ mflag |= TIOCM_RI;
+
+ if (mstat & ch->dcd)
+ mflag |= TIOCM_CD;
+
+ error = verify_area(VERIFY_WRITE, (void *) arg,sizeof(long));
+
+ if (error)
+ return error;
+
+ putUser(mflag, (unsigned long *) arg);
+
+ break;
+
+ case TIOCMBIS:
+ case TIOCMBIC:
+ case TIOCMODS:
+ case TIOCMSET:
+
+ getUser(mstat, (unsigned int *)arg);
+
+ mflag = 0;
+ if (mstat & TIOCM_DTR)
+ mflag |= ch->m_dtr;
+
+ if (mstat & TIOCM_RTS)
+ mflag |= ch->m_rts;
+
+ switch (cmd)
+ { /* Begin switch cmd */
+
+ case TIOCMODS:
+ case TIOCMSET:
+ ch->modemfake = ch->m_dtr|ch->m_rts;
+ ch->modem = mflag;
+ break;
+
+ case TIOCMBIS:
+ ch->modemfake |= mflag;
+ ch->modem |= mflag;
+ break;
+
+ case TIOCMBIC:
+ ch->modemfake |= mflag;
+ ch->modem &= ~mflag;
+ break;
+
+ } /* End switch cmd */
+
+ cli();
+ globalwinon(ch);
+
+ /* --------------------------------------------------------------
+ The below routine generally sets up parity, baud, flow control
+ issues, etc.... It effect both control flags and input flags.
+ ------------------------------------------------------------------ */
+
+ epcaparam(tty,ch);
+ memoff(ch);
+ restore_flags(flags);
+ break;
+
+ case TIOCSDTR:
+ ch->omodem |= ch->m_dtr;
+ cli();
+ globalwinon(ch);
+ fepcmd(ch, SETMODEM, ch->m_dtr, 0, 10, 1);
+ memoff(ch);
+ restore_flags(flags);
+ break;
+
+ case TIOCCDTR:
+ ch->omodem &= ~ch->m_dtr;
+ cli();
+ globalwinon(ch);
+ fepcmd(ch, SETMODEM, 0, ch->m_dtr, 10, 1);
+ memoff(ch);
+ restore_flags(flags);
+ break;
+
+ case DIGI_GETA:
+ if ((error=
+ verify_area(VERIFY_WRITE, (char*)arg, sizeof(digi_t))))
+ {
+ printk(KERN_ERR "<Error> - Digi GETA failed\n");
+ return(error);
+ }
+
+ copy_to_user((char*)arg, &ch->digiext, sizeof(digi_t));
+ break;
+
+ case DIGI_SETAW:
+ case DIGI_SETAF:
+ if ((cmd) == (DIGI_SETAW))
+ {
+ /* Setup an event to indicate when the transmit buffer empties */
+
+ setup_empty_event(tty,ch);
+ tty_wait_until_sent(tty, 0);
+ }
+ else
+ {
+ if (tty->ldisc.flush_buffer)
+ tty->ldisc.flush_buffer(tty);
+ }
+
+ /* Fall Thru */
+
+ case DIGI_SETA:
+ if ((error =
+ verify_area(VERIFY_READ, (char*)arg,sizeof(digi_t))))
+ return(error);
+
+ copy_from_user(&ch->digiext, (char*)arg, sizeof(digi_t));
+
+ if (ch->digiext.digi_flags & DIGI_ALTPIN)
+ {
+ ch->dcd = ch->m_dsr;
+ ch->dsr = ch->m_dcd;
+ }
+ else
+ {
+ ch->dcd = ch->m_dcd;
+ ch->dsr = ch->m_dsr;
+ }
+
+ cli();
+ globalwinon(ch);
+
+ /* -----------------------------------------------------------------
+ The below routine generally sets up parity, baud, flow control
+ issues, etc.... It effect both control flags and input flags.
+ ------------------------------------------------------------------- */
+
+ epcaparam(tty,ch);
+ memoff(ch);
+ restore_flags(flags);
+ break;
+
+ case DIGI_GETFLOW:
+ case DIGI_GETAFLOW:
+ cli();
+ globalwinon(ch);
+ if ((cmd) == (DIGI_GETFLOW))
+ {
+ dflow.startc = bc->startc;
+ dflow.stopc = bc->stopc;
+ }
+ else
+ {
+ dflow.startc = bc->startca;
+ dflow.stopc = bc->stopca;
+ }
+ memoff(ch);
+ restore_flags(flags);
+
+ if ((error = verify_area(VERIFY_WRITE, (char*)arg,sizeof(dflow))))
+ return(error);
+
+ copy_to_user((char*)arg, &dflow, sizeof(dflow));
+ break;
+
+ case DIGI_SETAFLOW:
+ case DIGI_SETFLOW:
+ if ((cmd) == (DIGI_SETFLOW))
+ {
+ startc = ch->startc;
+ stopc = ch->stopc;
+ }
+ else
+ {
+ startc = ch->startca;
+ stopc = ch->stopca;
+ }
+
+ if ((error = verify_area(VERIFY_READ, (char*)arg,sizeof(dflow))))
+ return(error);
+
+ copy_from_user(&dflow, (char*)arg, sizeof(dflow));
+
+ if (dflow.startc != startc || dflow.stopc != stopc)
+ { /* Begin if setflow toggled */
+ cli();
+ globalwinon(ch);
+
+ if ((cmd) == (DIGI_SETFLOW))
+ {
+ ch->fepstartc = ch->startc = dflow.startc;
+ ch->fepstopc = ch->stopc = dflow.stopc;
+ fepcmd(ch, SONOFFC, ch->fepstartc, ch->fepstopc, 0, 1);
+ }
+ else
+ {
+ ch->fepstartca = ch->startca = dflow.startc;
+ ch->fepstopca = ch->stopca = dflow.stopc;
+ fepcmd(ch, SAUXONOFFC, ch->fepstartca, ch->fepstopca, 0, 1);
+ }
+
+ if (ch->statusflags & TXSTOPPED)
+ pc_start(tty);
+
+ memoff(ch);
+ restore_flags(flags);
+
+ } /* End if setflow toggled */
+ break;
+
+ default:
+ return -ENOIOCTLCMD;
+
+ } /* End switch cmd */
+
+ return 0;
+
+} /* End pc_ioctl */
+
+/* --------------------- Begin pc_set_termios ----------------------- */
+
+static void pc_set_termios(struct tty_struct *tty, struct termios *old_termios)
+{ /* Begin pc_set_termios */
+
+ struct channel *ch;
+ unsigned long flags;
+
+ /* ---------------------------------------------------------
+ verifyChannel returns the channel from the tty struct
+ if it is valid. This serves as a sanity check.
+ ------------------------------------------------------------- */
+
+ if ((ch = verifyChannel(tty)) != NULL)
+ { /* Begin if channel valid */
+
+ save_flags(flags);
+ cli();
+ globalwinon(ch);
+ epcaparam(tty, ch);
+ memoff(ch);
+
+ if ((old_termios->c_cflag & CRTSCTS) &&
+ ((tty->termios->c_cflag & CRTSCTS) == 0))
+ tty->hw_stopped = 0;
+
+ if (!(old_termios->c_cflag & CLOCAL) &&
+ (tty->termios->c_cflag & CLOCAL))
+ wake_up_interruptible(&ch->open_wait);
+
+ restore_flags(flags);
+
+ } /* End if channel valid */
+
+} /* End pc_set_termios */
+
+/* --------------------- Begin do_softint ----------------------- */
+
+static void do_softint(void *private_)
+{ /* Begin do_softint */
+
+ struct channel *ch = (struct channel *) private_;
+
+
+ /* Called in response to a modem change event */
+
+ if (ch && ch->magic == EPCA_MAGIC)
+ { /* Begin EPCA_MAGIC */
+
+ struct tty_struct *tty = ch->tty;
+
+ if (tty && tty->driver_data)
+ {
+ if (test_and_clear_bit(EPCA_EVENT_HANGUP, &ch->event))
+ { /* Begin if clear_bit */
+
+ tty_hangup(tty);
+ wake_up_interruptible(&ch->open_wait);
+ ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE);
+
+ } /* End if clear_bit */
+ }
+
+ } /* End EPCA_MAGIC */
+
+} /* End do_softint */
+
+/* ------------------------------------------------------------
+ pc_stop and pc_start provide software flow control to the
+ routine and the pc_ioctl routine.
+---------------------------------------------------------------- */
+
+/* --------------------- Begin pc_stop ----------------------- */
+
+static void pc_stop(struct tty_struct *tty)
+{ /* Begin pc_stop */
+
+ struct channel *ch;
+ unsigned long flags;
+
+ /* ---------------------------------------------------------
+ verifyChannel returns the channel from the tty struct
+ if it is valid. This serves as a sanity check.
+ ------------------------------------------------------------- */
+
+ if ((ch = verifyChannel(tty)) != NULL)
+ { /* Begin if valid channel */
+
+ save_flags(flags);
+ cli();
+
+ if ((ch->statusflags & TXSTOPPED) == 0)
+ { /* Begin if transmit stop requested */
+
+ globalwinon(ch);
+
+ /* STOP transmitting now !! */
+
+ fepcmd(ch, PAUSETX, 0, 0, 0, 0);
+
+ ch->statusflags |= TXSTOPPED;
+ memoff(ch);
+
+ } /* End if transmit stop requested */
+
+ restore_flags(flags);
+
+ } /* End if valid channel */
+
+} /* End pc_stop */
+
+/* --------------------- Begin pc_start ----------------------- */
+
+static void pc_start(struct tty_struct *tty)
+{ /* Begin pc_start */
+
+ struct channel *ch;
+
+ /* ---------------------------------------------------------
+ verifyChannel returns the channel from the tty struct
+ if it is valid. This serves as a sanity check.
+ ------------------------------------------------------------- */
+
+ if ((ch = verifyChannel(tty)) != NULL)
+ { /* Begin if channel valid */
+
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+
+ /* Just in case output was resumed because of a change in Digi-flow */
+ if (ch->statusflags & TXSTOPPED)
+ { /* Begin transmit resume requested */
+
+ volatile struct board_chan *bc;
+
+ globalwinon(ch);
+ bc = ch->brdchan;
+ if (ch->statusflags & LOWWAIT)
+ bc->ilow = 1;
+
+ /* Okay, you can start transmitting again... */
+
+ fepcmd(ch, RESUMETX, 0, 0, 0, 0);
+
+ ch->statusflags &= ~TXSTOPPED;
+ memoff(ch);
+
+ } /* End transmit resume requested */
+
+ restore_flags(flags);
+
+ } /* End if channel valid */
+
+} /* End pc_start */
+
+/* ------------------------------------------------------------------
+ The below routines pc_throttle and pc_unthrottle are used
+ to slow (And resume) the receipt of data into the kernels
+ receive buffers. The exact occurence of this depends on the
+ size of the kernels receive buffer and what the 'watermarks'
+ are set to for that buffer. See the n_ttys.c file for more
+ details.
+______________________________________________________________________ */
+/* --------------------- Begin throttle ----------------------- */
+
+static void pc_throttle(struct tty_struct * tty)
+{ /* Begin pc_throttle */
+
+ struct channel *ch;
+ unsigned long flags;
+
+ /* ---------------------------------------------------------
+ verifyChannel returns the channel from the tty struct
+ if it is valid. This serves as a sanity check.
+ ------------------------------------------------------------- */
+
+ if ((ch = verifyChannel(tty)) != NULL)
+ { /* Begin if channel valid */
+
+
+ save_flags(flags);
+ cli();
+
+ if ((ch->statusflags & RXSTOPPED) == 0)
+ {
+ globalwinon(ch);
+ fepcmd(ch, PAUSERX, 0, 0, 0, 0);
+
+ ch->statusflags |= RXSTOPPED;
+ memoff(ch);
+ }
+ restore_flags(flags);
+
+ } /* End if channel valid */
+
+} /* End pc_throttle */
+
+/* --------------------- Begin unthrottle ----------------------- */
+
+static void pc_unthrottle(struct tty_struct *tty)
+{ /* Begin pc_unthrottle */
+
+ struct channel *ch;
+ unsigned long flags;
+ volatile struct board_chan *bc;
+
+
+ /* ---------------------------------------------------------
+ verifyChannel returns the channel from the tty struct
+ if it is valid. This serves as a sanity check.
+ ------------------------------------------------------------- */
+
+ if ((ch = verifyChannel(tty)) != NULL)
+ { /* Begin if channel valid */
+
+
+ /* Just in case output was resumed because of a change in Digi-flow */
+ save_flags(flags);
+ cli();
+
+ if (ch->statusflags & RXSTOPPED)
+ {
+
+ globalwinon(ch);
+ bc = ch->brdchan;
+ fepcmd(ch, RESUMERX, 0, 0, 0, 0);
+
+ ch->statusflags &= ~RXSTOPPED;
+ memoff(ch);
+ }
+ restore_flags(flags);
+
+ } /* End if channel valid */
+
+} /* End pc_unthrottle */
+
+/* --------------------- Begin digi_send_break ----------------------- */
+
+void digi_send_break(struct channel *ch, int msec)
+{ /* Begin digi_send_break */
+
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ globalwinon(ch);
+
+ /* --------------------------------------------------------------------
+ Maybe I should send an infinite break here, schedule() for
+ msec amount of time, and then stop the break. This way,
+ the user can't screw up the FEP by causing digi_send_break()
+ to be called (i.e. via an ioctl()) more than once in msec amount
+ of time. Try this for now...
+ ------------------------------------------------------------------------ */
+
+ fepcmd(ch, SENDBREAK, msec, 0, 10, 0);
+ memoff(ch);
+
+ restore_flags(flags);
+
+} /* End digi_send_break */
+
+/* --------------------- Begin setup_empty_event ----------------------- */
+
+static void setup_empty_event(struct tty_struct *tty, struct channel *ch)
+{ /* Begin setup_empty_event */
+
+ volatile struct board_chan *bc = ch->brdchan;
+ unsigned long int flags;
+
+ save_flags(flags);
+ cli();
+ globalwinon(ch);
+ ch->statusflags |= EMPTYWAIT;
+
+ /* ------------------------------------------------------------------
+ When set the iempty flag request a event to be generated when the
+ transmit buffer is empty (If there is no BREAK in progress).
+ --------------------------------------------------------------------- */
+
+ bc->iempty = 1;
+ memoff(ch);
+ restore_flags(flags);
+
+} /* End setup_empty_event */
+
+/* --------------------- Begin get_termio ----------------------- */
+
+static int get_termio(struct tty_struct * tty, struct termio * termio)
+{ /* Begin get_termio */
+ int error;
+
+ error = verify_area(VERIFY_WRITE, termio, sizeof (struct termio));
+ if (error)
+ return error;
+
+ kernel_termios_to_user_termio(termio, tty->termios);
+
+ return 0;
+} /* End get_termio */
+/* ---------------------- Begin epca_setup -------------------------- */
+void epca_setup(char *str, int *ints)
+{ /* Begin epca_setup */
+
+ struct board_info board;
+ int index, loop, last;
+ char *temp, *t2;
+ unsigned len;
+
+ /* ----------------------------------------------------------------------
+ If this routine looks a little strange it is because it is only called
+ if a LILO append command is given to boot the kernel with parameters.
+ In this way, we can provide the user a method of changing his board
+ configuration without rebuilding the kernel.
+ ----------------------------------------------------------------------- */
+ if (!liloconfig)
+ liloconfig = 1;
+
+ memset(&board, 0, sizeof(board));
+
+ /* Assume the data is int first, later we can change it */
+ /* I think that array position 0 of ints holds the number of args */
+ for (last = 0, index = 1; index <= ints[0]; index++)
+ switch(index)
+ { /* Begin parse switch */
+
+ case 1:
+ board.status = ints[index];
+
+ /* ---------------------------------------------------------
+ We check for 2 (As opposed to 1; because 2 is a flag
+ instructing the driver to ignore epcaconfig.) For this
+ reason we check for 2.
+ ------------------------------------------------------------ */
+ if (board.status == 2)
+ { /* Begin ignore epcaconfig as well as lilo cmd line */
+ nbdevs = 0;
+ num_cards = 0;
+ return;
+ } /* End ignore epcaconfig as well as lilo cmd line */
+
+ if (board.status > 2)
+ {
+ printk(KERN_ERR "<Error> - epca_setup: Invalid board status 0x%x\n", board.status);
+ invalid_lilo_config = 1;
+ setup_error_code |= INVALID_BOARD_STATUS;
+ return;
+ }
+ last = index;
+ break;
+
+ case 2:
+ board.type = ints[index];
+ if (board.type >= PCIXEM)
+ {
+ printk(KERN_ERR "<Error> - epca_setup: Invalid board type 0x%x\n", board.type);
+ invalid_lilo_config = 1;
+ setup_error_code |= INVALID_BOARD_TYPE;
+ return;
+ }
+ last = index;
+ break;
+
+ case 3:
+ board.altpin = ints[index];
+ if (board.altpin > 1)
+ {
+ printk(KERN_ERR "<Error> - epca_setup: Invalid board altpin 0x%x\n", board.altpin);
+ invalid_lilo_config = 1;
+ setup_error_code |= INVALID_ALTPIN;
+ return;
+ }
+ last = index;
+ break;
+
+ case 4:
+ board.numports = ints[index];
+ if ((board.numports < 2) || (board.numports > 256))
+ {
+ printk(KERN_ERR "<Error> - epca_setup: Invalid board numports 0x%x\n", board.numports);
+ invalid_lilo_config = 1;
+ setup_error_code |= INVALID_NUM_PORTS;
+ return;
+ }
+ nbdevs += board.numports;
+ last = index;
+ break;
+
+ case 5:
+ board.port = (unsigned char *)ints[index];
+ if (board.port <= 0)
+ {
+ printk(KERN_ERR "<Error> - epca_setup: Invalid io port 0x%x\n", (unsigned int)board.port);
+ invalid_lilo_config = 1;
+ setup_error_code |= INVALID_PORT_BASE;
+ return;
+ }
+ last = index;
+ break;
+
+ case 6:
+ board.membase = (unsigned char *)ints[index];
+ if (board.membase <= 0)
+ {
+ printk(KERN_ERR "<Error> - epca_setup: Invalid memory base 0x%x\n",(unsigned int)board.membase);
+ invalid_lilo_config = 1;
+ setup_error_code |= INVALID_MEM_BASE;
+ return;
+ }
+ last = index;
+ break;
+
+ default:
+ printk(KERN_ERR "<Error> - epca_setup: Too many integer parms\n");
+ return;
+
+ } /* End parse switch */
+
+ while (str && *str)
+ { /* Begin while there is a string arg */
+
+ /* find the next comma or terminator */
+ temp = str;
+
+ /* While string is not null, and a comma hasn't been found */
+ while (*temp && (*temp != ','))
+ temp++;
+
+ if (!*temp)
+ temp = NULL;
+ else
+ *temp++ = 0;
+
+ /* Set index to the number of args + 1 */
+ index = last + 1;
+
+ switch(index)
+ {
+ case 1:
+ len = strlen(str);
+ if (strncmp("Disable", str, len) == 0)
+ board.status = 0;
+ else
+ if (strncmp("Enable", str, len) == 0)
+ board.status = 1;
+ else
+ {
+ printk(KERN_ERR "<Error> - epca_setup: Invalid status %s\n", str);
+ invalid_lilo_config = 1;
+ setup_error_code |= INVALID_BOARD_STATUS;
+ return;
+ }
+ last = index;
+ break;
+
+ case 2:
+
+ for(loop = 0; loop < EPCA_NUM_TYPES; loop++)
+ if (strcmp(board_desc[loop], str) == 0)
+ break;
+
+
+ /* ---------------------------------------------------------------
+ If the index incremented above refers to a legitamate board
+ type set it here.
+ ------------------------------------------------------------------*/
+
+ if (index < EPCA_NUM_TYPES)
+ board.type = loop;
+ else
+ {
+ printk(KERN_ERR "<Error> - epca_setup: Invalid board type: %s\n", str);
+ invalid_lilo_config = 1;
+ setup_error_code |= INVALID_BOARD_TYPE;
+ return;
+ }
+ last = index;
+ break;
+
+ case 3:
+ len = strlen(str);
+ if (strncmp("Disable", str, len) == 0)
+ board.altpin = 0;
+ else
+ if (strncmp("Enable", str, len) == 0)
+ board.altpin = 1;
+ else
+ {
+ printk(KERN_ERR "<Error> - epca_setup: Invalid altpin %s\n", str);
+ invalid_lilo_config = 1;
+ setup_error_code |= INVALID_ALTPIN;
+ return;
+ }
+ last = index;
+ break;
+
+ case 4:
+ t2 = str;
+ while (isdigit(*t2))
+ t2++;
+
+ if (*t2)
+ {
+ printk(KERN_ERR "<Error> - epca_setup: Invalid port count %s\n", str);
+ invalid_lilo_config = 1;
+ setup_error_code |= INVALID_NUM_PORTS;
+ return;
+ }
+
+ /* ------------------------------------------------------------
+ There is not a man page for simple_strtoul but the code can be
+ found in vsprintf.c. The first argument is the string to
+ translate (To an unsigned long obviously), the second argument
+ can be the address of any character variable or a NULL. If a
+ variable is given, the end pointer of the string will be stored
+ in that variable; if a NULL is given the the end pointer will
+ not be returned. The last argument is the base to use. If
+ a 0 is indicated, the routine will attempt to determine the
+ proper base by looking at the values prefix (A '0' for octal,
+ a 'x' for hex, etc ... If a value is given it will use that
+ value as the base.
+ ---------------------------------------------------------------- */
+ board.numports = simple_strtoul(str, NULL, 0);
+ nbdevs += board.numports;
+ last = index;
+ break;
+
+ case 5:
+ t2 = str;
+ while (isxdigit(*t2))
+ t2++;
+
+ if (*t2)
+ {
+ printk(KERN_ERR "<Error> - epca_setup: Invalid i/o address %s\n", str);
+ invalid_lilo_config = 1;
+ setup_error_code |= INVALID_PORT_BASE;
+ return;
+ }
+
+ board.port = (unsigned char *)simple_strtoul(str, NULL, 16);
+ last = index;
+ break;
+
+ case 6:
+ t2 = str;
+ while (isxdigit(*t2))
+ t2++;
+
+ if (*t2)
+ {
+ printk(KERN_ERR "<Error> - epca_setup: Invalid memory base %s\n",str);
+ invalid_lilo_config = 1;
+ setup_error_code |= INVALID_MEM_BASE;
+ return;
+ }
+
+ board.membase = (unsigned char *)simple_strtoul(str, NULL, 16);
+ last = index;
+ break;
+
+ default:
+ printk(KERN_ERR "PC/Xx: Too many string parms\n");
+ return;
+ }
+ str = temp;
+
+ } /* End while there is a string arg */
+
+
+ if (last < 6)
+ {
+ printk(KERN_ERR "PC/Xx: Insufficient parms specified\n");
+ return;
+ }
+
+ /* I should REALLY validate the stuff here */
+
+ /* Copies our local copy of board into boards */
+ memcpy((void *)&boards[num_cards],(void *)&board, sizeof(board));
+
+
+ /* Does this get called once per lilo arg are what ? */
+
+ printk(KERN_INFO "PC/Xx: Added board %i, %s %i ports at 0x%4.4X base 0x%6.6X\n",
+ num_cards, board_desc[board.type],
+ board.numports, (int)board.port, (unsigned int) board.membase);
+
+ num_cards++;
+
+} /* End epca_setup */
+
+
+
+#ifdef ENABLE_PCI
+/* --------------------- Begin get_PCI_configuration ---------------------- */
+
+int get_PCI_configuration(char bus, char device_fn,
+ unsigned int *base_addr0, unsigned int *base_addr1,
+ unsigned int *base_addr2, unsigned int *base_addr3,
+ unsigned int *base_addr4, unsigned int *base_addr5)
+{ /* Begin get_PCI_configuration */
+
+ int error;
+
+ error = pcibios_read_config_dword(bus, device_fn, PCI_BASE_ADDRESS_0,
+ base_addr0);
+
+ error |= pcibios_read_config_dword(bus, device_fn, PCI_BASE_ADDRESS_1,
+ base_addr1);
+
+ error |= pcibios_read_config_dword(bus, device_fn, PCI_BASE_ADDRESS_2,
+ base_addr2);
+
+ error |= pcibios_read_config_dword(bus, device_fn, PCI_BASE_ADDRESS_3,
+ base_addr3);
+
+ error |= pcibios_read_config_dword(bus, device_fn, PCI_BASE_ADDRESS_4,
+ base_addr4);
+
+ error |= pcibios_read_config_dword(bus, device_fn, PCI_BASE_ADDRESS_5,
+ base_addr5);
+
+ /* ------------------------------------------------------------------------
+ NOTE - The code below mask out either the 2 or 4 bits dependant on the
+ space being addressed. (base_addr value reflecting io space, have their
+ first 2 bits mask out, while base_addr value reflecting mem space, have
+ their first 4 bits mask out.) These bits are flag bits and should always
+ be 0 when used as an address.
+ ---------------------------------------------------------------------------- */
+
+ if ((*base_addr0) & PCI_BASE_ADDRESS_SPACE_IO) /* Is this an io address ? */
+ (*base_addr0) &= PCI_BASE_ADDRESS_IO_MASK;
+ else
+ (*base_addr0) &= PCI_BASE_ADDRESS_MEM_MASK;
+
+ if ((*base_addr1) & PCI_BASE_ADDRESS_SPACE_IO) /* Is this an io address ? */
+ (*base_addr1) &= PCI_BASE_ADDRESS_IO_MASK;
+ else
+ (*base_addr1) &= PCI_BASE_ADDRESS_MEM_MASK;
+
+ if ((*base_addr2) & PCI_BASE_ADDRESS_SPACE_IO) /* Is this an io address ? */
+ (*base_addr2) &= PCI_BASE_ADDRESS_IO_MASK;
+ else
+ (*base_addr2) &= PCI_BASE_ADDRESS_MEM_MASK;
+
+ if ((*base_addr3) & PCI_BASE_ADDRESS_SPACE_IO) /* Is this an io address ? */
+ (*base_addr3) &= PCI_BASE_ADDRESS_IO_MASK;
+ else
+ (*base_addr3) &= PCI_BASE_ADDRESS_MEM_MASK;
+
+ if ((*base_addr4) & PCI_BASE_ADDRESS_SPACE_IO) /* Is this an io address ? */
+ (*base_addr4) &= PCI_BASE_ADDRESS_IO_MASK;
+ else
+ (*base_addr4) &= PCI_BASE_ADDRESS_MEM_MASK;
+
+ if ((*base_addr5) & PCI_BASE_ADDRESS_SPACE_IO) /* Is this an io address ? */
+ (*base_addr5) &= PCI_BASE_ADDRESS_IO_MASK;
+ else
+ (*base_addr5) &= PCI_BASE_ADDRESS_MEM_MASK;
+
+ if (error)
+ {
+ printk(KERN_ERR "<Error> - DIGI PCI error: board not initializing due to error\n");
+ return(0);
+ }
+ return(1);
+} /* End get_PCI_configuration */
+
+/* ------------------------ Begin init_PCI --------------------------- */
+
+int init_PCI(int boards_found)
+{ /* Begin init_PCI */
+
+ unsigned char bus, device_fn;
+ int i, pci_count = 0;
+ unsigned int base_addr0, base_addr1, base_addr2,
+ base_addr3, base_addr4, base_addr5;
+
+ base_addr0 = base_addr1 = base_addr2 = 0;
+ base_addr3 = base_addr4 = base_addr5 = 0;
+
+ for(i = 0; i < (MAXBOARDS - boards_found); i++)
+ { /* Begin for each POSSIBLE remaining board */
+
+ if (!pcibios_find_device(PCI_VENDOR_DIGI, PCI_DEVICE_XR,
+ i, &bus, &device_fn))
+ { /* Begin found XR */
+ if (get_PCI_configuration(bus, device_fn, &base_addr0, &base_addr1,
+ &base_addr2, &base_addr3,
+ &base_addr4, &base_addr5))
+ { /* Store a PCI/XR into the boards structure */
+
+
+ boards[boards_found + pci_count].status = ENABLED;
+ boards[boards_found + pci_count].type = PCIXR;
+
+ boards[boards_found + pci_count].numports = 0x0;
+
+ boards[boards_found + pci_count].port = (unsigned char *)((char *)base_addr0 + PCI_IO_OFFSET);
+ /* Most cards use base_addr0, but some use base_addr2 */
+ boards[boards_found + pci_count].membase = (unsigned char *)base_addr0;
+
+ if (base_addr0 >= 0x100000)
+ {
+ /* ------------------------------------------------------------
+ Standard physical addresses are valid to the kernel as long
+ as they aren't above RAM. Higher addresses (Such as are
+ typical of a PCI system) need to be mapped in with the
+ ioremap command. For boards using such high addresses the
+ driver will store both addresses. One address (The physical)
+ will be held for the apps use (And mmap) and the other (The
+ ioremapped address) will be used in the kernel.
+
+ ---------------------------------------------------------------- */
+ boards[boards_found + pci_count].re_map_port = ioremap((base_addr0 + PCI_IO_OFFSET),0x200000);
+ boards[boards_found + pci_count].re_map_membase = ioremap(base_addr0, 0x200000);
+ }
+
+ pci_count++;
+
+ /* --------------------------------------------------------------
+ I don't know what the below does, but the hardware guys say
+ its required on everything except PLX (In this case XRJ).
+ ---------------------------------------------------------------- */
+ pcibios_write_config_byte(bus, device_fn, 0x40, 0);
+ pcibios_write_config_byte(bus, device_fn, 0x46, 0);
+
+ } /* End store a PCI/XR into the board structure */
+
+ } /* End found XR */
+
+ if (!pcibios_find_device(PCI_VENDOR_DIGI, PCI_DEVICE_XEM,
+ i, &bus, &device_fn))
+ { /* Begin found XEM */
+
+ if (get_PCI_configuration(bus, device_fn, &base_addr0, &base_addr1,
+ &base_addr2, &base_addr3,
+ &base_addr4, &base_addr5))
+ { /* Begin store a PCI/XEM into the boards structure */
+
+ boards[boards_found + pci_count].status = ENABLED;
+ boards[boards_found + pci_count].type = PCIXEM;
+
+ boards[boards_found + pci_count].numports = 0x0;
+ boards[boards_found + pci_count].port = (char *)((char *)base_addr0 + PCI_IO_OFFSET);
+ /* Most cards use base_addr0, but some use base_addr2 */
+ boards[boards_found + pci_count].membase = (unsigned char *)base_addr0;
+
+ if (base_addr0 >= 0x100000)
+ {
+ /* ------------------------------------------------------------
+ Standard physical addresses are valid to the kernel as long
+ as they aren't above RAM. Higher addresses (Such as are
+ typical of a PCI system) need to be mapped in with the
+ ioremap command. For boards using such high addresses the
+ driver will store both addresses. One address (The physical)
+ will be held for the apps use (And mmap) and the other (The
+ vremapped address) will be used in the kernel.
+
+ ---------------------------------------------------------------- */
+ boards[boards_found + pci_count].re_map_port = ioremap((base_addr0 + PCI_IO_OFFSET),0x200000);
+ boards[boards_found + pci_count].re_map_membase = ioremap(base_addr0, 0x200000);
+ }
+
+ pci_count++;
+ /* --------------------------------------------------------------
+ I don't know what the below does, but the hardware guys say
+ its required on everything except PLX (In this case XRJ).
+ ---------------------------------------------------------------- */
+ pcibios_write_config_byte(bus, device_fn, 0x40, 0);
+ pcibios_write_config_byte(bus, device_fn, 0x46, 0);
+
+ } /* End store a PCI/XEM into the boards structure */
+
+ } /* End found XEM */
+
+
+ if (!pcibios_find_device(PCI_VENDOR_DIGI, PCI_DEVICE_CX,
+ i, &bus, &device_fn))
+ { /* Begin found CX */
+
+ if (get_PCI_configuration(bus, device_fn, &base_addr0, &base_addr1,
+ &base_addr2, &base_addr3,
+ &base_addr4, &base_addr5))
+ { /* Begin store a PCI/CX into the boards structure */
+
+ boards[boards_found + pci_count].status = ENABLED;
+ boards[boards_found + pci_count].type = PCICX;
+
+ boards[boards_found + pci_count].numports = 0x0;
+ boards[boards_found + pci_count].port = (char *)((char *)base_addr0 + PCI_IO_OFFSET);
+ /* Most cards use base_addr0, but some use base_addr2 */
+ boards[boards_found + pci_count].membase = (unsigned char *)base_addr0;
+
+ if (base_addr0 >= 0x100000)
+ {
+ /* ------------------------------------------------------------
+ Standard physical addresses are valid to the kernel as long
+ as they aren't above RAM. Higher addresses (Such as are
+ typical of a PCI system) need to be mapped in with the
+ ioremap command. For boards using such high addresses the
+ driver will store both addresses. One address (The physical)
+ will be held for the apps use (And mmap) and the other (The
+ vremapped address) will be used in the kernel.
+
+ ---------------------------------------------------------------- */
+ boards[boards_found + pci_count].re_map_port = ioremap((base_addr0 + PCI_IO_OFFSET),0x200000);
+ boards[boards_found + pci_count].re_map_membase = ioremap(base_addr0, 0x200000);
+ }
+
+ pci_count++;
+ /* --------------------------------------------------------------
+ I don't know what the below does, but the hardware guys say
+ its required on everything except PLX (In this case XRJ).
+ ---------------------------------------------------------------- */
+ pcibios_write_config_byte(bus, device_fn, 0x40, 0);
+ pcibios_write_config_byte(bus, device_fn, 0x46, 0);
+
+ } /* End store a PCI/CX into the boards structure */
+
+ } /* End found CX */
+
+ if (!pcibios_find_device(PCI_VENDOR_DIGI, PCI_DEVICE_XRJ,
+ i, &bus, &device_fn))
+ { /* Begin found XRJ */
+
+ if (get_PCI_configuration(bus, device_fn, &base_addr0, &base_addr1,
+ &base_addr2, &base_addr3,
+ &base_addr4, &base_addr5))
+ { /* Begin store a PCI/XRJ into the boards structure */
+
+ boards[boards_found + pci_count].status = ENABLED;
+ boards[boards_found + pci_count].type = PCIXRJ;
+
+ boards[boards_found + pci_count].numports = 0x0;
+ boards[boards_found + pci_count].port = (unsigned char *)(base_addr2 + PCI_IO_OFFSET);
+ /* Most cards use base_addr0, but some use base_addr2 */
+ boards[boards_found + pci_count].membase = (unsigned char *)base_addr2;
+
+ if (base_addr2 >= 0x100000)
+ {
+ /* ------------------------------------------------------------
+ Standard physical addresses are valid to the kernel as long
+ as they aren't above RAM. Higher addresses (Such as are
+ typical of a PCI system) need to be mapped in with the
+ ioremap command. For boards using such high addresses the
+ driver will store both addresses. One address (The physical)
+ will be held for the apps use (And mmap) and the other (The
+ vremapped address) will be used in the kernel.
+
+ ---------------------------------------------------------------- */
+ boards[boards_found + pci_count].re_map_port = ioremap((base_addr2 + PCI_IO_OFFSET),0x200000);
+ boards[boards_found + pci_count].re_map_membase = ioremap(base_addr2, 0x200000);
+ }
+
+ pci_count++;
+
+ } /* End store a PCI/XRJ into the boards structure */
+
+ } /* End found XRJ */
+
+ } /* End for each POSSIBLE remaining board */
+
+ return(pci_count);
+
+} /* End init_PCI */
+
+#endif /* ENABLE_PCI */
+
+
diff --git a/drivers/char/esp.c b/drivers/char/esp.c
index c1eb47de0..42ed91080 100644
--- a/drivers/char/esp.c
+++ b/drivers/char/esp.c
@@ -689,7 +689,7 @@ static void do_softint(void *private_)
if (!tty)
return;
- if (clear_bit(ESP_EVENT_WRITE_WAKEUP, &info->event)) {
+ if (test_and_clear_bit(ESP_EVENT_WRITE_WAKEUP, &info->event)) {
if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
tty->ldisc.write_wakeup)
(tty->ldisc.write_wakeup)(tty);
diff --git a/drivers/char/fbmem.c b/drivers/char/fbmem.c
index 1493f4932..b267f84d3 100644
--- a/drivers/char/fbmem.c
+++ b/drivers/char/fbmem.c
@@ -16,6 +16,7 @@
#include <linux/malloc.h>
#include <linux/mman.h>
#include <linux/tty.h>
+#include <linux/init.h>
#include <asm/setup.h>
#include <asm/uaccess.h>
@@ -300,8 +301,8 @@ unregister_framebuffer(int node)
return 0;
}
-void
-fbmem_init(void)
+__initfunc(void
+fbmem_init(void))
{
if (register_chrdev(FB_MAJOR,"fb",&fb_fops))
printk("unable to get major %d for fb devs\n", FB_MAJOR);
diff --git a/drivers/char/ftape/kernel-interface.c b/drivers/char/ftape/kernel-interface.c
index 31719a451..9bcb35e46 100644
--- a/drivers/char/ftape/kernel-interface.c
+++ b/drivers/char/ftape/kernel-interface.c
@@ -29,6 +29,7 @@
#include <linux/signal.h>
#include <linux/major.h>
#include <linux/malloc.h>
+#include <linux/init.h>
#include <linux/ftape.h>
#include <asm/dma.h>
@@ -120,7 +121,7 @@ EXPORT_NO_SYMBOLS;
#define ftape_init init_module
#endif
-int ftape_init(void)
+__initfunc(int ftape_init(void))
{
int n;
int order;
diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c
index a0f2f10c5..f21693bff 100644
--- a/drivers/char/istallion.c
+++ b/drivers/char/istallion.c
@@ -1005,7 +1005,7 @@ static int stli_initopen(stlibrd_t *brdp, stliport_t *portp)
set_bit(ST_GETSIGS, &portp->state);
if ((rc = stli_cmdwait(brdp, portp, A_GETSIGNALS, &portp->asig, sizeof(asysigs_t), 1)) < 0)
return(rc);
- if (clear_bit(ST_GETSIGS, &portp->state))
+ if (test_and_clear_bit(ST_GETSIGS, &portp->state))
portp->sigs = stli_mktiocm(portp->asig.sigvalue);
stli_mkasysigs(&portp->asig, 1, 1);
if ((rc = stli_cmdwait(brdp, portp, A_SETSIGNALS, &portp->asig, sizeof(asysigs_t), 0)) < 0)
diff --git a/drivers/char/keyb_m68k.c b/drivers/char/keyb_m68k.c
deleted file mode 100644
index 587d61a4b..000000000
--- a/drivers/char/keyb_m68k.c
+++ /dev/null
@@ -1,876 +0,0 @@
-/*
- * linux/drivers/char/keyboard.c
- *
- * Keyboard driver for Linux v0.99 using Latin-1.
- *
- * Written for linux by Johan Myreen as a translation from
- * the assembly version by Linus (with diacriticals added)
- *
- * Some additional features added by Christoph Niemann (ChN), March 1993
- *
- * Loadable keymaps by Risto Kankkunen, May 1993
- *
- * Diacriticals redone & other small changes, aeb@cwi.nl, June 1993
- * Added decr/incr_console, dynamic keymaps, Unicode support,
- * dynamic function/string keys, led setting, Sept 1994
- * `Sticky' modifier keys, 951006.
- *
- */
-
-/*
- * modified to provide 'generic' keyboard support by Hamish Macdonald
- */
-
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/mm.h>
-#include <linux/random.h>
-#include <linux/init.h>
-
-#include <asm/bitops.h>
-#include <asm/machdep.h>
-
-#include "kbd_kern.h"
-#include "diacr.h"
-#include "vt_kern.h"
-
-#define SIZE(x) (sizeof(x)/sizeof((x)[0]))
-
-#define KBD_REPORT_ERR
-#define KBD_REPORT_UNKN
-/* #define KBD_IS_FOCUS_9000 */
-
-#ifndef KBD_DEFMODE
-#define KBD_DEFMODE ((1 << VC_REPEAT) | (1 << VC_META))
-#endif
-
-#ifndef KBD_DEFLEDS
-/*
- * Some laptops take the 789uiojklm,. keys as number pad when NumLock
- * is on. This seems a good reason to start with NumLock off.
- */
-#define KBD_DEFLEDS 0
-#endif
-
-#ifndef KBD_DEFLOCK
-#define KBD_DEFLOCK 0
-#endif
-
-/*
- * The default IO slowdown is doing 'inb()'s from 0x61, which should be
- * safe. But as that is the keyboard controller chip address, we do our
- * slowdowns here by doing short jumps: the keyboard controller should
- * be able to keep up
- */
-#define REALLY_SLOW_IO
-#define SLOW_IO_BY_JUMPING
-#include <asm/io.h>
-#include <asm/system.h>
-
-extern void poke_blanked_console(void);
-extern void ctrl_alt_del(void);
-extern void reset_vc(unsigned int new_console);
-extern void scrollback(int);
-extern void scrollfront(int);
-extern int vc_cons_allocated(unsigned int);
-
-unsigned char kbd_read_mask = 0x01; /* modified by psaux.c */
-
-struct wait_queue * keypress_wait = NULL;
-
-void keyboard_wait_for_keypress(void)
-{
- sleep_on(&keypress_wait);
-}
-
-/*
- * global state includes the following, and various static variables
- * in this module: prev_scancode, shift_state, diacr, npadch, dead_key_next.
- * (last_console is now a global variable)
- */
-
-/* shift state counters.. */
-static unsigned char k_down[NR_SHIFT] = {0, };
-/* keyboard key bitmap */
-#define BITS_PER_LONG (8*sizeof(unsigned long))
-static unsigned long key_down[256/BITS_PER_LONG] = { 0, };
-
-static int dead_key_next = 0;
-/*
- * In order to retrieve the shift_state (for the mouse server), either
- * the variable must be global, or a new procedure must be created to
- * return the value. I chose the former way.
- */
-/*static*/ int shift_state = 0;
-static int npadch = -1; /* -1 or number assembled on pad */
-static unsigned char diacr = 0;
-static char rep = 0; /* flag telling character repeat */
-struct kbd_struct kbd_table[MAX_NR_CONSOLES];
-static struct tty_struct **ttytab;
-static struct kbd_struct *kbd = kbd_table;
-static struct tty_struct *tty = NULL;
-
-extern void compute_shiftstate(void);
-
-typedef void (*k_hand)(unsigned char value, char up_flag);
-typedef void (k_handfn)(unsigned char value, char up_flag);
-
-static k_handfn
- do_self, do_fn, do_spec, do_pad, do_dead, do_cons, do_cur, do_shift,
- do_meta, do_ascii, do_lock, do_lowercase, do_slock, do_ignore;
-
-static k_hand key_handler[16] = {
- do_self, do_fn, do_spec, do_pad, do_dead, do_cons, do_cur, do_shift,
- do_meta, do_ascii, do_lock, do_lowercase, do_slock,
- do_ignore, do_ignore, do_ignore
-};
-
-typedef void (*void_fnp)(void);
-typedef void (void_fn)(void);
-
-static void_fn do_null, enter, show_ptregs, send_intr, lastcons, caps_toggle,
- num, hold, scroll_forw, scroll_back, boot_it, caps_on, compose,
- SAK, decr_console, incr_console, spawn_console, bare_num;
-
-static void_fnp spec_fn_table[] = {
- do_null, enter, show_ptregs, show_mem,
- show_state, send_intr, lastcons, caps_toggle,
- num, hold, scroll_forw, scroll_back,
- boot_it, caps_on, compose, SAK,
- decr_console, incr_console, spawn_console, bare_num
-};
-
-/* maximum values each key_handler can handle */
-const int max_vals[] = {
- 255, SIZE(func_table) - 1, SIZE(spec_fn_table) - 1, NR_PAD - 1,
- NR_DEAD - 1, 255, 3, NR_SHIFT - 1,
- 255, NR_ASCII - 1, NR_LOCK - 1, 255,
- NR_LOCK - 1
-};
-
-const int NR_TYPES = SIZE(max_vals);
-
-static void put_queue(int);
-static unsigned char handle_diacr(unsigned char);
-
-/*
- * Many other routines do put_queue, but I think either
- * they produce ASCII, or they produce some user-assigned
- * string, and in both cases we might assume that it is
- * in utf-8 already.
- */
-void to_utf8(ushort c) {
- if (c < 0x80)
- put_queue(c); /* 0******* */
- else if (c < 0x800) {
- put_queue(0xc0 | (c >> 6)); /* 110***** 10****** */
- put_queue(0x80 | (c & 0x3f));
- } else {
- put_queue(0xe0 | (c >> 12)); /* 1110**** 10****** 10****** */
- put_queue(0x80 | ((c >> 6) & 0x3f));
- put_queue(0x80 | (c & 0x3f));
- }
- /* UTF-8 is defined for words of up to 31 bits,
- but we need only 16 bits here */
-}
-
-void process_keycode (int keycode)
-{
- char up_flag; /* 0 or 0200 */
- char raw_mode;
-
- do_poke_blanked_console = 1;
- mark_bh(KEYBOARD_BH);
- add_keyboard_randomness(keycode);
-
- tty = ttytab[fg_console];
- kbd = kbd_table + fg_console;
- if ((raw_mode = (kbd->kbdmode == VC_RAW))) {
- put_queue(keycode);
- /* we do not return yet, because we want to maintain
- the key_down array, so that we have the correct
- values when finishing RAW mode or when changing VT's */
- }
-
- /*
- * At this point the variable `keycode' contains the keycode.
- * Note: the keycode must not be 0.
- * We keep track of the up/down status of the key, and
- * return the keycode if in MEDIUMRAW mode.
- */
-
- up_flag = (keycode & 0200);
- keycode &= 0x7f;
- if (up_flag) {
- rep = 0;
- if(!clear_bit(keycode, key_down)) {
- /* unexpected, but this can happen:
- maybe this was a key release for a FOCUS 9000
- PF key; if we want to see it, we have to clear
- up_flag */
-#ifndef __mc68000__
- if (keycode >= SC_LIM || keycode == 85)
- up_flag = 0;
-#endif
- }
- } else
- rep = set_bit(keycode, key_down);
-
- if (raw_mode)
- return;
-
- if (kbd->kbdmode == VC_MEDIUMRAW) {
- /* soon keycodes will require more than one byte */
- put_queue(keycode + up_flag);
- return;
- }
-
- /*
- * Small change in philosophy: earlier we defined repetition by
- * rep = keycode == prev_keycode;
- * prev_keycode = keycode;
- * but now by the fact that the depressed key was down already.
- * Does this ever make a difference? Yes.
- */
-
- /*
- * Repeat a key only if the input buffers are empty or the
- * characters get echoed locally. This makes key repeat usable
- * with slow applications and under heavy loads.
- */
- if (!rep ||
- (vc_kbd_mode(kbd,VC_REPEAT) && tty &&
- (L_ECHO(tty) || (tty->driver.chars_in_buffer(tty) == 0)))) {
- u_short keysym;
- u_char type;
-
- /* the XOR below used to be an OR */
- int shift_final = shift_state ^ kbd->lockstate ^ kbd->slockstate;
- ushort *key_map = key_maps[shift_final];
-
- if (key_map != NULL) {
- keysym = key_map[keycode];
- type = KTYP(keysym);
-
- if (type >= 0xf0) {
- type -= 0xf0;
- if (type == KT_LETTER) {
- type = KT_LATIN;
- if (vc_kbd_led(kbd, VC_CAPSLOCK)) {
- key_map = key_maps[shift_final ^ (1<<KG_SHIFT)];
- if (key_map)
- keysym = key_map[keycode];
- }
- }
- (*key_handler[type])(keysym & 0xff, up_flag);
- if (type != KT_SLOCK)
- kbd->slockstate = 0;
- } else {
- /* maybe only if (kbd->kbdmode == VC_UNICODE) ? */
- if (!up_flag)
- to_utf8(keysym);
- }
- } else {
- /* maybe beep? */
- /* we have at least to update shift_state */
-#if 1 /* how? two almost equivalent choices follow */
- compute_shiftstate();
-#else
- keysym = U(plain_map[keycode]);
- type = KTYP(keysym);
- if (type == KT_SHIFT)
- (*key_handler[type])(keysym & 0xff, up_flag);
-#endif
- }
- }
-}
-
-static void put_queue(int ch)
-{
- wake_up(&keypress_wait);
- if (tty) {
- tty_insert_flip_char(tty, ch, 0);
- tty_schedule_flip(tty);
- }
-}
-
-static void puts_queue(char *cp)
-{
- wake_up(&keypress_wait);
- if (!tty)
- return;
-
- while (*cp) {
- tty_insert_flip_char(tty, *cp, 0);
- cp++;
- }
- tty_schedule_flip(tty);
-}
-
-static void applkey(int key, char mode)
-{
- static char buf[] = { 0x1b, 'O', 0x00, 0x00 };
-
- buf[1] = (mode ? 'O' : '[');
- buf[2] = key;
- puts_queue(buf);
-}
-
-static void enter(void)
-{
- put_queue(13);
- if (vc_kbd_mode(kbd,VC_CRLF))
- put_queue(10);
-}
-
-static void caps_toggle(void)
-{
- if (rep)
- return;
- chg_vc_kbd_led(kbd, VC_CAPSLOCK);
-}
-
-static void caps_on(void)
-{
- if (rep)
- return;
- set_vc_kbd_led(kbd, VC_CAPSLOCK);
-}
-
-struct pt_regs *pt_regs;
-
-static void show_ptregs(void)
-{
- if (pt_regs)
- show_regs(pt_regs);
- return;
-}
-
-static void hold(void)
-{
- if (rep || !tty)
- return;
-
- /*
- * Note: SCROLLOCK will be set (cleared) by stop_tty (start_tty);
- * these routines are also activated by ^S/^Q.
- * (And SCROLLOCK can also be set by the ioctl KDSKBLED.)
- */
- if (tty->stopped)
- start_tty(tty);
- else
- stop_tty(tty);
-}
-
-static void num(void)
-{
- if (vc_kbd_mode(kbd,VC_APPLIC))
- applkey('P', 1);
- else
- bare_num();
-}
-
-/*
- * Bind this to Shift-NumLock if you work in application keypad mode
- * but want to be able to change the NumLock flag.
- * Bind this to NumLock if you prefer that the NumLock key always
- * changes the NumLock flag.
- */
-static void bare_num(void)
-{
- if (!rep)
- chg_vc_kbd_led(kbd,VC_NUMLOCK);
-}
-
-static void lastcons(void)
-{
- /* switch to the last used console, ChN */
- set_console(last_console);
-}
-
-static void decr_console(void)
-{
- int i;
-
- for (i = fg_console-1; i != fg_console; i--) {
- if (i == -1)
- i = MAX_NR_CONSOLES-1;
- if (vc_cons_allocated(i))
- break;
- }
- set_console(i);
-}
-
-static void incr_console(void)
-{
- int i;
-
- for (i = fg_console+1; i != fg_console; i++) {
- if (i == MAX_NR_CONSOLES)
- i = 0;
- if (vc_cons_allocated(i))
- break;
- }
- set_console(i);
-}
-
-static void send_intr(void)
-{
- if (!tty)
- return;
- tty_insert_flip_char(tty, 0, TTY_BREAK);
- tty_schedule_flip(tty);
-}
-
-static void scroll_forw(void)
-{
- scrollfront(0);
-}
-
-static void scroll_back(void)
-{
- scrollback(0);
-}
-
-static void boot_it(void)
-{
- ctrl_alt_del();
-}
-
-static void compose(void)
-{
- dead_key_next = 1;
-}
-
-int spawnpid, spawnsig;
-
-static void spawn_console(void)
-{
- if (spawnpid)
- if(kill_proc(spawnpid, spawnsig, 1))
- spawnpid = 0;
-}
-
-static void SAK(void)
-{
- do_SAK(tty);
-#if 0
- /*
- * Need to fix SAK handling to fix up RAW/MEDIUM_RAW and
- * vt_cons modes before we can enable RAW/MEDIUM_RAW SAK
- * handling.
- *
- * We should do this some day --- the whole point of a secure
- * attention key is that it should be guaranteed to always
- * work.
- */
- reset_vc(fg_console);
- do_unblank_screen(); /* not in interrupt routine? */
-#endif
-}
-
-static void do_ignore(unsigned char value, char up_flag)
-{
-}
-
-static void do_null()
-{
- compute_shiftstate();
-}
-
-static void do_spec(unsigned char value, char up_flag)
-{
- if (up_flag)
- return;
- if (value >= SIZE(spec_fn_table))
- return;
- spec_fn_table[value]();
-}
-
-static void do_lowercase(unsigned char value, char up_flag)
-{
- printk("keyboard.c: do_lowercase was called - impossible\n");
-}
-
-static void do_self(unsigned char value, char up_flag)
-{
- if (up_flag)
- return; /* no action, if this is a key release */
-
- if (diacr)
- value = handle_diacr(value);
-
- if (dead_key_next) {
- dead_key_next = 0;
- diacr = value;
- return;
- }
-
- put_queue(value);
-}
-
-#define A_GRAVE '`'
-#define A_ACUTE '\''
-#define A_CFLEX '^'
-#define A_TILDE '~'
-#define A_DIAER '"'
-#define A_CEDIL ','
-static unsigned char ret_diacr[NR_DEAD] =
- {A_GRAVE, A_ACUTE, A_CFLEX, A_TILDE, A_DIAER, A_CEDIL };
-
-/* If a dead key pressed twice, output a character corresponding to it, */
-/* otherwise just remember the dead key. */
-
-static void do_dead(unsigned char value, char up_flag)
-{
- if (up_flag)
- return;
-
- value = ret_diacr[value];
- if (diacr == value) { /* pressed twice */
- diacr = 0;
- put_queue(value);
- return;
- }
- diacr = value;
-}
-
-
-/* If space is pressed, return the character corresponding the pending */
-/* dead key, otherwise try to combine the two. */
-
-unsigned char handle_diacr(unsigned char ch)
-{
- int d = diacr;
- int i;
-
- diacr = 0;
- if (ch == ' ')
- return d;
-
- for (i = 0; i < accent_table_size; i++) {
- if (accent_table[i].diacr == d && accent_table[i].base == ch)
- return accent_table[i].result;
- }
-
- put_queue(d);
- return ch;
-}
-
-static void do_cons(unsigned char value, char up_flag)
-{
- if (up_flag)
- return;
- set_console(value);
-}
-
-static void do_fn(unsigned char value, char up_flag)
-{
- if (up_flag)
- return;
- if (value < SIZE(func_table)) {
- if (func_table[value])
- puts_queue(func_table[value]);
- } else
- printk("do_fn called with value=%d\n", value);
-}
-
-static void do_pad(unsigned char value, char up_flag)
-{
- static const char *pad_chars = "0123456789+-*/\015,.?";
- static const char *app_map = "pqrstuvwxylSRQMnn?";
-
- if (up_flag)
- return; /* no action, if this is a key release */
-
- /* kludge... shift forces cursor/number keys */
- if (vc_kbd_mode(kbd,VC_APPLIC) && !k_down[KG_SHIFT]) {
- applkey(app_map[value], 1);
- return;
- }
-
- if (!vc_kbd_led(kbd,VC_NUMLOCK))
- switch (value) {
- case KVAL(K_PCOMMA):
- case KVAL(K_PDOT):
- do_fn(KVAL(K_REMOVE), 0);
- return;
- case KVAL(K_P0):
- do_fn(KVAL(K_INSERT), 0);
- return;
- case KVAL(K_P1):
- do_fn(KVAL(K_SELECT), 0);
- return;
- case KVAL(K_P2):
- do_cur(KVAL(K_DOWN), 0);
- return;
- case KVAL(K_P3):
- do_fn(KVAL(K_PGDN), 0);
- return;
- case KVAL(K_P4):
- do_cur(KVAL(K_LEFT), 0);
- return;
- case KVAL(K_P6):
- do_cur(KVAL(K_RIGHT), 0);
- return;
- case KVAL(K_P7):
- do_fn(KVAL(K_FIND), 0);
- return;
- case KVAL(K_P8):
- do_cur(KVAL(K_UP), 0);
- return;
- case KVAL(K_P9):
- do_fn(KVAL(K_PGUP), 0);
- return;
- case KVAL(K_P5):
- applkey('G', vc_kbd_mode(kbd, VC_APPLIC));
- return;
- }
-
- put_queue(pad_chars[value]);
- if (value == KVAL(K_PENTER) && vc_kbd_mode(kbd, VC_CRLF))
- put_queue(10);
-}
-
-static void do_cur(unsigned char value, char up_flag)
-{
- static const char *cur_chars = "BDCA";
- if (up_flag)
- return;
-
- applkey(cur_chars[value], vc_kbd_mode(kbd,VC_CKMODE));
-}
-
-static void do_shift(unsigned char value, char up_flag)
-{
- int old_state = shift_state;
-
- if (rep)
- return;
-
- /* Mimic typewriter:
- a CapsShift key acts like Shift but undoes CapsLock */
- if (value == KVAL(K_CAPSSHIFT)) {
- value = KVAL(K_SHIFT);
- if (!up_flag)
- clr_vc_kbd_led(kbd, VC_CAPSLOCK);
- }
-
- if (up_flag) {
- /* handle the case that two shift or control
- keys are depressed simultaneously */
- if (k_down[value])
- k_down[value]--;
- } else
- k_down[value]++;
-
- if (k_down[value])
- shift_state |= (1 << value);
- else
- shift_state &= ~ (1 << value);
-
- /* kludge */
- if (up_flag && shift_state != old_state && npadch != -1) {
- if (kbd->kbdmode == VC_UNICODE)
- to_utf8(npadch & 0xffff);
- else
- put_queue(npadch & 0xff);
- npadch = -1;
- }
-}
-
-/* called after returning from RAW mode or when changing consoles -
- recompute k_down[] and shift_state from key_down[] */
-/* maybe called when keymap is undefined, so that shiftkey release is seen */
-void compute_shiftstate(void)
-{
- int i, j, k, sym, val;
-
- shift_state = 0;
- for(i=0; i < SIZE(k_down); i++)
- k_down[i] = 0;
-
- for(i=0; i < SIZE(key_down); i++)
- if(key_down[i]) { /* skip this word if not a single bit on */
- k = i*BITS_PER_LONG;
- for(j=0; j<BITS_PER_LONG; j++,k++)
- if(test_bit(k, key_down)) {
- sym = U(plain_map[k]);
- if(KTYP(sym) == KT_SHIFT) {
- val = KVAL(sym);
- if (val == KVAL(K_CAPSSHIFT))
- val = KVAL(K_SHIFT);
- k_down[val]++;
- shift_state |= (1<<val);
- }
- }
- }
-}
-
-static void do_meta(unsigned char value, char up_flag)
-{
- if (up_flag)
- return;
-
- if (vc_kbd_mode(kbd, VC_META)) {
- put_queue('\033');
- put_queue(value);
- } else
- put_queue(value | 0x80);
-}
-
-static void do_ascii(unsigned char value, char up_flag)
-{
- int base;
-
- if (up_flag)
- return;
-
- if (value < 10) /* decimal input of code, while Alt depressed */
- base = 10;
- else { /* hexadecimal input of code, while AltGr depressed */
- value -= 10;
- base = 16;
- }
-
- if (npadch == -1)
- npadch = value;
- else
- npadch = npadch * base + value;
-}
-
-static void do_lock(unsigned char value, char up_flag)
-{
- if (up_flag || rep)
- return;
- chg_vc_kbd_lock(kbd, value);
-}
-
-static void do_slock(unsigned char value, char up_flag)
-{
- if (up_flag || rep)
- return;
- chg_vc_kbd_slock(kbd, value);
-}
-
-/*
- * The leds display either (i) the status of NumLock, CapsLock, ScrollLock,
- * or (ii) whatever pattern of lights people want to show using KDSETLED,
- * or (iii) specified bits of specified words in kernel memory.
- */
-
-static unsigned char ledstate = 0xff; /* undefined */
-static unsigned char ledioctl;
-
-unsigned char getledstate(void) {
- return ledstate;
-}
-
-void setledstate(struct kbd_struct *kbd, unsigned int led) {
- if (!(led & ~7)) {
- ledioctl = led;
- kbd->ledmode = LED_SHOW_IOCTL;
- } else
- kbd->ledmode = LED_SHOW_FLAGS;
- set_leds();
-}
-
-static struct ledptr {
- unsigned int *addr;
- unsigned int mask;
- unsigned char valid:1;
-} ledptrs[3];
-
-void register_leds(int console, unsigned int led,
- unsigned int *addr, unsigned int mask) {
- struct kbd_struct *kbd = kbd_table + console;
- if (led < 3) {
- ledptrs[led].addr = addr;
- ledptrs[led].mask = mask;
- ledptrs[led].valid = 1;
- kbd->ledmode = LED_SHOW_MEM;
- } else
- kbd->ledmode = LED_SHOW_FLAGS;
-}
-
-static inline unsigned char getleds(void){
- struct kbd_struct *kbd = kbd_table + fg_console;
- unsigned char leds;
-
- if (kbd->ledmode == LED_SHOW_IOCTL)
- return ledioctl;
- leds = kbd->ledflagstate;
- if (kbd->ledmode == LED_SHOW_MEM) {
- if (ledptrs[0].valid) {
- if (*ledptrs[0].addr & ledptrs[0].mask)
- leds |= 1;
- else
- leds &= ~1;
- }
- if (ledptrs[1].valid) {
- if (*ledptrs[1].addr & ledptrs[1].mask)
- leds |= 2;
- else
- leds &= ~2;
- }
- if (ledptrs[2].valid) {
- if (*ledptrs[2].addr & ledptrs[2].mask)
- leds |= 4;
- else
- leds &= ~4;
- }
- }
- return leds;
-}
-
-/*
- * This routine is the bottom half of the keyboard interrupt
- * routine, and runs with all interrupts enabled. It does
- * console changing, led setting and copy_to_cooked, which can
- * take a reasonably long time.
- *
- * Aside from timing (which isn't really that important for
- * keyboard interrupts as they happen often), using the software
- * interrupt routines for this thing allows us to easily mask
- * this when we don't want any of the above to happen. Not yet
- * used, but this allows for easy and efficient race-condition
- * prevention later on.
- */
-static void kbd_bh(void)
-{
- unsigned char leds = getleds();
-
- if (leds != ledstate) {
- ledstate = leds;
- if (mach_kbd_leds)
- mach_kbd_leds(leds);
- }
-}
-
-__initfunc(int kbd_init(void))
-{
- int i;
- struct kbd_struct kbd0;
- extern struct tty_driver console_driver;
-
- kbd0.ledflagstate = kbd0.default_ledflagstate = KBD_DEFLEDS;
- kbd0.ledmode = LED_SHOW_FLAGS;
- kbd0.lockstate = KBD_DEFLOCK;
- kbd0.slockstate = 0;
- kbd0.modeflags = KBD_DEFMODE;
- kbd0.kbdmode = VC_XLATE;
-
- for (i = 0 ; i < MAX_NR_CONSOLES ; i++)
- kbd_table[i] = kbd0;
-
- ttytab = console_driver.table;
-
- init_bh(KEYBOARD_BH, kbd_bh);
- mark_bh(KEYBOARD_BH);
-
- mach_keyb_init ();
-
- return 0;
-}
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c
index d63aa20df..0185c2bda 100644
--- a/drivers/char/keyboard.c
+++ b/drivers/char/keyboard.c
@@ -1,4 +1,3 @@
-
/*
* linux/drivers/char/keyboard.c
*
@@ -14,41 +13,29 @@
* dynamic function/string keys, led setting, Sept 1994
* `Sticky' modifier keys, 951006.
* 11-11-96: SAK should now work in the raw mode (Martin Mares)
+ *
+ * Modified to provide 'generic' keyboard support by Hamish Macdonald
+ * Merge with the m68k keyboard driver and split-off of the PC low-level
+ * parts by Geert Uytterhoeven, May 1997
*/
-#include <linux/config.h>
-#include <linux/kbdcntrlr.h>
#include <linux/sched.h>
-#include <linux/interrupt.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/mm.h>
-#include <linux/ptrace.h>
-#include <linux/signal.h>
#include <linux/string.h>
-#include <linux/ioport.h>
#include <linux/random.h>
#include <linux/init.h>
+#include <asm/keyboard.h>
#include <asm/bitops.h>
-/*
- * Declare functions used in machine dependand parts of the kbd driver.
- */
-static inline void kb_wait(void);
-static int send_data(unsigned char data);
-
-#include <asm/keyboard.h>
-
#include "kbd_kern.h"
#include "diacr.h"
#include "vt_kern.h"
#define SIZE(x) (sizeof(x)/sizeof((x)[0]))
-#define KBD_REPORT_UNKN
-/* #define KBD_IS_FOCUS_9000 */
-
#ifndef KBD_DEFMODE
#define KBD_DEFMODE ((1 << VC_REPEAT) | (1 << VC_META))
#endif
@@ -65,15 +52,11 @@ static int send_data(unsigned char data);
#define KBD_DEFLOCK 0
#endif
-#include <asm/system.h>
-
extern void ctrl_alt_del(void);
extern void reset_vc(unsigned int new_console);
extern void scrollback(int);
extern void scrollfront(int);
-unsigned char kbd_read_mask = 0x01; /* modified by psaux.c */
-
struct wait_queue * keypress_wait = NULL;
void keyboard_wait_for_keypress(void)
@@ -108,12 +91,7 @@ static struct tty_struct **ttytab;
static struct kbd_struct * kbd = kbd_table;
static struct tty_struct * tty = NULL;
-/* used only by send_data - set by keyboard_interrupt */
-static volatile unsigned char reply_expected = 0;
-static volatile unsigned char acknowledge = 0;
-static volatile unsigned char resend = 0;
-
-extern void compute_shiftstate(void);
+void compute_shiftstate(void);
typedef void (*k_hand)(unsigned char value, char up_flag);
typedef void (k_handfn)(unsigned char value, char up_flag);
@@ -163,23 +141,7 @@ static void put_queue(int);
static unsigned char handle_diacr(unsigned char);
/* pt_regs - set by keyboard_interrupt(), used by show_ptregs() */
-static struct pt_regs * pt_regs;
-
-static inline void kb_wait(void)
-{
- int i;
-
- for (i=0; i<0x100000; i++)
- if ((kbd_inb_p(0x64) & 0x02) == 0)
- return;
- printk(KERN_WARNING "Keyboard timed out\n");
-}
-
-static inline void send_cmd(unsigned char c)
-{
- kb_wait();
- kbd_outb(c,0x64);
-}
+struct pt_regs * pt_regs;
/*
* Many other routines do put_queue, but I think either
@@ -204,182 +166,25 @@ void to_utf8(ushort c) {
/*
* Translation of escaped scancodes to keycodes.
- * This is now user-settable.
- * The keycodes 1-88,96-111,119 are fairly standard, and
- * should probably not be changed - changing might confuse X.
- * X also interprets scancode 0x5d (KEY_Begin).
- *
- * For 1-88 keycode equals scancode.
+ * This is now user-settable (for machines were it makes sense).
*/
-#define E0_KPENTER 96
-#define E0_RCTRL 97
-#define E0_KPSLASH 98
-#define E0_PRSCR 99
-#define E0_RALT 100
-#define E0_BREAK 101 /* (control-pause) */
-#define E0_HOME 102
-#define E0_UP 103
-#define E0_PGUP 104
-#define E0_LEFT 105
-#define E0_RIGHT 106
-#define E0_END 107
-#define E0_DOWN 108
-#define E0_PGDN 109
-#define E0_INS 110
-#define E0_DEL 111
-
-#define E1_PAUSE 119
-
-/*
- * The keycodes below are randomly located in 89-95,112-118,120-127.
- * They could be thrown away (and all occurrences below replaced by 0),
- * but that would force many users to use the `setkeycodes' utility, where
- * they needed not before. It does not matter that there are duplicates, as
- * long as no duplication occurs for any single keyboard.
- */
-#define SC_LIM 89
-
-#define FOCUS_PF1 85 /* actual code! */
-#define FOCUS_PF2 89
-#define FOCUS_PF3 90
-#define FOCUS_PF4 91
-#define FOCUS_PF5 92
-#define FOCUS_PF6 93
-#define FOCUS_PF7 94
-#define FOCUS_PF8 95
-#define FOCUS_PF9 120
-#define FOCUS_PF10 121
-#define FOCUS_PF11 122
-#define FOCUS_PF12 123
-
-#define JAP_86 124
-/* tfj@olivia.ping.dk:
- * The four keys are located over the numeric keypad, and are
- * labelled A1-A4. It's an rc930 keyboard, from
- * Regnecentralen/RC International, Now ICL.
- * Scancodes: 59, 5a, 5b, 5c.
- */
-#define RGN1 124
-#define RGN2 125
-#define RGN3 126
-#define RGN4 127
-
-static unsigned char high_keys[128 - SC_LIM] = {
- RGN1, RGN2, RGN3, RGN4, 0, 0, 0, /* 0x59-0x5f */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x67 */
- 0, 0, 0, 0, 0, FOCUS_PF11, 0, FOCUS_PF12, /* 0x68-0x6f */
- 0, 0, 0, FOCUS_PF2, FOCUS_PF9, 0, 0, FOCUS_PF3, /* 0x70-0x77 */
- FOCUS_PF4, FOCUS_PF5, FOCUS_PF6, FOCUS_PF7, /* 0x78-0x7b */
- FOCUS_PF8, JAP_86, FOCUS_PF10, 0 /* 0x7c-0x7f */
-};
-
-/* BTC */
-#define E0_MACRO 112
-/* LK450 */
-#define E0_F13 113
-#define E0_F14 114
-#define E0_HELP 115
-#define E0_DO 116
-#define E0_F17 117
-#define E0_KPMINPLUS 118
-/*
- * My OmniKey generates e0 4c for the "OMNI" key and the
- * right alt key does nada. [kkoller@nyx10.cs.du.edu]
- */
-#define E0_OK 124
-/*
- * New microsoft keyboard is rumoured to have
- * e0 5b (left window button), e0 5c (right window button),
- * e0 5d (menu button). [or: LBANNER, RBANNER, RMENU]
- * [or: Windows_L, Windows_R, TaskMan]
- */
-#define E0_MSLW 125
-#define E0_MSRW 126
-#define E0_MSTM 127
-
-static unsigned char e0_keys[128] = {
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00-0x07 */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0x08-0x0f */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10-0x17 */
- 0, 0, 0, 0, E0_KPENTER, E0_RCTRL, 0, 0, /* 0x18-0x1f */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20-0x27 */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0x28-0x2f */
- 0, 0, 0, 0, 0, E0_KPSLASH, 0, E0_PRSCR, /* 0x30-0x37 */
- E0_RALT, 0, 0, 0, 0, E0_F13, E0_F14, E0_HELP, /* 0x38-0x3f */
- E0_DO, E0_F17, 0, 0, 0, 0, E0_BREAK, E0_HOME, /* 0x40-0x47 */
- E0_UP, E0_PGUP, 0, E0_LEFT, E0_OK, E0_RIGHT, E0_KPMINPLUS, E0_END,/* 0x48-0x4f */
- E0_DOWN, E0_PGDN, E0_INS, E0_DEL, 0, 0, 0, 0, /* 0x50-0x57 */
- 0, 0, 0, E0_MSLW, E0_MSRW, E0_MSTM, 0, 0, /* 0x58-0x5f */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x67 */
- 0, 0, 0, 0, 0, 0, 0, E0_MACRO, /* 0x68-0x6f */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70-0x77 */
- 0, 0, 0, 0, 0, 0, 0, 0 /* 0x78-0x7f */
-};
-
int setkeycode(unsigned int scancode, unsigned int keycode)
{
- if (scancode < SC_LIM || scancode > 255 || keycode > 127)
- return -EINVAL;
- if (scancode < 128)
- high_keys[scancode - SC_LIM] = keycode;
- else
- e0_keys[scancode - 128] = keycode;
- return 0;
+ return kbd_setkeycode(scancode, keycode);
}
int getkeycode(unsigned int scancode)
{
- return
- (scancode < SC_LIM || scancode > 255) ? -EINVAL :
- (scancode < 128) ? high_keys[scancode - SC_LIM] :
- e0_keys[scancode - 128];
+ return kbd_getkeycode(scancode);
}
-#if defined(CONFIG_SGI) && defined(CONFIG_PSMOUSE)
-extern void aux_interrupt(unsigned char status, unsigned char data);
-#endif
-
-#if DISABLE_KBD_DURING_INTERRUPTS
-#define disable_keyboard() do { send_cmd(0xAD); kb_wait(); } while (0)
-#define enable_keyboard() send_cmd(0xAE)
-#else
-#define disable_keyboard() /* nothing */
-#define enable_keyboard() /* nothing */
-#endif
-
-static void handle_scancode(unsigned char scancode)
+void handle_scancode(unsigned char scancode)
{
unsigned char keycode;
- static unsigned int prev_scancode = 0; /* remember E0, E1 */
char up_flag; /* 0 or 0200 */
char raw_mode;
- if (reply_expected) {
- /* 0xfa, 0xfe only mean "acknowledge", "resend" for most keyboards */
- /* but they are the key-up scancodes for PF6, PF10 on a FOCUS 9000 */
- reply_expected = 0;
- if (scancode == 0xfa) {
- acknowledge = 1;
- return;
- } else if (scancode == 0xfe) {
- resend = 1;
- return;
- }
- /* strange ... */
- reply_expected = 1;
-#if 0
- printk(KERN_DEBUG "keyboard reply expected - got %02x\n",
- scancode);
-#endif
- }
- if (scancode == 0) {
-#ifdef KBD_REPORT_ERR
- printk(KERN_INFO "keyboard buffer overflow\n");
-#endif
- prev_scancode = 0;
- return;
- }
do_poke_blanked_console = 1;
mark_bh(CONSOLE_BH);
add_keyboard_randomness(scancode);
@@ -393,123 +198,30 @@ static void handle_scancode(unsigned char scancode)
values when finishing RAW mode or when changing VT's */
}
- if (scancode == 0xff) {
- /* in scancode mode 1, my ESC key generates 0xff */
- /* the calculator keys on a FOCUS 9000 generate 0xff */
-#ifndef KBD_IS_FOCUS_9000
-#ifdef KBD_REPORT_ERR
- if (!raw_mode)
- printk(KERN_DEBUG "keyboard error\n");
-#endif
-#endif
- prev_scancode = 0;
- return;
- }
-
- if (scancode == 0xe0 || scancode == 0xe1) {
- prev_scancode = scancode;
- return;
- }
-
+ if (!kbd_pretranslate(scancode, raw_mode))
+ return;
/*
- * Convert scancode to keycode, using prev_scancode.
+ * Convert scancode to keycode
*/
up_flag = (scancode & 0200);
scancode &= 0x7f;
- if (prev_scancode) {
- /*
- * usually it will be 0xe0, but a Pause key generates
- * e1 1d 45 e1 9d c5 when pressed, and nothing when released
- */
- if (prev_scancode != 0xe0) {
- if (prev_scancode == 0xe1 && scancode == 0x1d) {
- prev_scancode = 0x100;
- return;
- } else if (prev_scancode == 0x100 && scancode == 0x45) {
- keycode = E1_PAUSE;
- prev_scancode = 0;
- } else {
-#ifdef KBD_REPORT_UNKN
- if (!raw_mode)
- printk(KERN_INFO "keyboard: unknown e1 escape sequence\n");
-#endif
- prev_scancode = 0;
- return;
- }
- } else {
- prev_scancode = 0;
- /*
- * The keyboard maintains its own internal caps lock and
- * num lock statuses. In caps lock mode E0 AA precedes make
- * code and E0 2A follows break code. In num lock mode,
- * E0 2A precedes make code and E0 AA follows break code.
- * We do our own book-keeping, so we will just ignore these.
- */
- /*
- * For my keyboard there is no caps lock mode, but there are
- * both Shift-L and Shift-R modes. The former mode generates
- * E0 2A / E0 AA pairs, the latter E0 B6 / E0 36 pairs.
- * So, we should also ignore the latter. - aeb@cwi.nl
- */
- if (scancode == 0x2a || scancode == 0x36)
- return;
-
- if (e0_keys[scancode])
- keycode = e0_keys[scancode];
- else {
-#ifdef KBD_REPORT_UNKN
- if (!raw_mode)
- printk(KERN_INFO "keyboard: unknown scancode e0 %02x\n",
- scancode);
-#endif
- return;
- }
- }
- } else if (scancode >= SC_LIM) {
- /* This happens with the FOCUS 9000 keyboard
- Its keys PF1..PF12 are reported to generate
- 55 73 77 78 79 7a 7b 7c 74 7e 6d 6f
- Moreover, unless repeated, they do not generate
- key-down events, so we have to zero up_flag below */
- /* Also, Japanese 86/106 keyboards are reported to
- generate 0x73 and 0x7d for \ - and \ | respectively. */
- /* Also, some Brazilian keyboard is reported to produce
- 0x73 and 0x7e for \ ? and KP-dot, respectively. */
-
- keycode = high_keys[scancode - SC_LIM];
-
- if (!keycode) {
- if (!raw_mode) {
-#ifdef KBD_REPORT_UNKN
- printk(KERN_INFO "keyboard: unrecognized scancode (%02x)"
- " - ignored\n", scancode);
-#endif
- }
- return;
- }
- } else
- keycode = scancode;
+ if (!kbd_translate(scancode, &keycode, raw_mode))
+ return;
/*
* At this point the variable `keycode' contains the keycode.
- * Note: the keycode must not be 0.
+ * Note: the keycode must not be 0 (++Geert: on m68k 0 is valid).
* We keep track of the up/down status of the key, and
* return the keycode if in MEDIUMRAW mode.
*/
if (up_flag) {
rep = 0;
- if(!clear_bit(keycode, key_down)) {
- /* unexpected, but this can happen:
- maybe this was a key release for a FOCUS 9000
- PF key; if we want to see it, we have to clear
- up_flag */
- if (keycode >= SC_LIM || keycode == 85)
- up_flag = 0;
- }
+ if(!test_and_clear_bit(keycode, key_down))
+ up_flag = kbd_unexpected_up(keycode);
} else
- rep = set_bit(keycode, key_down);
+ rep = test_and_set_bit(keycode, key_down);
if (kbd->kbdmode == VC_MEDIUMRAW) {
/* soon keycodes will require more than one byte */
@@ -579,36 +291,6 @@ static void handle_scancode(unsigned char scancode)
}
}
-static void keyboard_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
- unsigned char status;
-
- pt_regs = regs;
- disable_keyboard();
-
- status = kbd_inb_p(0x64);
- do {
- unsigned char scancode;
-
- /* mouse data? */
- if (status & kbd_read_mask & 0x20) {
-#if defined(CONFIG_SGI) && defined(CONFIG_PSMOUSE)
- scancode = kbd_inb(0x60);
- aux_interrupt(status, scancode);
-#endif
- break;
- }
-
- scancode = kbd_inb(0x60);
- if (status & 0x01)
- handle_scancode(scancode);
-
- status = kbd_inb(0x64);
- } while (status & 0x01);
-
- mark_bh(KEYBOARD_BH);
- enable_keyboard();
-}
static void put_queue(int ch)
{
@@ -898,8 +580,8 @@ static void do_fn(unsigned char value, char up_flag)
static void do_pad(unsigned char value, char up_flag)
{
- static const char *pad_chars = "0123456789+-*/\015,.?";
- static const char *app_map = "pqrstuvwxylSRQMnn?";
+ static const char *pad_chars = "0123456789+-*/\015,.?()";
+ static const char *app_map = "pqrstuvwxylSRQMnn?PQ";
if (up_flag)
return; /* no action, if this is a key release */
@@ -1075,35 +757,6 @@ static void do_slock(unsigned char value, char up_flag)
}
/*
- * send_data sends a character to the keyboard and waits
- * for an acknowledge, possibly retrying if asked to. Returns
- * the success status.
- */
-static int send_data(unsigned char data)
-{
- int retries = 3;
- int i;
-
- do {
- kb_wait();
- acknowledge = 0;
- resend = 0;
- reply_expected = 1;
- kbd_outb_p(data, 0x60);
- for(i=0; i<0x200000; i++) {
- kbd_inb_p(0x64); /* just as a delay */
- if (acknowledge)
- return 1;
- if (resend)
- break;
- }
- if (!resend)
- return 0;
- } while (retries-- > 0);
- return 0;
-}
-
-/*
* The leds display either (i) the status of NumLock, CapsLock, ScrollLock,
* or (ii) whatever pattern of lights people want to show using KDSETLED,
* or (iii) specified bits of specified words in kernel memory.
@@ -1192,8 +845,7 @@ static void kbd_bh(void)
if (leds != ledstate) {
ledstate = leds;
- if (!send_data(0xed) || !send_data(leds))
- send_data(0xf4); /* re-enable kbd if any errors */
+ kbd_leds(leds);
}
}
@@ -1215,8 +867,7 @@ __initfunc(int kbd_init(void))
ttytab = console_driver.table;
- request_irq(KEYBOARD_IRQ, keyboard_interrupt, 0, "keyboard", NULL);
- keyboard_setup();
+ kbd_init_hw();
init_bh(KEYBOARD_BH, kbd_bh);
mark_bh(KEYBOARD_BH);
return 0;
diff --git a/drivers/char/lp.c b/drivers/char/lp.c
index 7fd2f9b35..599ae87fc 100644
--- a/drivers/char/lp.c
+++ b/drivers/char/lp.c
@@ -631,7 +631,7 @@ MODULE_PARM(parport, "1-" __MODULE_STRING(LP_NO) "i");
static int parport_ptr = 0;
-void lp_setup(char *str, int *ints)
+__initfunc(void lp_setup(char *str, int *ints))
{
/* Ugh. */
if (!strncmp(str, "parport", 7)) {
diff --git a/drivers/char/lp_intern.c b/drivers/char/lp_intern.c
index 9d676f927..7bb4ec634 100644
--- a/drivers/char/lp_intern.c
+++ b/drivers/char/lp_intern.c
@@ -19,6 +19,7 @@
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/sched.h>
+#include <linux/init.h>
#include <asm/irq.h>
#include <asm/setup.h>
#ifdef CONFIG_AMIGA
@@ -33,7 +34,6 @@
#endif
#include <linux/lp_intern.h>
-static int my_inter = 0;
static int minor = -1;
static void lp_int_out(int, int);
@@ -126,24 +126,18 @@ lp_int_online (int dev)
}
}
-static int lp_int_my_interrupt(int dev)
-{
- return my_inter;
-}
-
static void lp_int_interrupt(int irq, void *data, struct pt_regs *fp)
{
- my_inter = 1;
- lp_interrupt(irq, data, fp);
- my_inter = 0;
+ lp_interrupt(minor);
}
-static void lp_int_open(void)
+static int lp_int_open(int dev)
{
MOD_INC_USE_COUNT;
+ return 0;
}
-static void lp_int_release(void)
+static void lp_int_release(int dev)
{
MOD_DEC_USE_COUNT;
}
@@ -155,7 +149,7 @@ static struct lp_struct tab = {
lp_int_busy,
lp_int_pout,
lp_int_online,
- lp_int_my_interrupt,
+ 0,
NULL, /* ioctl */
lp_int_open,
lp_int_release,
@@ -167,7 +161,7 @@ static struct lp_struct tab = {
NULL,
};
-int lp_internal_init(void)
+__initfunc(int lp_internal_init(void))
{
#ifdef CONFIG_AMIGA
if (MACH_IS_AMIGA && AMIGAHW_PRESENT(AMI_PARALLEL))
diff --git a/drivers/char/lp_m68k.c b/drivers/char/lp_m68k.c
index 3cc9458bd..17405c191 100644
--- a/drivers/char/lp_m68k.c
+++ b/drivers/char/lp_m68k.c
@@ -41,6 +41,7 @@
#include <linux/major.h>
#include <linux/sched.h>
#include <linux/string.h>
+#include <linux/init.h>
#include <asm/irq.h>
#ifdef CONFIG_KERNELD
#include <linux/kerneld.h>
@@ -465,7 +466,7 @@ EXPORT_SYMBOL(lp_init);
EXPORT_SYMBOL(register_parallel);
EXPORT_SYMBOL(unregister_parallel);
-int lp_init(void)
+__initfunc(int lp_init(void))
{
extern char m68k_debug_device[];
@@ -498,7 +499,7 @@ int lp_init(void)
/*
* Currently we do not accept any lp-parameters, but that may change.
*/
-void lp_setup(char *str, int *ints)
+__initfunc(void lp_setup(char *str, int *ints))
{
}
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 3d973d2a8..56d537fb3 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -139,7 +139,8 @@ static long read_kmem(struct inode *inode, struct file *file,
else
tmp = count;
read = tmp;
-#if defined(__sparc__) /* we don't have page 0 mapped on sparc.. */
+#if defined(__sparc__) || defined(__mc68000__)
+ /* we don't have page 0 mapped on sparc and m68k.. */
while (p < PAGE_SIZE && tmp > 0) {
put_user(0,buf);
buf++;
@@ -172,7 +173,8 @@ static long write_kmem(struct inode * inode, struct file * file,
if (count > (unsigned long) high_memory - p)
count = (unsigned long) high_memory - p;
written = 0;
-#if defined(__sparc__) /* we don't have page 0 mapped on sparc.. */
+#if defined(__sparc__) || defined(__mc68000__)
+ /* we don't have page 0 mapped on sparc and m68k.. */
while (p < PAGE_SIZE && count > 0) {
/* Hmm. Do something? */
buf++;
@@ -236,38 +238,38 @@ static long write_null(struct inode * inode, struct file * file,
*/
static inline unsigned long read_zero_pagealigned(char * buf, unsigned long size)
{
- struct vm_area_struct * curr_vma;
+ struct vm_area_struct * vma;
unsigned long addr=(unsigned long)buf;
-/*
- * First we take the most obvious case: when we have one VM area to deal with,
- * and it's privately mapped.
- */
- curr_vma = find_vma(current->mm, addr);
-
- if ( !(curr_vma->vm_flags & VM_SHARED) &&
- (addr + size <= curr_vma->vm_end) ) {
+ /* For private mappings, just map in zero pages. */
+ for (vma = find_vma(current->mm, addr); vma; vma = vma->vm_next) {
+ unsigned long count;
- flush_cache_range(current->mm, addr, addr + size);
- zap_page_range(current->mm, addr, size);
- zeromap_page_range(addr, size, PAGE_COPY);
- flush_tlb_range(current->mm, addr, addr + size);
-
- return 0;
+ if (vma->vm_start > addr || (vma->vm_flags & VM_WRITE) == 0)
+ return size;
+ if (vma->vm_flags & VM_SHARED)
+ break;
+ count = vma->vm_end - addr;
+ if (count > size)
+ count = size;
+
+ flush_cache_range(current->mm, addr, addr + count);
+ zap_page_range(current->mm, addr, count);
+ zeromap_page_range(addr, count, PAGE_COPY);
+ flush_tlb_range(current->mm, addr, addr + count);
+
+ size -= count;
+ buf += count;
+ addr += count;
+ if (size == 0)
+ return 0;
}
-
-/*
- * Ooops, the shared case is hard. Lets do the conventional
- * zeroing.
- *
- * FIXME: same for the multiple-vma case, we dont handle it
- * now for simplicity, although it's much easier than
- * the shared case. Not that it should happen often ...
- */
-
+
+ /* The shared case is hard. Lets do the conventional zeroing. */
do {
- if (clear_user(buf, PAGE_SIZE))
- break;
+ unsigned long unwritten = clear_user(buf, PAGE_SIZE);
+ if (unwritten)
+ return size + unwritten - PAGE_SIZE;
if (need_resched)
schedule();
buf += PAGE_SIZE;
@@ -280,7 +282,10 @@ static inline unsigned long read_zero_pagealigned(char * buf, unsigned long size
static long read_zero(struct inode * node, struct file * file,
char * buf, unsigned long count)
{
- unsigned long left;
+ unsigned long left, unwritten, written = 0;
+
+ if (!count)
+ return 0;
if (!access_ok(VERIFY_WRITE, buf, count))
return -EFAULT;
@@ -289,21 +294,27 @@ static long read_zero(struct inode * node, struct file * file,
/* do we want to be clever? Arbitrary cut-off */
if (count >= PAGE_SIZE*4) {
- unsigned long partial, unwritten;
+ unsigned long partial;
/* How much left of the page? */
partial = (PAGE_SIZE-1) & -(unsigned long) buf;
- clear_user(buf, partial);
+ unwritten = clear_user(buf, partial);
+ written = partial - unwritten;
+ if (unwritten)
+ goto out;
left -= partial;
buf += partial;
unwritten = read_zero_pagealigned(buf, left & PAGE_MASK);
+ written += (left & PAGE_MASK) - unwritten;
+ if (unwritten)
+ goto out;
buf += left & PAGE_MASK;
left &= ~PAGE_MASK;
- if (unwritten)
- return count - left - unwritten;
}
- clear_user(buf, left);
- return count;
+ unwritten = clear_user(buf, left);
+ written += left - unwritten;
+out:
+ return written ? written : -EFAULT;
}
static int mmap_zero(struct inode * inode, struct file * file, struct vm_area_struct * vma)
diff --git a/drivers/char/misc.c b/drivers/char/misc.c
index fd72f33d8..d632e4788 100644
--- a/drivers/char/misc.c
+++ b/drivers/char/misc.c
@@ -73,6 +73,7 @@ extern void watchdog_init(void);
extern void wdt_init(void);
extern void pcwatchdog_init(void);
extern int rtc_init(void);
+extern int dsp56k_init(void);
#ifdef CONFIG_PROC_FS
static int misc_read_proc(char *buf, char **start, off_t offset,
@@ -235,6 +236,9 @@ __initfunc(int misc_init(void))
#ifdef CONFIG_RTC
rtc_init();
#endif
+#ifdef CONFIG_ATARI_DSP56K
+ dsp56k_init();
+#endif
#endif /* !MODULE */
if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) {
printk("unable to get major %d for misc devices\n",
diff --git a/drivers/char/msbusmouse.c b/drivers/char/msbusmouse.c
index b11730f70..8f98231b8 100644
--- a/drivers/char/msbusmouse.c
+++ b/drivers/char/msbusmouse.c
@@ -51,7 +51,7 @@
static struct mouse_status mouse;
static int mouse_irq = MOUSE_IRQ;
-void msmouse_setup(char *str, int *ints)
+__initfunc(void msmouse_setup(char *str, int *ints))
{
if (ints[0] > 0)
mouse_irq=ints[1];
diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c
index cf50a9781..8db4e1443 100644
--- a/drivers/char/n_tty.c
+++ b/drivers/char/n_tty.c
@@ -78,7 +78,7 @@ void n_tty_flush_buffer(struct tty_struct * tty)
return;
if (tty->driver.unthrottle &&
- clear_bit(TTY_THROTTLED, &tty->flags))
+ test_and_clear_bit(TTY_THROTTLED, &tty->flags))
tty->driver.unthrottle(tty);
if (tty->link->packet) {
tty->ctrl_status |= TIOCPKT_FLUSHREAD;
@@ -598,7 +598,7 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
if ((tty->read_cnt >= TTY_THRESHOLD_THROTTLE) &&
tty->driver.throttle &&
- !set_bit(TTY_THROTTLED, &tty->flags))
+ !test_and_set_bit(TTY_THROTTLED, &tty->flags))
tty->driver.throttle(tty);
}
@@ -874,7 +874,7 @@ do_it_again:
if (!tty->read_cnt) {
break;
}
- eol = clear_bit(tty->read_tail,
+ eol = test_and_clear_bit(tty->read_tail,
&tty->read_flags);
c = tty->read_buf[tty->read_tail];
tty->read_tail = ((tty->read_tail+1) &
@@ -904,7 +904,7 @@ do_it_again:
low-level driver know. */
if (tty->driver.unthrottle &&
(tty->read_cnt <= TTY_THRESHOLD_UNTHROTTLE)
- && clear_bit(TTY_THROTTLED, &tty->flags))
+ && test_and_clear_bit(TTY_THROTTLED, &tty->flags))
tty->driver.unthrottle(tty);
if (b - buf >= minimum || !nr)
@@ -923,7 +923,7 @@ do_it_again:
size = b - buf;
if (size && nr)
clear_bit(TTY_PUSH, &tty->flags);
- if (!size && clear_bit(TTY_PUSH, &tty->flags))
+ if (!size && test_and_clear_bit(TTY_PUSH, &tty->flags))
goto do_it_again;
if (!size && !retval)
clear_bit(TTY_PUSH, &tty->flags);
diff --git a/drivers/char/pc_keyb.c b/drivers/char/pc_keyb.c
new file mode 100644
index 000000000..88dcb1986
--- /dev/null
+++ b/drivers/char/pc_keyb.c
@@ -0,0 +1,647 @@
+/*
+ * linux/drivers/char/pc_keyb.c
+ *
+ * Written for linux by Johan Myreen as a translation from
+ * the assembly version by Linus (with diacriticals added)
+ *
+ * Some additional features added by Christoph Niemann (ChN), March 1993
+ *
+ * Loadable keymaps by Risto Kankkunen, May 1993
+ *
+ * Diacriticals redone & other small changes, aeb@cwi.nl, June 1993
+ * Added decr/incr_console, dynamic keymaps, Unicode support,
+ * dynamic function/string keys, led setting, Sept 1994
+ * `Sticky' modifier keys, 951006.
+ * 11-11-96: SAK should now work in the raw mode (Martin Mares)
+ *
+ * Separation of the PC low-level part by Geert Uytterhoeven, May 1997
+ */
+
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/mm.h>
+#include <linux/signal.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/config.h>
+
+#include <asm/bitops.h>
+
+/*
+ * Define these here, include/asm-mips/keyboard.h depends on them.
+ *
+ * keyboard controller registers
+ */
+#define KBD_STATUS_REG (unsigned int) 0x64
+#define KBD_CNTL_REG (unsigned int) 0x64
+#define KBD_DATA_REG (unsigned int) 0x60
+/*
+ * controller commands
+ */
+#define KBD_READ_MODE (unsigned int) 0x20
+#define KBD_WRITE_MODE (unsigned int) 0x60
+#define KBD_SELF_TEST (unsigned int) 0xAA
+#define KBD_SELF_TEST2 (unsigned int) 0xAB
+#define KBD_CNTL_ENABLE (unsigned int) 0xAE
+/*
+ * keyboard commands
+ */
+#define KBD_ENABLE (unsigned int) 0xF4
+#define KBD_DISABLE (unsigned int) 0xF5
+#define KBD_RESET (unsigned int) 0xFF
+/*
+ * keyboard replies
+ */
+#define KBD_ACK (unsigned int) 0xFA
+#define KBD_POR (unsigned int) 0xAA
+/*
+ * status register bits
+ */
+#define KBD_OBF (unsigned int) 0x01
+#define KBD_IBF (unsigned int) 0x02
+#define KBD_GTO (unsigned int) 0x40
+#define KBD_PERR (unsigned int) 0x80
+/*
+ * keyboard controller mode register bits
+ */
+#define KBD_EKI (unsigned int) 0x01
+#define KBD_SYS (unsigned int) 0x04
+#define KBD_DMS (unsigned int) 0x20
+#define KBD_KCC (unsigned int) 0x40
+
+#include <asm/keyboard.h>
+
+/*
+ * On non-x86 hardware we do a full keyboard controller
+ * initialization, in case the bootup software hasn't done
+ * it. On a x86, the BIOS will already have initialized the
+ * keyboard.
+ */
+#ifdef INIT_KBD
+int initialize_kbd(void);
+#endif
+
+#include <asm/io.h>
+#include <asm/system.h>
+
+unsigned char kbd_read_mask = 0x01; /* modified by psaux.c */
+
+/* used only by send_data - set by keyboard_interrupt */
+static volatile unsigned char reply_expected = 0;
+static volatile unsigned char acknowledge = 0;
+static volatile unsigned char resend = 0;
+
+/* pt_regs - set by keyboard_interrupt(), used by show_ptregs() */
+static inline void kb_wait(void)
+{
+ int i;
+
+ for (i=0; i<0x100000; i++)
+ if ((kbd_inb_p(0x64) & 0x02) == 0)
+ return;
+ printk(KERN_WARNING "Keyboard timed out\n");
+}
+
+extern struct pt_regs *pt_regs;
+
+extern void handle_scancode(unsigned char scancode);
+
+
+/*
+ * Translation of escaped scancodes to keycodes.
+ * This is now user-settable.
+ * The keycodes 1-88,96-111,119 are fairly standard, and
+ * should probably not be changed - changing might confuse X.
+ * X also interprets scancode 0x5d (KEY_Begin).
+ *
+ * For 1-88 keycode equals scancode.
+ */
+
+#define E0_KPENTER 96
+#define E0_RCTRL 97
+#define E0_KPSLASH 98
+#define E0_PRSCR 99
+#define E0_RALT 100
+#define E0_BREAK 101 /* (control-pause) */
+#define E0_HOME 102
+#define E0_UP 103
+#define E0_PGUP 104
+#define E0_LEFT 105
+#define E0_RIGHT 106
+#define E0_END 107
+#define E0_DOWN 108
+#define E0_PGDN 109
+#define E0_INS 110
+#define E0_DEL 111
+
+#define E1_PAUSE 119
+
+/*
+ * The keycodes below are randomly located in 89-95,112-118,120-127.
+ * They could be thrown away (and all occurrences below replaced by 0),
+ * but that would force many users to use the `setkeycodes' utility, where
+ * they needed not before. It does not matter that there are duplicates, as
+ * long as no duplication occurs for any single keyboard.
+ */
+#define SC_LIM 89
+
+#define FOCUS_PF1 85 /* actual code! */
+#define FOCUS_PF2 89
+#define FOCUS_PF3 90
+#define FOCUS_PF4 91
+#define FOCUS_PF5 92
+#define FOCUS_PF6 93
+#define FOCUS_PF7 94
+#define FOCUS_PF8 95
+#define FOCUS_PF9 120
+#define FOCUS_PF10 121
+#define FOCUS_PF11 122
+#define FOCUS_PF12 123
+
+#define JAP_86 124
+/* tfj@olivia.ping.dk:
+ * The four keys are located over the numeric keypad, and are
+ * labelled A1-A4. It's an rc930 keyboard, from
+ * Regnecentralen/RC International, Now ICL.
+ * Scancodes: 59, 5a, 5b, 5c.
+ */
+#define RGN1 124
+#define RGN2 125
+#define RGN3 126
+#define RGN4 127
+
+static unsigned char high_keys[128 - SC_LIM] = {
+ RGN1, RGN2, RGN3, RGN4, 0, 0, 0, /* 0x59-0x5f */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x67 */
+ 0, 0, 0, 0, 0, FOCUS_PF11, 0, FOCUS_PF12, /* 0x68-0x6f */
+ 0, 0, 0, FOCUS_PF2, FOCUS_PF9, 0, 0, FOCUS_PF3, /* 0x70-0x77 */
+ FOCUS_PF4, FOCUS_PF5, FOCUS_PF6, FOCUS_PF7, /* 0x78-0x7b */
+ FOCUS_PF8, JAP_86, FOCUS_PF10, 0 /* 0x7c-0x7f */
+};
+
+/* BTC */
+#define E0_MACRO 112
+/* LK450 */
+#define E0_F13 113
+#define E0_F14 114
+#define E0_HELP 115
+#define E0_DO 116
+#define E0_F17 117
+#define E0_KPMINPLUS 118
+/*
+ * My OmniKey generates e0 4c for the "OMNI" key and the
+ * right alt key does nada. [kkoller@nyx10.cs.du.edu]
+ */
+#define E0_OK 124
+/*
+ * New microsoft keyboard is rumoured to have
+ * e0 5b (left window button), e0 5c (right window button),
+ * e0 5d (menu button). [or: LBANNER, RBANNER, RMENU]
+ * [or: Windows_L, Windows_R, TaskMan]
+ */
+#define E0_MSLW 125
+#define E0_MSRW 126
+#define E0_MSTM 127
+
+static unsigned char e0_keys[128] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00-0x07 */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x08-0x0f */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10-0x17 */
+ 0, 0, 0, 0, E0_KPENTER, E0_RCTRL, 0, 0, /* 0x18-0x1f */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20-0x27 */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x28-0x2f */
+ 0, 0, 0, 0, 0, E0_KPSLASH, 0, E0_PRSCR, /* 0x30-0x37 */
+ E0_RALT, 0, 0, 0, 0, E0_F13, E0_F14, E0_HELP, /* 0x38-0x3f */
+ E0_DO, E0_F17, 0, 0, 0, 0, E0_BREAK, E0_HOME, /* 0x40-0x47 */
+ E0_UP, E0_PGUP, 0, E0_LEFT, E0_OK, E0_RIGHT, E0_KPMINPLUS, E0_END,/* 0x48-0x4f */
+ E0_DOWN, E0_PGDN, E0_INS, E0_DEL, 0, 0, 0, 0, /* 0x50-0x57 */
+ 0, 0, 0, E0_MSLW, E0_MSRW, E0_MSTM, 0, 0, /* 0x58-0x5f */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x67 */
+ 0, 0, 0, 0, 0, 0, 0, E0_MACRO, /* 0x68-0x6f */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70-0x77 */
+ 0, 0, 0, 0, 0, 0, 0, 0 /* 0x78-0x7f */
+};
+
+static unsigned int prev_scancode = 0; /* remember E0, E1 */
+
+int pckbd_setkeycode(unsigned int scancode, unsigned int keycode)
+{
+ if (scancode < SC_LIM || scancode > 255 || keycode > 127)
+ return -EINVAL;
+ if (scancode < 128)
+ high_keys[scancode - SC_LIM] = keycode;
+ else
+ e0_keys[scancode - 128] = keycode;
+ return 0;
+}
+
+int pckbd_getkeycode(unsigned int scancode)
+{
+ return
+ (scancode < SC_LIM || scancode > 255) ? -EINVAL :
+ (scancode < 128) ? high_keys[scancode - SC_LIM] :
+ e0_keys[scancode - 128];
+}
+
+#if DISABLE_KBD_DURING_INTERRUPTS
+static inline void send_cmd(unsigned char c)
+{
+ kb_wait();
+ kbd_outb(c,0x64);
+}
+
+#define disable_keyboard() do { send_cmd(0xAD); kb_wait(); } while (0)
+#define enable_keyboard() send_cmd(0xAE)
+#else
+#define disable_keyboard() /* nothing */
+#define enable_keyboard() /* nothing */
+#endif
+
+static int do_acknowledge(unsigned char scancode)
+{
+ if (reply_expected) {
+ /* 0xfa, 0xfe only mean "acknowledge", "resend" for most keyboards */
+ /* but they are the key-up scancodes for PF6, PF10 on a FOCUS 9000 */
+ reply_expected = 0;
+ if (scancode == 0xfa) {
+ acknowledge = 1;
+ return 0;
+ } else if (scancode == 0xfe) {
+ resend = 1;
+ return 0;
+ }
+ /* strange ... */
+ reply_expected = 1;
+#if 0
+ printk(KERN_DEBUG "keyboard reply expected - got %02x\n",
+ scancode);
+#endif
+ }
+ if (scancode == 0) {
+#ifdef KBD_REPORT_ERR
+ printk(KERN_INFO "keyboard buffer overflow\n");
+#endif
+ prev_scancode = 0;
+ return 0;
+ }
+ return 1;
+}
+
+int pckbd_pretranslate(unsigned char scancode, char raw_mode)
+{
+ if (scancode == 0xff) {
+ /* in scancode mode 1, my ESC key generates 0xff */
+ /* the calculator keys on a FOCUS 9000 generate 0xff */
+#ifndef KBD_IS_FOCUS_9000
+#ifdef KBD_REPORT_ERR
+ if (!raw_mode)
+ printk(KERN_DEBUG "keyboard error\n");
+#endif
+#endif
+ prev_scancode = 0;
+ return 0;
+ }
+
+ if (scancode == 0xe0 || scancode == 0xe1) {
+ prev_scancode = scancode;
+ return 0;
+ }
+ return 1;
+}
+
+int pckbd_translate(unsigned char scancode, unsigned char *keycode,
+ char raw_mode)
+{
+ if (prev_scancode) {
+ /*
+ * usually it will be 0xe0, but a Pause key generates
+ * e1 1d 45 e1 9d c5 when pressed, and nothing when released
+ */
+ if (prev_scancode != 0xe0) {
+ if (prev_scancode == 0xe1 && scancode == 0x1d) {
+ prev_scancode = 0x100;
+ return 0;
+ } else if (prev_scancode == 0x100 && scancode == 0x45) {
+ *keycode = E1_PAUSE;
+ prev_scancode = 0;
+ } else {
+#ifdef KBD_REPORT_UNKN
+ if (!raw_mode)
+ printk(KERN_INFO "keyboard: unknown e1 escape sequence\n");
+#endif
+ prev_scancode = 0;
+ return 0;
+ }
+ } else {
+ prev_scancode = 0;
+ /*
+ * The keyboard maintains its own internal caps lock and
+ * num lock statuses. In caps lock mode E0 AA precedes make
+ * code and E0 2A follows break code. In num lock mode,
+ * E0 2A precedes make code and E0 AA follows break code.
+ * We do our own book-keeping, so we will just ignore these.
+ */
+ /*
+ * For my keyboard there is no caps lock mode, but there are
+ * both Shift-L and Shift-R modes. The former mode generates
+ * E0 2A / E0 AA pairs, the latter E0 B6 / E0 36 pairs.
+ * So, we should also ignore the latter. - aeb@cwi.nl
+ */
+ if (scancode == 0x2a || scancode == 0x36)
+ return 0;
+
+ if (e0_keys[scancode])
+ *keycode = e0_keys[scancode];
+ else {
+#ifdef KBD_REPORT_UNKN
+ if (!raw_mode)
+ printk(KERN_INFO "keyboard: unknown scancode e0 %02x\n",
+ scancode);
+#endif
+ return 0;
+ }
+ }
+ } else if (scancode >= SC_LIM) {
+ /* This happens with the FOCUS 9000 keyboard
+ Its keys PF1..PF12 are reported to generate
+ 55 73 77 78 79 7a 7b 7c 74 7e 6d 6f
+ Moreover, unless repeated, they do not generate
+ key-down events, so we have to zero up_flag below */
+ /* Also, Japanese 86/106 keyboards are reported to
+ generate 0x73 and 0x7d for \ - and \ | respectively. */
+ /* Also, some Brazilian keyboard is reported to produce
+ 0x73 and 0x7e for \ ? and KP-dot, respectively. */
+
+ *keycode = high_keys[scancode - SC_LIM];
+
+ if (!*keycode) {
+ if (!raw_mode) {
+#ifdef KBD_REPORT_UNKN
+ printk(KERN_INFO "keyboard: unrecognized scancode (%02x)"
+ " - ignored\n", scancode);
+#endif
+ }
+ return 0;
+ }
+ } else
+ *keycode = scancode;
+ return 1;
+}
+
+char pckbd_unexpected_up(unsigned char keycode)
+{
+ /* unexpected, but this can happen: maybe this was a key release for a
+ FOCUS 9000 PF key; if we want to see it, we have to clear up_flag */
+ if (keycode >= SC_LIM || keycode == 85)
+ return 0;
+ else
+ return 0200;
+}
+
+static void keyboard_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ unsigned char status;
+
+ pt_regs = regs;
+ disable_keyboard();
+
+ status = kbd_inb_p(0x64);
+ do {
+ unsigned char scancode;
+
+ /* mouse data? */
+ if (status & kbd_read_mask & 0x20)
+ break;
+
+ scancode = kbd_inb(0x60);
+ if ((status & 0x01) && do_acknowledge(scancode))
+ handle_scancode(scancode);
+
+ status = kbd_inb(0x64);
+ } while (status & 0x01);
+
+ mark_bh(KEYBOARD_BH);
+ enable_keyboard();
+}
+
+/*
+ * send_data sends a character to the keyboard and waits
+ * for an acknowledge, possibly retrying if asked to. Returns
+ * the success status.
+ */
+static int send_data(unsigned char data)
+{
+ int retries = 3;
+ int i;
+
+ do {
+ kb_wait();
+ acknowledge = 0;
+ resend = 0;
+ reply_expected = 1;
+ kbd_outb_p(data, 0x60);
+ for(i=0; i<0x200000; i++) {
+ kbd_inb_p(0x64); /* just as a delay */
+ if (acknowledge)
+ return 1;
+ if (resend)
+ break;
+ }
+ if (!resend)
+ return 0;
+ } while (retries-- > 0);
+ return 0;
+}
+
+void pckbd_leds(unsigned char leds)
+{
+ if (!send_data(0xed) || !send_data(leds))
+ send_data(0xf4); /* re-enable kbd if any errors */
+}
+
+__initfunc(void pckbd_init_hw(void))
+{
+ request_irq(KEYBOARD_IRQ, keyboard_interrupt, 0, "keyboard", NULL);
+ keyboard_setup();
+#ifdef INIT_KBD
+ initialize_kbd();
+#endif
+}
+
+#ifdef INIT_KBD
+
+/*
+ * controller commands
+ */
+#define KBD_READ_MODE (unsigned int) 0x20
+#define KBD_WRITE_MODE (unsigned int) 0x60
+#define KBD_SELF_TEST (unsigned int) 0xAA
+#define KBD_SELF_TEST2 (unsigned int) 0xAB
+#define KBD_CNTL_ENABLE (unsigned int) 0xAE
+/*
+ * keyboard commands
+ */
+#define KBD_ENABLE (unsigned int) 0xF4
+#define KBD_DISABLE (unsigned int) 0xF5
+#define KBD_RESET (unsigned int) 0xFF
+/*
+ * keyboard replies
+ */
+#define KBD_ACK (unsigned int) 0xFA
+#define KBD_POR (unsigned int) 0xAA
+/*
+ * status register bits
+ */
+#define KBD_OBF (unsigned int) 0x01
+#define KBD_IBF (unsigned int) 0x02
+#define KBD_GTO (unsigned int) 0x40
+#define KBD_PERR (unsigned int) 0x80
+/*
+ * keyboard controller mode register bits
+ */
+#define KBD_EKI (unsigned int) 0x01
+#define KBD_SYS (unsigned int) 0x04
+#define KBD_DMS (unsigned int) 0x20
+#define KBD_KCC (unsigned int) 0x40
+
+#define TIMEOUT_CONST 500000
+
+static int kbd_wait_for_input(void)
+{
+ int n;
+ int status, data;
+
+ n = TIMEOUT_CONST;
+ do {
+ status = kbd_inb(KBD_STATUS_REG);
+ /*
+ * Wait for input data to become available. This bit will
+ * then be cleared by the following read of the DATA
+ * register.
+ */
+
+ if (!(status & KBD_OBF))
+ continue;
+
+ data = kbd_inb(KBD_DATA_REG);
+
+ /*
+ * Check to see if a timeout error has occurred. This means
+ * that transmission was started but did not complete in the
+ * normal time cycle. PERR is set when a parity error occurred
+ * in the last transmission.
+ */
+ if (status & (KBD_GTO | KBD_PERR)) {
+ continue;
+ }
+ return (data & 0xff);
+ } while (--n);
+ return (-1); /* timed-out if fell through to here... */
+}
+
+static void kbd_write(int address, int data)
+{
+ int status;
+
+ do {
+ status = kbd_inb(KBD_STATUS_REG); /* spin until input buffer empty*/
+ } while (status & KBD_IBF);
+ kbd_outb(data, address); /* write out the data*/
+}
+
+__initfunc(int initialize_kbd(void))
+{
+ unsigned long flags;
+
+ save_flags(flags); cli();
+
+ /* Flush any pending input. */
+ while (kbd_wait_for_input() != -1)
+ continue;
+
+ /*
+ * Test the keyboard interface.
+ * This seems to be the only way to get it going.
+ * If the test is successful a x55 is placed in the input buffer.
+ */
+ kbd_write(KBD_CNTL_REG, KBD_SELF_TEST);
+ if (kbd_wait_for_input() != 0x55) {
+ printk(KERN_WARNING "initialize_kbd: "
+ "keyboard failed self test.\n");
+ restore_flags(flags);
+ return(-1);
+ }
+
+ /*
+ * Perform a keyboard interface test. This causes the controller
+ * to test the keyboard clock and data lines. The results of the
+ * test are placed in the input buffer.
+ */
+ kbd_write(KBD_CNTL_REG, KBD_SELF_TEST2);
+ if (kbd_wait_for_input() != 0x00) {
+ printk(KERN_WARNING "initialize_kbd: "
+ "keyboard failed self test 2.\n");
+ restore_flags(flags);
+ return(-1);
+ }
+
+ /* Enable the keyboard by allowing the keyboard clock to run. */
+ kbd_write(KBD_CNTL_REG, KBD_CNTL_ENABLE);
+
+ /*
+ * Reset keyboard. If the read times out
+ * then the assumption is that no keyboard is
+ * plugged into the machine.
+ * This defaults the keyboard to scan-code set 2.
+ */
+ kbd_write(KBD_DATA_REG, KBD_RESET);
+ if (kbd_wait_for_input() != KBD_ACK) {
+ printk(KERN_WARNING "initialize_kbd: "
+ "reset kbd failed, no ACK.\n");
+ restore_flags(flags);
+ return(-1);
+ }
+
+ if (kbd_wait_for_input() != KBD_POR) {
+ printk(KERN_WARNING "initialize_kbd: "
+ "reset kbd failed, not POR.\n");
+ restore_flags(flags);
+ return(-1);
+ }
+
+ /*
+ * now do a DEFAULTS_DISABLE always
+ */
+ kbd_write(KBD_DATA_REG, KBD_DISABLE);
+ if (kbd_wait_for_input() != KBD_ACK) {
+ printk(KERN_WARNING "initialize_kbd: "
+ "disable kbd failed, no ACK.\n");
+ restore_flags(flags);
+ return(-1);
+ }
+
+ /*
+ * Enable keyboard interrupt, operate in "sys" mode,
+ * enable keyboard (by clearing the disable keyboard bit),
+ * disable mouse, do conversion of keycodes.
+ */
+ kbd_write(KBD_CNTL_REG, KBD_WRITE_MODE);
+ kbd_write(KBD_DATA_REG, KBD_EKI|KBD_SYS|KBD_DMS|KBD_KCC);
+
+ /*
+ * now ENABLE the keyboard to set it scanning...
+ */
+ kbd_write(KBD_DATA_REG, KBD_ENABLE);
+ if (kbd_wait_for_input() != KBD_ACK) {
+ printk(KERN_WARNING "initialize_kbd: "
+ "keyboard enable failed.\n");
+ restore_flags(flags);
+ return(-1);
+ }
+
+ restore_flags(flags);
+
+ return (1);
+}
+#endif /* INIT_KBD */
diff --git a/drivers/char/pcxx.c b/drivers/char/pcxx.c
index c09c7dbbe..9a68bb472 100644
--- a/drivers/char/pcxx.c
+++ b/drivers/char/pcxx.c
@@ -895,7 +895,7 @@ static void pcxe_flush_chars(struct tty_struct *tty)
* Driver setup function when linked into the kernel to optionally parse multible
* "digi="-lines and initialize the driver at boot time. No probing.
*/
-void pcxx_setup(char *str, int *ints)
+__initfunc(void pcxx_setup(char *str, int *ints))
{
struct board_info board;
@@ -2358,7 +2358,7 @@ static void do_softint(void *private_)
if(info && info->magic == PCXX_MAGIC) {
struct tty_struct *tty = info->tty;
if (tty && tty->driver_data) {
- if(clear_bit(PCXE_EVENT_HANGUP, &info->event)) {
+ if(test_and_clear_bit(PCXE_EVENT_HANGUP, &info->event)) {
tty_hangup(tty);
wake_up_interruptible(&info->open_wait);
info->asyncflags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
diff --git a/drivers/char/random.c b/drivers/char/random.c
index 3fb64b28d..5f7619391 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -1,7 +1,7 @@
/*
* random.c -- A strong random number generator
*
- * Version 1.01, last modified 13-Feb-97
+ * Version 1.02, last modified 15-Apr-97
*
* Copyright Theodore Ts'o, 1994, 1995, 1996, 1997. All rights reserved.
*
@@ -839,6 +839,18 @@ static void SHATransform(__u32 *digest, __u32 *data)
digest[ 4 ] += E;
}
+#undef ROTL
+#undef f1
+#undef f2
+#undef f3
+#undef f4
+#undef K1
+#undef K2
+#undef K3
+#undef K4
+#undef expand
+#undef subRound
+
#else
#define HASH_BUFFER_SIZE 4
#define HASH_TRANSFORM MD5Transform
@@ -1324,22 +1336,90 @@ struct file_operations urandom_fops = {
* attacks which rely on guessing the initial TCP sequence number.
* This algorithm was suggested by Steve Bellovin.
*/
+
+/* F, G and H are basic MD4 functions: selection, majority, parity */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+
+#define ROTL(n,X) ( ( ( X ) << n ) | ( ( X ) >> ( 32 - n ) ) )
+
+/* FF, GG and HH are MD4 transformations for rounds 1, 2 and 3 */
+/* Rotation is separate from addition to prevent recomputation */
+#define FF(a, b, c, d, x, s) \
+ {(a) += F ((b), (c), (d)) + (x); \
+ (a) = ROTL ((s), (a));}
+#define GG(a, b, c, d, x, s) \
+ {(a) += G ((b), (c), (d)) + (x) + 013240474631UL; \
+ (a) = ROTL ((s), (a));}
+#define HH(a, b, c, d, x, s) \
+ {(a) += H ((b), (c), (d)) + (x) + 015666365641UL; \
+ (a) = ROTL ((s), (a));}
+
+/*
+ * Basic cut-down MD4 transform
+ */
+static void halfMD4Transform (__u32 buf[4], __u32 in[8])
+{
+ __u32 a = buf[0], b = buf[1], c = buf[2], d = buf[3];
+
+ /* Round 1 */
+ FF (a, b, c, d, in[ 0], 3);
+ FF (d, a, b, c, in[ 1], 7);
+ FF (c, d, a, b, in[ 2], 11);
+ FF (b, c, d, a, in[ 3], 19);
+ FF (a, b, c, d, in[ 4], 3);
+ FF (d, a, b, c, in[ 5], 7);
+ FF (c, d, a, b, in[ 6], 11);
+ FF (b, c, d, a, in[ 7], 19);
+
+ /* Round 2 */
+ GG (a, b, c, d, in[ 0], 3);
+ GG (d, a, b, c, in[ 4], 5);
+ GG (a, b, c, d, in[ 1], 9);
+ GG (d, a, b, c, in[ 5], 13);
+ GG (a, b, c, d, in[ 2], 3);
+ GG (d, a, b, c, in[ 6], 5);
+ GG (a, b, c, d, in[ 3], 9);
+ GG (d, a, b, c, in[ 7], 13);
+
+ /* Round 3 */
+ HH (a, b, c, d, in[ 0], 3);
+ HH (c, d, a, b, in[ 4], 9);
+ HH (a, b, c, d, in[ 2], 11);
+ HH (c, d, a, b, in[ 6], 15);
+ HH (a, b, c, d, in[ 1], 3);
+ HH (c, d, a, b, in[ 5], 9);
+ HH (a, b, c, d, in[ 3], 11);
+ HH (c, d, a, b, in[ 7], 15);
+
+ buf[0] += a;
+ buf[1] += b;
+ buf[2] += c;
+ buf[3] += d;
+}
+
+#define REKEY_INTERVAL 300
+
__u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr,
__u16 sport, __u16 dport)
{
- static int is_init = 0;
- static __u32 secret[16];
+ static __u32 rekey_time = 0;
+ static __u32 secret[12];
+ static char count = 0;
struct timeval tv;
- __u32 tmp[16];
+ __u32 tmp[12];
__u32 seq;
/*
- * Pick a random secret the first time we open a TCP
- * connection.
+ * Pick a random secret every REKEY_INTERVAL seconds
*/
- if (is_init == 0) {
+ do_gettimeofday(&tv);
+ if (!rekey_time ||
+ (tv.tv_sec - rekey_time) > REKEY_INTERVAL) {
get_random_bytes(&secret, sizeof(secret));
- is_init = 1;
+ rekey_time = tv.tv_sec;
+ count++;
}
memcpy(tmp, secret, sizeof(tmp));
@@ -1350,7 +1430,7 @@ __u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr,
tmp[8]=saddr;
tmp[9]=daddr;
tmp[10]=(sport << 16) + dport;
- HASH_TRANSFORM(tmp, tmp);
+ halfMD4Transform(tmp, tmp+4);
/*
* As close as possible to RFC 793, which
@@ -1359,8 +1439,8 @@ __u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr,
* For 10MB/s ethernet, a 1MHz clock is appropriate.
* That's funny, Linux has one built in! Use it!
*/
- do_gettimeofday(&tv);
- seq = tmp[1] + tv.tv_usec+tv.tv_sec*1000000;
+ seq = (tmp[1]&0xFFFFFF) + (tv.tv_usec+tv.tv_sec*1000000) +
+ (count << 24);
#if 0
printk("init_seq(%lx, %lx, %d, %d) = %d\n",
saddr, daddr, sport, dport, seq);
diff --git a/drivers/char/riscom8.c b/drivers/char/riscom8.c
index 301babf81..dfe150e07 100644
--- a/drivers/char/riscom8.c
+++ b/drivers/char/riscom8.c
@@ -1711,7 +1711,7 @@ static void do_softint(void *private_)
if(!(tty = port->tty))
return;
- if (clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) {
+ if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) {
if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
tty->ldisc.write_wakeup)
(tty->ldisc.write_wakeup)(tty);
@@ -1821,7 +1821,7 @@ static void rc_release_drivers(void)
* addresses in this case.
*
*/
-void riscom8_setup(char *str, int * ints)
+__initfunc(void riscom8_setup(char *str, int * ints))
{
int i;
diff --git a/drivers/char/serial.c b/drivers/char/serial.c
index e1a69a85e..e2a93a0c3 100644
--- a/drivers/char/serial.c
+++ b/drivers/char/serial.c
@@ -992,7 +992,7 @@ static void do_softint(void *private_)
if (!tty)
return;
- if (clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
+ if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
tty->ldisc.write_wakeup)
(tty->ldisc.write_wakeup)(tty);
diff --git a/drivers/char/tga.c b/drivers/char/tga.c
index 723cbc631..a85f4cba4 100644
--- a/drivers/char/tga.c
+++ b/drivers/char/tga.c
@@ -26,6 +26,7 @@
#include <linux/ioport.h>
#include <linux/bios32.h>
#include <linux/pci.h>
+#include <linux/init.h>
#include <asm/io.h>
#include <asm/system.h>
@@ -140,35 +141,35 @@ unsigned long tga_fb_base;
unsigned long tga_regs_base;
unsigned int tga_bpp, tga_fb_width, tga_fb_height, tga_fb_stride;
-static unsigned int fb_offset_presets[4] = {
+static unsigned int fb_offset_presets[4] __initdata = {
TGA_8PLANE_FB_OFFSET,
TGA_24PLANE_FB_OFFSET,
0xffffffff,
TGA_24PLUSZ_FB_OFFSET
};
-static unsigned int deep_presets[4] = {
+static unsigned int deep_presets[4] __initdata = {
0x00014000,
0x0001440d,
0xffffffff,
0x0001441d
};
-static unsigned int rasterop_presets[4] = {
+static unsigned int rasterop_presets[4] __initdata = {
0x00000003,
0x00000303,
0xffffffff,
0x00000303
};
-static unsigned int mode_presets[4] = {
+static unsigned int mode_presets[4] __initdata = {
0x00002000,
0x00002300,
0xffffffff,
0x00002300
};
-static unsigned int base_addr_presets[4] = {
+static unsigned int base_addr_presets[4] __initdata = {
0x00000000,
0x00000001,
0xffffffff,
@@ -304,8 +305,8 @@ set_cursor(int currcons)
restore_flags(flags);
}
-unsigned long
-con_type_init(unsigned long kmem_start, const char **display_desc)
+__initfunc(unsigned long
+con_type_init(unsigned long kmem_start, const char **display_desc))
{
can_do_color = 1;
@@ -323,8 +324,8 @@ con_type_init(unsigned long kmem_start, const char **display_desc)
return kmem_start;
}
-void
-con_type_init_finish(void)
+__initfunc(void
+con_type_init_finish(void))
{
}
@@ -447,8 +448,8 @@ void set_vesa_blanking(const unsigned long arg)
* when TGA console is configured, at the end of the probing code,
* we call here to look for a TGA device, and proceed...
*/
-void
-tga_console_init(void)
+__initfunc(void
+tga_console_init(void))
{
unsigned char pci_bus, pci_devfn;
int status;
@@ -490,9 +491,9 @@ tga_console_init(void)
#endif
}
-unsigned char PLLbits[7] = { 0x80, 0x04, 0x00, 0x24, 0x44, 0x80, 0xb8 };
+unsigned char PLLbits[7] __initdata = { 0x80, 0x04, 0x00, 0x24, 0x44, 0x80, 0xb8 };
-const unsigned long bt485_cursor_source[64] = {
+const unsigned long bt485_cursor_source[64] __initdata = {
0x00000000000000ff,0x00000000000000ff,0x00000000000000ff,0x00000000000000ff,
0x00000000000000ff,0x00000000000000ff,0x00000000000000ff,0x00000000000000ff,
0x00000000000000ff,0x00000000000000ff,0x00000000000000ff,0x00000000000000ff,
@@ -502,7 +503,7 @@ const unsigned long bt485_cursor_source[64] = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
};
-const unsigned int bt463_cursor_source[256] = {
+const unsigned int bt463_cursor_source[256] __initdata = {
0xffff0000, 0x00000000, 0x00000000, 0x00000000,
0xffff0000, 0x00000000, 0x00000000, 0x00000000,
0xffff0000, 0x00000000, 0x00000000, 0x00000000,
@@ -533,8 +534,8 @@ const unsigned int bt463_cursor_source[256] = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
};
-void
-tga_init_video()
+__initfunc(void
+tga_init_video(void))
{
int i, j, temp;
unsigned char *cbp;
@@ -750,8 +751,8 @@ tga_init_video()
tga_fb_stride = tga_fb_width / sizeof(int);
}
-void
-tga_clear_screen()
+__initfunc(void
+tga_clear_screen(void))
{
register int i, j;
register unsigned int *dst;
diff --git a/drivers/char/tpqic02.c b/drivers/char/tpqic02.c
index 4f2dbf768..9d4ee2449 100644
--- a/drivers/char/tpqic02.c
+++ b/drivers/char/tpqic02.c
@@ -89,6 +89,7 @@
#include <linux/tpqic02.h>
#include <linux/mm.h>
#include <linux/malloc.h>
+#include <linux/init.h>
#include <asm/dma.h>
#include <asm/system.h>
@@ -2866,10 +2867,7 @@ static int qic02_get_resources(void)
return 0;
} /* qic02_get_resources */
-#ifdef MODULE
-static
-#endif
-int qic02_tape_init(void)
+__initfunc(static int qic02_tape_init(void))
{
if (TPSTATSIZE != 6)
{
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 0d0f0a4ed..12109e524 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -166,14 +166,11 @@ static int check_tty_count(struct tty_struct *tty, const char *routine)
{
#ifdef CHECK_TTY_COUNT
struct file *f;
- int i, count = 0;
+ int count = 0;
- for (f = first_file, i=0; i<nr_files; i++, f = f->f_next) {
- if (!f->f_count)
- continue;
- if (f->private_data == tty) {
+ for(f = inuse_filps; f; f = f->f_next) {
+ if(f->private_data == tty)
count++;
- }
}
if (tty->driver.type == TTY_DRIVER_TYPE_PTY &&
tty->driver.subtype == PTY_TYPE_SLAVE &&
@@ -363,16 +360,14 @@ static struct file_operations hung_up_tty_fops = {
void do_tty_hangup(struct tty_struct * tty, struct file_operations *fops)
{
- int i;
+
struct file * filp;
struct task_struct *p;
if (!tty)
return;
check_tty_count(tty, "do_tty_hangup");
- for (filp = first_file, i=0; i<nr_files; i++, filp = filp->f_next) {
- if (!filp->f_count)
- continue;
+ for (filp = inuse_filps; filp; filp = filp->f_next) {
if (filp->private_data != tty)
continue;
if (!filp->f_inode)
@@ -405,13 +400,14 @@ void do_tty_hangup(struct tty_struct * tty, struct file_operations *fops)
tty->ldisc = ldiscs[N_TTY];
tty->termios->c_line = N_TTY;
if (tty->ldisc.open) {
- i = (tty->ldisc.open)(tty);
+ int i = (tty->ldisc.open)(tty);
if (i < 0)
printk("do_tty_hangup: N_TTY open: error %d\n",
-i);
}
}
+ read_lock(&tasklist_lock);
for_each_task(p) {
if ((tty->session > 0) && (p->session == tty->session) &&
p->leader) {
@@ -423,6 +419,8 @@ void do_tty_hangup(struct tty_struct * tty, struct file_operations *fops)
if (p->tty == tty)
p->tty = NULL;
}
+ read_unlock(&tasklist_lock);
+
tty->flags = 0;
tty->session = 0;
tty->pgrp = -1;
@@ -494,9 +492,11 @@ void disassociate_ctty(int on_exit)
tty->session = 0;
tty->pgrp = -1;
+ read_lock(&tasklist_lock);
for_each_task(p)
if (p->session == current->session)
p->tty = NULL;
+ read_unlock(&tasklist_lock);
}
void wait_for_keypress(void)
@@ -838,7 +838,7 @@ static void release_dev(struct file * filp)
{
struct tty_struct *tty, *o_tty;
struct termios *tp, *o_tp, *ltp, *o_ltp;
- struct task_struct **p;
+ struct task_struct *p;
int idx;
tty = (struct tty_struct *)filp->private_data;
@@ -972,14 +972,14 @@ static void release_dev(struct file * filp)
* Make sure there aren't any processes that still think this
* tty is their controlling tty.
*/
- for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
- if (*p == 0)
- continue;
- if ((*p)->tty == tty)
- (*p)->tty = NULL;
- if (o_tty && (*p)->tty == o_tty)
- (*p)->tty = NULL;
+ read_lock(&tasklist_lock);
+ for_each_task(p) {
+ if (p->tty == tty)
+ p->tty = NULL;
+ if (o_tty && p->tty == o_tty)
+ p->tty = NULL;
}
+ read_unlock(&tasklist_lock);
/*
* Shutdown the current line discipline, and reset it to
@@ -1216,40 +1216,6 @@ static int tty_fasync(struct inode * inode, struct file * filp, int on)
return 0;
}
-#if 0
-/*
- * XXX does anyone use this anymore?!?
- */
-static int do_get_ps_info(unsigned long arg)
-{
- struct tstruct {
- int flag;
- int present[NR_TASKS];
- struct task_struct tasks[NR_TASKS];
- };
- struct tstruct *ts = (struct tstruct *)arg;
- struct task_struct **p;
- char *c, *d;
- int i, n = 0;
-
- i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(struct tstruct));
- if (i)
- return i;
- for (p = &FIRST_TASK ; p <= &LAST_TASK ; p++, n++)
- if (*p)
- {
- c = (char *)(*p);
- d = (char *)(ts->tasks+n);
- for (i=0 ; i<sizeof(struct task_struct) ; i++)
- put_user(*c++, d++);
- put_user(1, ts->present+n);
- }
- else
- put_user(0, ts->present+n);
- return(0);
-}
-#endif
-
static int tiocsti(struct tty_struct *tty, char * arg)
{
char ch, mbz = 0;
@@ -1338,9 +1304,11 @@ static int tiocsctty(struct tty_struct *tty, int arg)
*/
struct task_struct *p;
+ read_lock(&tasklist_lock);
for_each_task(p)
if (p->tty == tty)
p->tty = NULL;
+ read_unlock(&tasklist_lock);
} else
return -EPERM;
}
@@ -1493,7 +1461,7 @@ void do_SAK( struct tty_struct *tty)
#ifdef TTY_SOFT_SAK
tty_hangup(tty);
#else
- struct task_struct **p;
+ struct task_struct *p;
int session;
int i;
struct file *filp;
@@ -1505,23 +1473,23 @@ void do_SAK( struct tty_struct *tty)
tty->ldisc.flush_buffer(tty);
if (tty->driver.flush_buffer)
tty->driver.flush_buffer(tty);
- for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
- if (!(*p))
- continue;
- if (((*p)->tty == tty) ||
- ((session > 0) && ((*p)->session == session)))
- send_sig(SIGKILL, *p, 1);
- else if ((*p)->files) {
+ read_lock(&tasklist_lock);
+ for_each_task(p) {
+ if ((p->tty == tty) ||
+ ((session > 0) && (p->session == session)))
+ send_sig(SIGKILL, p, 1);
+ else if (p->files) {
for (i=0; i < NR_OPEN; i++) {
- filp = (*p)->files->fd[i];
+ filp = p->files->fd[i];
if (filp && (filp->f_op == &tty_fops) &&
(filp->private_data == tty)) {
- send_sig(SIGKILL, *p, 1);
+ send_sig(SIGKILL, p, 1);
break;
}
}
}
}
+ read_unlock(&tasklist_lock);
#endif
}
@@ -1761,6 +1729,9 @@ __initfunc(int tty_init(void))
#ifdef CONFIG_DIGI
pcxe_init();
#endif
+#ifdef CONFIG_DIGIEPCA
+ pc_init();
+#endif
#ifdef CONFIG_RISCOM8
riscom8_init();
#endif
diff --git a/drivers/char/vga.c b/drivers/char/vga.c
index 7ae406d8e..e82bbc083 100644
--- a/drivers/char/vga.c
+++ b/drivers/char/vga.c
@@ -53,6 +53,7 @@
#include <linux/major.h>
#include <linux/mm.h>
#include <linux/ioport.h>
+#include <linux/init.h>
#ifdef __mips__
#include <asm/bootinfo.h>
@@ -159,8 +160,8 @@ set_cursor(int currcons)
hide_cursor();
}
-unsigned long
-con_type_init(unsigned long kmem_start, const char **display_desc)
+__initfunc(unsigned long
+con_type_init(unsigned long kmem_start, const char **display_desc))
{
#ifdef CONFIG_ACER_PICA_61
/*
@@ -328,8 +329,8 @@ con_type_init(unsigned long kmem_start, const char **display_desc)
return kmem_start;
}
-void
-con_type_init_finish(void)
+__initfunc(void
+con_type_init_finish(void))
{
}
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index 0f4957971..b3e25c010 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -123,6 +123,7 @@ kd_size_changed(int row, int col)
}
}
+ read_lock(&tasklist_lock);
for_each_task(p)
{
if ( p->tty && MAJOR(p->tty->device) == TTY_MAJOR &&
@@ -131,6 +132,7 @@ kd_size_changed(int row, int col)
send_sig(SIGWINCH, p, 1);
}
}
+ read_unlock(&tasklist_lock);
return 0;
}
diff --git a/drivers/char/wdt.c b/drivers/char/wdt.c
index e32131b63..31837eee2 100644
--- a/drivers/char/wdt.c
+++ b/drivers/char/wdt.c
@@ -61,7 +61,7 @@ static int irq=14;
* Setup options
*/
-void wdt_setup(char *str, int *ints)
+__initfunc(void wdt_setup(char *str, int *ints))
{
if(ints[0]>0)
{
diff --git a/drivers/isdn/Config.in b/drivers/isdn/Config.in
index af07e9bca..f731a096d 100644
--- a/drivers/isdn/Config.in
+++ b/drivers/isdn/Config.in
@@ -11,7 +11,6 @@ fi
bool 'Support audio via ISDN' CONFIG_ISDN_AUDIO
dep_tristate 'ICN 2B and 4B support' CONFIG_ISDN_DRV_ICN $CONFIG_ISDN
dep_tristate 'PCBIT-D support' CONFIG_ISDN_DRV_PCBIT $CONFIG_ISDN
-dep_tristate 'Teles/NICCY1016PC/Creatix support' CONFIG_ISDN_DRV_TELES $CONFIG_ISDN
dep_tristate 'HiSax SiemensChipSet driver support' CONFIG_ISDN_DRV_HISAX $CONFIG_ISDN
if [ "$CONFIG_ISDN_DRV_HISAX" != "n" ]; then
bool 'HiSax Support for Teles 16.0/8.0' CONFIG_HISAX_16_0
diff --git a/drivers/isdn/Makefile b/drivers/isdn/Makefile
index 8ef5d8e39..e88e81735 100644
--- a/drivers/isdn/Makefile
+++ b/drivers/isdn/Makefile
@@ -1,6 +1,6 @@
SUB_DIRS :=
MOD_SUB_DIRS :=
-ALL_SUB_DIRS := icn teles pcbit hisax
+ALL_SUB_DIRS := icn pcbit hisax
L_OBJS :=
LX_OBJS :=
@@ -36,16 +36,6 @@ else
endif
endif
-ifeq ($(CONFIG_ISDN_DRV_TELES),y)
- L_OBJS += teles/teles.o
- SUB_DIRS += teles
- MOD_SUB_DIRS += teles
-else
- ifeq ($(CONFIG_ISDN_DRV_TELES),m)
- MOD_SUB_DIRS += teles
- endif
-endif
-
ifeq ($(CONFIG_ISDN_DRV_HISAX),y)
L_OBJS += hisax/hisax.o
SUB_DIRS += hisax
diff --git a/drivers/isdn/hisax/.cvsignore b/drivers/isdn/hisax/.cvsignore
new file mode 100644
index 000000000..4671378ae
--- /dev/null
+++ b/drivers/isdn/hisax/.cvsignore
@@ -0,0 +1 @@
+.depend
diff --git a/drivers/isdn/hisax/isdnl1.c b/drivers/isdn/hisax/isdnl1.c
index cbc91e9d6..ebf0957b5 100644
--- a/drivers/isdn/hisax/isdnl1.c
+++ b/drivers/isdn/hisax/isdnl1.c
@@ -461,11 +461,11 @@ isac_bh(struct IsdnCardState *sp)
if (!sp)
return;
- if (clear_bit(ISAC_PHCHANGE, &sp->event))
+ if (test_and_clear_bit(ISAC_PHCHANGE, &sp->event))
process_new_ph(sp);
- if (clear_bit(ISAC_RCVBUFREADY, &sp->event))
+ if (test_and_clear_bit(ISAC_RCVBUFREADY, &sp->event))
process_rcv(sp);
- if (clear_bit(ISAC_XMTBUFREADY, &sp->event))
+ if (test_and_clear_bit(ISAC_XMTBUFREADY, &sp->event))
process_xmt(sp);
}
@@ -578,9 +578,9 @@ hscx_bh(struct HscxState *hsp)
if (!hsp)
return;
- if (clear_bit(HSCX_RCVBUFREADY, &hsp->event))
+ if (test_and_clear_bit(HSCX_RCVBUFREADY, &hsp->event))
hscx_process_rcv(hsp);
- if (clear_bit(HSCX_XMTBUFREADY, &hsp->event))
+ if (test_and_clear_bit(HSCX_XMTBUFREADY, &hsp->event))
hscx_process_xmt(hsp);
}
diff --git a/drivers/isdn/isdn_net.c b/drivers/isdn/isdn_net.c
index 5d3ab899e..b6b076360 100644
--- a/drivers/isdn/isdn_net.c
+++ b/drivers/isdn/isdn_net.c
@@ -934,7 +934,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct device *ndev)
return 0;
}
/* Avoid timer-based retransmission conflicts. */
- if (set_bit(0, (void *) &ndev->tbusy) != 0)
+ if (test_and_set_bit(0, (void *) &ndev->tbusy) != 0)
printk(KERN_WARNING
"%s: Transmitter access conflict.\n",
ndev->name);
diff --git a/drivers/isdn/sc/Makefile b/drivers/isdn/sc/Makefile
index 5440cdaff..be0d8b76c 100644
--- a/drivers/isdn/sc/Makefile
+++ b/drivers/isdn/sc/Makefile
@@ -1,5 +1,5 @@
#
-# $Id: Makefile.kernel,v 1.1 1996/11/07 13:07:40 fritz Exp $
+# $Id: Makefile,v 1.2 1997/05/01 08:53:47 davem Exp $
# Copyright (C) 1996 SpellCaster Telecommunications Inc.
#
# This program is free software; you can redistribute it and/or modify
diff --git a/drivers/isdn/teles/Makefile b/drivers/isdn/teles/Makefile
deleted file mode 100644
index a252f46ba..000000000
--- a/drivers/isdn/teles/Makefile
+++ /dev/null
@@ -1,17 +0,0 @@
-L_OBJS :=
-M_OBJS :=
-O_OBJS := mod.o card.o config.o buffers.o tei.o isdnl2.o isdnl3.o \
-llglue.o q931.o callc.o fsm.o
-
-O_TARGET :=
-ifeq ($(CONFIG_ISDN_DRV_TELES),y)
- O_TARGET += teles.o
-else
- ifeq ($(CONFIG_ISDN_DRV_TELES),m)
- O_TARGET += teles.o
- M_OBJS += teles.o
- endif
-endif
-
-include $(TOPDIR)/Rules.make
-
diff --git a/drivers/isdn/teles/buffers.c b/drivers/isdn/teles/buffers.c
deleted file mode 100644
index 74510a664..000000000
--- a/drivers/isdn/teles/buffers.c
+++ /dev/null
@@ -1,329 +0,0 @@
-/* $Id: buffers.c,v 1.2 1996/07/04 22:46:20 dm Exp $
- *
- * $Log: buffers.c,v $
- * Revision 1.2 1996/07/04 22:46:20 dm
- * Merge to 2.0.1
- *
- * Revision 1.3 1996/05/31 00:56:53 fritz
- * removed cli() from BufPoolAdd, since it is called
- * with interrupts off anyway.
- *
- * Revision 1.2 1996/04/29 22:48:14 fritz
- * Removed compatibility-macros. No longer needed.
- *
- * Revision 1.1 1996/04/13 10:19:28 fritz
- * Initial revision
- *
- *
- */
-#define __NO_VERSION__
-#include "teles.h"
-#include <linux/mm.h>
-#include <linux/malloc.h>
-
-
-void
-BufPoolInit(struct BufPool *bp, int order, int bpps,
- int maxpages)
-{
-#ifdef DEBUG_MAGIC
- generateerror
- bp->magic = 010167;
-#endif
-
-#if 0
- printk(KERN_DEBUG "BufPoolInit bp %x\n", bp);
-#endif
-
- bp->freelist = NULL;
- bp->pageslist = NULL;
- bp->pageorder = order;
- bp->pagescount = 0;
- bp->bpps = bpps;
- bp->bufsize = BUFFER_SIZE(order, bpps);
- bp->maxpages = maxpages;
-}
-
-int
-BufPoolAdd(struct BufPool *bp, int priority)
-{
- struct Pages *ptr;
- byte *bptr;
- int i;
- struct BufHeader *bh = NULL, *prev, *first;
-
-#if 0
- printk(KERN_DEBUG "BufPoolAdd bp %x\n", bp);
-#endif
-
- ptr = (struct Pages *) __get_free_pages(priority, bp->pageorder, 0);
- if (!ptr) {
- printk(KERN_WARNING "BufPoolAdd couldn't get pages!\n");
- return (-1);
- }
-#if 0
- printk(KERN_DEBUG "Order %d pages allocated at %x\n", bp->pageorder, ptr);
-#endif
-
- ptr->next = bp->pageslist;
- bp->pageslist = ptr;
- bp->pagescount++;
-
- bptr = (byte *) ptr + sizeof(struct Pages *);
-
- i = bp->bpps;
- first = (struct BufHeader *) bptr;
- prev = NULL;
- while (i--) {
- bh = (struct BufHeader *) bptr;
-#ifdef DEBUG_MAGIC
- bh->magic = 020167;
-#endif
- bh->next = prev;
- prev = bh;
- bh->bp = bp;
- bptr += PART_SIZE(bp->pageorder, bp->bpps);
- }
-
- first->next = bp->freelist;
- bp->freelist = bh;
- return (0);
-}
-
-void
-BufPoolFree(struct BufPool *bp)
-{
- struct Pages *p;
-
-#if 0
- printk(KERN_DEBUG "BufPoolFree bp %x\n", bp);
-#endif
-
- while (bp->pagescount--) {
- p = bp->pageslist->next;
- free_pages((unsigned long) bp->pageslist, bp->pageorder);
-#if 0
- printk(KERN_DEBUG "Free pages %x order %d\n", bp->pageslist, bp->pageorder);
-#endif
- bp->pageslist = p;
- }
-}
-
-int
-BufPoolGet(struct BufHeader **bh,
- struct BufPool *bp, int priority, void *heldby, int where)
-{
- long flags;
- int i;
-
-#ifdef DEBUG_MAGIC
- if (bp->magic != 010167) {
- printk(KERN_DEBUG "BufPoolGet: not a BufHeader\n");
- return (-1);
- }
-#endif
-
- save_flags(flags);
- cli();
- i = 0;
- while (!0) {
- if (bp->freelist) {
- *bh = bp->freelist;
- bp->freelist = bp->freelist->next;
- (*bh)->heldby = heldby;
- (*bh)->where = where;
- restore_flags(flags);
- return (0);
- }
- if ((i == 0) && (bp->pagescount < bp->maxpages)) {
- if (BufPoolAdd(bp, priority)) {
- restore_flags(flags);
- return -1;
- }
- i++;
- } else {
- *bh = NULL;
- restore_flags(flags);
- return (-1);
- }
- }
-
-}
-
-void
-BufPoolRelease(struct BufHeader *bh)
-{
- struct BufPool *bp;
- long flags;
-
-#ifdef DEBUG_MAGIC
- if (bh->magic != 020167) {
- printk(KERN_DEBUG "BufPoolRelease: not a BufHeader\n");
- printk(KERN_DEBUG "called from %x\n", return_address());
- return;
- }
-#endif
-
- bp = bh->bp;
-
-#ifdef DEBUG_MAGIC
- if (bp->magic != 010167) {
- printk(KERN_DEBUG "BufPoolRelease: not a BufPool\n");
- return;
- }
-#endif
-
- save_flags(flags);
- cli();
- bh->next = bp->freelist;
- bp->freelist = bh;
- restore_flags(flags);
-}
-
-void
-BufQueueLink(struct BufQueue *bq,
- struct BufHeader *bh)
-{
- unsigned long flags;
-
- save_flags(flags);
- cli();
- if (!bq->head)
- bq->head = bh;
- if (bq->tail)
- bq->tail->next = bh;
- bq->tail = bh;
- bh->next = NULL;
- restore_flags(flags);
-}
-
-void
-BufQueueLinkFront(struct BufQueue *bq,
- struct BufHeader *bh)
-{
- unsigned long flags;
-
- save_flags(flags);
- cli();
- bh->next = bq->head;
- bq->head = bh;
- if (!bq->tail)
- bq->tail = bh;
- restore_flags(flags);
-}
-
-int
-BufQueueUnlink(struct BufHeader **bh, struct BufQueue *bq)
-{
- long flags;
-
- save_flags(flags);
- cli();
-
- if (bq->head) {
- if (bq->tail == bq->head)
- bq->tail = NULL;
- *bh = bq->head;
- bq->head = (*bh)->next;
- restore_flags(flags);
- return (0);
- } else {
- restore_flags(flags);
- return (-1);
- }
-}
-
-void
-BufQueueInit(struct BufQueue *bq)
-{
-#ifdef DEBUG_MAGIC
- bq->magic = 030167;
-#endif
- bq->head = NULL;
- bq->tail = NULL;
-}
-
-void
-BufQueueRelease(struct BufQueue *bq)
-{
- struct BufHeader *bh;
-
- while (bq->head) {
- BufQueueUnlink(&bh, bq);
- BufPoolRelease(bh);
- }
-}
-
-int
-BufQueueLength(struct BufQueue *bq)
-{
- int i = 0;
- struct BufHeader *bh;
-
- bh = bq->head;
- while (bh) {
- i++;
- bh = bh->next;
- }
- return (i);
-}
-
-void
-BufQueueDiscard(struct BufQueue *q, int pr, void *heldby,
- int releasetoo)
-{
- long flags;
- struct BufHeader *sp;
-
- save_flags(flags);
- cli();
-
- while (!0) {
- sp = q->head;
- if (!sp)
- break;
- if ((sp->primitive == pr) && (sp->heldby == heldby)) {
- q->head = sp->next;
- if (q->tail == sp)
- q->tail = NULL;
- if (releasetoo)
- BufPoolRelease(sp);
- } else
- break;
- }
-
- sp = q->head;
- if (sp)
- while (sp->next) {
- if ((sp->next->primitive == pr) && (sp->next->heldby == heldby)) {
- if (q->tail == sp->next)
- q->tail = sp;
- if (releasetoo)
- BufPoolRelease(sp->next);
- sp->next = sp->next->next;
- } else
- sp = sp->next;
- }
- restore_flags(flags);
-}
-
-void
-Sfree(byte * ptr)
-{
-#if 0
- printk(KERN_DEBUG "Sfree %x\n", ptr);
-#endif
- kfree(ptr);
-}
-
-byte *
-Smalloc(int size, int pr, char *why)
-{
- byte *p;
-
- p = (byte *) kmalloc(size, pr);
-#if 0
- printk(KERN_DEBUG "Smalloc %s size %d res %x\n", why, size, p);
-#endif
- return (p);
-}
diff --git a/drivers/isdn/teles/callc.c b/drivers/isdn/teles/callc.c
deleted file mode 100644
index b065d5670..000000000
--- a/drivers/isdn/teles/callc.c
+++ /dev/null
@@ -1,1453 +0,0 @@
-/* $Id: callc.c,v 1.16 1997/02/11 01:39:46 keil Exp $
- *
- * $Log: callc.c,v $
- * Revision 1.16 1997/02/11 01:39:46 keil
- * Changed setup-interface (incoming and outgoing)
- *
- * Revision 1.15 1996/11/23 11:32:20 keil
- * windowsize = 7 X.75 bugfix Thanks to Martin Maurer
- *
- * Revision 1.14 1996/10/22 23:14:14 fritz
- * Changes for compatibility to 2.0.X and 2.1.X kernels.
- *
- * Revision 1.13 1996/06/24 17:15:55 fritz
- * corrected return code of teles_writebuf()
- *
- * Revision 1.12 1996/06/12 16:15:33 fritz
- * Extended user-configurable debugging flags.
- *
- * Revision 1.11 1996/06/07 12:32:20 fritz
- * More changes to support suspend/resume.
- *
- * Revision 1.10 1996/06/06 21:24:21 fritz
- * Started adding support for suspend/resume.
- *
- * Revision 1.9 1996/05/31 12:23:57 jdenoud
- * Jan: added channel open check to teles_writebuf
- *
- * Revision 1.8 1996/05/31 01:00:38 fritz
- * Changed return code of teles_writebuf, when out of memory.
- *
- * Revision 1.7 1996/05/17 03:40:37 fritz
- * General cleanup.
- *
- * Revision 1.6 1996/05/10 22:42:07 fritz
- * Added entry for EV_RELEASE_CNF in ST_OUT (if no D-Channel avail.)
- *
- * Revision 1.5 1996/05/06 10:16:15 fritz
- * Added voice stuff.
- *
- * Revision 1.4 1996/04/30 22:04:05 isdn4dev
- * improved callback Karsten Keil
- *
- * Revision 1.3 1996/04/30 10:04:19 fritz
- * Started voice support.
- * Added printk() to debug-switcher for easier
- * synchronization between printk()'s and output
- * of /dev/isdnctrl.
- *
- * Revision 1.2 1996/04/20 16:42:29 fritz
- * Changed statemachine to allow reject of incoming calls.
- *
- * Revision 1.1 1996/04/13 10:20:59 fritz
- * Initial revision
- *
- *
- */
-#define __NO_VERSION__
-#include "teles.h"
-
-extern struct IsdnCard cards[];
-extern int nrcards;
-extern int drid;
-extern isdn_if iif;
-extern void teles_mod_dec_use_count(void);
-extern void teles_mod_inc_use_count(void);
-
-static int init_ds(int chan, int incoming);
-static void release_ds(int chan);
-
-static struct Fsm callcfsm =
-{NULL, 0, 0}, lcfsm =
-{NULL, 0, 0};
-
-struct Channel *chanlist;
-static int chancount = 0;
-unsigned int debugflags = 0;
-
-#define TMR_DCHAN_EST 2000
-
-static void
-stat_debug(struct Channel *chanp, char *s)
-{
- char tmp[100], tm[32];
-
- jiftime(tm, jiffies);
- sprintf(tmp, "%s Channel %d HL->LL %s\n", tm, chanp->chan, s);
- teles_putstatus(tmp);
-}
-
-enum {
- ST_NULL, /* 0 inactive */
- ST_OUT, /* 1 outgoing, awaiting SETUP confirm */
- ST_CLEAR, /* 2 call release, awaiting RELEASE confirm */
- ST_OUT_W, /* 3 outgoing, awaiting d-channel establishment */
- ST_REL_W, /* 4 awaiting d-channel release */
- ST_IN_W, /* 5 incoming, awaiting d-channel establishment */
- ST_IN, /* 6 incoming call received */
- ST_IN_SETUP, /* 7 incoming, SETUP response sent */
- ST_IN_DACT, /* 8 incoming connected, no b-channel prot. */
- ST_OUT_ESTB, /* 10 outgoing connected, awaiting b-channel prot. estbl. */
- ST_ACTIVE, /* 11 active, b channel prot. established */
- ST_BC_HANGUP, /* 12 call clear. (initiator), awaiting b channel prot. rel. */
- ST_PRO_W, /* 13 call clear. (initiator), DISCONNECT req. sent */
- ST_ANT_W, /* 14 call clear. (receiver), awaiting DISCONNECT ind. */
- ST_DISC_BC_HANGUP, /* d channel gone, wait for b channel deactivation */
- ST_OUT_W_HANGUP, /* Outgoing waiting for D-Channel hangup received */
- ST_D_ERR, /* d channel released while active */
-};
-
-#define STATE_COUNT (ST_D_ERR+1)
-
-static char *strState[] =
-{
- "ST_NULL",
- "ST_OUT",
- "ST_CLEAR",
- "ST_OUT_W",
- "ST_REL_W",
- "ST_IN_W",
- "ST_IN",
- "ST_IN_SETUP",
- "ST_IN_DACT",
- "ST_OUT_ESTB",
- "ST_ACTIVE",
- "ST_BC_HANGUP",
- "ST_PRO_W",
- "ST_ANT_W",
- "ST_DISC_BC_HANGUP",
- "ST_OUT_W_HANGUP",
- "ST_D_ERR",
-};
-
-enum {
- EV_DIAL, /* 0 */
- EV_SETUP_CNF, /* 1 */
- EV_ACCEPTB, /* 2 */
- EV_DISCONNECT_CNF, /* 5 */
- EV_DISCONNECT_IND, /* 6 */
- EV_RELEASE_CNF, /* 7 */
- EV_DLEST, /* 8 */
- EV_DLRL, /* 9 */
- EV_SETUP_IND, /* 10 */
- EV_RELEASE_IND, /* 11 */
- EV_ACCEPTD, /* 12 */
- EV_SETUP_CMPL_IND, /* 13 */
- EV_BC_EST, /* 14 */
- EV_WRITEBUF, /* 15 */
- EV_DATAIN, /* 16 */
- EV_HANGUP, /* 17 */
- EV_BC_REL, /* 18 */
- EV_CINF, /* 19 */
- EV_SUSPEND, /* 20 */
- EV_RESUME, /* 21 */
-};
-
-#define EVENT_COUNT (EV_CINF+1)
-
-static char *strEvent[] =
-{
- "EV_DIAL",
- "EV_SETUP_CNF",
- "EV_ACCEPTB",
- "EV_DISCONNECT_CNF",
- "EV_DISCONNECT_IND",
- "EV_RELEASE_CNF",
- "EV_DLEST",
- "EV_DLRL",
- "EV_SETUP_IND",
- "EV_RELEASE_IND",
- "EV_ACCEPTD",
- "EV_SETUP_CMPL_IND",
- "EV_BC_EST",
- "EV_WRITEBUF",
- "EV_DATAIN",
- "EV_HANGUP",
- "EV_BC_REL",
- "EV_CINF",
- "EV_SUSPEND",
- "EV_RESUME",
-};
-
-enum {
- ST_LC_NULL,
- ST_LC_ACTIVATE_WAIT,
- ST_LC_DELAY,
- ST_LC_ESTABLISH_WAIT,
- ST_LC_CONNECTED,
- ST_LC_RELEASE_WAIT,
-};
-
-#define LC_STATE_COUNT (ST_LC_RELEASE_WAIT+1)
-
-static char *strLcState[] =
-{
- "ST_LC_NULL",
- "ST_LC_ACTIVATE_WAIT",
- "ST_LC_DELAY",
- "ST_LC_ESTABLISH_WAIT",
- "ST_LC_CONNECTED",
- "ST_LC_RELEASE_WAIT",
-};
-
-enum {
- EV_LC_ESTABLISH,
- EV_LC_PH_ACTIVATE,
- EV_LC_PH_DEACTIVATE,
- EV_LC_DL_ESTABLISH,
- EV_LC_TIMER,
- EV_LC_DL_RELEASE,
- EV_LC_RELEASE,
-};
-
-#define LC_EVENT_COUNT (EV_LC_RELEASE+1)
-
-static char *strLcEvent[] =
-{
- "EV_LC_ESTABLISH",
- "EV_LC_PH_ACTIVATE",
- "EV_LC_PH_DEACTIVATE",
- "EV_LC_DL_ESTABLISH",
- "EV_LC_TIMER",
- "EV_LC_DL_RELEASE",
- "EV_LC_RELEASE",
-};
-
-#define LC_D 0
-#define LC_B 1
-
-/*
- * Dial out
- */
-static void
-r1(struct FsmInst *fi, int event, void *arg)
-{
- isdn_ctrl *ic = arg;
- struct Channel *chanp = fi->userdata;
-
- chanp->para.setup = ic->parm.setup;
- if (!strcmp(chanp->para.setup.eazmsn, "0"))
- chanp->para.setup.eazmsn[0] = '\0';
-
- chanp->l2_active_protocol = chanp->l2_protocol;
- chanp->incoming = 0;
- chanp->lc_b.l2_start = !0;
-
- switch (chanp->l2_active_protocol) {
- case (ISDN_PROTO_L2_X75I):
- chanp->lc_b.l2_establish = !0;
- break;
- case (ISDN_PROTO_L2_HDLC):
- case (ISDN_PROTO_L2_TRANS):
- chanp->lc_b.l2_establish = 0;
- break;
- default:
- printk(KERN_WARNING "r1 unknown protocol\n");
- break;
- }
-
- FsmChangeState(fi, ST_OUT_W);
- FsmEvent(&chanp->lc_d.lcfi, EV_LC_ESTABLISH, NULL);
-}
-
-static void
-ll_hangup(struct Channel *chanp, int bchantoo)
-{
- isdn_ctrl ic;
-
- if (bchantoo) {
- if (chanp->debug & 1)
- stat_debug(chanp, "STAT_BHUP");
- ic.driver = drid;
- ic.command = ISDN_STAT_BHUP;
- ic.arg = chanp->chan;
- iif.statcallb(&ic);
- }
- if (chanp->debug & 1)
- stat_debug(chanp, "STAT_DHUP");
- ic.driver = drid;
- ic.command = ISDN_STAT_DHUP;
- ic.arg = chanp->chan;
- iif.statcallb(&ic);
-}
-
-static void
-r2(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- chanp->is.l4.l4l3(&chanp->is, CC_RELEASE_REQ, NULL);
-
- FsmChangeState(fi, ST_CLEAR);
- ll_hangup(chanp, 0);
-}
-
-
-static void
-r2_1(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- chanp->is.l4.l4l3(&chanp->is, CC_DISCONNECT_REQ, NULL);
-
- FsmChangeState(fi, ST_OUT_W_HANGUP);
-}
-
-
-static void
-r2_2(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- FsmChangeState(fi, ST_REL_W);
- FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL);
- ll_hangup(chanp, 0);
-}
-
-
-static void
-r3(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL);
- FsmChangeState(fi, ST_REL_W);
-}
-
-
-static void
-r3_1(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- chanp->is.l4.l4l3(&chanp->is,CC_DLRL,NULL);
-
- FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL);
- FsmChangeState(fi, ST_REL_W);
- ll_hangup(chanp, 0);
-}
-
-
-static void
-r4(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp=fi->userdata;
-
- chanp->is.l4.l4l3(&chanp->is,CC_DLRL,NULL);
- FsmChangeState(fi, ST_NULL);
-}
-
-static void
-r5(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- chanp->para.callref = chanp->outcallref;
-
- chanp->outcallref++;
- if (chanp->outcallref == 128)
- chanp->outcallref = 64;
-
- chanp->is.l4.l4l3(&chanp->is, CC_SETUP_REQ, NULL);
-
- FsmChangeState(fi, ST_OUT);
-}
-
-static void
-r6(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- FsmChangeState(fi, ST_IN_W);
- FsmEvent(&chanp->lc_d.lcfi, EV_LC_ESTABLISH, NULL);
-}
-
-static void
-r7(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
- isdn_ctrl ic;
-
- /*
- * Report incoming calls only once to linklevel, use octet 3 of
- * channel identification information element. (it's value
- * is copied to chanp->para.bchannel in l3s12(), file isdnl3.c)
- */
- if (((chanp->chan & 1) + 1) & chanp->para.bchannel) {
- chanp->is.l4.l4l3(&chanp->is, CC_ALERTING_REQ, NULL);
- FsmChangeState(fi, ST_IN);
- if (chanp->debug & 1)
- stat_debug(chanp, "STAT_ICALL");
- ic.driver = drid;
- ic.command = ISDN_STAT_ICALL;
- ic.arg = chanp->chan;
- /*
- * No need to return "unknown" for calls without OAD,
- * cause that's handled in linklevel now (replaced by '0')
- */
- ic.parm.setup = chanp->para.setup;
- iif.statcallb(&ic);
- } else {
- chanp->is.l4.l4l3(&chanp->is,CC_DLRL,NULL);
- FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL);
- FsmChangeState(fi, ST_REL_W);
- }
-}
-
-static void
-r8(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- FsmChangeState(fi, ST_IN_SETUP);
- chanp->is.l4.l4l3(&chanp->is, CC_SETUP_RSP, NULL);
-
-}
-
-static void
-r9(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- FsmChangeState(fi, ST_IN_DACT);
-
- chanp->l2_active_protocol = chanp->l2_protocol;
- chanp->incoming = !0;
- chanp->lc_b.l2_start = 0;
-
- switch (chanp->l2_active_protocol) {
- case (ISDN_PROTO_L2_X75I):
- chanp->lc_b.l2_establish = !0;
- break;
- case (ISDN_PROTO_L2_HDLC):
- case (ISDN_PROTO_L2_TRANS):
- chanp->lc_b.l2_establish = 0;
- break;
- default:
- printk(KERN_WARNING "r9 unknown protocol\n");
- break;
- }
-
- init_ds(chanp->chan, !0);
-
- FsmEvent(&chanp->lc_b.lcfi, EV_LC_ESTABLISH, NULL);
-}
-
-static void
-r10(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- FsmChangeState(fi, ST_OUT_ESTB);
-
- init_ds(chanp->chan, 0);
- FsmEvent(&chanp->lc_b.lcfi, EV_LC_ESTABLISH, NULL);
-
-}
-
-static void
-r12(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
- isdn_ctrl ic;
-
- FsmChangeState(fi, ST_ACTIVE);
- chanp->data_open = !0;
-
- if (chanp->debug & 1)
- stat_debug(chanp, "STAT_DCONN");
- ic.driver = drid;
- ic.command = ISDN_STAT_DCONN;
- ic.arg = chanp->chan;
- iif.statcallb(&ic);
-
- if (chanp->debug & 1)
- stat_debug(chanp, "STAT_BCONN");
- ic.driver = drid;
- ic.command = ISDN_STAT_BCONN;
- ic.arg = chanp->chan;
- iif.statcallb(&ic);
-}
-
-static void
-r15(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- chanp->data_open = 0;
- FsmChangeState(fi, ST_BC_HANGUP);
- FsmEvent(&chanp->lc_b.lcfi, EV_LC_RELEASE, NULL);
-}
-
-static void
-r16(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- release_ds(chanp->chan);
-
- FsmChangeState(fi, ST_PRO_W);
- chanp->is.l4.l4l3(&chanp->is, CC_DISCONNECT_REQ, NULL);
-}
-
-static void
-r17(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- chanp->data_open = 0;
- release_ds(chanp->chan);
-
- FsmChangeState(fi, ST_ANT_W);
-}
-
-
-static void
-r17_1(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- chanp->data_open = 0;
- release_ds(chanp->chan);
-
- chanp->is.l4.l4l3(&chanp->is,CC_DLRL,NULL);
-
- FsmEvent(&chanp->lc_d.lcfi,EV_LC_RELEASE,NULL);
-
- FsmChangeState(fi, ST_NULL);
-
- ll_hangup(chanp,!0);
-}
-
-static void
-r18(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- FsmChangeState(fi, ST_REL_W);
- FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL);
-
- ll_hangup(chanp, !0);
-}
-
-static void
-r19(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- FsmChangeState(fi, ST_CLEAR);
-
- chanp->is.l4.l4l3(&chanp->is, CC_RELEASE_REQ, NULL);
-
- ll_hangup(chanp, !0);
-}
-
-static void
-r20(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- chanp->is.l4.l4l3(&chanp->is,CC_DLRL,NULL);
-
- FsmEvent(&chanp->lc_d.lcfi,EV_LC_RELEASE,NULL);
-
- FsmChangeState(fi, ST_NULL);
-
- ll_hangup(chanp, 0);
-}
-
-
-static void
-r21(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- chanp->data_open = 0;
- FsmChangeState(fi, ST_DISC_BC_HANGUP);
- FsmEvent(&chanp->lc_b.lcfi, EV_LC_RELEASE, NULL);
-}
-
-static void
-r22(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- release_ds(chanp->chan);
-
- FsmChangeState(fi, ST_CLEAR);
-
- chanp->is.l4.l4l3(&chanp->is, CC_RELEASE_REQ, NULL);
-
- ll_hangup(chanp, !0);
-}
-
-static void
-r23(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- release_ds(chanp->chan);
-
- FsmChangeState(fi, ST_PRO_W);
- chanp->is.l4.l4l3(&chanp->is, CC_DISCONNECT_REQ, NULL);
-}
-
-static void
-r23_1(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- release_ds(chanp->chan);
-
- chanp->is.l4.l4l3(&chanp->is, CC_DLRL,NULL);
-
- FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE,NULL);
-
- FsmChangeState(fi, ST_NULL);
-
- ll_hangup(chanp,!0);
-}
-
-static void
-r24(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- chanp->data_open = 0;
- FsmChangeState(fi, ST_D_ERR);
- FsmEvent(&chanp->lc_b.lcfi, EV_LC_RELEASE, NULL);
-}
-
-static void
-r25(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- release_ds(chanp->chan);
-
- FsmChangeState(fi, ST_NULL);
-
- ll_hangup(chanp, !0);
-}
-
-static void
-r26(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
- isdn_ctrl ic;
-
-
- ic.driver = drid;
- ic.command = ISDN_STAT_CINF;
- ic.arg = chanp->chan;
- sprintf(ic.parm.num, "%d", chanp->para.chargeinfo);
- iif.statcallb(&ic);
-}
-
-
-
-static struct FsmNode fnlist[] =
-{
- {ST_NULL, EV_DIAL, r1},
- {ST_OUT_W, EV_DLEST, r5},
- {ST_OUT_W, EV_DLRL, r20},
- {ST_OUT_W, EV_RELEASE_CNF, r2_2 },
- {ST_OUT, EV_DISCONNECT_IND, r2},
- {ST_OUT, EV_SETUP_CNF, r10},
- {ST_OUT, EV_HANGUP, r2_1},
- {ST_OUT, EV_RELEASE_IND, r20},
- {ST_OUT, EV_RELEASE_CNF, r20},
- {ST_OUT, EV_DLRL, r2_2},
- {ST_OUT_W_HANGUP, EV_RELEASE_IND, r2_2},
- {ST_OUT_W_HANGUP, EV_DLRL, r20},
- {ST_CLEAR, EV_RELEASE_CNF, r3},
- {ST_CLEAR, EV_DLRL, r20},
- {ST_REL_W, EV_DLRL, r4},
- {ST_NULL, EV_SETUP_IND, r6},
- {ST_IN_W, EV_DLEST, r7},
- {ST_IN_W, EV_DLRL, r3_1},
- {ST_IN, EV_DLRL, r3_1},
- {ST_IN, EV_HANGUP, r2_1},
- {ST_IN, EV_RELEASE_IND, r2_2},
- {ST_IN, EV_RELEASE_CNF, r2_2},
- {ST_IN, EV_ACCEPTD, r8},
- {ST_IN_SETUP, EV_HANGUP, r2_1},
- {ST_IN_SETUP, EV_SETUP_CMPL_IND, r9},
- {ST_IN_SETUP, EV_RELEASE_IND, r2_2},
- {ST_IN_SETUP, EV_DISCONNECT_IND, r2},
- {ST_IN_SETUP, EV_DLRL, r20},
- {ST_OUT_ESTB, EV_BC_EST, r12},
- {ST_OUT_ESTB, EV_BC_REL, r23},
- {ST_OUT_ESTB, EV_DLRL, r23_1},
- {ST_IN_DACT, EV_BC_EST, r12},
- {ST_IN_DACT, EV_BC_REL, r17},
- {ST_IN_DACT, EV_DLRL, r17_1},
- {ST_ACTIVE, EV_HANGUP, r15},
- {ST_ACTIVE, EV_BC_REL, r17},
- {ST_ACTIVE, EV_DISCONNECT_IND, r21},
- {ST_ACTIVE, EV_DLRL, r24},
- {ST_ACTIVE, EV_CINF, r26},
- {ST_ACTIVE, EV_RELEASE_IND, r17},
- {ST_BC_HANGUP, EV_BC_REL, r16},
- {ST_BC_HANGUP, EV_DISCONNECT_IND, r21},
- {ST_PRO_W, EV_RELEASE_IND, r18},
- {ST_ANT_W, EV_DISCONNECT_IND, r19},
- {ST_DISC_BC_HANGUP, EV_BC_REL, r22},
- {ST_D_ERR, EV_BC_REL, r25},
-};
-
-#define FNCOUNT (sizeof(fnlist)/sizeof(struct FsmNode))
-
-static void
-lc_r1(struct FsmInst *fi, int event, void *arg)
-{
- struct LcFsm *lf = fi->userdata;
-
- FsmChangeState(fi, ST_LC_ACTIVATE_WAIT);
- FsmAddTimer(&lf->act_timer, 1000, EV_LC_TIMER, NULL, 50);
- lf->st->ma.manl1(lf->st, PH_ACTIVATE, NULL);
-
-}
-
-static void
-lc_r6(struct FsmInst *fi, int event, void *arg)
-{
- struct LcFsm *lf = fi->userdata;
-
- FsmDelTimer(&lf->act_timer, 50);
- FsmChangeState(fi, ST_LC_DELAY);
- FsmAddTimer(&lf->act_timer, 40, EV_LC_TIMER, NULL, 51);
-}
-
-static void
-lc_r2(struct FsmInst *fi, int event, void *arg)
-{
- struct LcFsm *lf = fi->userdata;
-
- if (lf->l2_establish) {
- FsmChangeState(fi, ST_LC_ESTABLISH_WAIT);
- if (lf->l2_start)
- lf->st->ma.manl2(lf->st, DL_ESTABLISH, NULL);
- } else {
- FsmChangeState(fi, ST_LC_CONNECTED);
- lf->lccall(lf, LC_ESTABLISH, NULL);
- }
-}
-
-static void
-lc_r3(struct FsmInst *fi, int event, void *arg)
-{
- struct LcFsm *lf = fi->userdata;
-
- FsmChangeState(fi, ST_LC_CONNECTED);
- lf->lccall(lf, LC_ESTABLISH, NULL);
-}
-
-static void
-lc_r4(struct FsmInst *fi, int event, void *arg)
-{
- struct LcFsm *lf = fi->userdata;
-
- if (lf->l2_establish) {
- FsmChangeState(fi, ST_LC_RELEASE_WAIT);
- lf->st->ma.manl2(lf->st, DL_RELEASE, NULL);
- } else {
- FsmChangeState(fi, ST_LC_NULL);
- lf->st->ma.manl1(lf->st, PH_DEACTIVATE, NULL);
- lf->lccall(lf, LC_RELEASE, NULL);
- }
-}
-
-static void
-lc_r5(struct FsmInst *fi, int event, void *arg)
-{
- struct LcFsm *lf = fi->userdata;
-
- FsmChangeState(fi, ST_LC_NULL);
- lf->st->ma.manl1(lf->st, PH_DEACTIVATE, NULL);
- lf->lccall(lf, LC_RELEASE, NULL);
-}
-
-static struct FsmNode LcFnList[] =
-{
- {ST_LC_NULL, EV_LC_ESTABLISH, lc_r1},
- {ST_LC_ACTIVATE_WAIT, EV_LC_PH_ACTIVATE, lc_r6},
- {ST_LC_DELAY, EV_LC_TIMER, lc_r2},
- {ST_LC_ESTABLISH_WAIT, EV_LC_DL_ESTABLISH, lc_r3},
- {ST_LC_CONNECTED, EV_LC_RELEASE, lc_r4},
- {ST_LC_CONNECTED, EV_LC_DL_RELEASE, lc_r5},
- {ST_LC_RELEASE_WAIT, EV_LC_DL_RELEASE, lc_r5},
- {ST_LC_ACTIVATE_WAIT, EV_LC_TIMER, lc_r5},
- {ST_LC_ESTABLISH_WAIT, EV_LC_DL_RELEASE, lc_r5},
-};
-
-#define LC_FN_COUNT (sizeof(LcFnList)/sizeof(struct FsmNode))
-
-void
-CallcNew(void)
-{
- callcfsm.state_count = STATE_COUNT;
- callcfsm.event_count = EVENT_COUNT;
- callcfsm.strEvent = strEvent;
- callcfsm.strState = strState;
- FsmNew(&callcfsm, fnlist, FNCOUNT);
-
- lcfsm.state_count = LC_STATE_COUNT;
- lcfsm.event_count = LC_EVENT_COUNT;
- lcfsm.strEvent = strLcEvent;
- lcfsm.strState = strLcState;
- FsmNew(&lcfsm, LcFnList, LC_FN_COUNT);
-}
-
-void
-CallcFree(void)
-{
- FsmFree(&lcfsm);
- FsmFree(&callcfsm);
-}
-
-static void
-release_ds(int chan)
-{
- struct PStack *st = &chanlist[chan].ds;
- struct IsdnCardState *sp;
- struct HscxState *hsp;
-
- sp = st->l1.hardware;
- hsp = sp->hs + chanlist[chan].hscx;
-
- close_hscxstate(hsp);
-
- switch (chanlist[chan].l2_active_protocol) {
- case (ISDN_PROTO_L2_X75I):
- releasestack_isdnl2(st);
- break;
- case (ISDN_PROTO_L2_HDLC):
- case (ISDN_PROTO_L2_TRANS):
- releasestack_transl2(st);
- break;
- }
-}
-
-static void
-cc_l1man(struct PStack *st, int pr, void *arg)
-{
- struct Channel *chanp = (struct Channel *) st->l4.userdata;
-
- switch (pr) {
- case (PH_ACTIVATE):
- FsmEvent(&chanp->lc_d.lcfi, EV_LC_PH_ACTIVATE, NULL);
- break;
- case (PH_DEACTIVATE):
- FsmEvent(&chanp->lc_d.lcfi, EV_LC_PH_DEACTIVATE, NULL);
- break;
- }
-}
-
-static void
-cc_l2man(struct PStack *st, int pr, void *arg)
-{
- struct Channel *chanp = (struct Channel *) st->l4.userdata;
-
- switch (pr) {
- case (DL_ESTABLISH):
- FsmEvent(&chanp->lc_d.lcfi, EV_LC_DL_ESTABLISH, NULL);
- break;
- case (DL_RELEASE):
- FsmEvent(&chanp->lc_d.lcfi, EV_LC_DL_RELEASE, NULL);
- break;
- }
-}
-
-static void
-dcc_l1man(struct PStack *st, int pr, void *arg)
-{
- struct Channel *chanp = (struct Channel *) st->l4.userdata;
-
- switch (pr) {
- case (PH_ACTIVATE):
- FsmEvent(&chanp->lc_b.lcfi, EV_LC_PH_ACTIVATE, NULL);
- break;
- case (PH_DEACTIVATE):
- FsmEvent(&chanp->lc_b.lcfi, EV_LC_PH_DEACTIVATE, NULL);
- break;
- }
-}
-
-static void
-dcc_l2man(struct PStack *st, int pr, void *arg)
-{
- struct Channel *chanp = (struct Channel *) st->l4.userdata;
-
- switch (pr) {
- case (DL_ESTABLISH):
- FsmEvent(&chanp->lc_b.lcfi, EV_LC_DL_ESTABLISH, NULL);
- break;
- case (DL_RELEASE):
- FsmEvent(&chanp->lc_b.lcfi, EV_LC_DL_RELEASE, NULL);
- break;
- }
-}
-
-static void
-ll_handler(struct PStack *st, int pr,
- struct BufHeader *ibh)
-{
- struct Channel *chanp = (struct Channel *) st->l4.userdata;
-
- switch (pr) {
- case (CC_DISCONNECT_IND):
- FsmEvent(&chanp->fi, EV_DISCONNECT_IND, NULL);
- break;
- case (CC_RELEASE_CNF):
- FsmEvent(&chanp->fi, EV_RELEASE_CNF, NULL);
- break;
- case (CC_SETUP_IND):
- FsmEvent(&chanp->fi, EV_SETUP_IND, NULL);
- break;
- case (CC_RELEASE_IND):
- FsmEvent(&chanp->fi, EV_RELEASE_IND, NULL);
- break;
- case (CC_SETUP_COMPLETE_IND):
- FsmEvent(&chanp->fi, EV_SETUP_CMPL_IND, NULL);
- break;
- case (CC_SETUP_CNF):
- FsmEvent(&chanp->fi, EV_SETUP_CNF, NULL);
- break;
- case (CC_INFO_CHARGE):
- FsmEvent(&chanp->fi, EV_CINF, NULL);
- break;
- }
-}
-
-static void
-init_is(int chan, unsigned int ces)
-{
- struct PStack *st = &(chanlist[chan].is);
- struct IsdnCardState *sp = chanlist[chan].sp;
- char tmp[128];
-
- setstack_teles(st, sp);
-
- st->l2.sap = 0;
-
- st->l2.tei = 255;
-
- st->l2.ces = ces;
- st->l2.extended = !0;
- st->l2.laptype = LAPD;
- st->l2.window = 1;
- st->l2.orig = !0;
- st->l2.t200 = 1000; /* 1000 milliseconds */
- if (st->protocol == ISDN_PTYPE_1TR6) {
- st->l2.n200 = 3; /* try 3 times */
- st->l2.t203 = 10000; /* 10000 milliseconds */
- } else {
- st->l2.n200 = 4; /* try 4 times */
- st->l2.t203 = 5000; /* 5000 milliseconds */
- }
-
- sprintf(tmp, "Channel %d q.921", chan);
- setstack_isdnl2(st, tmp);
- setstack_isdnl3(st);
- st->l2.debug = 2;
- st->l3.debug = 2;
- st->l2.debug = 0xff;
- st->l3.debug = 0xff;
- st->l4.userdata = chanlist + chan;
- st->l4.l2writewakeup = NULL;
-
- st->l3.l3l4 = ll_handler;
- st->l1.l1man = cc_l1man;
- st->l2.l2man = cc_l2man;
-
- st->pa = &chanlist[chan].para;
- teles_addlist(sp, st);
-}
-
-static void
-callc_debug(struct FsmInst *fi, char *s)
-{
- char str[80], tm[32];
- struct Channel *chanp = fi->userdata;
-
- jiftime(tm, jiffies);
- sprintf(str, "%s Channel %d callc %s\n", tm, chanp->chan, s);
- teles_putstatus(str);
-}
-
-static void
-lc_debug(struct FsmInst *fi, char *s)
-{
- char str[256], tm[32];
- struct LcFsm *lf = fi->userdata;
-
- jiftime(tm, jiffies);
- sprintf(str, "%s Channel %d lc %s\n", tm, lf->ch->chan, s);
- teles_putstatus(str);
-}
-
-static void
-dlc_debug(struct FsmInst *fi, char *s)
-{
- char str[256], tm[32];
- struct LcFsm *lf = fi->userdata;
-
- jiftime(tm, jiffies);
- sprintf(str, "%s Channel %d dlc %s\n", tm, lf->ch->chan, s);
- teles_putstatus(str);
-}
-
-static void
-lccall_d(struct LcFsm *lf, int pr, void *arg)
-{
- struct Channel *chanp = lf->ch;
-
- switch (pr) {
- case (LC_ESTABLISH):
- FsmEvent(&chanp->fi, EV_DLEST, NULL);
- break;
- case (LC_RELEASE):
- FsmEvent(&chanp->fi, EV_DLRL, NULL);
- break;
- }
-}
-
-static void
-lccall_b(struct LcFsm *lf, int pr, void *arg)
-{
- struct Channel *chanp = lf->ch;
-
- switch (pr) {
- case (LC_ESTABLISH):
- FsmEvent(&chanp->fi, EV_BC_EST, NULL);
- break;
- case (LC_RELEASE):
- FsmEvent(&chanp->fi, EV_BC_REL, NULL);
- break;
- }
-}
-
-static void
-init_chan(int chan, int cardnr, int hscx,
- unsigned int ces)
-{
- struct IsdnCard *card = cards + cardnr;
- struct Channel *chanp = chanlist + chan;
-
- chanp->sp = card->sp;
- chanp->hscx = hscx;
- chanp->chan = chan;
- chanp->incoming = 0;
- chanp->debug = 0;
- init_is(chan, ces);
-
- chanp->fi.fsm = &callcfsm;
- chanp->fi.state = ST_NULL;
- chanp->fi.debug = 0;
- chanp->fi.userdata = chanp;
- chanp->fi.printdebug = callc_debug;
-
- chanp->lc_d.lcfi.fsm = &lcfsm;
- chanp->lc_d.lcfi.state = ST_LC_NULL;
- chanp->lc_d.lcfi.debug = 0;
- chanp->lc_d.lcfi.userdata = &chanp->lc_d;
- chanp->lc_d.lcfi.printdebug = lc_debug;
- chanp->lc_d.type = LC_D;
- chanp->lc_d.ch = chanp;
- chanp->lc_d.st = &chanp->is;
- chanp->lc_d.l2_establish = !0;
- chanp->lc_d.l2_start = !0;
- chanp->lc_d.lccall = lccall_d;
- FsmInitTimer(&chanp->lc_d.lcfi, &chanp->lc_d.act_timer);
-
- chanp->lc_b.lcfi.fsm = &lcfsm;
- chanp->lc_b.lcfi.state = ST_LC_NULL;
- chanp->lc_b.lcfi.debug = 0;
- chanp->lc_b.lcfi.userdata = &chanp->lc_b;
- chanp->lc_b.lcfi.printdebug = dlc_debug;
- chanp->lc_b.type = LC_B;
- chanp->lc_b.ch = chanp;
- chanp->lc_b.st = &chanp->ds;
- chanp->lc_b.l2_establish = !0;
- chanp->lc_b.l2_start = !0;
- chanp->lc_b.lccall = lccall_b;
- FsmInitTimer(&chanp->lc_b.lcfi, &chanp->lc_b.act_timer);
-
- chanp->outcallref = 64;
- chanp->data_open = 0;
-}
-
-int
-CallcNewChan(void)
-{
- int i, ces, c;
-
- chancount = 0;
- for (i = 0; i < nrcards; i++)
- if (cards[i].sp)
- chancount += 2;
-
- chanlist = (struct Channel *) Smalloc(sizeof(struct Channel) *
- chancount, GFP_KERNEL, "chanlist");
-
- c = 0;
- ces = randomces();
- for (i = 0; i < nrcards; i++)
- if (cards[i].sp) {
- init_chan(c++, i, 1, ces++);
- ces %= 0xffff;
- init_chan(c++, i, 0, ces++);
- ces %= 0xffff;
- }
- printk(KERN_INFO "channels %d\n", chancount);
- return (chancount);
-
-}
-
-static void
-release_is(int chan)
-{
- struct PStack *st = &chanlist[chan].is;
-
- releasestack_isdnl2(st);
- teles_rmlist(st->l1.hardware, st);
- BufQueueRelease(&st->l2.i_queue);
-}
-
-void
-CallcFreeChan(void)
-{
- int i;
-
- for (i = 0; i < chancount; i++)
- release_is(i);
- Sfree((void *) chanlist);
-}
-
-static void
-lldata_handler(struct PStack *st, int pr,
- void *arg)
-{
- struct Channel *chanp = (struct Channel *) st->l4.userdata;
- byte *ptr;
- int size;
- struct BufHeader *ibh = arg;
-
- switch (pr) {
- case (DL_DATA):
- if (chanp->data_open) {
- ptr = DATAPTR(ibh);
- ptr += chanp->ds.l2.ihsize;
- size = ibh->datasize - chanp->ds.l2.ihsize;
- iif.rcvcallb(drid, chanp->chan, ptr, size);
- }
- BufPoolRelease(ibh);
- break;
- default:
- printk(KERN_WARNING "lldata_handler unknown primitive\n");
- break;
- }
-}
-
-static void
-lltrans_handler(struct PStack *st, int pr,
- struct BufHeader *ibh)
-{
- struct Channel *chanp = (struct Channel *) st->l4.userdata;
- byte *ptr;
-
- switch (pr) {
- case (PH_DATA):
- if (chanp->data_open) {
- ptr = DATAPTR(ibh);
- iif.rcvcallb(drid, chanp->chan, ptr, ibh->datasize);
- }
- BufPoolRelease(ibh);
- break;
- default:
- printk(KERN_WARNING "lltrans_handler unknown primitive\n");
- break;
- }
-}
-
-static void
-ll_writewakeup(struct PStack *st)
-{
- struct Channel *chanp = st->l4.userdata;
- isdn_ctrl ic;
-
- ic.driver = drid;
- ic.command = ISDN_STAT_BSENT;
- ic.arg = chanp->chan;
- iif.statcallb(&ic);
-}
-
-static int
-init_ds(int chan, int incoming)
-{
- struct PStack *st = &(chanlist[chan].ds);
- struct IsdnCardState *sp = (struct IsdnCardState *)
- chanlist[chan].is.l1.hardware;
- struct HscxState *hsp = sp->hs + chanlist[chan].hscx;
- char tmp[128];
-
- st->l1.hardware = sp;
-
- hsp->mode = 2;
- hsp->transbufsize = 4000;
-
- if (setstack_hscx(st, hsp))
- return (-1);
-
- st->l2.extended = 0;
- st->l2.laptype = LAPB;
- st->l2.orig = !incoming;
- st->l2.t200 = 1000; /* 1000 milliseconds */
- st->l2.window = 7;
- st->l2.n200 = 4; /* try 4 times */
- st->l2.t203 = 5000; /* 5000 milliseconds */
-
- st->l2.debug = 0xff;
- st->l3.debug = 0xff;
- switch (chanlist[chan].l2_active_protocol) {
- case (ISDN_PROTO_L2_X75I):
- sprintf(tmp, "Channel %d x.75", chan);
- setstack_isdnl2(st, tmp);
- st->l2.l2l3 = lldata_handler;
- st->l1.l1man = dcc_l1man;
- st->l2.l2man = dcc_l2man;
- st->l4.userdata = chanlist + chan;
- st->l4.l1writewakeup = NULL;
- st->l4.l2writewakeup = ll_writewakeup;
- st->l2.l2m.debug = debugflags & 16;
- st->ma.manl2(st, MDL_NOTEIPROC, NULL);
- st->l1.hscxmode = 2; /* Packet-Mode ? */
- st->l1.hscxchannel = chanlist[chan].para.bchannel - 1;
- break;
- case (ISDN_PROTO_L2_HDLC):
- st->l1.l1l2 = lltrans_handler;
- st->l1.l1man = dcc_l1man;
- st->l4.userdata = chanlist + chan;
- st->l4.l1writewakeup = ll_writewakeup;
- st->l1.hscxmode = 2;
- st->l1.hscxchannel = chanlist[chan].para.bchannel - 1;
- break;
- case (ISDN_PROTO_L2_TRANS):
- st->l1.l1l2 = lltrans_handler;
- st->l1.l1man = dcc_l1man;
- st->l4.userdata = chanlist + chan;
- st->l4.l1writewakeup = ll_writewakeup;
- st->l1.hscxmode = 1;
- st->l1.hscxchannel = chanlist[chan].para.bchannel - 1;
- break;
- }
-
- return (0);
-
-}
-
-static void
-channel_report(int i)
-{
-}
-
-static void
-command_debug(struct Channel *chanp, char *s)
-{
- char tmp[64], tm[32];
-
- jiftime(tm, jiffies);
- sprintf(tmp, "%s Channel %d LL->HL %s\n", tm, chanp->chan, s);
- teles_putstatus(tmp);
-}
-
-static void
-distr_debug(void)
-{
- int i;
-
- for (i = 0; i < chancount; i++) {
- chanlist[i].debug = debugflags & 1;
- chanlist[i].fi.debug = debugflags & 2;
- chanlist[i].is.l2.l2m.debug = debugflags & 8;
- chanlist[i].ds.l2.l2m.debug = debugflags & 16;
- }
- for (i = 0; i < nrcards; i++)
- if (cards[i].sp) {
- cards[i].sp->dlogflag = debugflags & 4;
- cards[i].sp->debug = debugflags & 32;
- }
-}
-
-int
-teles_command(isdn_ctrl * ic)
-{
- struct Channel *chanp;
- char tmp[64];
- int i;
- unsigned int num;
-
- switch (ic->command) {
- case (ISDN_CMD_SETEAZ):
- chanp = chanlist + ic->arg;
- if (chanp->debug & 1)
- command_debug(chanp, "SETEAZ");
- return (0);
- case (ISDN_CMD_DIAL):
- chanp = chanlist + (ic->arg & 0xff);
- if (chanp->debug & 1) {
- sprintf(tmp, "DIAL %s -> %s (%d,%d)",
- ic->parm.setup.eazmsn, ic->parm.setup.phone,
- ic->parm.setup.si1, ic->parm.setup.si2);
- command_debug(chanp, tmp);
- }
- FsmEvent(&chanp->fi, EV_DIAL, ic);
- return (0);
- case (ISDN_CMD_ACCEPTB):
- chanp = chanlist + ic->arg;
- if (chanp->debug & 1)
- command_debug(chanp, "ACCEPTB");
- FsmEvent(&chanp->fi, EV_ACCEPTB, NULL);
- break;
- case (ISDN_CMD_ACCEPTD):
- chanp = chanlist + ic->arg;
- if (chanp->debug & 1)
- command_debug(chanp, "ACCEPTD");
- FsmEvent(&chanp->fi, EV_ACCEPTD, NULL);
- break;
- case (ISDN_CMD_HANGUP):
- chanp = chanlist + ic->arg;
- if (chanp->debug & 1)
- command_debug(chanp, "HANGUP");
- FsmEvent(&chanp->fi, EV_HANGUP, NULL);
- break;
- case (ISDN_CMD_SUSPEND):
- chanp = chanlist + ic->arg;
- if (chanp->debug & 1) {
- sprintf(tmp, "SUSPEND %s", ic->parm.num);
- command_debug(chanp, tmp);
- }
- FsmEvent(&chanp->fi, EV_SUSPEND, ic);
- break;
- case (ISDN_CMD_RESUME):
- chanp = chanlist + ic->arg;
- if (chanp->debug & 1) {
- sprintf(tmp, "RESUME %s", ic->parm.num);
- command_debug(chanp, tmp);
- }
- FsmEvent(&chanp->fi, EV_RESUME, ic);
- break;
- case (ISDN_CMD_LOCK):
- teles_mod_inc_use_count();
- break;
- case (ISDN_CMD_UNLOCK):
- teles_mod_dec_use_count();
- break;
- case (ISDN_CMD_IOCTL):
- switch (ic->arg) {
- case (0):
- for (i = 0; i < nrcards; i++)
- if (cards[i].sp)
- teles_reportcard(i);
- for (i = 0; i < chancount; i++)
- channel_report(i);
- break;
- case (1):
- debugflags = *(unsigned int *) ic->parm.num;
- distr_debug();
- sprintf(tmp, "debugging flags set to %x\n", debugflags);
- teles_putstatus(tmp);
- printk(KERN_DEBUG "%s", tmp);
- break;
- case (2):
- num = *(unsigned int *) ic->parm.num;
- i = num >> 8;
- if (i >= chancount)
- break;
- chanp = chanlist + i;
- chanp->impair = num & 0xff;
- if (chanp->debug & 1) {
- sprintf(tmp, "IMPAIR %x", chanp->impair);
- command_debug(chanp, tmp);
- }
- break;
- }
- break;
- case (ISDN_CMD_SETL2):
- chanp = chanlist + (ic->arg & 0xff);
- if (chanp->debug & 1) {
- sprintf(tmp, "SETL2 %ld", ic->arg >> 8);
- command_debug(chanp, tmp);
- }
- chanp->l2_protocol = ic->arg >> 8;
- break;
- default:
- break;
- }
-
- return (0);
-}
-
-int
-teles_writebuf(int id, int chan, const u_char * buf, int count, int user)
-{
- struct Channel *chanp = chanlist + chan;
- struct PStack *st = &chanp->ds;
- struct BufHeader *ibh;
- int err, i;
- byte *ptr;
-
- if (!chanp->data_open) {
- printk(KERN_DEBUG "teles_writebuf: channel not open\n");
- return -EIO;
- }
-
- err = BufPoolGet(&ibh, st->l1.sbufpool, GFP_ATOMIC, st, 21);
- if (err)
- /* Must return 0 here, since this is not an error
- * but a temporary lack of resources.
- */
- return 0;
-
- ptr = DATAPTR(ibh);
- if (chanp->lc_b.l2_establish)
- i = st->l2.ihsize;
- else
- i = 0;
-
- if ((count+i) > BUFFER_SIZE(HSCX_SBUF_ORDER, HSCX_SBUF_BPPS)) {
- printk(KERN_WARNING "teles_writebuf: packet too large!\n");
- return (-EINVAL);
- }
-
- ptr += i;
-
- if (user)
- copy_from_user(ptr, buf, count);
- else
- memcpy(ptr, buf, count);
- ibh->datasize = count + i;
-
- if (chanp->data_open) {
- if (chanp->lc_b.l2_establish)
- chanp->ds.l3.l3l2(&chanp->ds, DL_DATA, ibh);
- else
- chanp->ds.l2.l2l1(&chanp->ds, PH_DATA, ibh);
- return (count);
- } else {
- BufPoolRelease(ibh);
- return (0);
- }
-
-}
diff --git a/drivers/isdn/teles/card.c b/drivers/isdn/teles/card.c
deleted file mode 100644
index 2ada8a29d..000000000
--- a/drivers/isdn/teles/card.c
+++ /dev/null
@@ -1,1900 +0,0 @@
-/* $Id: card.c,v 1.16 1996/10/22 23:14:16 fritz Exp $
- *
- * card.c low level stuff for the Teles S0 isdn card
- *
- * Author Jan den Ouden
- *
- * Beat Doebeli log all D channel traffic
- *
- * $Log: card.c,v $
- * Revision 1.16 1996/10/22 23:14:16 fritz
- * Changes for compatibility to 2.0.X and 2.1.X kernels.
- *
- * Revision 1.15 1996/09/29 19:41:56 fritz
- * Bugfix: ignore unknown frames.
- *
- * Revision 1.14 1996/09/23 01:53:49 fritz
- * Bugfix: discard unknown frames (non-EDSS1 and non-1TR6).
- *
- * Revision 1.13 1996/07/18 11:21:24 jdenoud
- * Use small buffers for incoming audio data
- *
- * Revision 1.12 1996/06/24 17:16:52 fritz
- * Added check for misconfigured membase.
- *
- * Revision 1.11 1996/06/14 03:30:37 fritz
- * Added recovery from EXIR 40 interrupt.
- * Some cleanup.
- *
- * Revision 1.10 1996/06/11 14:57:20 hipp
- * minor changes to ensure, that SKBs are sent in the right order
- *
- * Revision 1.9 1996/06/06 14:42:09 fritz
- * Bugfix: forgot hsp-> in last change.
- *
- * Revision 1.7 1996/05/31 01:02:21 fritz
- * Cosmetic changes.
- *
- * Revision 1.6 1996/05/26 14:58:10 fritz
- * Bugfix: Did not show port correctly, when no card found.
- *
- * Revision 1.5 1996/05/17 03:45:02 fritz
- * Made error messages more clearly.
- * Bugfix: Only 31 bytes of 32-byte audio frames
- * have been transfered to upper layers.
- *
- * Revision 1.4 1996/05/06 10:17:57 fritz
- * Added voice-send stuff
- * (Not reporting EXIR when in voice-mode, since it's normal).
- *
- * Revision 1.3 1996/04/30 22:02:40 isdn4dev
- * Bugfixes for 16.3
- * -improved IO allocation
- * -fix second B channel problem
- * -correct ph_command patch
- *
- * Revision 1.2 1996/04/30 10:00:59 fritz
- * Bugfix: Added ph_command(8) for 16.3.
- * Bugfix: Ports did not get registered correctly
- * when using a 16.3.
- * Started voice support.
- * Some experimental changes of waitforXFW().
- *
- * Revision 1.1 1996/04/13 10:22:42 fritz
- * Initial revision
- *
- *
- */
-
-#define __NO_VERSION__
-#include "teles.h"
-#include "proto.h"
-
-#define INCLUDE_INLINE_FUNCS
-#include <linux/tqueue.h>
-#include <linux/interrupt.h>
-
-#undef DCHAN_VERBOSE
-
-extern void tei_handler(struct PStack *st, byte pr,
- struct BufHeader *ibh);
-extern struct IsdnCard cards[];
-extern int nrcards;
-
-#define byteout(addr,val) outb_p(val,addr)
-#define bytein(addr) inb_p(addr)
-
-static inline byte
-readisac_0(byte * cardm, byte offset)
-{
- return readb(cardm + 0x100 + ((offset & 1) ? 0x1ff : 0) + offset);
-}
-
-static inline byte
-readisac_3(int iobase, byte offset)
-{
- return (bytein(iobase - 0x420 + offset));
-}
-
-#define READISAC(mbase,ibase,ofs) \
- ((mbase)?readisac_0(mbase,ofs):readisac_3(ibase,ofs))
-
-static inline void
-writeisac_0(byte * cardm, byte offset, byte value)
-{
- writeb(value, cardm + 0x100 + ((offset & 1) ? 0x1ff : 0) + offset);
-}
-
-static inline void
-writeisac_3(int iobase, byte offset, byte value)
-{
- byteout(iobase - 0x420 + offset, value);
-}
-
-#define WRITEISAC(mbase,ibase,ofs,val) \
- ((mbase)?writeisac_0(mbase,ofs,val):writeisac_3(ibase,ofs,val))
-
-static inline void
-readisac_s(int iobase, byte offset, byte * dest, int count)
-{
- insb(iobase - 0x420 + offset, dest, count);
-}
-
-static inline void
-writeisac_s(int iobase, byte offset, byte * src, int count)
-{
- outsb(iobase - 0x420 + offset, src, count);
-}
-
-static inline byte
-readhscx_0(byte * base, byte hscx, byte offset)
-{
- return readb(base + 0x180 + ((offset & 1) ? 0x1FF : 0) +
- ((hscx & 1) ? 0x40 : 0) + offset);
-}
-
-static inline byte
-readhscx_3(int iobase, byte hscx, byte offset)
-{
- return (bytein(iobase - (hscx ? 0x820 : 0xc20) + offset));
-}
-
-#define READHSCX(mbase,ibase,hscx,ofs) \
- ((mbase)?readhscx_0(mbase,hscx,ofs):readhscx_3(ibase,hscx,ofs))
-
-static inline void
-writehscx_0(byte * base, byte hscx, byte offset, byte data)
-{
- writeb(data, base + 0x180 + ((offset & 1) ? 0x1FF : 0) +
- ((hscx & 1) ? 0x40 : 0) + offset);
-}
-
-static inline void
-writehscx_3(int iobase, byte hscx, byte offset, byte data)
-{
- byteout(iobase - (hscx ? 0x820 : 0xc20) + offset, data);
-}
-
-static inline void
-readhscx_s(int iobase, byte hscx, byte offset, byte * dest, int count)
-{
- insb(iobase - (hscx ? 0x820 : 0xc20) + offset, dest, count);
-}
-
-static inline void
-writehscx_s(int iobase, byte hscx, byte offset, byte * src, int count)
-{
- outsb(iobase - (hscx ? 0x820 : 0xc20) + offset, src, count);
-}
-
-#define ISAC_MASK 0x20
-#define ISAC_ISTA 0x20
-#define ISAC_STAR 0x21
-#define ISAC_CMDR 0x21
-#define ISAC_EXIR 0x24
-
-#define ISAC_RBCH 0x2a
-
-#define ISAC_ADF2 0x39
-#define ISAC_SPCR 0x30
-#define ISAC_ADF1 0x38
-#define ISAC_CIX0 0x31
-#define ISAC_STCR 0x37
-#define ISAC_MODE 0x22
-#define ISAC_RSTA 0x27
-#define ISAC_RBCL 0x25
-#define ISAC_TIMR 0x23
-#define ISAC_SQXR 0x3b
-
-#define HSCX_ISTA 0x20
-#define HSCX_CCR1 0x2f
-#define HSCX_CCR2 0x2c
-#define HSCX_TSAR 0x31
-#define HSCX_TSAX 0x30
-#define HSCX_XCCR 0x32
-#define HSCX_RCCR 0x33
-#define HSCX_MODE 0x22
-#define HSCX_CMDR 0x21
-#define HSCX_EXIR 0x24
-#define HSCX_XAD1 0x24
-#define HSCX_XAD2 0x25
-#define HSCX_RAH2 0x27
-#define HSCX_RSTA 0x27
-#define HSCX_TIMR 0x23
-#define HSCX_STAR 0x21
-#define HSCX_RBCL 0x25
-#define HSCX_XBCH 0x2d
-#define HSCX_VSTR 0x2e
-#define HSCX_RLCR 0x2e
-#define HSCX_MASK 0x20
-
-static inline void
-waitforCEC_0(byte * base, byte hscx)
-{
- long to = 10;
-
- while ((readhscx_0(base, hscx, HSCX_STAR) & 0x04) && to) {
- udelay(5);
- to--;
- }
- if (!to)
- printk(KERN_WARNING "waitforCEC timeout\n");
-}
-
-static inline void
-waitforCEC_3(int iobase, byte hscx)
-{
- long to = 10;
-
- while ((readhscx_3(iobase, hscx, HSCX_STAR) & 0x04) && to) {
- udelay(5);
- to--;
- }
- if (!to)
- printk(KERN_WARNING "waitforCEC timeout\n");
-}
-
-static inline void
-waitforXFW_0(byte * base, byte hscx)
-{
- long to = 20;
-
- while ((!(readhscx_0(base, hscx, HSCX_STAR) & 0x44)==0x40) && to) {
- udelay(5);
- to--;
- }
- if (!to)
- printk(KERN_WARNING "waitforXFW timeout\n");
-}
-
-static inline void
-waitforXFW_3(int iobase, byte hscx)
-{
- long to = 20;
-
- while ((!(readhscx_3(iobase, hscx, HSCX_STAR) & 0x44)==0x40) && to) {
- udelay(5);
- to--;
- }
- if (!to)
- printk(KERN_WARNING "waitforXFW timeout\n");
-}
-
-static inline void
-writehscxCMDR_0(byte * base, byte hscx, byte data)
-{
- long flags;
-
- save_flags(flags);
- cli();
- waitforCEC_0(base, hscx);
- writehscx_0(base, hscx, HSCX_CMDR, data);
- restore_flags(flags);
-}
-
-static inline void
-writehscxCMDR_3(int iobase, byte hscx, byte data)
-{
- long flags;
-
- save_flags(flags);
- cli();
- waitforCEC_3(iobase, hscx);
- writehscx_3(iobase, hscx, HSCX_CMDR, data);
- restore_flags(flags);
-}
-
-#define WRITEHSCX_CMDR(mbase,ibase,hscx,data) \
- ((mbase)?writehscxCMDR_0(mbase,hscx,data):writehscxCMDR_3(ibase,hscx,data))
-
-/*
- * fast interrupt here
- */
-
-#define ISAC_RCVBUFREADY 0
-#define ISAC_XMTBUFREADY 1
-#define ISAC_PHCHANGE 2
-
-#define HSCX_RCVBUFREADY 0
-#define HSCX_XMTBUFREADY 1
-
-void
-teles_hscxreport(struct IsdnCardState *sp, int hscx)
-{
- printk(KERN_DEBUG "HSCX %d\n", hscx);
- if (sp->membase) {
- printk(KERN_DEBUG " ISTA %x\n", readhscx_0(sp->membase,
- hscx, HSCX_ISTA));
- printk(KERN_DEBUG " STAR %x\n", readhscx_0(sp->membase,
- hscx, HSCX_STAR));
- printk(KERN_DEBUG " EXIR %x\n", readhscx_0(sp->membase,
- hscx, HSCX_EXIR));
- } else {
- printk(KERN_DEBUG " ISTA %x\n", readhscx_3(sp->iobase,
- hscx, HSCX_ISTA));
- printk(KERN_DEBUG " STAR %x\n", readhscx_3(sp->iobase,
- hscx, HSCX_STAR));
- printk(KERN_DEBUG " EXIR %x\n", readhscx_3(sp->iobase,
- hscx, HSCX_EXIR));
- }
-}
-
-void
-teles_report(struct IsdnCardState *sp)
-{
- printk(KERN_DEBUG "ISAC\n");
- if (sp->membase) {
- printk(KERN_DEBUG " ISTA %x\n", readisac_0(sp->membase,
- ISAC_ISTA));
- printk(KERN_DEBUG " STAR %x\n", readisac_0(sp->membase,
- ISAC_STAR));
- printk(KERN_DEBUG " EXIR %x\n", readisac_0(sp->membase,
- ISAC_EXIR));
- } else {
- printk(KERN_DEBUG " ISTA %x\n", readisac_3(sp->iobase,
- ISAC_ISTA));
- printk(KERN_DEBUG " STAR %x\n", readisac_3(sp->iobase,
- ISAC_STAR));
- printk(KERN_DEBUG " EXIR %x\n", readisac_3(sp->iobase,
- ISAC_EXIR));
- }
- teles_hscxreport(sp, 0);
- teles_hscxreport(sp, 1);
-}
-
-/*
- * HSCX stuff goes here
- */
-
-static void
-hscx_sched_event(struct HscxState *hsp, int event)
-{
- hsp->event |= 1 << event;
- queue_task_irq_off(&hsp->tqueue, &tq_immediate);
- mark_bh(IMMEDIATE_BH);
-}
-
-static void
-hscx_empty_fifo(struct HscxState *hsp, int count)
-{
- byte *ptr;
- struct BufHeader *ibh = hsp->rcvibh;
-
- if (hsp->sp->debug)
- printk(KERN_DEBUG "hscx_empty_fifo\n");
-
- if (hsp->rcvptr + count > BUFFER_SIZE(HSCX_RBUF_ORDER,
- HSCX_RBUF_BPPS)) {
- printk(KERN_WARNING
- "hscx_empty_fifo: incoming packet too large\n");
- WRITEHSCX_CMDR(hsp->membase, hsp->iobase, hsp->hscx, 0x80);
- return;
- }
- ptr = DATAPTR(ibh);
- ptr += hsp->rcvptr;
-
- hsp->rcvptr += count;
- if (hsp->membase) {
- while (count--)
- *ptr++ = readhscx_0(hsp->membase, hsp->hscx, 0x0);
- writehscxCMDR_0(hsp->membase, hsp->hscx, 0x80);
- } else {
- readhscx_s(hsp->iobase, hsp->hscx, 0x3e, ptr, count);
- writehscxCMDR_3(hsp->iobase, hsp->hscx, 0x80);
- }
-}
-
-static void
-hscx_fill_fifo(struct HscxState *hsp)
-{
- struct BufHeader *ibh;
- int more, count;
- byte *ptr;
-
- if (hsp->sp->debug)
- printk(KERN_DEBUG "hscx_fill_fifo\n");
-
- ibh = hsp->xmtibh;
- if (!ibh)
- return;
-
- count = ibh->datasize - hsp->sendptr;
- if (count <= 0)
- return;
-
- more = (hsp->mode == 1)?1:0;
- if (count > 32) {
- more = !0;
- count = 32;
- }
- ptr = DATAPTR(ibh);
- ptr += hsp->sendptr;
- hsp->sendptr += count;
-
-#ifdef BCHAN_VERBOSE
- {
- int i;
- printk(KERN_DEBUG "hscx_fill_fifo ");
- for (i = 0; i < count; i++)
- printk(" %2x", ptr[i]);
- printk("\n");
- }
-#endif
- if (hsp->membase) {
- waitforXFW_0(hsp->membase, hsp->hscx);
- while (count--)
- writehscx_0(hsp->membase, hsp->hscx, 0x0, *ptr++);
- writehscxCMDR_0(hsp->membase, hsp->hscx, more ? 0x8 : 0xa);
- } else {
- waitforXFW_3(hsp->iobase, hsp->hscx);
- writehscx_s(hsp->iobase, hsp->hscx, 0x3e, ptr, count);
- writehscxCMDR_3(hsp->iobase, hsp->hscx, more ? 0x8 : 0xa);
- }
-}
-
-static inline void
-hscx_interrupt(struct IsdnCardState *sp, byte val, byte hscx)
-{
- byte r;
- struct HscxState *hsp = sp->hs + hscx;
- int count, err;
-
- if (!hsp->init)
- return;
-
- if (val & 0x80) { /* RME */
-
- r = READHSCX(hsp->membase, sp->iobase, hsp->hscx, HSCX_RSTA);
- if ((r & 0xf0) != 0xa0) {
- if (!r & 0x80)
- printk(KERN_WARNING
- "Teles: HSCX invalid frame\n");
- if ((r & 0x40) && hsp->mode)
- printk(KERN_WARNING "Teles: HSCX RDO mode=%d\n",hsp->mode);
- if (!r & 0x20)
- printk(KERN_WARNING "Teles: HSCX CRC error\n");
- if (hsp->rcvibh)
- BufPoolRelease(hsp->rcvibh);
- hsp->rcvibh = NULL;
- WRITEHSCX_CMDR(hsp->membase, hsp->iobase, hsp->hscx,
- 0x80);
- goto afterRME;
- }
- if (!hsp->rcvibh)
- if (BufPoolGet(&hsp->rcvibh, &hsp->rbufpool,
- GFP_ATOMIC, (void *) 1, 1)) {
- printk(KERN_WARNING
- "HSCX RME out of buffers at %ld\n",
- jiffies);
- WRITEHSCX_CMDR(hsp->membase, hsp->iobase,
- hsp->hscx, 0x80);
- goto afterRME;
- } else
- hsp->rcvptr = 0;
-
- count = READHSCX(hsp->membase, sp->iobase, hsp->hscx,
- HSCX_RBCL) & 0x1f;
- if (count == 0)
- count = 32;
- hscx_empty_fifo(hsp, count);
- hsp->rcvibh->datasize = hsp->rcvptr - 1;
- BufQueueLink(&hsp->rq, hsp->rcvibh);
- hsp->rcvibh = NULL;
- hscx_sched_event(hsp, HSCX_RCVBUFREADY);
- }
- afterRME:
- if (val & 0x40) { /* RPF */
- if (!hsp->rcvibh) {
- if (hsp->mode == 1)
- err=BufPoolGet(&hsp->rcvibh, &hsp->smallpool,
- GFP_ATOMIC, (void *)1, 2);
- else
- err=BufPoolGet(&hsp->rcvibh, &hsp->rbufpool,
- GFP_ATOMIC, (void *)1, 2);
-
- if (err) {
- printk(KERN_WARNING
- "HSCX RPF out of buffers at %ld\n",
- jiffies);
- WRITEHSCX_CMDR(hsp->membase, hsp->iobase,
- hsp->hscx, 0x80);
- goto afterRPF;
- } else
- hsp->rcvptr = 0;
- }
-
- hscx_empty_fifo(hsp, 32);
- if (hsp->mode == 1) {
- /* receive audio data */
- hsp->rcvibh->datasize = hsp->rcvptr;
- BufQueueLink(&hsp->rq, hsp->rcvibh);
- hsp->rcvibh = NULL;
- hscx_sched_event(hsp, HSCX_RCVBUFREADY);
- }
-
- }
- afterRPF:
- if (val & 0x10) { /* XPR */
- if (hsp->xmtibh)
- if (hsp->xmtibh->datasize > hsp->sendptr) {
- hscx_fill_fifo(hsp);
- goto afterXPR;
- } else {
- if (hsp->releasebuf)
- BufPoolRelease(hsp->xmtibh);
- hsp->sendptr = 0;
- if (hsp->st->l4.l1writewakeup)
- hsp->st->l4.l1writewakeup(hsp->st);
- hsp->xmtibh = NULL;
- }
- if (!BufQueueUnlink(&hsp->xmtibh, &hsp->sq)) {
- hsp->releasebuf = !0;
- hscx_fill_fifo(hsp);
- } else
- hscx_sched_event(hsp, HSCX_XMTBUFREADY);
- }
- afterXPR:
-}
-
-/*
- * ISAC stuff goes here
- */
-
-static void
-isac_sched_event(struct IsdnCardState *sp, int event)
-{
- sp->event |= 1 << event;
- queue_task_irq_off(&sp->tqueue, &tq_immediate);
- mark_bh(IMMEDIATE_BH);
-}
-
-static void
-empty_fifo(struct IsdnCardState *sp, int count)
-{
- byte *ptr;
- struct BufHeader *ibh = sp->rcvibh;
-
- if (sp->debug)
- printk(KERN_DEBUG "empty_fifo\n");
-
- if (sp->rcvptr >= 3072) {
- printk(KERN_WARNING "empty_fifo rcvptr %d\n", sp->rcvptr);
- return;
- }
- ptr = DATAPTR(ibh);
- ptr += sp->rcvptr;
- sp->rcvptr += count;
-
- if (sp->membase) {
-#ifdef DCHAN_VERBOSE
- printk(KERN_DEBUG "empty_fifo ");
- while (count--) {
- *ptr = readisac_0(sp->membase, 0x0);
- printk("%2x ", *ptr);
- ptr++;
- }
- printk("\n");
-#else
- while (count--)
- *ptr++ = readisac_0(sp->membase, 0x0);
-#endif
- writeisac_0(sp->membase, ISAC_CMDR, 0x80);
- } else {
-#ifdef DCHAN_VERBOSE
- int i;
- printk(KERN_DEBUG "empty_fifo ");
- readisac_s(sp->iobase, 0x3e, ptr, count);
- for (i = 0; i < count; i++)
- printk("%2x ", ptr[i]);
- printk("\n");
-#else
- readisac_s(sp->iobase, 0x3e, ptr, count);
-#endif
- writeisac_3(sp->iobase, ISAC_CMDR, 0x80);
- }
-}
-
-static void
-fill_fifo(struct IsdnCardState *sp)
-{
- struct BufHeader *ibh;
- int count, more;
- byte *ptr;
-
- if (sp->debug)
- printk(KERN_DEBUG "fill_fifo\n");
-
- ibh = sp->xmtibh;
- if (!ibh)
- return;
-
- count = ibh->datasize - sp->sendptr;
- if (count <= 0)
- return;
- if (count >= 3072)
- return;
-
- more = 0;
- if (count > 32) {
- more = !0;
- count = 32;
- }
- ptr = DATAPTR(ibh);
- ptr += sp->sendptr;
- sp->sendptr += count;
-
- if (sp->membase) {
-#ifdef DCHAN_VERBOSE
- printk(KERN_DEBUG "fill_fifo ");
- while (count--) {
- writeisac_0(sp->membase, 0x0, *ptr);
- printk("%2x ", *ptr);
- ptr++;
- }
- printk("\n");
-#else
- while (count--)
- writeisac_0(sp->membase, 0x0, *ptr++);
-#endif
- writeisac_0(sp->membase, ISAC_CMDR, more ? 0x8 : 0xa);
- } else {
-#ifdef DCHAN_VERBOSE
- int i;
- writeisac_s(sp->iobase, 0x3e, ptr, count);
- printk(KERN_DEBUG "fill_fifo ");
- for (i = 0; i < count; i++)
- printk("%2x ", ptr[i]);
- printk("\n");
-#else
- writeisac_s(sp->iobase, 0x3e, ptr, count);
-#endif
- writeisac_3(sp->iobase, ISAC_CMDR, more ? 0x8 : 0xa);
- }
-}
-
-static int
-act_wanted(struct IsdnCardState *sp)
-{
- struct PStack *st;
-
- st = sp->stlist;
- while (st)
- if (st->l1.act_state)
- return (!0);
- else
- st = st->next;
- return (0);
-}
-
-static void
-ph_command(struct IsdnCardState *sp, unsigned int command)
-{
- printk(KERN_DEBUG "ph_command %d\n", command);
- WRITEISAC(sp->membase, sp->iobase, ISAC_CIX0, (command << 2) | 3);
-}
-
-static void
-isac_new_ph(struct IsdnCardState *sp)
-{
- int enq;
-
- enq = act_wanted(sp);
-
- switch (sp->ph_state) {
- case (0):
- case (6):
- if (enq)
- ph_command(sp, 0);
- else
- ph_command(sp, 15);
- break;
- case (7):
- if (enq)
- ph_command(sp, 9);
- break;
- case (12):
- ph_command(sp, 8);
- sp->ph_active = 5;
- isac_sched_event(sp, ISAC_PHCHANGE);
- if (!sp->xmtibh)
- if (!BufQueueUnlink(&sp->xmtibh, &sp->sq))
- sp->sendptr = 0;
- if (sp->xmtibh)
- fill_fifo(sp);
- break;
- case (13):
- ph_command(sp, 9);
- sp->ph_active = 5;
- isac_sched_event(sp, ISAC_PHCHANGE);
- if (!sp->xmtibh)
- if (!BufQueueUnlink(&sp->xmtibh, &sp->sq))
- sp->sendptr = 0;
- if (sp->xmtibh)
- fill_fifo(sp);
- break;
- case (4):
- case (8):
- break;
- default:
- sp->ph_active = 0;
- break;
- }
-}
-
-static void
-teles_interrupt(int intno, void *dev_id, struct pt_regs *regs)
-{
- byte val, r, exval;
- struct IsdnCardState *sp;
- unsigned int count;
- struct HscxState *hsp;
-
- sp = (struct IsdnCardState *) irq2dev_map[intno];
-
- if (!sp) {
- printk(KERN_WARNING "Teles: Spurious interrupt!\n");
- return;
- }
- val = READHSCX(sp->membase, sp->iobase, 1, HSCX_ISTA);
-
- if (val & 0x01) {
- hsp = sp->hs + 1;
- exval = READHSCX(sp->membase, sp->iobase, 1, HSCX_EXIR);
- if (exval == 0x40) {
- if (hsp->mode == 1)
- hscx_fill_fifo(hsp);
- else {
- /* Here we lost an TX interrupt, so
- * restart transmitting the whole frame.
- */
- hsp->sendptr = 0;
- WRITEHSCX_CMDR(hsp->membase, hsp->iobase,
- hsp->hscx, 0x01);
- printk(KERN_DEBUG "HSCX B EXIR %x\n", exval);
- }
- } else
- printk(KERN_WARNING "HSCX B EXIR %x\n", exval);
- }
- if (val & 0xf8) {
- if (sp->debug)
- printk(KERN_DEBUG "HSCX B interrupt %x\n", val);
- hscx_interrupt(sp, val, 1);
- }
- if (val & 0x02) {
- hsp = sp->hs;
- exval = READHSCX(sp->membase, sp->iobase, 0, HSCX_EXIR);
- if (exval == 0x40) {
- if (hsp->mode == 1)
- hscx_fill_fifo(hsp);
- else {
- /* Here we lost an TX interrupt, so
- * restart transmitting the whole frame.
- */
- hsp->sendptr = 0;
- WRITEHSCX_CMDR(hsp->membase, hsp->iobase,
- hsp->hscx, 0x01);
- printk(KERN_DEBUG "HSCX A EXIR %x\n", exval);
- }
- } else
- printk(KERN_WARNING "HSCX A EXIR %x\n", exval);
- }
- if (val & 0x04) {
- val = READHSCX(sp->membase, sp->iobase, 0, HSCX_ISTA);
- if (sp->debug)
- printk(KERN_DEBUG "HSCX A interrupt %x\n",
- val);
- hscx_interrupt(sp, val, 0);
- }
-
- val = READISAC(sp->membase, sp->iobase, ISAC_ISTA);
-
- if (sp->debug)
- printk(KERN_DEBUG "ISAC interrupt %x\n", val);
-
- if (val & 0x80) { /* RME */
-
- r = READISAC(sp->membase, sp->iobase, ISAC_RSTA);
- if ((r & 0x70) != 0x20) {
- if (r & 0x40)
- printk(KERN_WARNING "Teles: ISAC RDO\n");
- if (!r & 0x20)
- printk(KERN_WARNING "Teles: ISAC CRC error\n");
- if (sp->rcvibh)
- BufPoolRelease(sp->rcvibh);
- sp->rcvibh = NULL;
- WRITEISAC(sp->membase, sp->iobase, ISAC_CMDR, 0x80);
- goto afterRME;
- }
- if (!sp->rcvibh)
- if (BufPoolGet(&(sp->rcvibh), &(sp->rbufpool),
- GFP_ATOMIC,
- (void *) 1, 3)) {
- printk(KERN_WARNING
- "ISAC RME out of buffers!\n");
- WRITEISAC(sp->membase, sp->iobase,
- ISAC_CMDR, 0x80);
- goto afterRME;
- } else
- sp->rcvptr = 0;
-
- count = READISAC(sp->membase, sp->iobase, ISAC_RBCL) & 0x1f;
- if (count == 0)
- count = 32;
- empty_fifo(sp, count);
- sp->rcvibh->datasize = sp->rcvptr;
- BufQueueLink(&(sp->rq), sp->rcvibh);
- sp->rcvibh = NULL;
- isac_sched_event(sp, ISAC_RCVBUFREADY);
- }
- afterRME:
- if (val & 0x40) { /* RPF */
- if (!sp->rcvibh)
- if (BufPoolGet(&(sp->rcvibh), &(sp->rbufpool),
- GFP_ATOMIC,
- (void *) 1, 4)) {
- printk(KERN_WARNING
- "ISAC RME out of buffers!\n");
- WRITEISAC(sp->membase, sp->iobase,
- ISAC_CMDR, 0x80);
- goto afterRPF;
- } else
- sp->rcvptr = 0;
- empty_fifo(sp, 32);
- }
- afterRPF:
- if (val & 0x20) {
- }
- if (val & 0x10) { /* XPR */
- if (sp->xmtibh)
- if (sp->xmtibh->datasize > sp->sendptr) {
- fill_fifo(sp);
- goto afterXPR;
- } else {
- if (sp->releasebuf)
- BufPoolRelease(sp->xmtibh);
- sp->xmtibh = NULL;
- sp->sendptr = 0;
- }
- if (!BufQueueUnlink(&sp->xmtibh, &sp->sq)) {
- sp->releasebuf = !0;
- fill_fifo(sp);
- } else
- isac_sched_event(sp, ISAC_XMTBUFREADY);
- }
- afterXPR:
- if (val & 0x04) { /* CISQ */
- sp->ph_state = (READISAC(sp->membase, sp->iobase, ISAC_CIX0)
- >> 2) & 0xf;
- printk(KERN_DEBUG "l1state %d\n", sp->ph_state);
- isac_new_ph(sp);
- }
- if (sp->membase) {
- writeisac_0(sp->membase, ISAC_MASK, 0xFF);
- writehscx_0(sp->membase, 0, HSCX_MASK, 0xFF);
- writehscx_0(sp->membase, 1, HSCX_MASK, 0xFF);
- writeisac_0(sp->membase, ISAC_MASK, 0x0);
- writehscx_0(sp->membase, 0, HSCX_MASK, 0x0);
- writehscx_0(sp->membase, 1, HSCX_MASK, 0x0);
- } else {
- writeisac_3(sp->iobase, ISAC_MASK, 0xFF);
- writehscx_3(sp->iobase, 0, HSCX_MASK, 0xFF);
- writehscx_3(sp->iobase, 1, HSCX_MASK, 0xFF);
- writeisac_3(sp->iobase, ISAC_MASK, 0x0);
- writehscx_3(sp->iobase, 0, HSCX_MASK, 0x0);
- writehscx_3(sp->iobase, 1, HSCX_MASK, 0x0);
- }
-}
-
-/*
- * soft interrupt
- */
-
-static void
-act_ivated(struct IsdnCardState *sp)
-{
- struct PStack *st;
-
- st = sp->stlist;
- while (st) {
- if (st->l1.act_state == 1) {
- st->l1.act_state = 2;
- st->l1.l1man(st, PH_ACTIVATE, NULL);
- }
- st = st->next;
- }
-}
-
-static void
-process_new_ph(struct IsdnCardState *sp)
-{
- if (sp->ph_active == 5)
- act_ivated(sp);
-}
-
-static void
-process_xmt(struct IsdnCardState *sp)
-{
- struct PStack *stptr;
-
- if (sp->xmtibh)
- return;
-
- stptr = sp->stlist;
- while (stptr != NULL)
- if (stptr->l1.requestpull) {
- stptr->l1.requestpull = 0;
- stptr->l1.l1l2(stptr, PH_PULL_ACK, NULL);
- break;
- } else
- stptr = stptr->next;
-}
-
-static void
-process_rcv(struct IsdnCardState *sp)
-{
- struct BufHeader *ibh, *cibh;
- struct PStack *stptr;
- byte *ptr;
- int found, broadc;
- char tmp[64];
-
- while (!BufQueueUnlink(&ibh, &sp->rq)) {
- stptr = sp->stlist;
- ptr = DATAPTR(ibh);
- broadc = (ptr[1] >> 1) == 127;
-
- if (broadc && sp->dlogflag && (!(ptr[0] >> 2)))
- dlogframe(sp, ptr + 3, ibh->datasize - 3,
- "Q.931 frame network->user broadcast");
-
- if (broadc) {
- while (stptr != NULL) {
- if ((ptr[0] >> 2) == stptr->l2.sap)
- if (!BufPoolGet(&cibh, &sp->rbufpool, GFP_ATOMIC,
- (void *) 1, 5)) {
- memcpy(DATAPTR(cibh), DATAPTR(ibh), ibh->datasize);
- cibh->datasize = ibh->datasize;
- stptr->l1.l1l2(stptr, PH_DATA, cibh);
- } else
- printk(KERN_WARNING "isdn broadcast buffer shortage\n");
- stptr = stptr->next;
- }
- BufPoolRelease(ibh);
- } else {
- found = 0;
- while (stptr != NULL)
- if (((ptr[0] >> 2) == stptr->l2.sap) &&
- ((ptr[1] >> 1) == stptr->l2.tei)) {
- stptr->l1.l1l2(stptr, PH_DATA, ibh);
- found = !0;
- break;
- } else
- stptr = stptr->next;
- if (!found) {
- /* BD 10.10.95
- * Print out D-Channel msg not processed
- * by isdn4linux
- */
-
- if ((!(ptr[0] >> 2)) && (!(ptr[2] & 0x01))) {
- sprintf(tmp, "Q.931 frame network->user with tei %d (not for us)", ptr[1] >> 1);
- dlogframe(sp, ptr + 4, ibh->datasize - 4, tmp);
- }
- BufPoolRelease(ibh);
- }
- }
-
- }
-
-}
-
-static void
-isac_bh(struct IsdnCardState *sp)
-{
- if (!sp)
- return;
-
- if (clear_bit(ISAC_PHCHANGE, &sp->event))
- process_new_ph(sp);
- if (clear_bit(ISAC_RCVBUFREADY, &sp->event))
- process_rcv(sp);
- if (clear_bit(ISAC_XMTBUFREADY, &sp->event))
- process_xmt(sp);
-}
-
-
-static void
-hscx_process_xmt(struct HscxState *hsp)
-{
- struct PStack *st = hsp->st;
-
- if (hsp->xmtibh)
- return;
-
- if (st->l1.requestpull) {
- st->l1.requestpull = 0;
- st->l1.l1l2(st, PH_PULL_ACK, NULL);
- }
- if (!hsp->active)
- if ((!hsp->xmtibh) && (!hsp->sq.head))
- modehscx(hsp, 0, 0);
-}
-
-static void
-hscx_process_rcv(struct HscxState *hsp)
-{
- struct BufHeader *ibh;
-
-#ifdef DEBUG_MAGIC
- if (hsp->magic != 301270) {
- printk(KERN_DEBUG "hscx_process_rcv magic not 301270\n");
- return;
- }
-#endif
- while (!BufQueueUnlink(&ibh, &hsp->rq)) {
- hsp->st->l1.l1l2(hsp->st, PH_DATA, ibh);
- }
-}
-
-static void
-hscx_bh(struct HscxState *hsp)
-{
-
- if (!hsp)
- return;
-
- if (clear_bit(HSCX_RCVBUFREADY, &hsp->event))
- hscx_process_rcv(hsp);
- if (clear_bit(HSCX_XMTBUFREADY, &hsp->event))
- hscx_process_xmt(hsp);
-
-}
-
-/*
- * interrupt stuff ends here
- */
-
-static void
-restart_ph(struct IsdnCardState *sp)
-{
- switch (sp->ph_active) {
- case (0):
- if (sp->ph_state == 6)
- ph_command(sp, 0);
- else
- ph_command(sp, 1);
- sp->ph_active = 1;
- break;
- }
-}
-
-static void
-initisac(byte * cardmem, int iobase)
-{
- if (cardmem) {
- writeisac_0(cardmem, ISAC_MASK, 0xff);
- writeisac_0(cardmem, ISAC_ADF2, 0x0);
- writeisac_0(cardmem, ISAC_SPCR, 0xa);
- writeisac_0(cardmem, ISAC_ADF1, 0x2);
- writeisac_0(cardmem, ISAC_STCR, 0x70);
- writeisac_0(cardmem, ISAC_MODE, 0xc9);
- writeisac_0(cardmem, ISAC_CMDR, 0x41);
- writeisac_0(cardmem, ISAC_CIX0, (1 << 2) | 3);
- } else {
- writeisac_3(iobase, ISAC_MASK, 0xff);
- writeisac_3(iobase, ISAC_ADF2, 0x80);
- writeisac_3(iobase, ISAC_SQXR, 0x2f);
- writeisac_3(iobase, ISAC_SPCR, 0x00);
- writeisac_3(iobase, ISAC_ADF1, 0x02);
- writeisac_3(iobase, ISAC_STCR, 0x70);
- writeisac_3(iobase, ISAC_MODE, 0xc9);
- writeisac_3(iobase, ISAC_TIMR, 0x00);
- writeisac_3(iobase, ISAC_ADF1, 0x00);
- writeisac_3(iobase, ISAC_CMDR, 0x41);
- writeisac_3(iobase, ISAC_CIX0, (1 << 2) | 3);
- }
-}
-
-static int
-checkcard(int cardnr)
-{
- int timout;
- byte cfval, val;
- struct IsdnCard *card = cards + cardnr;
-
- if (card->membase)
- if ((unsigned long)card->membase < 0x10000) {
- (unsigned long)card->membase <<= 4;
- printk(KERN_INFO
- "Teles membase configured DOSish, assuming 0x%lx\n",
- (unsigned long)card->membase);
- }
- if (!card->iobase) {
- if (card->membase) {
- printk(KERN_NOTICE
- "Teles 8 assumed, mem: %lx irq: %d proto: %s\n",
- (long) card->membase, card->interrupt,
- (card->protocol == ISDN_PTYPE_1TR6) ?
- "1TR6" : "EDSS1");
- printk(KERN_INFO "HSCX version A:%x B:%x\n",
- readhscx_0(card->membase, 0, HSCX_VSTR) & 0xf,
- readhscx_0(card->membase, 1, HSCX_VSTR) & 0xf);
- }
- } else {
- switch (card->iobase) {
- case 0x180:
- case 0x280:
- case 0x380:
- card->iobase |= 0xc00;
- break;
- }
- if (card->membase) { /* 16.0 */
- if (check_region(card->iobase, 8)) {
- printk(KERN_WARNING
- "teles: ports %x-%x already in use\n",
- card->iobase,
- card->iobase + 8 );
- return -1;
- }
- } else { /* 16.3 */
- if (check_region(card->iobase, 16)) {
- printk(KERN_WARNING
- "teles: 16.3 ports %x-%x already in use\n",
- card->iobase,
- card->iobase + 16 );
- return -1;
- }
- if (check_region((card->iobase - 0xc00) , 32)) {
- printk(KERN_WARNING
- "teles: 16.3 ports %x-%x already in use\n",
- card->iobase - 0xc00,
- card->iobase - 0xc00 + 32);
- return -1;
- }
- if (check_region((card->iobase - 0x800) , 32)) {
- printk(KERN_WARNING
- "teles: 16.3 ports %x-%x already in use\n",
- card->iobase - 0x800,
- card->iobase - 0x800 + 32);
- return -1;
- }
- if (check_region((card->iobase - 0x400) , 32)) {
- printk(KERN_WARNING
- "teles: 16.3 ports %x-%x already in use\n",
- card->iobase - 0x400,
- card->iobase - 0x400 + 32);
- return -1;
- }
- }
- switch (card->interrupt) {
- case 2:
- cfval = 0x00;
- break;
- case 3:
- cfval = 0x02;
- break;
- case 4:
- cfval = 0x04;
- break;
- case 5:
- cfval = 0x06;
- break;
- case 10:
- cfval = 0x08;
- break;
- case 11:
- cfval = 0x0A;
- break;
- case 12:
- cfval = 0x0C;
- break;
- case 15:
- cfval = 0x0E;
- break;
- default:
- cfval = 0x00;
- break;
- }
- if (card->membase) {
- cfval |= (((unsigned int) card->membase >> 9) & 0xF0);
- }
- if (bytein(card->iobase + 0) != 0x51) {
- printk(KERN_INFO "XXX Byte at %x is %x\n",
- card->iobase + 0,
- bytein(card->iobase + 0));
- return -2;
- }
- if (bytein(card->iobase + 1) != 0x93) {
- printk(KERN_INFO "XXX Byte at %x is %x\n",
- card->iobase + 1,
- bytein(card->iobase + 1));
- return -2;
- }
- val = bytein(card->iobase + 2); /* 0x1e=without AB
- * 0x1f=with AB
- * 0x1c 16.3 ???
- */
- if (val != 0x1c && val != 0x1e && val != 0x1f) {
- printk(KERN_INFO "XXX Byte at %x is %x\n",
- card->iobase + 2,
- bytein(card->iobase + 2));
- return -2;
- }
- if (card->membase) { /* 16.0 */
- request_region(card->iobase, 8, "teles 16.0");
- } else {
- request_region(card->iobase, 16, "teles 16.3");
- request_region(card->iobase - 0xC00, 32, "teles HSCX0");
- request_region(card->iobase - 0x800, 32, "teles HSCX1");
- request_region(card->iobase - 0x400, 32, "teles ISAC");
- }
- cli();
- timout = jiffies + (HZ / 10) + 1;
- byteout(card->iobase + 4, cfval);
- sti();
- while (jiffies <= timout);
-
- cli();
- timout = jiffies + (HZ / 10) + 1;
- byteout(card->iobase + 4, cfval | 1);
- sti();
- while (jiffies <= timout);
-
- if (card->membase)
- printk(KERN_NOTICE
- "Teles 16.0 found, io: %x mem: %lx irq: %d proto: %s\n",
- card->iobase, (long) card->membase,
- card->interrupt,
- (card->protocol == ISDN_PTYPE_1TR6) ?
- "1TR6" : "EDSS1");
- else
- printk(KERN_NOTICE
- "Teles 16.3 found, io: %x irq: %d proto: %s\n",
- card->iobase, card->interrupt,
- (card->protocol == ISDN_PTYPE_1TR6) ?
- "1TR6" : "EDSS1");
- printk(KERN_INFO "HSCX version A:%x B:%x\n",
- READHSCX(card->membase, card->iobase, 0,
- HSCX_VSTR) & 0xf,
- READHSCX(card->membase, card->iobase, 1,
- HSCX_VSTR) & 0xf);
-
- }
- if (card->membase) {
- cli();
- timout = jiffies + (HZ / 5) + 1;
- writeb(0, card->membase + 0x80);
- sti();
- while (jiffies <= timout);
-
- cli();
- writeb(1, card->membase + 0x80);
- timout = jiffies + (HZ / 5) + 1;
- sti();
- while (jiffies <= timout);
- }
- return (0);
-}
-
-void
-modehscx(struct HscxState *hs, int mode,
- int ichan)
-{
- struct IsdnCardState *sp = hs->sp;
- int hscx = hs->hscx;
-
- printk(KERN_DEBUG "modehscx hscx %d mode %d ichan %d\n",
- hscx, mode, ichan);
-
- hs->mode = mode;
- if (sp->membase) {
- /* What's that ??? KKeil */
- if (hscx == 0)
- ichan = 1 - ichan; /* raar maar waar... */
- writehscx_0(sp->membase, hscx, HSCX_CCR1, 0x85);
- writehscx_0(sp->membase, hscx, HSCX_XAD1, 0xFF);
- writehscx_0(sp->membase, hscx, HSCX_XAD2, 0xFF);
- writehscx_0(sp->membase, hscx, HSCX_RAH2, 0xFF);
- writehscx_0(sp->membase, hscx, HSCX_XBCH, 0x0);
-
- switch (mode) {
- case (0):
- writehscx_0(sp->membase, hscx, HSCX_CCR2, 0x30);
- writehscx_0(sp->membase, hscx, HSCX_TSAX, 0xff);
- writehscx_0(sp->membase, hscx, HSCX_TSAR, 0xff);
- writehscx_0(sp->membase, hscx, HSCX_XCCR, 7);
- writehscx_0(sp->membase, hscx, HSCX_RCCR, 7);
- writehscx_0(sp->membase, hscx, HSCX_MODE, 0x84);
- break;
- case (1):
- if (ichan == 0) {
- writehscx_0(sp->membase, hscx, HSCX_CCR2, 0x30);
- writehscx_0(sp->membase, hscx, HSCX_TSAX, 0x7);
- writehscx_0(sp->membase, hscx, HSCX_TSAR, 0x7);
- writehscx_0(sp->membase, hscx, HSCX_XCCR, 7);
- writehscx_0(sp->membase, hscx, HSCX_RCCR, 7);
- } else {
- writehscx_0(sp->membase, hscx, HSCX_CCR2, 0x30);
- writehscx_0(sp->membase, hscx, HSCX_TSAX, 0x3);
- writehscx_0(sp->membase, hscx, HSCX_TSAR, 0x3);
- writehscx_0(sp->membase, hscx, HSCX_XCCR, 7);
- writehscx_0(sp->membase, hscx, HSCX_RCCR, 7);
- }
- writehscx_0(sp->membase, hscx, HSCX_MODE, 0xe4);
- writehscx_0(sp->membase, hscx, HSCX_CMDR, 0x41);
- break;
- case (2):
- if (ichan == 0) {
- writehscx_0(sp->membase, hscx, HSCX_CCR2, 0x30);
- writehscx_0(sp->membase, hscx, HSCX_TSAX, 0x7);
- writehscx_0(sp->membase, hscx, HSCX_TSAR, 0x7);
- writehscx_0(sp->membase, hscx, HSCX_XCCR, 7);
- writehscx_0(sp->membase, hscx, HSCX_RCCR, 7);
- } else {
- writehscx_0(sp->membase, hscx, HSCX_CCR2, 0x30);
- writehscx_0(sp->membase, hscx, HSCX_TSAX, 0x3);
- writehscx_0(sp->membase, hscx, HSCX_TSAR, 0x3);
- writehscx_0(sp->membase, hscx, HSCX_XCCR, 7);
- writehscx_0(sp->membase, hscx, HSCX_RCCR, 7);
- }
- writehscx_0(sp->membase, hscx, HSCX_MODE, 0x8c);
- writehscx_0(sp->membase, hscx, HSCX_CMDR, 0x41);
- break;
- }
- writehscx_0(sp->membase, hscx, HSCX_ISTA, 0x00);
- } else {
- writehscx_3(sp->iobase, hscx, HSCX_CCR1, 0x85);
- writehscx_3(sp->iobase, hscx, HSCX_XAD1, 0xFF);
- writehscx_3(sp->iobase, hscx, HSCX_XAD2, 0xFF);
- writehscx_3(sp->iobase, hscx, HSCX_RAH2, 0xFF);
- writehscx_3(sp->iobase, hscx, HSCX_XBCH, 0x00);
- writehscx_3(sp->iobase, hscx, HSCX_RLCR, 0x00);
-
- switch (mode) {
- case (0):
- writehscx_3(sp->iobase, hscx, HSCX_CCR2, 0x30);
- writehscx_3(sp->iobase, hscx, HSCX_TSAX, 0xff);
- writehscx_3(sp->iobase, hscx, HSCX_TSAR, 0xff);
- writehscx_3(sp->iobase, hscx, HSCX_XCCR, 7);
- writehscx_3(sp->iobase, hscx, HSCX_RCCR, 7);
- writehscx_3(sp->iobase, hscx, HSCX_MODE, 0x84);
- break;
- case (1):
- if (ichan == 0) {
- writehscx_3(sp->iobase, hscx, HSCX_CCR2, 0x30);
- writehscx_3(sp->iobase, hscx, HSCX_TSAX, 0x2f);
- writehscx_3(sp->iobase, hscx, HSCX_TSAR, 0x2f);
- writehscx_3(sp->iobase, hscx, HSCX_XCCR, 7);
- writehscx_3(sp->iobase, hscx, HSCX_RCCR, 7);
- } else {
- writehscx_3(sp->iobase, hscx, HSCX_CCR2, 0x30);
- writehscx_3(sp->iobase, hscx, HSCX_TSAX, 0x3);
- writehscx_3(sp->iobase, hscx, HSCX_TSAR, 0x3);
- writehscx_3(sp->iobase, hscx, HSCX_XCCR, 7);
- writehscx_3(sp->iobase, hscx, HSCX_RCCR, 7);
- }
- writehscx_3(sp->iobase, hscx, HSCX_MODE, 0xe4);
- writehscx_3(sp->iobase, hscx, HSCX_CMDR, 0x41);
- break;
- case (2):
- if (ichan == 0) {
- writehscx_3(sp->iobase, hscx, HSCX_CCR2, 0x30);
- writehscx_3(sp->iobase, hscx, HSCX_TSAX, 0x2f);
- writehscx_3(sp->iobase, hscx, HSCX_TSAR, 0x2f);
- writehscx_3(sp->iobase, hscx, HSCX_XCCR, 7);
- writehscx_3(sp->iobase, hscx, HSCX_RCCR, 7);
- } else {
- writehscx_3(sp->iobase, hscx, HSCX_CCR2, 0x30);
- writehscx_3(sp->iobase, hscx, HSCX_TSAX, 0x3);
- writehscx_3(sp->iobase, hscx, HSCX_TSAR, 0x3);
- writehscx_3(sp->iobase, hscx, HSCX_XCCR, 7);
- writehscx_3(sp->iobase, hscx, HSCX_RCCR, 7);
- }
- writehscx_3(sp->iobase, hscx, HSCX_MODE, 0x8c);
- writehscx_3(sp->iobase, hscx, HSCX_CMDR, 0x41);
- break;
- }
- writehscx_3(sp->iobase, hscx, HSCX_ISTA, 0x00);
- }
-}
-
-void
-teles_addlist(struct IsdnCardState *sp,
- struct PStack *st)
-{
- st->next = sp->stlist;
- sp->stlist = st;
-}
-
-void
-teles_rmlist(struct IsdnCardState *sp,
- struct PStack *st)
-{
- struct PStack *p;
-
- if (sp->stlist == st)
- sp->stlist = st->next;
- else {
- p = sp->stlist;
- while (p)
- if (p->next == st) {
- p->next = st->next;
- return;
- } else
- p = p->next;
- }
-}
-
-
-static void
-teles_l2l1(struct PStack *st, int pr,
- struct BufHeader *ibh)
-{
- struct IsdnCardState *sp = (struct IsdnCardState *)
- st->l1.hardware;
-
-
- switch (pr) {
- case (PH_DATA):
- if (sp->xmtibh)
- BufQueueLink(&sp->sq, ibh);
- else {
- sp->xmtibh = ibh;
- sp->sendptr = 0;
- sp->releasebuf = !0;
- fill_fifo(sp);
- }
- break;
- case (PH_DATA_PULLED):
- if (sp->xmtibh) {
- printk(KERN_DEBUG "teles_l2l1: this shouldn't happen\n");
- break;
- }
- sp->xmtibh = ibh;
- sp->sendptr = 0;
- sp->releasebuf = 0;
- fill_fifo(sp);
- break;
- case (PH_REQUEST_PULL):
- if (!sp->xmtibh) {
- st->l1.requestpull = 0;
- st->l1.l1l2(st, PH_PULL_ACK, NULL);
- } else
- st->l1.requestpull = !0;
- break;
- }
-}
-
-static void
-check_ph_act(struct IsdnCardState *sp)
-{
- struct PStack *st = sp->stlist;
-
- while (st) {
- if (st->l1.act_state)
- return;
- st = st->next;
- }
- sp->ph_active = 0;
-}
-
-static void
-teles_manl1(struct PStack *st, int pr,
- void *arg)
-{
- struct IsdnCardState *sp = (struct IsdnCardState *)
- st->l1.hardware;
- long flags;
-
- switch (pr) {
- case (PH_ACTIVATE):
- save_flags(flags);
- cli();
- if (sp->ph_active == 5) {
- st->l1.act_state = 2;
- restore_flags(flags);
- st->l1.l1man(st, PH_ACTIVATE, NULL);
- } else {
- st->l1.act_state = 1;
- if (sp->ph_active == 0)
- restart_ph(sp);
- restore_flags(flags);
- }
- break;
- case (PH_DEACTIVATE):
- st->l1.act_state = 0;
- check_ph_act(sp);
- break;
- }
-}
-
-static void
-teles_l2l1discardq(struct PStack *st, int pr,
- void *heldby, int releasetoo)
-{
- struct IsdnCardState *sp = (struct IsdnCardState *) st->l1.hardware;
-
-#ifdef DEBUG_MAGIC
- if (sp->magic != 301271) {
- printk(KERN_DEBUG "isac_discardq magic not 301271\n");
- return;
- }
-#endif
-
- BufQueueDiscard(&sp->sq, pr, heldby, releasetoo);
-}
-
-void
-setstack_teles(struct PStack *st, struct IsdnCardState *sp)
-{
- st->l1.hardware = sp;
- st->l1.sbufpool = &(sp->sbufpool);
- st->l1.rbufpool = &(sp->rbufpool);
- st->l1.smallpool = &(sp->smallpool);
- st->protocol = sp->teistack->protocol;
-
- setstack_tei(st);
-
- st->l1.stlistp = &(sp->stlist);
- st->l1.act_state = 0;
- st->l2.l2l1 = teles_l2l1;
- st->l2.l2l1discardq = teles_l2l1discardq;
- st->ma.manl1 = teles_manl1;
- st->l1.requestpull = 0;
-}
-
-void
-init_hscxstate(struct IsdnCardState *sp,
- int hscx)
-{
- struct HscxState *hsp = sp->hs + hscx;
-
- hsp->sp = sp;
- hsp->hscx = hscx;
- hsp->membase = sp->membase;
- hsp->iobase = sp->iobase;
-
- hsp->tqueue.next = 0;
- hsp->tqueue.sync = 0;
- hsp->tqueue.routine = (void *) (void *) hscx_bh;
- hsp->tqueue.data = hsp;
-
- hsp->inuse = 0;
- hsp->init = 0;
- hsp->active = 0;
-
-#ifdef DEBUG_MAGIC
- hsp->magic = 301270;
-#endif
-}
-
-void
-initcard(int cardnr)
-{
- struct IsdnCardState *sp;
- struct IsdnCard *card = cards + cardnr;
-
- sp = (struct IsdnCardState *)
- Smalloc(sizeof(struct IsdnCardState), GFP_KERNEL,
- "struct IsdnCardState");
-
- sp->membase = card->membase;
- sp->iobase = card->iobase;
- sp->cardnr = cardnr;
-
- BufPoolInit(&sp->sbufpool, ISAC_SBUF_ORDER, ISAC_SBUF_BPPS,
- ISAC_SBUF_MAXPAGES);
- BufPoolInit(&sp->rbufpool, ISAC_RBUF_ORDER, ISAC_RBUF_BPPS,
- ISAC_RBUF_MAXPAGES);
- BufPoolInit(&sp->smallpool, ISAC_SMALLBUF_ORDER, ISAC_SMALLBUF_BPPS,
- ISAC_SMALLBUF_MAXPAGES);
-
- sp->dlogspace = Smalloc(4096, GFP_KERNEL, "dlogspace");
-
- initisac(card->membase, card->iobase);
-
- sp->rcvibh = NULL;
- sp->rcvptr = 0;
- sp->xmtibh = NULL;
- sp->sendptr = 0;
- sp->event = 0;
- sp->tqueue.next = 0;
- sp->tqueue.sync = 0;
- sp->tqueue.routine = (void *) (void *) isac_bh;
- sp->tqueue.data = sp;
-
- BufQueueInit(&sp->rq);
- BufQueueInit(&sp->sq);
-
- sp->stlist = NULL;
-
- sp->ph_active = 0;
-
- sp->dlogflag = 0;
- sp->debug = 0;
-
- sp->releasebuf = 0;
-#ifdef DEBUG_MAGIC
- sp->magic = 301271;
-#endif
-
- cards[sp->cardnr].sp = sp;
-
- init_hscxstate(sp, 0);
- init_hscxstate(sp, 1);
-
- modehscx(sp->hs, 0, 0);
- modehscx(sp->hs + 1, 0, 0);
-
- WRITEISAC(sp->membase, sp->iobase, ISAC_MASK, 0x0);
-}
-
-static int
-get_irq(int cardnr)
-{
- struct IsdnCard *card = cards + cardnr;
- long flags;
-
- save_flags(flags);
- cli();
- if (request_irq(card->interrupt, &teles_interrupt,
- SA_INTERRUPT, "teles", NULL)) {
- printk(KERN_WARNING "Teles couldn't get interrupt %d\n",
- card->interrupt);
- restore_flags(flags);
- return (!0);
- }
- irq2dev_map[card->interrupt] = (void *) card->sp;
- restore_flags(flags);
- return (0);
-}
-
-static void
-release_irq(int cardnr)
-{
- struct IsdnCard *card = cards + cardnr;
-
- irq2dev_map[card->interrupt] = NULL;
- free_irq(card->interrupt, NULL);
-}
-
-void
-close_hscxstate(struct HscxState *hs)
-{
- modehscx(hs, 0, 0);
- hs->inuse = 0;
-
- if (hs->init) {
- BufPoolFree(&hs->smallpool);
- BufPoolFree(&hs->rbufpool);
- BufPoolFree(&hs->sbufpool);
- }
- hs->init = 0;
-}
-
-void
-closecard(int cardnr)
-{
- struct IsdnCardState *sp = cards[cardnr].sp;
-
- cards[cardnr].sp = NULL;
-
- Sfree(sp->dlogspace);
-
- BufPoolFree(&sp->smallpool);
- BufPoolFree(&sp->rbufpool);
- BufPoolFree(&sp->sbufpool);
-
- close_hscxstate(sp->hs + 1);
- close_hscxstate(sp->hs);
-
- if (cards[cardnr].iobase)
- if (cards[cardnr].membase) { /* 16.0 */
- release_region(cards[cardnr].iobase, 8);
- } else {
- release_region(cards[cardnr].iobase, 16);
- release_region(cards[cardnr].iobase - 0xC00, 32);
- release_region(cards[cardnr].iobase - 0x800, 32);
- release_region(cards[cardnr].iobase - 0x400, 32);
- }
-
- Sfree((void *) sp);
-}
-
-void
-teles_shiftcards(int idx)
-{
- int i;
-
- for (i = idx; i < 15; i++)
- memcpy(&cards[i],&cards[i+1],sizeof(cards[i]));
-}
-
-int
-teles_inithardware(void)
-{
- int foundcards = 0;
- int i = 0;
-
- while (i < nrcards) {
- if (!cards[i].protocol)
- break;
- switch (checkcard(i)) {
- case (0):
- initcard(i);
- if (get_irq(i)) {
- closecard(i);
- teles_shiftcards(i);
- } else {
- foundcards++;
- i++;
- }
- break;
- case (-1):
- teles_shiftcards(i);
- break;
- case (-2):
- release_region(cards[i].iobase, 8);
- printk(KERN_WARNING "NO Teles card found at 0x%x!\n", cards[i].iobase);
- teles_shiftcards(i);
- break;
- }
- }
- return foundcards;
-}
-
-void
-teles_closehardware(void)
-{
- int i;
-
- for (i = 0; i < nrcards; i++)
- if (cards[i].sp) {
- release_irq(i);
- closecard(i);
- }
-}
-
-static void
-hscx_l2l1(struct PStack *st, int pr,
- struct BufHeader *ibh)
-{
- struct IsdnCardState *sp = (struct IsdnCardState *)
- st->l1.hardware;
- struct HscxState *hsp = sp->hs + st->l1.hscx;
- long flags;
-
- switch (pr) {
- case (PH_DATA):
- save_flags(flags);
- cli();
- if (hsp->xmtibh) {
- BufQueueLink(&hsp->sq, ibh);
- restore_flags(flags);
- }
- else {
- restore_flags(flags);
- hsp->xmtibh = ibh;
- hsp->sendptr = 0;
- hsp->releasebuf = !0;
- hscx_fill_fifo(hsp);
- }
- break;
- case (PH_DATA_PULLED):
- if (hsp->xmtibh) {
- printk(KERN_DEBUG "hscx_l2l1: this shouldn't happen\n");
- break;
- }
- hsp->xmtibh = ibh;
- hsp->sendptr = 0;
- hsp->releasebuf = 0;
- hscx_fill_fifo(hsp);
- break;
- case (PH_REQUEST_PULL):
- if (!hsp->xmtibh) {
- st->l1.requestpull = 0;
- st->l1.l1l2(st, PH_PULL_ACK, NULL);
- } else
- st->l1.requestpull = !0;
- break;
- }
-
-}
-
-extern struct IsdnBuffers *tracebuf;
-
-static void
-hscx_l2l1discardq(struct PStack *st, int pr, void *heldby,
- int releasetoo)
-{
- struct IsdnCardState *sp = (struct IsdnCardState *)
- st->l1.hardware;
- struct HscxState *hsp = sp->hs + st->l1.hscx;
-
-#ifdef DEBUG_MAGIC
- if (hsp->magic != 301270) {
- printk(KERN_DEBUG "hscx_discardq magic not 301270\n");
- return;
- }
-#endif
-
- BufQueueDiscard(&hsp->sq, pr, heldby, releasetoo);
-}
-
-static int
-open_hscxstate(struct IsdnCardState *sp,
- int hscx)
-{
- struct HscxState *hsp = sp->hs + hscx;
-
- if (!hsp->init) {
- BufPoolInit(&hsp->sbufpool, HSCX_SBUF_ORDER, HSCX_SBUF_BPPS,
- HSCX_SBUF_MAXPAGES);
- BufPoolInit(&hsp->rbufpool, HSCX_RBUF_ORDER, HSCX_RBUF_BPPS,
- HSCX_RBUF_MAXPAGES);
- BufPoolInit(&hsp->smallpool, HSCX_SMALLBUF_ORDER, HSCX_SMALLBUF_BPPS,
- HSCX_SMALLBUF_MAXPAGES);
- }
- hsp->init = !0;
-
- BufQueueInit(&hsp->rq);
- BufQueueInit(&hsp->sq);
-
- hsp->releasebuf = 0;
- hsp->rcvibh = NULL;
- hsp->xmtibh = NULL;
- hsp->rcvptr = 0;
- hsp->sendptr = 0;
- hsp->event = 0;
- return (0);
-}
-
-static void
-hscx_manl1(struct PStack *st, int pr,
- void *arg)
-{
- struct IsdnCardState *sp = (struct IsdnCardState *)
- st->l1.hardware;
- struct HscxState *hsp = sp->hs + st->l1.hscx;
-
- switch (pr) {
- case (PH_ACTIVATE):
- hsp->active = !0;
- modehscx(hsp, st->l1.hscxmode, st->l1.hscxchannel);
- st->l1.l1man(st, PH_ACTIVATE, NULL);
- break;
- case (PH_DEACTIVATE):
- if (!hsp->xmtibh)
- modehscx(hsp, 0, 0);
-
- hsp->active = 0;
- break;
- }
-}
-
-int
-setstack_hscx(struct PStack *st, struct HscxState *hs)
-{
- if (open_hscxstate(st->l1.hardware, hs->hscx))
- return (-1);
-
- st->l1.hscx = hs->hscx;
- st->l2.l2l1 = hscx_l2l1;
- st->ma.manl1 = hscx_manl1;
- st->l2.l2l1discardq = hscx_l2l1discardq;
-
- st->l1.sbufpool = &hs->sbufpool;
- st->l1.rbufpool = &hs->rbufpool;
- st->l1.smallpool = &hs->smallpool;
- st->l1.act_state = 0;
- st->l1.requestpull = 0;
-
- hs->st = st;
- return (0);
-}
-
-void
-teles_reportcard(int cardnr)
-{
- printk(KERN_DEBUG "teles_reportcard\n");
-}
diff --git a/drivers/isdn/teles/config.c b/drivers/isdn/teles/config.c
deleted file mode 100644
index 1a9d2d873..000000000
--- a/drivers/isdn/teles/config.c
+++ /dev/null
@@ -1,48 +0,0 @@
-/* $Id: config.c,v 1.1 1996/04/13 10:23:11 fritz Exp $
- *
- * $Log: config.c,v $
- * Revision 1.1 1996/04/13 10:23:11 fritz
- * Initial revision
- *
- *
- */
-#define __NO_VERSION__
-#include <linux/types.h>
-#include <linux/stddef.h>
-#include <linux/timer.h>
-#include "teles.h"
-
-/*
- * This structure array contains one entry per card. An entry looks
- * like this:
- *
- * { membase,irq,portbase,protocol,NULL }
- *
- * protocol can be either ISDN_PTYPE_EURO or ISDN_PTYPE_1TR6
- *
- * Cards which don't have an io port (Teles 8 bit cards for
- * example) can be entered with io port 0x0
- *
- * For the Teles 16.3, membase has to be set to 0.
- *
- */
-
-struct IsdnCard cards[] =
-{
- {(byte *) 0xd0000, 15, 0xd80, ISDN_PTYPE_EURO, NULL}, /* example */
- {NULL, 0, 0, 0, NULL},
- {NULL, 0, 0, 0, NULL},
- {NULL, 0, 0, 0, NULL},
- {NULL, 0, 0, 0, NULL},
- {NULL, 0, 0, 0, NULL},
- {NULL, 0, 0, 0, NULL},
- {NULL, 0, 0, 0, NULL},
- {NULL, 0, 0, 0, NULL},
- {NULL, 0, 0, 0, NULL},
- {NULL, 0, 0, 0, NULL},
- {NULL, 0, 0, 0, NULL},
- {NULL, 0, 0, 0, NULL},
- {NULL, 0, 0, 0, NULL},
- {NULL, 0, 0, 0, NULL},
- {NULL, 0, 0, 0, NULL},
-};
diff --git a/drivers/isdn/teles/fsm.c b/drivers/isdn/teles/fsm.c
deleted file mode 100644
index 4d651e73e..000000000
--- a/drivers/isdn/teles/fsm.c
+++ /dev/null
@@ -1,156 +0,0 @@
-/* $Id: fsm.c,v 1.3 1997/02/16 01:04:12 fritz Exp $
- *
- * $Log: fsm.c,v $
- * Revision 1.3 1997/02/16 01:04:12 fritz
- * Bugfix: Changed timer handling caused hang with 2.1.X
- *
- * Revision 1.2 1996/04/29 22:49:57 fritz
- * Removed compatibility-macros.
- *
- * Revision 1.1 1996/04/13 10:23:41 fritz
- * Initial revision
- *
- *
- */
-#define __NO_VERSION__
-#include "teles.h"
-
-void
-FsmNew(struct Fsm *fsm,
- struct FsmNode *fnlist, int fncount)
-{
- int i;
-
- fsm->jumpmatrix = (int *) Smalloc(4L * fsm->state_count * fsm->event_count,
- GFP_KERNEL, "Fsm jumpmatrix");
- memset(fsm->jumpmatrix, 0, 4L * fsm->state_count * fsm->event_count);
-
- for (i = 0; i < fncount; i++)
- fsm->jumpmatrix[fsm->state_count * fnlist[i].event +
- fnlist[i].state] = (int) fnlist[i].routine;
-}
-
-void
-FsmFree(struct Fsm *fsm)
-{
- Sfree((void *) fsm->jumpmatrix);
-}
-
-int
-FsmEvent(struct FsmInst *fi, int event, void *arg)
-{
- void (*r) (struct FsmInst *, int, void *);
- char str[80];
-
- r = (void (*)) fi->fsm->jumpmatrix[fi->fsm->state_count * event + fi->state];
- if (r) {
- if (fi->debug) {
- sprintf(str, "State %s Event %s",
- fi->fsm->strState[fi->state],
- fi->fsm->strEvent[event]);
- fi->printdebug(fi, str);
- }
- r(fi, event, arg);
- return (0);
- } else {
- if (fi->debug) {
- sprintf(str, "State %s Event %s no routine",
- fi->fsm->strState[fi->state],
- fi->fsm->strEvent[event]);
- fi->printdebug(fi, str);
- }
- return (!0);
- }
-}
-
-void
-FsmChangeState(struct FsmInst *fi, int newstate)
-{
- char str[80];
-
- fi->state = newstate;
- if (fi->debug) {
- sprintf(str, "ChangeState %s",
- fi->fsm->strState[newstate]);
- fi->printdebug(fi, str);
- }
-}
-
-static void
-FsmExpireTimer(struct FsmTimer *ft)
-{
- FsmEvent(ft->fi, ft->event, ft->arg);
-}
-
-void
-FsmInitTimer(struct FsmInst *fi, struct FsmTimer *ft)
-{
- ft->fi = fi;
- ft->tl.function = (void *) FsmExpireTimer;
- ft->tl.data = (long) ft;
- init_timer(&ft->tl);
-}
-
-void
-FsmDelTimer(struct FsmTimer *ft, int where)
-{
-#if 0
- if (ft->fi->debug) {
- sprintf(str, "FsmDelTimer %lx %d", ft, where);
- ft->fi->printdebug(ft->fi, str);
- }
-#endif
-
- del_timer(&ft->tl);
-}
-
-int
-FsmAddTimer(struct FsmTimer *ft,
- int millisec, int event, void *arg, int where)
-{
-
-#if 0
- if (ft->fi->debug) {
- sprintf(str, "FsmAddTimer %lx %d %d", ft, millisec, where);
- ft->fi->printdebug(ft->fi, str);
- }
-#endif
-
- if (ft->tl.next || ft->tl.prev) {
- printk(KERN_WARNING "FsmAddTimer: timer already active!\n");
- return -1;
- }
- init_timer(&ft->tl);
- ft->event = event;
- ft->arg = arg;
- ft->tl.expires = jiffies + (millisec * HZ) / 1000;
- add_timer(&ft->tl);
- return 0;
-}
-
-int
-FsmTimerRunning(struct FsmTimer *ft)
-{
- return (ft->tl.next != NULL);
-}
-
-void
-jiftime(char *s, long mark)
-{
- s += 8;
-
- *s-- = '\0';
- *s-- = mark % 10 + '0';
- mark /= 10;
- *s-- = mark % 10 + '0';
- mark /= 10;
- *s-- = '.';
- *s-- = mark % 10 + '0';
- mark /= 10;
- *s-- = mark % 6 + '0';
- mark /= 6;
- *s-- = ':';
- *s-- = mark % 10 + '0';
- mark /= 10;
- *s-- = mark % 10 + '0';
-}
diff --git a/drivers/isdn/teles/isdnl2.c b/drivers/isdn/teles/isdnl2.c
deleted file mode 100644
index 98171aa7d..000000000
--- a/drivers/isdn/teles/isdnl2.c
+++ /dev/null
@@ -1,1320 +0,0 @@
-/* $Id: isdnl2.c,v 1.3 1996/11/23 11:32:57 keil Exp $
- *
- * $Log: isdnl2.c,v $
- * Revision 1.3 1996/11/23 11:32:57 keil
- * X.75 bugfixies; Thanks to Martin Maurer
- *
- * Revision 1.2 1996/05/17 03:46:15 fritz
- * General cleanup.
- *
- * Revision 1.1 1996/04/13 10:24:16 fritz
- * Initial revision
- *
- *
- */
-#define __NO_VERSION__
-#include "teles.h"
-
-#define TIMER_1 2000
-
-static void l2m_debug(struct FsmInst *fi, char *s);
-
-struct Fsm l2fsm =
-{NULL, 0, 0};
-
-enum {
- ST_L2_1,
- ST_L2_3,
- ST_L2_4,
- ST_L2_5,
- ST_L2_6,
- ST_L2_7,
- ST_L2_8,
-};
-
-#define L2_STATE_COUNT (ST_L2_8+1)
-
-static char *strL2State[] =
-{
- "ST_L2_1",
- "ST_L2_3",
- "ST_L2_4",
- "ST_L2_5",
- "ST_L2_6",
- "ST_L2_7",
- "ST_L2_8",
-};
-
-enum {
- EV_L2_UI,
- EV_L2_SABMX,
- EV_L2_UA,
- EV_L2_DISC,
- EV_L2_I,
- EV_L2_RR,
- EV_L2_REJ,
- EV_L2_FRMR,
- EV_L2_DL_DATA,
- EV_L2_DL_ESTABLISH,
- EV_L2_MDL_ASSIGN,
- EV_L2_DL_UNIT_DATA,
- EV_L2_DL_RELEASE,
- EV_L2_MDL_NOTEIPROC,
- EV_L2_T200,
- EV_L2_ACK_PULL,
- EV_L2_T203,
- EV_L2_RNR,
-};
-
-#define L2_EVENT_COUNT (EV_L2_RNR+1)
-
-static char *strL2Event[] =
-{
- "EV_L2_UI",
- "EV_L2_SABMX",
- "EV_L2_UA",
- "EV_L2_DISC",
- "EV_L2_I",
- "EV_L2_RR",
- "EV_L2_REJ",
- "EV_L2_FRMR",
- "EV_L2_DL_DATA",
- "EV_L2_DL_ESTABLISH",
- "EV_L2_MDL_ASSIGN",
- "EV_L2_DL_UNIT_DATA",
- "EV_L2_DL_RELEASE",
- "EV_L2_MDL_NOTEIPROC",
- "EV_L2_T200",
- "EV_L2_ACK_PULL",
- "EV_L2_T203",
- "EV_L2_RNR",
-};
-
-int errcount = 0;
-
-static int l2addrsize(struct Layer2 *tsp);
-
-static int
-cansend(struct PStack *st)
-{
- int p1;
-
- p1 = (st->l2.va + st->l2.window) % (st->l2.extended ? 128 : 8);
- return (st->l2.vs != p1);
-}
-
-static void
-discard_i_queue(struct PStack *st)
-{
- struct BufHeader *ibh;
-
- while (!BufQueueUnlink(&ibh, &st->l2.i_queue))
- BufPoolRelease(ibh);
-}
-
-int
-l2headersize(struct Layer2 *tsp, int UI)
-{
- return ((tsp->extended && (!UI) ? 2 : 1) + (tsp->laptype == LAPD ? 2 : 1));
-}
-
-int
-l2addrsize(struct Layer2 *tsp)
-{
- return (tsp->laptype == LAPD ? 2 : 1);
-}
-
-static int
-sethdraddr(struct Layer2 *tsp,
- struct BufHeader *ibh, int rsp)
-{
- byte *ptr = DATAPTR(ibh);
- int crbit;
-
- if (tsp->laptype == LAPD) {
- crbit = rsp;
- if (!tsp->orig)
- crbit = !crbit;
- *ptr++ = (tsp->sap << 2) | (crbit ? 2 : 0);
- *ptr++ = (tsp->tei << 1) | 1;
- return (2);
- } else {
- crbit = rsp;
- if (tsp->orig)
- crbit = !crbit;
- if (crbit)
- *ptr++ = 1;
- else
- *ptr++ = 3;
- return (1);
- }
-}
-
-static void
-enqueue_ui(struct PStack *st,
- struct BufHeader *ibh)
-{
- st->l2.l2l1(st, PH_DATA, ibh);
-}
-
-static void
-enqueue_super(struct PStack *st,
- struct BufHeader *ibh)
-{
- st->l2.l2l1(st, PH_DATA, ibh);
-}
-
-static int
-legalnr(struct PStack *st, int nr)
-{
- struct Layer2 *l2 = &st->l2;
- int lnr, lvs;
-
- lvs = (l2->vs >= l2->va) ? l2->vs : (l2->vs + l2->extended ? 128 : 8);
- lnr = (nr >= l2->va) ? nr : (nr + l2->extended ? 128 : 8);
- return (lnr <= lvs);
-}
-
-static void
-setva(struct PStack *st, int nr)
-{
- struct Layer2 *l2 = &st->l2;
-
- if (l2->va != nr) {
- while (l2->va != nr) {
- l2->va = (l2->va + 1) % (l2->extended ? 128 : 8);
- BufPoolRelease(l2->windowar[l2->sow]);
- l2->sow = (l2->sow + 1) % l2->window;
- }
- if (st->l4.l2writewakeup)
- st->l4.l2writewakeup(st);
- }
-}
-
-static void
-l2s1(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- st->l2.l2tei(st, MDL_ASSIGN, (void *)st->l2.ces);
- FsmChangeState(fi, ST_L2_3);
-}
-
-static void
-l2s2(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct BufHeader *ibh = arg;
-
- byte *ptr;
- int i;
-
- i = sethdraddr(&(st->l2), ibh, 0);
- ptr = DATAPTR(ibh);
- ptr += i;
- *ptr = 0x3;
-
- enqueue_ui(st, ibh);
-}
-
-static void
-l2s3(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct BufHeader *ibh = arg;
-
- st->l2.l2l3(st, DL_UNIT_DATA, ibh);
-}
-
-static void
-establishlink(struct FsmInst *fi)
-{
- struct PStack *st = fi->userdata;
- struct BufHeader *ibh;
- int i;
- byte *ptr;
-
- FsmChangeState(fi, ST_L2_5);
- st->l2.rc = 0;
-
- if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 1))
- if (st->l2.l2m.debug)
- l2m_debug(&st->l2.l2m, "FAT 1");
-
-
- if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 15))
- return;
- i = sethdraddr(&st->l2, ibh, 0);
- ptr = DATAPTR(ibh);
- ptr += i;
- if (st->l2.extended)
- *ptr = 0x7f;
- else
- *ptr = 0x3f;
- ibh->datasize = i + 1;
-
- enqueue_super(st, ibh);
-}
-
-static void
-l2s11(struct FsmInst *fi, int event, void *arg)
-{
- establishlink(fi);
-}
-
-static void
-l2s13(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct Channel *chanp = st->l4.userdata;
- byte *ptr;
- struct BufHeader *ibh;
- int i;
-
- FsmChangeState(fi, ST_L2_6);
-
- FsmDelTimer(&st->l2.t203_timer, 1);
- if (st->l2.t200_running) {
- FsmDelTimer(&st->l2.t200_timer, 2);
- st->l2.t200_running = 0;
- }
- st->l2.rc = 0;
- if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 2))
- if (st->l2.l2m.debug)
- l2m_debug(&st->l2.l2m, "FAT 2");
-
-
- if ((chanp->impair == 2) && (st->l2.laptype == LAPB))
- goto nodisc;
-
- if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 9))
- return;
- i = sethdraddr(&(st->l2), ibh, 0);
- ptr = DATAPTR(ibh);
- ptr += i;
- *ptr = 0x53;
- ibh->datasize = i + 1;
- enqueue_super(st, ibh);
-
- nodisc:
- discard_i_queue(st);
-}
-
-static void
-l2s12(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct BufHeader *ibh = arg;
- byte *ptr;
- int i;
-
- BufPoolRelease(ibh);
- st->l2.vs = 0;
- st->l2.va = 0;
- st->l2.vr = 0;
- st->l2.sow = 0;
- FsmChangeState(fi, ST_L2_7);
- if (FsmAddTimer(&st->l2.t203_timer, st->l2.t203, EV_L2_T203, NULL, 3))
- if (st->l2.l2m.debug)
- l2m_debug(&st->l2.l2m, "FAT 3");
-
- st->l2.l2man(st, DL_ESTABLISH, NULL);
-
- if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 10))
- return;
- i = sethdraddr(&(st->l2), ibh, !0);
- ptr = DATAPTR(ibh);
- ptr += i;
- *ptr = 0x73;
- ibh->datasize = i + 1;
- enqueue_super(st, ibh);
-
-}
-
-static void
-l2s14(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct BufHeader *ibh = arg;
- struct Channel *chanp = st->l4.userdata;
- byte *ptr;
- int i, p;
-
- ptr = DATAPTR(ibh);
- ptr += l2addrsize(&(st->l2));
- p = (*ptr) & 0x10;
- BufPoolRelease(ibh);
-
- FsmChangeState(fi, ST_L2_4);
-
- FsmDelTimer(&st->l2.t203_timer, 3);
- if (st->l2.t200_running) {
- FsmDelTimer(&st->l2.t200_timer, 4);
- st->l2.t200_running = 0;
- }
- if ((chanp->impair == 1) && (st->l2.laptype == LAPB))
- goto noresponse;
-
- if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 11))
- return;
- i = sethdraddr(&(st->l2), ibh, 0);
- ptr = DATAPTR(ibh);
- ptr += i;
- *ptr = 0x63 | (p ? 0x10 : 0x0);
- ibh->datasize = i + 1;
- enqueue_super(st, ibh);
-
- noresponse:
- st->l2.l2man(st, DL_RELEASE, NULL);
-
-}
-
-static void
-l2s5(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct BufHeader *ibh = arg;
- int f;
- byte *data;
-
- data = DATAPTR(ibh);
- data += l2addrsize(&(st->l2));
-
- f = *data & 0x10;
- BufPoolRelease(ibh);
-
- if (f) {
- st->l2.vs = 0;
- st->l2.va = 0;
- st->l2.vr = 0;
- st->l2.sow = 0;
- FsmChangeState(fi, ST_L2_7);
-
- FsmDelTimer(&st->l2.t200_timer, 5);
- if (FsmAddTimer(&st->l2.t203_timer, st->l2.t203, EV_L2_T203, NULL, 4))
- if (st->l2.l2m.debug)
- l2m_debug(&st->l2.l2m, "FAT 4");
-
-
- st->l2.l2man(st, DL_ESTABLISH, NULL);
- }
-}
-
-static void
-l2s15(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct BufHeader *ibh = arg;
- int f;
- byte *data;
-
- data = DATAPTR(ibh);
- data += l2addrsize(&st->l2);
-
- f = *data & 0x10;
- BufPoolRelease(ibh);
-
- if (f) {
- FsmDelTimer(&st->l2.t200_timer, 6);
- FsmChangeState(fi, ST_L2_4);
- st->l2.l2man(st, DL_RELEASE, NULL);
- }
-}
-
-static void
-l2s6(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct Channel *chanp = st->l4.userdata;
- struct BufHeader *ibh = arg;
- int p, i, seq, rsp;
- byte *ptr;
- struct Layer2 *l2;
-
- l2 = &st->l2;
- ptr = DATAPTR(ibh);
-
- if (l2->laptype == LAPD) {
- rsp = ptr[0] & 0x2;
- if (l2->orig)
- rsp = !rsp;
- } else {
- rsp = ptr[0] == 0x3;
- if (l2->orig)
- rsp = !rsp;
- }
-
- ptr += l2addrsize(l2);
-
- if (l2->extended) {
- p = (ptr[1] & 0x1) == 0x1;
- seq = ptr[1] >> 1;
- } else {
- p = (ptr[0] & 0x10);
- seq = (ptr[0] >> 5) & 0x7;
- }
- BufPoolRelease(ibh);
-
- if ((chanp->impair == 4) && (st->l2.laptype == LAPB))
- goto noresp;
-
- if ((!rsp) && p) {
- if (!BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 12)) {
- i = sethdraddr(l2, ibh, !0);
- ptr = DATAPTR(ibh);
- ptr += i;
-
- if (l2->extended) {
- *ptr++ = 0x1;
- *ptr++ = (l2->vr << 1) | (p ? 1 : 0);
- i += 2;
- } else {
- *ptr++ = (l2->vr << 5) | 0x1 | (p ? 0x10 : 0x0);
- i += 1;
- }
- ibh->datasize = i;
- enqueue_super(st, ibh);
- }
- }
- noresp:
- if (legalnr(st, seq))
- if (seq == st->l2.vs) {
- setva(st, seq);
- FsmDelTimer(&st->l2.t200_timer, 7);
- st->l2.t200_running = 0;
- FsmDelTimer(&st->l2.t203_timer, 8);
- if (FsmAddTimer(&st->l2.t203_timer, st->l2.t203, EV_L2_T203, NULL, 5))
- if (st->l2.l2m.debug)
- l2m_debug(&st->l2.l2m, "FAT 5");
-
- if (st->l2.i_queue.head)
- st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
- } else if (st->l2.va != seq) {
- setva(st, seq);
- FsmDelTimer(&st->l2.t200_timer, 9);
- if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 6))
- if (st->l2.l2m.debug)
- l2m_debug(&st->l2.l2m, "FAT 6");
-
- if (st->l2.i_queue.head)
- st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
- }
-}
-
-static void
-l2s7(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct BufHeader *ibh = arg;
- int i;
- byte *ptr;
- struct IsdnCardState *sp = st->l1.hardware;
- char str[64];
-
- i = sethdraddr(&st->l2, ibh, 0);
- ptr = DATAPTR(ibh);
-
- if (st->l2.laptype == LAPD)
- if (sp->dlogflag) {
- sprintf(str, "Q.931 frame user->network tei %d", st->l2.tei);
- dlogframe(sp, ptr + st->l2.ihsize, ibh->datasize - st->l2.ihsize,
- str);
- }
- BufQueueLink(&st->l2.i_queue, ibh);
-
- st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
-}
-
-static void
-l2s8(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct Channel *chanp = st->l4.userdata;
- struct BufHeader *ibh = arg;
- byte *ptr;
- struct BufHeader *ibh2;
- struct IsdnCardState *sp = st->l1.hardware;
- struct Layer2 *l2 = &(st->l2);
- int i, p, seq, nr, wasok;
- char str[64];
-
- ptr = DATAPTR(ibh);
- ptr += l2addrsize(l2);
- if (l2->extended) {
- p = (ptr[1] & 0x1) == 0x1;
- seq = ptr[0] >> 1;
- nr = (ptr[1] >> 1) & 0x7f;
- } else {
- p = (ptr[0] & 0x10);
- seq = (ptr[0] >> 1) & 0x7;
- nr = (ptr[0] >> 5) & 0x7;
- }
-
- if (l2->vr == seq) {
- wasok = !0;
-
- l2->vr = (l2->vr + 1) % (l2->extended ? 128 : 8);
- l2->rejexp = 0;
-
- ptr = DATAPTR(ibh);
- if (st->l2.laptype == LAPD)
- if (sp->dlogflag) {
- sprintf(str, "Q.931 frame network->user tei %d", st->l2.tei);
- dlogframe(st->l1.hardware, ptr + l2->ihsize,
- ibh->datasize - l2->ihsize, str);
- }
- label8_1:
- if ((chanp->impair == 3) && (st->l2.laptype == LAPB))
- goto noRR;
-
- if (!BufPoolGet(&ibh2, st->l1.smallpool, GFP_ATOMIC, (void *) st, 13)) {
- i = sethdraddr(&(st->l2), ibh2, !0);
- ptr = DATAPTR(ibh2);
- ptr += i;
-
- if (l2->extended) {
- *ptr++ = 0x1;
- *ptr++ = (l2->vr << 1) | (p ? 1 : 0);
- i += 2;
- } else {
- *ptr++ = (l2->vr << 5) | 0x1 | (p ? 0x10 : 0x0);
- i += 1;
- }
- ibh2->datasize = i;
- enqueue_super(st, ibh2);
- noRR:
- }
- } else {
- /* n(s)!=v(r) */
- wasok = 0;
- BufPoolRelease(ibh);
- if (st->l2.rejexp) {
- if (p)
- goto label8_1;
- } else {
- st->l2.rejexp = !0;
- if (!BufPoolGet(&ibh2, st->l1.smallpool, GFP_ATOMIC, (void *) st, 14)) {
- i = sethdraddr(&(st->l2), ibh2, p);
- ptr = DATAPTR(ibh2);
- ptr += i;
-
- if (l2->extended) {
- *ptr++ = 0x9;
- *ptr++ = (l2->vr << 1) | (p ? 1 : 0);
- i += 2;
- } else {
- *ptr++ = (l2->vr << 5) | 0x9 | (p ? 0x10 : 0x0);
- i += 1;
- }
- ibh2->datasize = i;
- enqueue_super(st, ibh2);
- }
- }
- }
-
- if (legalnr(st, nr))
- if (nr == st->l2.vs) {
- setva(st, nr);
- FsmDelTimer(&st->l2.t200_timer, 10);
- st->l2.t200_running = 0;
- FsmDelTimer(&st->l2.t203_timer, 11);
- if (FsmAddTimer(&st->l2.t203_timer, st->l2.t203, EV_L2_T203, NULL, 7))
- if (st->l2.l2m.debug)
- l2m_debug(&st->l2.l2m, "FAT 5");
-
- if (st->l2.i_queue.head)
- st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
- } else if (nr != st->l2.va) {
- setva(st, nr);
- FsmDelTimer(&st->l2.t200_timer, 12);
- if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 8))
- if (st->l2.l2m.debug)
- l2m_debug(&st->l2.l2m, "FAT 6");
-
- if (st->l2.i_queue.head)
- st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
- }
- if (wasok)
- st->l2.l2l3(st, DL_DATA, ibh);
-
-}
-
-static void
-l2s17(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- st->l2.tei = (int) arg;
- establishlink(fi);
-}
-
-static void
-enquiry_response(struct PStack *st)
-{
- struct BufHeader *ibh2;
- int i;
- byte *ptr;
- struct Layer2 *l2;
-
- l2 = &st->l2;
- if (!BufPoolGet(&ibh2, st->l1.smallpool, GFP_ATOMIC, (void *) st, 16)) {
- i = sethdraddr(&(st->l2), ibh2, !0);
- ptr = DATAPTR(ibh2);
- ptr += i;
-
- if (l2->extended) {
- *ptr++ = 0x1;
- *ptr++ = (l2->vr << 1) | 0x1;
- i += 2;
- } else {
- *ptr++ = (l2->vr << 5) | 0x1 | 0x10;
- i += 1;
- }
- ibh2->datasize = i;
- enqueue_super(st, ibh2);
- }
-}
-
-static void
-invoke_retransmission(struct PStack *st, int nr)
-{
- struct Layer2 *l2 = &st->l2;
- int p1;
-
- if (l2->vs != nr) {
- while (l2->vs != nr) {
-
- l2->vs = l2->vs - 1;
- if (l2->vs < 0)
- l2->vs += l2->extended ? 128 : 8;
-
- p1 = l2->vs - l2->va;
- if (p1 < 0)
- p1 += l2->extended ? 128 : 8;
- p1 = (p1 + l2->sow) % l2->window;
-
- BufQueueLinkFront(&l2->i_queue, l2->windowar[p1]);
- }
- st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
- }
-}
-
-static void
-l2s16(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct BufHeader *ibh = arg;
- int p, seq, rsp;
- byte *ptr;
- struct Layer2 *l2;
-
- l2 = &(st->l2);
- ptr = DATAPTR(ibh);
-
- if (l2->laptype == LAPD) {
- rsp = ptr[0] & 0x2;
- if (l2->orig)
- rsp = !rsp;
- } else {
- rsp = ptr[0] == 0x3;
- if (l2->orig)
- rsp = !rsp;
- }
-
-
- ptr += l2addrsize(l2);
-
- if (l2->extended) {
- p = (ptr[1] & 0x1) == 0x1;
- seq = ptr[1] >> 1;
- } else {
- p = (ptr[0] & 0x10);
- seq = (ptr[0] >> 5) & 0x7;
- }
- BufPoolRelease(ibh);
-
- if ((!rsp) && p)
- enquiry_response(st);
-
- if (!legalnr(st, seq))
- return;
-
- setva(st, seq);
- invoke_retransmission(st, seq);
-
-}
-
-static void
-l2s19(struct FsmInst *fi, int event, void *arg)
-{
- FsmChangeState(fi, ST_L2_4);
-}
-
-static void
-l2s20(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- int i;
- struct BufHeader *ibh;
- byte *ptr;
-
- if (st->l2.rc == st->l2.n200) {
- FsmChangeState(fi, ST_L2_4);
- st->l2.l2man(st, DL_RELEASE, NULL);
- } else {
- st->l2.rc++;
-
- if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 9))
- if (st->l2.l2m.debug)
- l2m_debug(&st->l2.l2m, "FAT 7");
-
- if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 15))
- return;
-
- i = sethdraddr(&st->l2, ibh, 0);
- ptr = DATAPTR(ibh);
- ptr += i;
- if (st->l2.extended)
- *ptr = 0x7f;
- else
- *ptr = 0x3f;
- ibh->datasize = i + 1;
- enqueue_super(st, ibh);
- }
-}
-
-static void
-l2s21(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct Channel *chanp = st->l4.userdata;
- int i;
- struct BufHeader *ibh;
- byte *ptr;
-
- if (st->l2.rc == st->l2.n200) {
- FsmChangeState(fi, ST_L2_4);
- st->l2.l2man(st, DL_RELEASE, NULL);
- } else {
- st->l2.rc++;
-
- if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 10))
- if (st->l2.l2m.debug)
- l2m_debug(&st->l2.l2m, "FAT 8");
-
-
- if ((chanp->impair == 2) && (st->l2.laptype == LAPB))
- goto nodisc;
-
- if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 15))
- return;
-
- i = sethdraddr(&st->l2, ibh, 0);
- ptr = DATAPTR(ibh);
- ptr += i;
- *ptr = 0x53;
- ibh->datasize = i + 1;
- enqueue_super(st, ibh);
- nodisc:
-
- }
-}
-
-static void
-l2s22(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct BufHeader *ibh;
- struct Layer2 *l2 = &st->l2;
- byte *ptr;
- int p1;
-
- if (!cansend(st))
- return;
-
- if (BufQueueUnlink(&ibh, &l2->i_queue))
- return;
-
-
- p1 = l2->vs - l2->va;
- if (p1 < 0)
- p1 += l2->extended ? 128 : 8;
- p1 = (p1 + l2->sow) % l2->window;
- l2->windowar[p1] = ibh;
-
- ptr = DATAPTR(ibh);
- ptr += l2addrsize(l2);
-
- if (l2->extended) {
- *ptr++ = l2->vs << 1;
- *ptr++ = (l2->vr << 1) | 0x1;
- l2->vs = (l2->vs + 1) % 128;
- } else {
- *ptr++ = (l2->vr << 5) | (l2->vs << 1);
- l2->vs = (l2->vs + 1) % 8;
- }
-
- st->l2.l2l1(st, PH_DATA_PULLED, ibh);
-
- if (!st->l2.t200_running) {
- FsmDelTimer(&st->l2.t203_timer, 13);
- if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 11))
- if (st->l2.l2m.debug)
- l2m_debug(&st->l2.l2m, "FAT 9");
-
- st->l2.t200_running = !0;
- }
- if (l2->i_queue.head && cansend(st))
- st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
-
-}
-
-static void
-transmit_enquiry(struct PStack *st)
-{
- struct BufHeader *ibh;
- byte *ptr;
-
- if (!BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 12)) {
- ptr = DATAPTR(ibh);
- ptr += sethdraddr(&st->l2, ibh, 0);
-
- if (st->l2.extended) {
- *ptr++ = 0x1;
- *ptr++ = (st->l2.vr << 1) | 1;
- } else {
- *ptr++ = (st->l2.vr << 5) | 0x11;
- }
- ibh->datasize = ptr - DATAPTR(ibh);
- enqueue_super(st, ibh);
- if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 12))
- if (st->l2.l2m.debug)
- l2m_debug(&st->l2.l2m, "FAT 10");
-
- st->l2.t200_running = !0;
- }
-}
-
-static void
-l2s23(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- st->l2.t200_running = 0;
-
- st->l2.rc = 1;
- FsmChangeState(fi, ST_L2_8);
- transmit_enquiry(st);
-}
-
-static void
-l2s24(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct BufHeader *ibh = arg;
- int p, seq, rsp;
- byte *ptr;
- struct Layer2 *l2;
-
- l2 = &st->l2;
- ptr = DATAPTR(ibh);
-
- if (l2->laptype == LAPD) {
- rsp = ptr[0] & 0x2;
- if (l2->orig)
- rsp = !rsp;
- } else {
- rsp = ptr[0] == 0x3;
- if (l2->orig)
- rsp = !rsp;
- }
-
-
- ptr += l2addrsize(l2);
-
- if (l2->extended) {
- p = (ptr[1] & 0x1) == 0x1;
- seq = ptr[1] >> 1;
- } else {
- p = (ptr[0] & 0x10);
- seq = (ptr[0] >> 5) & 0x7;
- }
- BufPoolRelease(ibh);
-
- if (rsp && p) {
- if (legalnr(st, seq)) {
- FsmChangeState(fi, ST_L2_7);
- setva(st, seq);
- if (st->l2.t200_running) {
- FsmDelTimer(&st->l2.t200_timer, 14);
- st->l2.t200_running = 0;
- }
- if (FsmAddTimer(&st->l2.t203_timer, st->l2.t203, EV_L2_T203, NULL, 13))
- if (st->l2.l2m.debug)
- l2m_debug(&st->l2.l2m, "FAT 11");
-
- invoke_retransmission(st, seq);
- }
- } else {
- if (!rsp && p)
- enquiry_response(st);
- if (legalnr(st, seq)) {
- setva(st, seq);
- }
- }
-}
-
-static void
-l2s25(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- st->l2.rc = 0;
- FsmChangeState(fi, ST_L2_8);
- transmit_enquiry(st);
-}
-
-static void
-l2s26(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- if (st->l2.rc == st->l2.n200) {
- l2s13(fi, event, NULL);
- } else {
- st->l2.rc++;
- transmit_enquiry(st);
- }
-}
-
-static void
-l2s27(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct BufHeader *ibh = arg;
- byte *ptr;
- int i, p, est;
-
- ptr = DATAPTR(ibh);
- ptr += l2addrsize(&st->l2);
-
- if (st->l2.extended)
- p = ptr[1] & 0x1;
- else
- p = ptr[0] & 0x10;
-
- BufPoolRelease(ibh);
-
- if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 10))
- return;
- i = sethdraddr(&st->l2, ibh, 0);
- ptr = DATAPTR(ibh);
- ptr += i;
- *ptr = 0x63 | p;
- ibh->datasize = i + 1;
- enqueue_super(st, ibh);
-
- if (st->l2.vs != st->l2.va) {
- discard_i_queue(st);
- est = !0;
- } else
- est = 0;
-
- FsmDelTimer(&st->l2.t200_timer, 15);
- st->l2.t200_running = 0;
-
- if (FsmAddTimer(&st->l2.t203_timer, st->l2.t203, EV_L2_T203, NULL, 3))
- if (st->l2.l2m.debug)
- l2m_debug(&st->l2.l2m, "FAT 12");
-
- st->l2.vs = 0;
- st->l2.va = 0;
- st->l2.vr = 0;
- st->l2.sow = 0;
-
-
- if (est)
- st->l2.l2man(st, DL_ESTABLISH, NULL);
-
-}
-
-static void
-l2s28(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct BufHeader *ibh = arg;
- byte *ptr;
- char tmp[64];
-
- ptr = DATAPTR(ibh);
- ptr += l2addrsize(&st->l2);
- ptr++;
-
- if (st->l2.l2m.debug) {
- if (st->l2.extended)
- sprintf(tmp, "FRMR information %2x %2x %2x %2x %2x",
- ptr[0], ptr[1], ptr[2], ptr[3], ptr[4]);
- else
- sprintf(tmp, "FRMR information %2x %2x %2x",
- ptr[0], ptr[1], ptr[2]);
-
- l2m_debug(&st->l2.l2m, tmp);
- }
- BufPoolRelease(ibh);
-}
-
-static int
-IsUI(byte * data, int ext)
-{
- return ((data[0] & 0xef) == 0x3);
-}
-
-static int
-IsUA(byte * data, int ext)
-{
- return ((data[0] & 0xef) == 0x63);
-}
-
-static int
-IsDISC(byte * data, int ext)
-{
- return ((data[0] & 0xef) == 0x43);
-}
-
-static int
-IsRR(byte * data, int ext)
-{
- if (ext)
- return (data[0] == 0x1);
- else
- return ((data[0] & 0xf) == 1);
-}
-
-static int
-IsI(byte * data, int ext)
-{
- return ((data[0] & 0x1) == 0x0);
-}
-
-static int
-IsSABMX(byte * data, int ext)
-{
- return (ext ? data[0] == 0x7f : data[0] == 0x3f);
-}
-
-static int
-IsREJ(byte * data, int ext)
-{
- return (ext ? data[0] == 0x9 : (data[0] & 0xf) == 0x9);
-}
-
-static int
-IsFRMR(byte * data, int ext)
-{
- return ((data[0] & 0xef) == 0x87);
-}
-
-static int
-IsRNR(byte * data, int ext)
-{
- if (ext)
- return (data[0] == 0x5);
- else
- return ((data[0] & 0xf) == 5);
-}
-
-static struct FsmNode L2FnList[] =
-{
- {ST_L2_1, EV_L2_DL_ESTABLISH, l2s1},
- {ST_L2_1, EV_L2_MDL_NOTEIPROC, l2s19},
- {ST_L2_3, EV_L2_MDL_ASSIGN, l2s17},
- {ST_L2_4, EV_L2_DL_UNIT_DATA, l2s2},
- {ST_L2_4, EV_L2_DL_ESTABLISH, l2s11},
- {ST_L2_7, EV_L2_DL_UNIT_DATA, l2s2},
- {ST_L2_7, EV_L2_DL_DATA, l2s7},
- {ST_L2_7, EV_L2_DL_RELEASE, l2s13},
- {ST_L2_7, EV_L2_ACK_PULL, l2s22},
- {ST_L2_8, EV_L2_DL_RELEASE, l2s13},
-
- {ST_L2_1, EV_L2_UI, l2s3},
- {ST_L2_4, EV_L2_UI, l2s3},
- {ST_L2_4, EV_L2_SABMX, l2s12},
- {ST_L2_5, EV_L2_UA, l2s5},
- {ST_L2_6, EV_L2_UA, l2s15},
- {ST_L2_7, EV_L2_UI, l2s3},
- {ST_L2_7, EV_L2_DISC, l2s14},
- {ST_L2_7, EV_L2_I, l2s8},
- {ST_L2_7, EV_L2_RR, l2s6},
- {ST_L2_7, EV_L2_REJ, l2s16},
- {ST_L2_7, EV_L2_SABMX, l2s27},
- {ST_L2_7, EV_L2_FRMR, l2s28},
- {ST_L2_8, EV_L2_RR, l2s24},
- {ST_L2_8, EV_L2_DISC, l2s14},
- {ST_L2_8, EV_L2_FRMR, l2s28},
-
- {ST_L2_5, EV_L2_T200, l2s20},
- {ST_L2_6, EV_L2_T200, l2s21},
- {ST_L2_7, EV_L2_T200, l2s23},
- {ST_L2_7, EV_L2_T203, l2s25},
- {ST_L2_8, EV_L2_T200, l2s26},
-};
-
-#define L2_FN_COUNT (sizeof(L2FnList)/sizeof(struct FsmNode))
-
-static void
-isdnl2_l1l2(struct PStack *st, int pr, struct BufHeader *arg)
-{
- struct BufHeader *ibh;
- byte *datap;
- int ret = !0;
-
- switch (pr) {
- case (PH_DATA):
-
- ibh = arg;
- datap = DATAPTR(ibh);
- datap += l2addrsize(&st->l2);
-
- if (IsI(datap, st->l2.extended))
- ret = FsmEvent(&st->l2.l2m, EV_L2_I, ibh);
- else if (IsRR(datap, st->l2.extended))
- ret = FsmEvent(&st->l2.l2m, EV_L2_RR, ibh);
- else if (IsUI(datap, st->l2.extended))
- ret = FsmEvent(&st->l2.l2m, EV_L2_UI, ibh);
- else if (IsSABMX(datap, st->l2.extended))
- ret = FsmEvent(&st->l2.l2m, EV_L2_SABMX, ibh);
- else if (IsUA(datap, st->l2.extended))
- ret = FsmEvent(&st->l2.l2m, EV_L2_UA, ibh);
- else if (IsDISC(datap, st->l2.extended))
- ret = FsmEvent(&st->l2.l2m, EV_L2_DISC, ibh);
- else if (IsREJ(datap, st->l2.extended))
- ret = FsmEvent(&st->l2.l2m, EV_L2_REJ, ibh);
- else if (IsFRMR(datap, st->l2.extended))
- ret = FsmEvent(&st->l2.l2m, EV_L2_FRMR, ibh);
- else if (IsRNR(datap, st->l2.extended))
- ret = FsmEvent(&st->l2.l2m, EV_L2_RNR, ibh);
-
- if (ret)
- BufPoolRelease(ibh);
-
- break;
- case (PH_PULL_ACK):
- FsmEvent(&st->l2.l2m, EV_L2_ACK_PULL, arg);
- break;
- }
-}
-
-static void
-isdnl2_l3l2(struct PStack *st, int pr,
- void *arg)
-{
- switch (pr) {
- case (DL_DATA):
- if (FsmEvent(&st->l2.l2m, EV_L2_DL_DATA, arg))
- BufPoolRelease((struct BufHeader *) arg);
- break;
- case (DL_UNIT_DATA):
- if (FsmEvent(&st->l2.l2m, EV_L2_DL_UNIT_DATA, arg))
- BufPoolRelease((struct BufHeader *) arg);
- break;
- }
-}
-
-static void
-isdnl2_manl2(struct PStack *st, int pr,
- void *arg)
-{
- switch (pr) {
- case (DL_ESTABLISH):
- FsmEvent(&st->l2.l2m, EV_L2_DL_ESTABLISH, arg);
- break;
- case (DL_RELEASE):
- FsmEvent(&st->l2.l2m, EV_L2_DL_RELEASE, arg);
- break;
- case (MDL_NOTEIPROC):
- FsmEvent(&st->l2.l2m, EV_L2_MDL_NOTEIPROC, NULL);
- break;
- }
-}
-
-static void
-isdnl2_teil2(struct PStack *st, int pr,
- void *arg)
-{
- switch (pr) {
- case (MDL_ASSIGN):
- FsmEvent(&st->l2.l2m, EV_L2_MDL_ASSIGN, arg);
- break;
- }
-}
-
-void
-releasestack_isdnl2(struct PStack *st)
-{
- FsmDelTimer(&st->l2.t200_timer, 15);
- FsmDelTimer(&st->l2.t203_timer, 16);
-}
-
-static void
-l2m_debug(struct FsmInst *fi, char *s)
-{
- struct PStack *st = fi->userdata;
- char tm[32], str[256];
-
- jiftime(tm, jiffies);
- sprintf(str, "%s %s %s\n", tm, st->l2.debug_id, s);
- teles_putstatus(str);
-}
-
-
-void
-setstack_isdnl2(struct PStack *st, char *debug_id)
-{
- st->l1.l1l2 = isdnl2_l1l2;
- st->l3.l3l2 = isdnl2_l3l2;
- st->ma.manl2 = isdnl2_manl2;
- st->ma.teil2 = isdnl2_teil2;
-
- st->l2.uihsize = l2headersize(&st->l2, !0);
- st->l2.ihsize = l2headersize(&st->l2, 0);
- BufQueueInit(&(st->l2.i_queue));
- st->l2.rejexp = 0;
- st->l2.debug = 1;
-
- st->l2.l2m.fsm = &l2fsm;
- st->l2.l2m.state = ST_L2_1;
- st->l2.l2m.debug = 0;
- st->l2.l2m.userdata = st;
- st->l2.l2m.printdebug = l2m_debug;
- strcpy(st->l2.debug_id, debug_id);
-
- FsmInitTimer(&st->l2.l2m, &st->l2.t200_timer);
- FsmInitTimer(&st->l2.l2m, &st->l2.t203_timer);
- st->l2.t200_running = 0;
-}
-
-void
-setstack_transl2(struct PStack *st)
-{
-}
-
-void
-releasestack_transl2(struct PStack *st)
-{
-}
-
-void
-Isdnl2New(void)
-{
- l2fsm.state_count = L2_STATE_COUNT;
- l2fsm.event_count = L2_EVENT_COUNT;
- l2fsm.strEvent = strL2Event;
- l2fsm.strState = strL2State;
- FsmNew(&l2fsm, L2FnList, L2_FN_COUNT);
-}
-
-void
-Isdnl2Free(void)
-{
- FsmFree(&l2fsm);
-}
diff --git a/drivers/isdn/teles/isdnl3.c b/drivers/isdn/teles/isdnl3.c
deleted file mode 100644
index 3bfb47255..000000000
--- a/drivers/isdn/teles/isdnl3.c
+++ /dev/null
@@ -1,673 +0,0 @@
-/* $Id: isdnl3.c,v 1.13 1997/02/16 12:12:51 fritz Exp $
- *
- * $Log: isdnl3.c,v $
- * Revision 1.13 1997/02/16 12:12:51 fritz
- * Bugfix: SI2 was nont initialized on incoming calls.
- *
- * Revision 1.12 1997/02/11 01:39:20 keil
- * Changed setup-interface (incoming and outgoing)
- *
- * Revision 1.11 1996/09/29 19:41:58 fritz
- * Bugfix: ignore unknown frames.
- *
- * Revision 1.10 1996/09/25 18:32:43 keil
- * response for STATUS_ENQ message added
- *
- * Revision 1.9 1996/06/06 14:22:27 fritz
- * Changed level of "non-digital call..." message, since
- * with audio support, this is quite normal.
- *
- * Revision 1.8 1996/06/03 20:35:04 fritz
- * Fixed typos.
- *
- * Revision 1.7 1996/06/03 20:03:39 fritz
- * Fixed typos.
- *
- * Revision 1.6 1996/05/21 11:33:50 keil
- * Adding SETUP_ACKNOWLEDGE as answer of a SETUP message.
- *
- * Revision 1.5 1996/05/18 01:37:16 fritz
- * Added spelling corrections and some minor changes
- * to stay in sync with kernel.
- *
- * Revision 1.4 1996/05/17 03:46:16 fritz
- * General cleanup.
- *
- * Revision 1.3 1996/04/30 21:57:53 isdn4dev
- * remove some debugging code, improve callback Karsten Keil
- *
- * Revision 1.2 1996/04/20 16:45:05 fritz
- * Changed to report all incoming calls to Linklevel, not just those
- * with Service 7.
- * Misc. typos
- *
- * Revision 1.1 1996/04/13 10:24:45 fritz
- * Initial revision
- *
- *
- */
-#define __NO_VERSION__
-#define P_1TR6
-#include "teles.h"
-#include "l3_1TR6.h"
-#define DEBUG_1TR6 0
-
-static void
-i_down(struct PStack *st,
- struct BufHeader *ibh)
-{
- st->l3.l3l2(st, DL_DATA, ibh);
-}
-
-static void
-newl3state(struct PStack *st, int state)
-{
- st->l3.state = state;
- if (DEBUG_1TR6 > 4)
- printk(KERN_INFO "isdnl3: bc:%d cr:%x new state %d\n",
- st->pa->bchannel, st->pa->callref, state);
-
-}
-
-static void
-l3_message(struct PStack *st, int mt)
-{
- struct BufHeader *dibh;
- byte *p;
- int size;
-
- BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 18);
- p = DATAPTR(dibh);
- p += st->l2.ihsize;
- size = st->l2.ihsize;
-
- *p++ = 0x8;
- *p++ = 0x1;
- *p++ = st->l3.callref;
- *p++ = mt;
- size += 4;
-
- dibh->datasize = size;
- i_down(st, dibh);
-}
-
-static void
-l3s3(struct PStack *st, byte pr, void *arg)
-{
- l3_message(st, MT_RELEASE);
- newl3state(st, 19);
-}
-
-static void
-l3s4(struct PStack *st, byte pr, void *arg)
-{
- struct BufHeader *ibh = arg;
-
- BufPoolRelease(ibh);
- newl3state(st, 0);
- st->l3.l3l4(st, CC_RELEASE_CNF, NULL);
-}
-
-static void
-l3s4_1(struct PStack *st, byte pr, void *arg)
-{
- struct BufHeader *ibh = arg;
-
- BufPoolRelease(ibh);
- newl3state(st, 19);
- l3_message(st, MT_RELEASE);
- st->l3.l3l4(st, CC_RELEASE_CNF, NULL);
-}
-
-static void
-l3s5(struct PStack *st, byte pr,
- void *arg)
-{
- struct BufHeader *dibh;
- byte *p;
- char *teln;
-
- st->l3.callref = st->pa->callref;
- BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 19);
- p = DATAPTR(dibh);
- p += st->l2.ihsize;
-
- *p++ = 0x8;
- *p++ = 0x1;
- *p++ = st->l3.callref;
- *p++ = MT_SETUP;
- *p++ = 0xa1;
-
- /*
- * Set Bearer Capability, Map info from 1TR6-convention to EDSS1
- */
- switch (st->pa->setup.si1) {
- case 1: /* Telephony */
- *p++ = 0x4; /* BC-IE-code */
- *p++ = 0x3; /* Length */
- *p++ = 0x90; /* Coding Std. national, 3.1 kHz audio */
- *p++ = 0x90; /* Circuit-Mode 64kbps */
- *p++ = 0xa3; /* A-Law Audio */
- break;
- case 5: /* Datatransmission 64k, BTX */
- case 7: /* Datatransmission 64k */
- default:
- *p++ = 0x4; /* BC-IE-code */
- *p++ = 0x2; /* Length */
- *p++ = 0x88; /* Coding Std. nat., unrestr. dig. Inform. */
- *p++ = 0x90; /* Packet-Mode 64kbps */
- break;
- }
- /*
- * What about info2? Mapping to High-Layer-Compatibility?
- */
- if (st->pa->setup.eazmsn[0] != '\0') {
- *p++ = 0x6c;
- *p++ = strlen(st->pa->setup.eazmsn) + 1;
- /* Classify as AnyPref. */
- *p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
- teln = st->pa->setup.eazmsn;
- while (*teln)
- *p++ = *teln++ & 0x7f;
- }
- *p++ = 0x70;
- *p++ = strlen(st->pa->setup.phone) + 1;
- /* Classify as AnyPref. */
- *p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
-
- teln = st->pa->setup.phone;
- while (*teln)
- *p++ = *teln++ & 0x7f;
-
-
- dibh->datasize = p - DATAPTR(dibh);
-
- newl3state(st, 1);
- i_down(st, dibh);
-
-}
-
-static void
-l3s6(struct PStack *st, byte pr, void *arg)
-{
- byte *p;
- struct BufHeader *ibh = arg;
-
- p = DATAPTR(ibh);
- if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize,
- 0x18, 0))) {
- st->pa->bchannel = p[2] & 0x3;
- } else
- printk(KERN_WARNING "octect 3 not found\n");
-
- BufPoolRelease(ibh);
- newl3state(st, 3);
- st->l3.l3l4(st, CC_PROCEEDING_IND, NULL);
-}
-
-static void
-l3s7(struct PStack *st, byte pr, void *arg)
-{
- struct BufHeader *ibh = arg;
-
- BufPoolRelease(ibh);
- newl3state(st, 12);
- st->l3.l3l4(st, CC_DISCONNECT_IND, NULL);
-}
-
-static void
-l3s8(struct PStack *st, byte pr, void *arg)
-{
- struct BufHeader *ibh = arg;
-
- BufPoolRelease(ibh);
- st->l3.l3l4(st, CC_SETUP_CNF, NULL);
- newl3state(st, 10);
-}
-
-static void
-l3s11(struct PStack *st, byte pr, void *arg)
-{
- struct BufHeader *ibh = arg;
-
- BufPoolRelease(ibh);
- newl3state(st, 4);
- st->l3.l3l4(st, CC_ALERTING_IND, NULL);
-}
-
-static void
-l3s12(struct PStack *st, byte pr, void *arg)
-{
- byte *p;
- int bcfound = 0;
- struct BufHeader *ibh = arg;
-
- p = DATAPTR(ibh);
- p += st->l2.uihsize;
- st->pa->callref = getcallref(p);
- st->l3.callref = 0x80 + st->pa->callref;
-
- /*
- * Channel Identification
- */
- p = DATAPTR(ibh);
- if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize,
- 0x18, 0))) {
- st->pa->bchannel = p[2] & 0x3;
- bcfound++ ;
- } else
- printk(KERN_WARNING "l3s12: Channel ident not found\n");
-
- p = DATAPTR(ibh);
- if (st->protocol == ISDN_PTYPE_1TR6) {
- if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize, 0x01, 6))) {
- st->pa->setup.si1 = p[2];
- st->pa->setup.si2 = p[3];
- } else
- printk(KERN_WARNING "l3s12(1TR6): ServiceIndicator not found\n");
- } else {
- /*
- * Bearer Capabilities
- */
- if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize, 0x04, 0))) {
- st->pa->setup.si2 = 0;
- switch (p[2] & 0x1f) {
- case 0x00:
- /* Speech */
- case 0x10:
- /* 3.1 Khz audio */
- st->pa->setup.si1 = 1;
- break;
- case 0x08:
- /* Unrestricted digital information */
- st->pa->setup.si1 = 7;
- break;
- case 0x09:
- /* Restricted digital information */
- st->pa->setup.si1 = 2;
- break;
- case 0x11:
- /* Unrestr. digital information with tones/announcements */
- st->pa->setup.si1 = 3;
- break;
- case 0x18:
- /* Video */
- st->pa->setup.si1 = 4;
- break;
- default:
- st->pa->setup.si1 = 0;
- }
- } else
- printk(KERN_WARNING "l3s12: Bearer capabilities not found\n");
- }
-
- p = DATAPTR(ibh);
- if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize,
- 0x70, 0)))
- iecpy(st->pa->setup.eazmsn, p, 1);
- else
- strcpy(st->pa->setup.eazmsn, "");
-
- p = DATAPTR(ibh);
- if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize,
- 0x6c, 0))) {
- st->pa->setup.plan = p[2];
- if (st->protocol == ISDN_PTYPE_1TR6) {
- iecpy(st->pa->setup.phone, p, 1);
- } else {
- st->pa->setup.screen = p[3];
- iecpy(st->pa->setup.phone, p, 2);
- }
- } else
- strcpy(st->pa->setup.phone, "");
- BufPoolRelease(ibh);
-
- if (bcfound) {
- if (st->pa->setup.si1 != 7) {
- printk(KERN_DEBUG "non-digital call: %s -> %s\n",
- st->pa->setup.phone,
- st->pa->setup.eazmsn);
- }
- newl3state(st, 6);
- st->l3.l3l4(st, CC_SETUP_IND, NULL);
- }
-}
-
-static void
-l3s13(struct PStack *st, byte pr, void *arg)
-{
- newl3state(st, 0);
-}
-
-static void
-l3s16(struct PStack *st, byte pr,
- void *arg)
-{
- st->l3.callref = 0x80 + st->pa->callref;
- l3_message(st, MT_CONNECT);
- newl3state(st, 8);
-}
-
-static void
-l3s17(struct PStack *st, byte pr, void *arg)
-{
- struct BufHeader *ibh = arg;
-
- BufPoolRelease(ibh);
- st->l3.l3l4(st, CC_SETUP_COMPLETE_IND, NULL);
- newl3state(st, 10);
-}
-
-static void
-l3s18(struct PStack *st, byte pr, void *arg)
-{
- struct BufHeader *dibh;
- byte *p;
- int size;
-
- BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 20);
- p = DATAPTR(dibh);
- p += st->l2.ihsize;
- size = st->l2.ihsize;
-
- *p++ = 0x8;
- *p++ = 0x1;
- *p++ = st->l3.callref;
- *p++ = MT_DISCONNECT;
- size += 4;
-
- *p++ = IE_CAUSE;
- *p++ = 0x2;
- *p++ = 0x80;
- *p++ = 0x90;
- size += 4;
-
- dibh->datasize = size;
- i_down(st, dibh);
-
- newl3state(st, 11);
-}
-
-static void
-l3s19(struct PStack *st, byte pr, void *arg)
-{
- struct BufHeader *ibh = arg;
-
- BufPoolRelease(ibh);
- newl3state(st, 0);
- l3_message(st, MT_RELEASE_COMPLETE);
- st->l3.l3l4(st, CC_RELEASE_IND, NULL);
-}
-
-static void
-l3s20(struct PStack *st, byte pr,
- void *arg)
-{
- l3_message(st, MT_ALERTING);
- newl3state(st, 7);
-}
-
-static void
-l3s21(struct PStack *st, byte pr, void *arg)
-{
- struct BufHeader *dibh=arg;
- byte *p;
- int size;
-
- BufPoolRelease(dibh);
-
- BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 20);
- p = DATAPTR(dibh);
- p += st->l2.ihsize;
- size = st->l2.ihsize;
-
- *p++ = 0x8;
- *p++ = 0x1;
- *p++ = st->l3.callref;
- *p++ = MT_STATUS;
- size += 4;
-
- *p++ = IE_CAUSE;
- *p++ = 0x2;
- *p++ = 0x80;
- *p++ = 0x9E; /* answer status enquire */
- size += 4;
-
- *p++ = 0x14; /* CallState */
- *p++ = 0x1;
- *p++ = st->l3.state & 0x3f; /* ISO L3 CallState */
- size += 3;
-
- dibh->datasize = size;
- i_down(st, dibh);
-
-}
-
-struct stateentry {
- int state;
- byte primitive;
- void (*rout) (struct PStack *, byte, void *);
-};
-
-static struct stateentry downstatelist[] =
-{
- {0,CC_SETUP_REQ,l3s5},
- {1,CC_DISCONNECT_REQ,l3s18},
- {1,CC_RELEASE_REQ,l3s3},
- {1,CC_DLRL,l3s13},
- {3,CC_DISCONNECT_REQ,l3s18},
- {3,CC_RELEASE_REQ,l3s3},
- {3,CC_DLRL,l3s13},
- {4,CC_RELEASE_REQ,l3s3},
- {4,CC_DISCONNECT_REQ,l3s18},
- {4,CC_DLRL,l3s13},
- {6,CC_RELEASE_REQ,l3s3},
- {6,CC_DISCONNECT_REQ,l3s18},
- {6,CC_ALERTING_REQ,l3s20},
- {6,CC_DLRL,l3s13},
- {7,CC_RELEASE_REQ,l3s3},
- {7,CC_SETUP_RSP,l3s16},
- {7,CC_DLRL,l3s13},
- {8,CC_RELEASE_REQ,l3s3},
- {8,CC_DISCONNECT_REQ,l3s18},
- {8,CC_DLRL,l3s13},
- {10,CC_DISCONNECT_REQ,l3s18},
- {10,CC_RELEASE_REQ,l3s3},
- {10,CC_DLRL,l3s13},
- {11,CC_RELEASE_REQ,l3s3},
- {12,CC_RELEASE_REQ,l3s3},
- {19,CC_DLRL,l3s13},
-};
-
-static int downsllen = sizeof(downstatelist) /
-sizeof(struct stateentry);
-
-static struct stateentry datastatelist[] =
-{
- {0,MT_STATUS_ENQUIRY,l3s21},
- {0,MT_SETUP,l3s12},
- {1,MT_STATUS_ENQUIRY,l3s21},
- {1,MT_CALL_PROCEEDING,l3s6},
- {1,MT_SETUP_ACKNOWLEDGE,l3s6},
- {1,MT_RELEASE_COMPLETE,l3s4},
- {1,MT_RELEASE,l3s19},
- {1,MT_DISCONNECT,l3s7},
- {3,MT_STATUS_ENQUIRY,l3s21},
- {3,MT_DISCONNECT,l3s7},
- {3,MT_CONNECT,l3s8},
- {3,MT_ALERTING,l3s11},
- {3,MT_RELEASE,l3s19},
- {3,MT_RELEASE_COMPLETE,l3s4},
- {4,MT_STATUS_ENQUIRY,l3s21},
- {4,MT_CONNECT,l3s8},
- {4,MT_DISCONNECT,l3s7},
- {4,MT_RELEASE,l3s19},
- {4,MT_RELEASE_COMPLETE,l3s4},
- {8,MT_STATUS_ENQUIRY,l3s21},
- {6,MT_SETUP,l3s12},
- {8,MT_STATUS_ENQUIRY,l3s21},
- {7,MT_RELEASE,l3s19},
- {7,MT_RELEASE_COMPLETE,l3s4_1},
- {7,MT_DISCONNECT,l3s7},
- {8,MT_STATUS_ENQUIRY,l3s21},
- {8,MT_RELEASE,l3s19},
- {8,MT_CONNECT_ACKNOWLEDGE,l3s17},
- {8,MT_DISCONNECT,l3s7},
- {8,MT_RELEASE_COMPLETE,l3s4_1},
- {10,MT_STATUS_ENQUIRY,l3s21},
- {10,MT_DISCONNECT,l3s7},
- {10,MT_RELEASE,l3s19},
- {10,MT_RELEASE_COMPLETE,l3s4_1},
- {11,MT_STATUS_ENQUIRY,l3s21},
- {11,MT_RELEASE,l3s19},
- {11,MT_RELEASE_COMPLETE,l3s4},
- {19,MT_STATUS_ENQUIRY,l3s21},
- {19,MT_RELEASE_COMPLETE,l3s4},
-};
-
-static int datasllen = sizeof(datastatelist) /
-sizeof(struct stateentry);
-
-#ifdef P_1TR6
-#include "l3_1TR6.c"
-#endif
-
-static void
-l3up(struct PStack *st,
- int pr, void *arg)
-{
- int i, mt, size;
- byte *ptr;
- struct BufHeader *ibh = arg;
-
- if (pr == DL_DATA) {
- ptr = DATAPTR(ibh);
- ptr += st->l2.ihsize;
- size = ibh->datasize - st->l2.ihsize;
- mt = ptr[3];
- switch (ptr[0]) {
-#ifdef P_1TR6
- case PROTO_DIS_N0:
- BufPoolRelease(ibh);
- break;
- case PROTO_DIS_N1:
- for (i = 0; i < datasl_1tr6t_len; i++)
- if ((st->l3.state == datastatelist_1tr6t[i].state) &&
- (mt == datastatelist_1tr6t[i].primitive))
- break;
- if (i == datasl_1tr6t_len) {
- BufPoolRelease(ibh);
- if (DEBUG_1TR6 > 0)
- printk(KERN_INFO "isdnl3up unhandled 1tr6 state %d MT %x\n",
- st->l3.state, mt);
- } else
- datastatelist_1tr6t[i].rout(st, pr, ibh);
- break;
-#endif
- case PROTO_EURO: /* E-DSS1 */
- for (i = 0; i < datasllen; i++)
- if ((st->l3.state == datastatelist[i].state) &&
- (mt == datastatelist[i].primitive))
- break;
- if (i == datasllen) {
- BufPoolRelease(ibh);
- if (DEBUG_1TR6 > 0)
- printk(KERN_INFO "isdnl3up unhandled E-DSS1 state %d MT %x\n",
- st->l3.state, mt);
- } else
- datastatelist[i].rout(st, pr, ibh);
- break;
- default:
- BufPoolRelease(ibh);
- break;
- }
- } else if (pr == DL_UNIT_DATA) {
- ptr = DATAPTR(ibh);
- ptr += st->l2.uihsize;
- size = ibh->datasize - st->l2.uihsize;
- mt = ptr[3];
- switch (ptr[0]) {
-#ifdef P_1TR6
- case PROTO_DIS_N0:
- BufPoolRelease(ibh);
- break;
- case PROTO_DIS_N1:
- for (i = 0; i < datasl_1tr6t_len; i++)
- if ((st->l3.state == datastatelist_1tr6t[i].state) &&
- (mt == datastatelist_1tr6t[i].primitive))
- break;
- if (i == datasl_1tr6t_len) {
- if (DEBUG_1TR6 > 0) {
- printk(KERN_INFO "isdnl3up unhandled 1tr6 state %d MT %x\n"
- ,st->l3.state, mt);
- }
- BufPoolRelease(ibh);
- } else
- datastatelist_1tr6t[i].rout(st, pr, ibh);
- break;
-#endif
- case PROTO_EURO: /* E-DSS1 */
- for (i = 0; i < datasllen; i++)
- if ((st->l3.state == datastatelist[i].state) &&
- (mt == datastatelist[i].primitive))
- break;
- if (i == datasllen) {
- BufPoolRelease(ibh);
- if (DEBUG_1TR6 > 0)
- printk(KERN_INFO "isdnl3up unhandled E-DSS1 state %d MT %x\n",
- st->l3.state, mt);
- } else
- datastatelist[i].rout(st, pr, ibh);
- break;
- default:
- BufPoolRelease(ibh);
- break;
- }
- }
-}
-
-static void
-l3down(struct PStack *st,
- int pr, void *arg)
-{
- int i;
- struct BufHeader *ibh = arg;
-
- switch (st->protocol) {
-#ifdef P_1TR6
- case ISDN_PTYPE_1TR6:
- for (i = 0; i < downsl_1tr6t_len; i++)
- if ((st->l3.state == downstatelist_1tr6t[i].state) &&
- (pr == downstatelist_1tr6t[i].primitive))
- break;
- if (i == downsl_1tr6t_len) {
- if (DEBUG_1TR6 > 0) {
- printk(KERN_INFO "isdnl3down unhandled 1tr6 state %d primitive %x\n", st->l3.state, pr);
- }
- } else
- downstatelist_1tr6t[i].rout(st, pr, ibh);
- break;
-#endif
- default:
- for (i = 0; i < downsllen; i++)
- if ((st->l3.state == downstatelist[i].state) &&
- (pr == downstatelist[i].primitive))
- break;
- if (i == downsllen) {
- if (DEBUG_1TR6 > 0) {
- printk(KERN_INFO "isdnl3down unhandled E-DSS1 state %d primitive %x\n", st->l3.state, pr);
- }
- } else
- downstatelist[i].rout(st, pr, ibh);
- }
-}
-
-void
-setstack_isdnl3(struct PStack *st)
-{
- st->l4.l4l3 = l3down;
- st->l2.l2l3 = l3up;
- st->l3.state = 0;
- st->l3.callref = 0;
- st->l3.debug = 0;
-}
diff --git a/drivers/isdn/teles/l3_1TR6.c b/drivers/isdn/teles/l3_1TR6.c
deleted file mode 100644
index 8566a14d4..000000000
--- a/drivers/isdn/teles/l3_1TR6.c
+++ /dev/null
@@ -1,538 +0,0 @@
-/* $Id: l3_1TR6.c,v 1.7 1997/02/11 01:38:55 keil Exp $
- *
- * $Log: l3_1TR6.c,v $
- * Revision 1.7 1997/02/11 01:38:55 keil
- * Changed setup-interface (incoming and outgoing)
- *
- * Revision 1.6 1996/09/25 18:34:57 keil
- * missing states in 1TR6 Statemachine added
- *
- * Revision 1.5 1996/09/23 01:53:51 fritz
- * Bugfix: discard unknown frames (non-EDSS1 and non-1TR6).
- *
- * Revision 1.4 1996/06/06 14:22:28 fritz
- * Changed level of "non-digital call..." message, since
- * with audio support, this is quite normal.
- *
- * Revision 1.3 1996/04/30 21:54:42 isdn4dev
- * SPV, callback , remove some debugging code Karsten Keil
- *
- * Revision 1.2 1996/04/20 16:47:23 fritz
- * Changed statemachine to allow reject of an incoming call.
- * Report all incoming calls, not just those with Service = 7.
- * Misc. typos
- *
- * Revision 1.1 1996/04/13 10:25:16 fritz
- * Initial revision
- *
- *
- */
-
-#include "proto.h"
-
-static void
-l3_1TR6_message(struct PStack *st, int mt, int pd)
-{
- struct BufHeader *dibh;
- byte *p;
-
- BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 18);
- p = DATAPTR(dibh);
- p += st->l2.ihsize;
-
- *p++ = pd;
- *p++ = 0x1;
- *p++ = st->l3.callref;
- *p++ = mt;
-
- dibh->datasize = p - DATAPTR(dibh);
- i_down(st, dibh);
-}
-
-static void
-l3_1tr6_setup(struct PStack *st, byte pr, void *arg)
-{
- struct BufHeader *dibh;
- byte *p;
- char *teln;
-
- st->l3.callref = st->pa->callref;
- BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 19);
- p = DATAPTR(dibh);
- p += st->l2.ihsize;
-
- *p++ = PROTO_DIS_N1;
- *p++ = 0x1;
- *p++ = st->l3.callref;
- *p++ = MT_N1_SETUP;
-
- if ('S' == (st->pa->setup.phone[0] & 0x5f)) { /* SPV ??? */
- /* NSF SPV */
- *p++ = WE0_netSpecFac;
- *p++ = 4; /* Laenge */
- *p++ = 0;
- *p++ = FAC_SPV; /* SPV */
- *p++ = st->pa->setup.si1; /* 0 for all Services */
- *p++ = st->pa->setup.si2; /* 0 for all Services */
- *p++ = WE0_netSpecFac;
- *p++ = 4; /* Laenge */
- *p++ = 0;
- *p++ = FAC_Activate; /* aktiviere SPV (default) */
- *p++ = st->pa->setup.si1; /* 0 for all Services */
- *p++ = st->pa->setup.si2; /* 0 for all Services */
- }
- if (st->pa->setup.eazmsn[0]) {
- *p++ = WE0_origAddr;
- *p++ = strlen(st->pa->setup.eazmsn) + 1;
- /* Classify as AnyPref. */
- *p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
- teln = st->pa->setup.eazmsn;
- while (*teln)
- *p++ = *teln++ & 0x7f;
- }
- *p++ = WE0_destAddr;
- teln = st->pa->setup.phone;
- if ('S' != (st->pa->setup.phone[0] & 0x5f)) { /* Keine SPV ??? */
- *p++ = strlen(st->pa->setup.phone) + 1;
- st->pa->spv = 0;
- } else { /* SPV */
- *p++ = strlen(st->pa->setup.phone);
- teln++; /* skip S */
- st->pa->spv = 1;
- }
- /* Classify as AnyPref. */
- *p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
- while (*teln)
- *p++ = *teln++ & 0x7f;
-
- *p++ = WE_Shift_F6;
- /* Codesatz 6 fuer Service */
- *p++ = WE6_serviceInd;
- *p++ = 2; /* len=2 info,info2 */
- *p++ = st->pa->setup.si1;
- *p++ = st->pa->setup.si2;
-
- dibh->datasize = p - DATAPTR(dibh);
-
- newl3state(st, 1);
- i_down(st, dibh);
-
-}
-
-static void
-l3_1tr6_tu_setup(struct PStack *st, byte pr, void *arg)
-{
- byte *p;
- struct BufHeader *ibh = arg;
-
- p = DATAPTR(ibh);
- p += st->l2.uihsize;
- st->pa->callref = getcallref(p);
- st->l3.callref = 0x80 + st->pa->callref;
-
- /* Channel Identification */
- p = DATAPTR(ibh);
- if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize,
- WE0_chanID, 0))) {
- st->pa->bchannel = p[2] & 0x3;
- } else
- printk(KERN_INFO "l3tu_setup: Channel ident not found\n");
-
- p = DATAPTR(ibh);
-
- if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize, WE6_serviceInd, 6))) {
- st->pa->setup.si1 = p[2];
- st->pa->setup.si2 = p[3];
- } else
- printk(KERN_INFO "l3s12(1TR6): ServiceIndicator not found\n");
-
- p = DATAPTR(ibh);
- if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize,
- WE0_destAddr, 0)))
- iecpy(st->pa->setup.eazmsn, p, 1);
- else
- strcpy(st->pa->setup.eazmsn, "");
-
- p = DATAPTR(ibh);
- if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize,
- WE0_origAddr, 0))) {
- iecpy(st->pa->setup.phone, p, 1);
- } else
- strcpy(st->pa->setup.phone, "");
-
- p = DATAPTR(ibh);
- st->pa->spv = 0;
- if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize,
- WE0_netSpecFac, 0))) {
- if ((FAC_SPV == p[3]) || (FAC_Activate == p[3]))
- st->pa->spv = 1;
- }
- BufPoolRelease(ibh);
-
- /* Signal all services, linklevel takes care of Service-Indicator */
- if (st->pa->setup.si1 != 7) {
- printk(KERN_DEBUG "non-digital call: %s -> %s\n",
- st->pa->setup.phone,
- st->pa->setup.eazmsn);
- }
- newl3state(st, 6);
- st->l3.l3l4(st, CC_SETUP_IND, NULL);
-}
-
-static void
-l3_1tr6_tu_setup_ack(struct PStack *st, byte pr, void *arg)
-{
- byte *p;
- struct BufHeader *ibh = arg;
-
- p = DATAPTR(ibh);
- if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize,
- WE0_chanID, 0))) {
- st->pa->bchannel = p[2] & 0x3;
- } else
- printk(KERN_INFO "octect 3 not found\n");
-
-
- BufPoolRelease(ibh);
- newl3state(st, 2);
-}
-
-static void
-l3_1tr6_tu_call_sent(struct PStack *st, byte pr, void *arg)
-{
- byte *p;
- struct BufHeader *ibh = arg;
-
- p = DATAPTR(ibh);
- if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize,
- WE0_chanID, 0))) {
- st->pa->bchannel = p[2] & 0x3;
- } else
- printk(KERN_INFO "octect 3 not found\n");
-
- BufPoolRelease(ibh);
- newl3state(st, 3);
- st->l3.l3l4(st, CC_PROCEEDING_IND, NULL);
-}
-
-static void
-l3_1tr6_tu_alert(struct PStack *st, byte pr, void *arg)
-{
- byte *p;
- struct BufHeader *ibh = arg;
-
-
- p = DATAPTR(ibh);
- if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize,
- WE6_statusCalled, 6))) {
- if (DEBUG_1TR6 > 2)
- printk(KERN_INFO "status called %x\n", p[2]);
- } else if (DEBUG_1TR6 > 0)
- printk(KERN_INFO "statusCalled not found\n");
-
- BufPoolRelease(ibh);
- newl3state(st, 4);
- st->l3.l3l4(st, CC_ALERTING_IND, NULL);
-}
-
-static void
-l3_1tr6_tu_info(struct PStack *st, byte pr, void *arg)
-{
- byte *p;
- int i,tmpcharge=0;
- char a_charge[8];
- struct BufHeader *ibh = arg;
-
- p = DATAPTR(ibh);
- if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize,
- WE6_chargingInfo, 6))) {
- iecpy(a_charge, p, 1);
- for (i = 0; i < strlen (a_charge); i++) {
- tmpcharge *= 10;
- tmpcharge += a_charge[i] & 0xf;
- }
- if (tmpcharge > st->pa->chargeinfo) {
- st->pa->chargeinfo = tmpcharge;
- st->l3.l3l4 (st, CC_INFO_CHARGE, NULL);
- }
- if (DEBUG_1TR6 > 2)
- printk(KERN_INFO "chargingInfo %d\n", st->pa->chargeinfo);
- } else if (DEBUG_1TR6 > 2)
- printk(KERN_INFO "chargingInfo not found\n");
-
- BufPoolRelease(ibh);
-}
-
-static void
-l3_1tr6_tu_info_s2(struct PStack *st, byte pr, void *arg)
-{
- byte *p;
- int i;
- struct BufHeader *ibh = arg;
-
- if (DEBUG_1TR6 > 4) {
- p = DATAPTR(ibh);
- for (i = 0; i < ibh->datasize; i++) {
- printk(KERN_INFO "Info DATA %x\n", p[i]);
- }
- }
- BufPoolRelease(ibh);
-}
-
-static void
-l3_1tr6_tu_connect(struct PStack *st, byte pr, void *arg)
-{
- struct BufHeader *ibh = arg;
-
- st->pa->chargeinfo=0;
- BufPoolRelease(ibh);
- st->l3.l3l4(st, CC_SETUP_CNF, NULL);
- newl3state(st, 10);
-}
-
-static void
-l3_1tr6_tu_rel(struct PStack *st, byte pr, void *arg)
-{
- struct BufHeader *ibh = arg;
-
- BufPoolRelease(ibh);
- l3_1TR6_message(st, MT_N1_REL_ACK, PROTO_DIS_N1);
- st->l3.l3l4(st, CC_RELEASE_IND, NULL);
- newl3state(st, 0);
-}
-
-static void
-l3_1tr6_tu_rel_ack(struct PStack *st, byte pr, void *arg)
-{
- struct BufHeader *ibh = arg;
-
- BufPoolRelease(ibh);
- newl3state(st, 0);
- st->l3.l3l4(st, CC_RELEASE_CNF, NULL);
-}
-
-static void
-l3_1tr6_tu_disc(struct PStack *st, byte pr, void *arg)
-{
- struct BufHeader *ibh = arg;
- byte *p;
- int i,tmpcharge=0;
- char a_charge[8];
-
- p = DATAPTR(ibh);
- if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize,
- WE6_chargingInfo, 6))) {
- iecpy(a_charge, p, 1);
- for (i = 0; i < strlen (a_charge); i++) {
- tmpcharge *= 10;
- tmpcharge += a_charge[i] & 0xf;
- }
- if (tmpcharge > st->pa->chargeinfo) {
- st->pa->chargeinfo = tmpcharge;
- st->l3.l3l4 (st, CC_INFO_CHARGE, NULL);
- }
- if (DEBUG_1TR6 > 2)
- printk(KERN_INFO "chargingInfo %d\n", st->pa->chargeinfo);
- } else if (DEBUG_1TR6 > 2)
- printk(KERN_INFO "chargingInfo not found\n");
-
- p = DATAPTR(ibh);
- if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize,
- WE0_cause, 0))) {
- if (p[1] > 0) {
- st->pa->cause = p[2];
- } else {
- st->pa->cause = 0;
- }
- if (DEBUG_1TR6 > 1)
- printk(KERN_INFO "Cause %x\n", st->pa->cause);
- } else if (DEBUG_1TR6 > 0)
- printk(KERN_INFO "Cause not found\n");
-
- BufPoolRelease(ibh);
- newl3state(st, 12);
- st->l3.l3l4(st, CC_DISCONNECT_IND, NULL);
-}
-
-
-static void
-l3_1tr6_tu_connect_ack(struct PStack *st, byte pr, void *arg)
-{
- struct BufHeader *ibh = arg;
-
- BufPoolRelease(ibh);
- st->pa->chargeinfo = 0;
- st->l3.l3l4(st, CC_SETUP_COMPLETE_IND, NULL);
- newl3state(st, 10);
-}
-
-static void
-l3_1tr6_alert(struct PStack *st, byte pr,
- void *arg)
-{
- l3_1TR6_message(st, MT_N1_ALERT, PROTO_DIS_N1);
- newl3state(st, 7);
-}
-
-static void
-l3_1tr6_conn(struct PStack *st, byte pr,
- void *arg)
-{
- struct BufHeader *dibh;
- byte *p;
-
- st->l3.callref = 0x80 + st->pa->callref;
-
- BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 20);
- p = DATAPTR(dibh);
- p += st->l2.ihsize;
-
- *p++ = PROTO_DIS_N1;
- *p++ = 0x1;
- *p++ = st->l3.callref;
- *p++ = MT_N1_CONN;
-
- if (st->pa->spv) { /* SPV ??? */
- /* NSF SPV */
- *p++ = WE0_netSpecFac;
- *p++ = 4; /* Laenge */
- *p++ = 0;
- *p++ = FAC_SPV; /* SPV */
- *p++ = st->pa->setup.si1;
- *p++ = st->pa->setup.si2;
- *p++ = WE0_netSpecFac;
- *p++ = 4; /* Laenge */
- *p++ = 0;
- *p++ = FAC_Activate; /* aktiviere SPV */
- *p++ = st->pa->setup.si1;
- *p++ = st->pa->setup.si2;
- }
- dibh->datasize = p - DATAPTR(dibh);
-
- i_down(st, dibh);
-
- newl3state(st, 8);
-}
-
-static void
-l3_1tr6_reset(struct PStack *st, byte pr, void *arg)
-{
- newl3state(st, 0);
-}
-
-static void
-l3_1tr6_disconn_req(struct PStack *st, byte pr, void *arg)
-{
- struct BufHeader *dibh;
- byte *p;
- byte rejflg;
-
- BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 21);
- p = DATAPTR(dibh);
- p += st->l2.ihsize;
-
- *p++ = PROTO_DIS_N1;
- *p++ = 0x1;
- *p++ = st->l3.callref;
- *p++ = MT_N1_DISC;
-
- if (st->l3.state == 7) {
- rejflg = 1;
- *p++ = WE0_cause; /* Anruf abweisen */
- *p++ = 0x01; /* Laenge = 1 */
- *p++ = CAUSE_CallRejected;
- } else {
- rejflg = 0;
- *p++ = WE0_cause;
- *p++ = 0x0; /* Laenge = 0 normales Ausloesen */
- }
-
- dibh->datasize = p - DATAPTR(dibh);
-
- i_down(st, dibh);
-
- newl3state(st, 11);
-}
-
-static void
-l3_1tr6_rel_req(struct PStack *st, byte pr, void *arg)
-{
- l3_1TR6_message(st, MT_N1_REL, PROTO_DIS_N1);
- newl3state(st, 19);
-}
-
-static struct stateentry downstatelist_1tr6t[] =
-{
- {0, CC_SETUP_REQ, l3_1tr6_setup},
- {1, CC_DISCONNECT_REQ, l3_1tr6_disconn_req},
- {1, CC_RELEASE_REQ, l3_1tr6_rel_req},
- {1, CC_DLRL, l3_1tr6_reset},
- {2, CC_DISCONNECT_REQ, l3_1tr6_disconn_req},
- {2, CC_RELEASE_REQ, l3_1tr6_rel_req},
- {2, CC_DLRL, l3_1tr6_reset},
- {3, CC_DISCONNECT_REQ, l3_1tr6_disconn_req},
- {3, CC_RELEASE_REQ, l3_1tr6_rel_req},
- {3, CC_DLRL, l3_1tr6_reset},
- {4, CC_DISCONNECT_REQ, l3_1tr6_disconn_req},
- {4, CC_RELEASE_REQ, l3_1tr6_rel_req},
- {4, CC_DLRL, l3_1tr6_reset},
- {6, CC_REJECT_REQ, l3_1tr6_reset},
- {6, CC_RELEASE_REQ, l3_1tr6_rel_req},
- {6, CC_SETUP_RSP, l3_1tr6_conn},
- {6, CC_ALERTING_REQ, l3_1tr6_alert},
- {6, CC_DLRL, l3_1tr6_reset},
- {7, CC_SETUP_RSP, l3_1tr6_conn},
- {7, CC_RELEASE_REQ, l3_1tr6_rel_req},
- {7, CC_DISCONNECT_REQ, l3_1tr6_disconn_req},
- {7, CC_DLRL, l3_1tr6_reset},
- {8, CC_DISCONNECT_REQ, l3_1tr6_disconn_req},
- {8, CC_RELEASE_REQ, l3_1tr6_rel_req},
- {8, CC_DLRL, l3_1tr6_reset},
- {10, CC_DISCONNECT_REQ, l3_1tr6_disconn_req},
- {10, CC_RELEASE_REQ, l3_1tr6_rel_req},
- {10, CC_DLRL, l3_1tr6_reset},
- {12, CC_RELEASE_REQ, l3_1tr6_rel_req},
- {12, CC_DLRL, l3_1tr6_reset},
- {19, CC_DLRL, l3_1tr6_reset},
-};
-
-static int downsl_1tr6t_len = sizeof(downstatelist_1tr6t) /
-sizeof(struct stateentry);
-
-static struct stateentry datastatelist_1tr6t[] =
-{
- {0, MT_N1_SETUP, l3_1tr6_tu_setup},
- {0, MT_N1_REL, l3_1tr6_tu_rel},
- {1, MT_N1_SETUP_ACK, l3_1tr6_tu_setup_ack},
- {1, MT_N1_CALL_SENT, l3_1tr6_tu_call_sent},
- {1, MT_N1_REL, l3_1tr6_tu_rel},
- {1, MT_N1_DISC, l3_1tr6_tu_disc},
- {2, MT_N1_CALL_SENT, l3_1tr6_tu_call_sent},
- {2, MT_N1_ALERT, l3_1tr6_tu_alert},
- {2, MT_N1_CONN, l3_1tr6_tu_connect},
- {2, MT_N1_REL, l3_1tr6_tu_rel},
- {2, MT_N1_DISC, l3_1tr6_tu_disc},
- {2, MT_N1_INFO, l3_1tr6_tu_info_s2},
- {3, MT_N1_ALERT, l3_1tr6_tu_alert},
- {3, MT_N1_CONN, l3_1tr6_tu_connect},
- {3, MT_N1_REL, l3_1tr6_tu_rel},
- {3, MT_N1_DISC, l3_1tr6_tu_disc},
- {4, MT_N1_ALERT, l3_1tr6_tu_alert},
- {4, MT_N1_CONN, l3_1tr6_tu_connect},
- {4, MT_N1_REL, l3_1tr6_tu_rel},
- {4, MT_N1_DISC, l3_1tr6_tu_disc},
- {7, MT_N1_REL, l3_1tr6_tu_rel},
- {7, MT_N1_DISC, l3_1tr6_tu_disc},
- {8, MT_N1_REL, l3_1tr6_tu_rel},
- {8, MT_N1_DISC, l3_1tr6_tu_disc},
- {8, MT_N1_CONN_ACK, l3_1tr6_tu_connect_ack},
- {10, MT_N1_REL, l3_1tr6_tu_rel},
- {10, MT_N1_DISC, l3_1tr6_tu_disc},
- {10, MT_N1_INFO, l3_1tr6_tu_info},
- {11, MT_N1_REL, l3_1tr6_tu_rel},
- {12, MT_N1_REL, l3_1tr6_tu_rel},
- {19, MT_N1_REL_ACK, l3_1tr6_tu_rel_ack}
-};
-
-static int datasl_1tr6t_len = sizeof(datastatelist_1tr6t) /
-sizeof(struct stateentry);
diff --git a/drivers/isdn/teles/l3_1TR6.h b/drivers/isdn/teles/l3_1TR6.h
deleted file mode 100644
index e3b538e26..000000000
--- a/drivers/isdn/teles/l3_1TR6.h
+++ /dev/null
@@ -1,160 +0,0 @@
-/* $Id: l3_1TR6.h,v 1.4 1996/09/23 01:53:52 fritz Exp $
- *
- * $Log: l3_1TR6.h,v $
- * Revision 1.4 1996/09/23 01:53:52 fritz
- * Bugfix: discard unknown frames (non-EDSS1 and non-1TR6).
- *
- * Revision 1.3 1996/04/30 21:53:48 isdn4dev
- * Bugs, SPV, Logging in q931.c Karsten Keil
- *
- * Revision 1.1 1996/04/13 10:25:42 fritz
- * Initial revision
- *
- *
- */
-#ifndef l3_1TR6
-#define l3_1TR6
-
-/*
- * MsgType N0
- */
-#define MT_N0_REG_IND 0x61
-#define MT_N0_CANC_IND 0x62
-#define MT_N0_FAC_STA 0x63
-#define MT_N0_STA_ACK 0x64
-#define MT_N0_STA_REJ 0x65
-#define MT_N0_FAC_INF 0x66
-#define MT_N0_INF_ACK 0x67
-#define MT_N0_INF_REJ 0x68
-#define MT_N0_CLOSE 0x75
-#define MT_N0_CLO_ACK 0x77
-
-
-/*
- * MsgType N1
- */
-
-#define MT_N1_ESC 0x00
-#define MT_N1_ALERT 0x01
-#define MT_N1_CALL_SENT 0x02
-#define MT_N1_CONN 0x07
-#define MT_N1_CONN_ACK 0x0F
-#define MT_N1_SETUP 0x05
-#define MT_N1_SETUP_ACK 0x0D
-#define MT_N1_RES 0x26
-#define MT_N1_RES_ACK 0x2E
-#define MT_N1_RES_REJ 0x22
-#define MT_N1_SUSP 0x25
-#define MT_N1_SUSP_ACK 0x2D
-#define MT_N1_SUSP_REJ 0x21
-#define MT_N1_USER_INFO 0x20
-#define MT_N1_DET 0x40
-#define MT_N1_DISC 0x45
-#define MT_N1_REL 0x4D
-#define MT_N1_REL_ACK 0x5A
-#define MT_N1_CANC_ACK 0x6E
-#define MT_N1_CANC_REJ 0x67
-#define MT_N1_CON_CON 0x69
-#define MT_N1_FAC 0x60
-#define MT_N1_FAC_ACK 0x68
-#define MT_N1_FAC_CAN 0x66
-#define MT_N1_FAC_REG 0x64
-#define MT_N1_FAC_REJ 0x65
-#define MT_N1_INFO 0x6D
-#define MT_N1_REG_ACK 0x6C
-#define MT_N1_REG_REJ 0x6F
-#define MT_N1_STAT 0x63
-
-
-
-/*
- * W Elemente
- */
-
-#define WE_Shift_F0 0x90
-#define WE_Shift_F6 0x96
-#define WE_Shift_OF0 0x98
-#define WE_Shift_OF6 0x9E
-
-#define WE0_cause 0x08
-#define WE0_connAddr 0x0C
-#define WE0_callID 0x10
-#define WE0_chanID 0x18
-#define WE0_netSpecFac 0x20
-#define WE0_display 0x28
-#define WE0_keypad 0x2C
-#define WE0_origAddr 0x6C
-#define WE0_destAddr 0x70
-#define WE0_userInfo 0x7E
-
-#define WE0_moreData 0xA0
-#define WE0_congestLevel 0xB0
-
-#define WE6_serviceInd 0x01
-#define WE6_chargingInfo 0x02
-#define WE6_date 0x03
-#define WE6_facSelect 0x05
-#define WE6_facStatus 0x06
-#define WE6_statusCalled 0x07
-#define WE6_addTransAttr 0x08
-
-/*
- * FacCodes
- */
-#define FAC_Sperre 0x01
-#define FAC_Sperre_All 0x02
-#define FAC_Sperre_Fern 0x03
-#define FAC_Sperre_Intl 0x04
-#define FAC_Sperre_Interk 0x05
-
-#define FAC_Forward1 0x02
-#define FAC_Forward2 0x03
-#define FAC_Konferenz 0x06
-#define FAC_GrabBchan 0x0F
-#define FAC_Reactivate 0x10
-#define FAC_Konferenz3 0x11
-#define FAC_Dienstwechsel1 0x12
-#define FAC_Dienstwechsel2 0x13
-#define FAC_NummernIdent 0x14
-#define FAC_GBG 0x15
-#define FAC_DisplayUebergeben 0x17
-#define FAC_DisplayUmgeleitet 0x1A
-#define FAC_Unterdruecke 0x1B
-#define FAC_Deactivate 0x1E
-#define FAC_Activate 0x1D
-#define FAC_SPV 0x1F
-#define FAC_Rueckwechsel 0x23
-#define FAC_Umleitung 0x24
-
-/*
- * Cause codes
- */
-#define CAUSE_InvCRef 0x01
-#define CAUSE_BearerNotImpl 0x03
-#define CAUSE_CIDunknown 0x07
-#define CAUSE_CIDinUse 0x08
-#define CAUSE_NoChans 0x0A
-#define CAUSE_FacNotImpl 0x10
-#define CAUSE_FacNotSubscr 0x11
-#define CAUSE_OutgoingBarred 0x20
-#define CAUSE_UserAccessBusy 0x21
-#define CAUSE_NegativeGBG 0x22
-#define CAUSE_UnknownGBG 0x23
-#define CAUSE_NoSPVknown 0x25
-#define CAUSE_DestNotObtain 0x35
-#define CAUSE_NumberChanged 0x38
-#define CAUSE_OutOfOrder 0x39
-#define CAUSE_NoUserResponse 0x3A
-#define CAUSE_UserBusy 0x3B
-#define CAUSE_IncomingBarred 0x3D
-#define CAUSE_CallRejected 0x3E
-#define CAUSE_NetworkCongestion 0x59
-#define CAUSE_RemoteUser 0x5A
-#define CAUSE_LocalProcErr 0x70
-#define CAUSE_RemoteProcErr 0x71
-#define CAUSE_RemoteUserSuspend 0x72
-#define CAUSE_RemoteUserResumed 0x73
-#define CAUSE_UserInfoDiscarded 0x7F
-
-
-#endif
diff --git a/drivers/isdn/teles/llglue.c b/drivers/isdn/teles/llglue.c
deleted file mode 100644
index 7e32c2f4f..000000000
--- a/drivers/isdn/teles/llglue.c
+++ /dev/null
@@ -1,151 +0,0 @@
-/* $Id: llglue.c,v 1.7 1996/10/22 23:14:17 fritz Exp $
- *
- * $Log: llglue.c,v $
- * Revision 1.7 1996/10/22 23:14:17 fritz
- * Changes for compatibility to 2.0.X and 2.1.X kernels.
- *
- * Revision 1.6 1996/06/03 20:03:39 fritz
- * Fixed typos.
- *
- * Revision 1.5 1996/05/31 00:58:47 fritz
- * Errata: Reverted change from rev 1.4.
- *
- * Revision 1.4 1996/05/26 14:59:57 fritz
- * Bugfix: maxbufsize had been set without respect to possible X.75 header.
- *
- * Revision 1.3 1996/05/01 14:19:57 fritz
- * Added ISDN_FEATURE_L2_TRANS
- *
- * Revision 1.2 1996/04/29 23:01:46 fritz
- * Added driverId and channel to readstatus().
- *
- * Revision 1.1 1996/04/13 10:26:29 fritz
- * Initial revision
- *
- *
- */
-#define __NO_VERSION__
-#include "teles.h"
-#include <linux/malloc.h>
-#include <linux/timer.h>
-
-
-extern struct Channel *chanlist;
-int drid;
-char *teles_id = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
-
-isdn_if iif;
-
-#define TELES_STATUS_BUFSIZE 4096
-static byte *teles_status_buf = NULL;
-static byte *teles_status_read = NULL;
-static byte *teles_status_write = NULL;
-static byte *teles_status_end = NULL;
-
-int
-teles_readstatus(byte * buf, int len, int user, int id, int channel)
-{
- int count;
- byte *p;
-
- for (p = buf, count = 0; count < len; p++, count++) {
- if (user)
- put_user(*teles_status_read++, p);
- else
- *p++ = *teles_status_read++;
- if (teles_status_read > teles_status_end)
- teles_status_read = teles_status_buf;
- }
- return count;
-}
-
-void
-teles_putstatus(char *buf)
-{
- long flags;
- int len, count, i;
- byte *p;
- isdn_ctrl ic;
-
- save_flags(flags);
- cli();
- count = 0;
- len = strlen(buf);
- for (p = buf, i = len; i > 0; i--, p++) {
- *teles_status_write++ = *p;
- if (teles_status_write > teles_status_end)
- teles_status_write = teles_status_buf;
- count++;
- }
- restore_flags(flags);
- if (count) {
- ic.command = ISDN_STAT_STAVAIL;
- ic.driver = drid;
- ic.arg = count;
- iif.statcallb(&ic);
- }
-}
-
-
-int
-ll_init(void)
-{
- isdn_ctrl ic;
-
- teles_status_buf = Smalloc(TELES_STATUS_BUFSIZE,
- GFP_KERNEL, "teles_status_buf");
- if (!teles_status_buf) {
- printk(KERN_ERR "teles: Could not allocate status-buffer\n");
- return (-EIO);
- } else {
- teles_status_read = teles_status_buf;
- teles_status_write = teles_status_buf;
- teles_status_end = teles_status_buf + TELES_STATUS_BUFSIZE - 1;
- }
-
- iif.channels = CallcNewChan();
- iif.maxbufsize = BUFFER_SIZE(HSCX_SBUF_ORDER, HSCX_SBUF_BPPS);
- iif.features =
- ISDN_FEATURE_L2_X75I |
- ISDN_FEATURE_L2_HDLC |
- ISDN_FEATURE_L2_TRANS |
- ISDN_FEATURE_L3_TRANS |
- ISDN_FEATURE_P_1TR6 |
- ISDN_FEATURE_P_EURO;
-
- iif.command = teles_command;
- iif.writebuf = teles_writebuf;
- iif.writecmd = NULL;
- iif.readstat = teles_readstatus;
- strncpy(iif.id, teles_id, sizeof(iif.id) - 1);
-
- register_isdn(&iif);
- drid = iif.channels;
-
- ic.driver = drid;
- ic.command = ISDN_STAT_RUN;
- iif.statcallb(&ic);
- return 0;
-}
-
-void
-ll_stop(void)
-{
- isdn_ctrl ic;
-
- ic.command = ISDN_STAT_STOP;
- ic.driver = drid;
- iif.statcallb(&ic);
-
- CallcFreeChan();
-}
-
-void
-ll_unload(void)
-{
- isdn_ctrl ic;
-
- ic.command = ISDN_STAT_UNLOAD;
- ic.driver = drid;
- iif.statcallb(&ic);
-}
diff --git a/drivers/isdn/teles/mod.c b/drivers/isdn/teles/mod.c
deleted file mode 100644
index d5486bd4b..000000000
--- a/drivers/isdn/teles/mod.c
+++ /dev/null
@@ -1,160 +0,0 @@
-/* $Id: mod.c,v 1.3 1997/02/14 12:23:31 fritz Exp $
- *
- * $Log: mod.c,v $
- * Revision 1.3 1997/02/14 12:23:31 fritz
- * Added support for new insmod parameter handling.
- *
- * Revision 1.2 1997/02/10 11:45:14 fritz
- * More changes for Kernel 2.1.X compatibility.
- *
- * Revision 1.1 1996/04/13 10:27:02 fritz
- * Initial revision
- *
- *
- */
-#include "teles.h"
-
-extern struct IsdnCard cards[];
-extern char *teles_id;
-
-int nrcards;
-
-typedef struct {
- byte *membase;
- int interrupt;
- unsigned int iobase;
- unsigned int protocol;
-} io_type;
-
-io_type io[] =
-{
- {0, 0, 0, 0},
- {0, 0, 0, 0},
- {0, 0, 0, 0},
- {0, 0, 0, 0},
- {0, 0, 0, 0},
- {0, 0, 0, 0},
- {0, 0, 0, 0},
- {0, 0, 0, 0},
- {0, 0, 0, 0},
- {0, 0, 0, 0},
- {0, 0, 0, 0},
- {0, 0, 0, 0},
- {0, 0, 0, 0},
- {0, 0, 0, 0},
- {0, 0, 0, 0},
- {0, 0, 0, 0},
-};
-
-#ifdef MODULE
-#if (LINUX_VERSION_CODE > 0x020111)
-MODULE_PARM(io, "1-64i");
-MODULE_PARM(teles_id, "s");
-#endif
-#endif
-
-void
-teles_mod_dec_use_count(void)
-{
- MOD_DEC_USE_COUNT;
-}
-
-void
-teles_mod_inc_use_count(void)
-{
- MOD_INC_USE_COUNT;
-}
-
-#ifdef MODULE
-#define teles_init init_module
-#else
-void teles_setup(char *str, int *ints)
-{
- int i, j, argc;
- static char sid[20];
-
- argc = ints[0];
- i = 0;
- j = 1;
- while (argc && (i<16)) {
- if (argc) {
- io[i].iobase = ints[j];
- j++; argc--;
- }
- if (argc) {
- io[i].interrupt = ints[j];
- j++; argc--;
- }
- if (argc) {
- io[i].membase = (byte *)ints[j];
- j++; argc--;
- }
- if (argc) {
- io[i].protocol = ints[j];
- j++; argc--;
- }
- i++;
- }
- if (strlen(str)) {
- strcpy(sid,str);
- teles_id = sid;
- }
-}
-#endif
-
-int
-teles_init(void)
-{
- int i;
-
- nrcards = 0;
- for (i = 0; i < 16; i++) {
- if (io[i].protocol) {
- cards[i].membase = io[i].membase;
- cards[i].interrupt = io[i].interrupt;
- cards[i].iobase = io[i].iobase;
- cards[i].protocol = io[i].protocol;
- }
- }
- for (i = 0; i < 16; i++)
- if (cards[i].protocol)
- nrcards++;
- printk(KERN_DEBUG "teles: Total %d card%s defined\n",
- nrcards, (nrcards > 1) ? "s" : "");
- if (teles_inithardware()) {
- /* Install only, if at least one card found */
- Isdnl2New();
- TeiNew();
- CallcNew();
- ll_init();
-
- /* No symbols to export, hide all symbols */
-
-#ifdef MODULE
-#if (LINUX_VERSION_CODE < 0x020111)
- register_symtab(NULL);
-#else
- EXPORT_NO_SYMBOLS;
-#endif
- printk(KERN_NOTICE "Teles module installed\n");
-#endif
- return (0);
- } else
- return -EIO;
-}
-
-#ifdef MODULE
-void
-cleanup_module(void)
-{
-
- ll_stop();
- TeiFree();
- Isdnl2Free();
- CallcFree();
- teles_closehardware();
- ll_unload();
- printk(KERN_NOTICE "Teles module removed\n");
-
-}
-#endif
diff --git a/drivers/isdn/teles/proto.h b/drivers/isdn/teles/proto.h
deleted file mode 100644
index 0d7ae8ef4..000000000
--- a/drivers/isdn/teles/proto.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/* $Id: proto.h,v 1.1 1996/09/23 01:53:52 fritz Exp $
- *
- * not much now - just the l3 proto discriminator
- *
- * $Log: proto.h,v $
- * Revision 1.1 1996/09/23 01:53:52 fritz
- * Bugfix: discard unknown frames (non-EDSS1 and non-1TR6).
- *
- */
-
-#ifndef PROTO_H
-#define PROTO_H
-
-#define PROTO_EURO 0x08
-#define PROTO_DIS_N0 0x40
-#define PROTO_DIS_N1 0x41
-
-#endif
diff --git a/drivers/isdn/teles/q931.c b/drivers/isdn/teles/q931.c
deleted file mode 100644
index c9f5fa692..000000000
--- a/drivers/isdn/teles/q931.c
+++ /dev/null
@@ -1,1155 +0,0 @@
-/* $Id: q931.c,v 1.6 1996/09/23 01:53:53 fritz Exp $
- *
- * q931.c code to decode ITU Q.931 call control messages
- *
- * Author Jan den Ouden
- *
- * Changelog
- *
- * Pauline Middelink general improvements
- *
- * Beat Doebeli cause texts, display information element
- *
- * Karsten Keil cause texts, display information element for 1TR6
- *
- *
- * $Log: q931.c,v $
- * Revision 1.6 1996/09/23 01:53:53 fritz
- * Bugfix: discard unknown frames (non-EDSS1 and non-1TR6).
- *
- * Revision 1.5 1996/06/03 20:03:40 fritz
- * Fixed typos.
- *
- * Revision 1.4 1996/05/17 03:46:17 fritz
- * General cleanup.
- *
- * Revision 1.3 1996/04/30 22:06:50 isdn4dev
- * logging 1TR6 messages correctly Karsten Keil
- *
- * Revision 1.2 1996/04/20 16:48:19 fritz
- * Misc. typos
- *
- * Revision 1.1 1996/04/13 10:27:49 fritz
- * Initial revision
- *
- *
- */
-
-
-#define __NO_VERSION__
-#include "teles.h"
-#include "proto.h"
-#include "l3_1TR6.h"
-
-byte *
-findie(byte * p, int size, byte ie, int wanted_set)
-{
- int l, codeset, maincodeset;
- byte *pend = p + size;
-
- /* skip protocol discriminator, callref and message type */
- p++;
- l = (*p++) & 0xf;
- p += l;
- p++;
- codeset = 0;
- maincodeset = 0;
- /* while there are bytes left... */
- while (p < pend) {
- if ((*p & 0xf0) == 0x90) {
- codeset = *p & 0x07;
- if (!(*p & 0x08))
- maincodeset = codeset;
- }
- if (*p & 0x80)
- p++;
- else {
- if (codeset == wanted_set) {
- if (*p == ie)
- return (p);
- if (*p > ie)
- return (NULL);
- }
- p++;
- l = *p++;
- p += l;
- codeset = maincodeset;
- }
- }
- return (NULL);
-}
-
-void
-iecpy(byte * dest, byte * iestart, int ieoffset)
-{
- byte *p;
- int l;
-
- p = iestart + ieoffset + 2;
- l = iestart[1] - ieoffset;
- while (l--)
- *dest++ = *p++;
- *dest++ = '\0';
-}
-
-int
-getcallref(byte * p)
-{
- p++; /* prot discr */
- p++; /* callref length */
- return (*p); /* assuming one-byte callref */
-}
-
-/*
- * According to Table 4-2/Q.931
- */
-static
-struct MessageType {
- byte nr;
- char *descr;
-} mtlist[] = {
-
- {
- 0x1, "ALERTING"
- },
- {
- 0x2, "CALL PROCEEDING"
- },
- {
- 0x7, "CONNECT"
- },
- {
- 0xf, "CONNECT ACKNOWLEDGE"
- },
- {
- 0x3, "PROGRESS"
- },
- {
- 0x5, "SETUP"
- },
- {
- 0xd, "SETUP ACKNOWLEDGE"
- },
- {
- 0x26, "RESUME"
- },
- {
- 0x2e, "RESUME ACKNOWLEDGE"
- },
- {
- 0x22, "RESUME REJECT"
- },
- {
- 0x25, "SUSPEND"
- },
- {
- 0x2d, "SUSPEND ACKNOWLEDGE"
- },
- {
- 0x21, "SUSPEND REJECT"
- },
- {
- 0x20, "USER INFORMATION"
- },
- {
- 0x45, "DISCONNECT"
- },
- {
- 0x4d, "RELEASE"
- },
- {
- 0x5a, "RELEASE COMPLETE"
- },
- {
- 0x46, "RESTART"
- },
- {
- 0x4e, "RESTART ACKNOWLEDGE"
- },
- {
- 0x60, "SEGMENT"
- },
- {
- 0x79, "CONGESTION CONTROL"
- },
- {
- 0x7b, "INFORMATION"
- },
- {
- 0x62, "FACILITY"
- },
- {
- 0x6e, "NOTIFY"
- },
- {
- 0x7d, "STATUS"
- },
- {
- 0x75, "STATUS ENQUIRY"
- }
-};
-
-#define MTSIZE sizeof(mtlist)/sizeof(struct MessageType)
-
-static
-struct MessageType mt_n0[] =
-{
- {MT_N0_REG_IND, "REGister INDication"},
- {MT_N0_CANC_IND, "CANCel INDication"},
- {MT_N0_FAC_STA, "FACility STAtus"},
- {MT_N0_STA_ACK, "STAtus ACKnowledge"},
- {MT_N0_STA_REJ, "STAtus REJect"},
- {MT_N0_FAC_INF, "FACility INFormation"},
- {MT_N0_INF_ACK, "INFormation ACKnowledge"},
- {MT_N0_INF_REJ, "INFormation REJect"},
- {MT_N0_CLOSE, "CLOSE"},
- {MT_N0_CLO_ACK, "CLOse ACKnowledge"}
-};
-
-int mt_n0_len = (sizeof(mt_n0) / sizeof(struct MessageType));
-
-static
-struct MessageType mt_n1[] =
-{
- {MT_N1_ESC, "ESCape"},
- {MT_N1_ALERT, "ALERT"},
- {MT_N1_CALL_SENT, "CALL SENT"},
- {MT_N1_CONN, "CONNect"},
- {MT_N1_CONN_ACK, "CONNect ACKnowledge"},
- {MT_N1_SETUP, "SETUP"},
- {MT_N1_SETUP_ACK, "SETUP ACKnowledge"},
- {MT_N1_RES, "RESume"},
- {MT_N1_RES_ACK, "RESume ACKnowledge"},
- {MT_N1_RES_REJ, "RESume REJect"},
- {MT_N1_SUSP, "SUSPend"},
- {MT_N1_SUSP_ACK, "SUSPend ACKnowledge"},
- {MT_N1_SUSP_REJ, "SUSPend REJect"},
- {MT_N1_USER_INFO, "USER INFO"},
- {MT_N1_DET, "DETach"},
- {MT_N1_DISC, "DISConnect"},
- {MT_N1_REL, "RELease"},
- {MT_N1_REL_ACK, "RELease ACKnowledge"},
- {MT_N1_CANC_ACK, "CANCel ACKnowledge"},
- {MT_N1_CANC_REJ, "CANCel REJect"},
- {MT_N1_CON_CON, "CONgestion CONtrol"},
- {MT_N1_FAC, "FACility"},
- {MT_N1_FAC_ACK, "FACility ACKnowledge"},
- {MT_N1_FAC_CAN, "FACility CANcel"},
- {MT_N1_FAC_REG, "FACility REGister"},
- {MT_N1_FAC_REJ, "FACility REJect"},
- {MT_N1_INFO, "INFOrmation"},
- {MT_N1_REG_ACK, "REGister ACKnowledge"},
- {MT_N1_REG_REJ, "REGister REJect"},
- {MT_N1_STAT, "STATus"}
-};
-
-int mt_n1_len = (sizeof(mt_n1) / sizeof(struct MessageType));
-
-static struct MessageType fac_1tr6[] =
-{
- {FAC_Sperre, "Sperre"},
- {FAC_Forward1, "Forward 1"},
- {FAC_Forward2, "Forward 2"},
- {FAC_Konferenz, "Konferenz"},
- {FAC_GrabBchan, "Grab Bchannel"},
- {FAC_Reactivate, "Reactivate"},
- {FAC_Konferenz3, "Dreier Konferenz"},
- {FAC_Dienstwechsel1, "Einseitiger Dienstwechsel"},
- {FAC_Dienstwechsel2, "Zweiseitiger Dienstwechsel"},
- {FAC_NummernIdent, "Rufnummer-Identifizierung"},
- {FAC_GBG, "GBG"},
- {FAC_DisplayUebergeben, "Display Uebergeben"},
- {FAC_DisplayUmgeleitet, "Display Umgeleitet"},
- {FAC_Unterdruecke, "Unterdruecke Rufnummer"},
- {FAC_Deactivate, "Deactivate"},
- {FAC_Activate, "Activate"},
- {FAC_SPV, "SPV"},
- {FAC_Rueckwechsel, "Rueckwechsel"},
- {FAC_Umleitung, "Umleitung"}
-};
-int fac_1tr6_len = (sizeof(fac_1tr6) / sizeof(struct MessageType));
-
-
-
-static int
-prbits(char *dest, byte b, int start, int len)
-{
- char *dp = dest;
-
- b = b << (8 - start);
- while (len--) {
- if (b & 0x80)
- *dp++ = '1';
- else
- *dp++ = '0';
- b = b << 1;
- }
- return (dp - dest);
-}
-
-static
-byte *
-skipext(byte * p)
-{
- while (!(*p++ & 0x80));
- return (p);
-}
-
-/*
- * Cause Values According to Q.850
- * edescr: English description
- * ddescr: German description used by Swissnet II (Swiss Telecom
- * not yet written...
- */
-
-static
-struct CauseValue {
- byte nr;
- char *edescr;
- char *ddescr;
-} cvlist[] = {
-
- {
- 0x01, "Unallocated (unassigned) number", "Nummer nicht zugeteilt"
- },
- {
- 0x02, "No route to specified transit network", ""
- },
- {
- 0x03, "No route to destination", ""
- },
- {
- 0x04, "Send special information tone", ""
- },
- {
- 0x05, "Misdialled trunk prefix", ""
- },
- {
- 0x06, "Channel unacceptable", "Kanal nicht akzeptierbar"
- },
- {
- 0x07, "Channel awarded and being delivered in an established channel", ""
- },
- {
- 0x08, "Preemption", ""
- },
- {
- 0x09, "Preemption - circuit reserved for reuse", ""
- },
- {
- 0x10, "Normal call clearing", "Normale Ausloesung"
- },
- {
- 0x11, "User busy", "TNB besetzt"
- },
- {
- 0x12, "No user responding", ""
- },
- {
- 0x13, "No answer from user (user alerted)", ""
- },
- {
- 0x14, "Subscriber absent", ""
- },
- {
- 0x15, "Call rejected", ""
- },
- {
- 0x16, "Number changed", ""
- },
- {
- 0x1a, "non-selected user clearing", ""
- },
- {
- 0x1b, "Destination out of order", ""
- },
- {
- 0x1c, "Invalid number format (address incomplete)", ""
- },
- {
- 0x1d, "Facility rejected", ""
- },
- {
- 0x1e, "Response to Status enquiry", ""
- },
- {
- 0x1f, "Normal, unspecified", ""
- },
- {
- 0x22, "No circuit/channel available", ""
- },
- {
- 0x26, "Network out of order", ""
- },
- {
- 0x27, "Permanent frame mode connection out-of-service", ""
- },
- {
- 0x28, "Permanent frame mode connection operational", ""
- },
- {
- 0x29, "Temporary failure", ""
- },
- {
- 0x2a, "Switching equipment congestion", ""
- },
- {
- 0x2b, "Access information discarded", ""
- },
- {
- 0x2c, "Requested circuit/channel not available", ""
- },
- {
- 0x2e, "Precedence call blocked", ""
- },
- {
- 0x2f, "Resource unavailable, unspecified", ""
- },
- {
- 0x31, "Quality of service unavailable", ""
- },
- {
- 0x32, "Requested facility not subscribed", ""
- },
- {
- 0x35, "Outgoing calls barred within CUG", ""
- },
- {
- 0x37, "Incoming calls barred within CUG", ""
- },
- {
- 0x39, "Bearer capability not authorized", ""
- },
- {
- 0x3a, "Bearer capability not presently available", ""
- },
- {
- 0x3e, "Inconsistency in designated outgoing access information and subscriber class ", " "
- },
- {
- 0x3f, "Service or option not available, unspecified", ""
- },
- {
- 0x41, "Bearer capability not implemented", ""
- },
- {
- 0x42, "Channel type not implemented", ""
- },
- {
- 0x43, "Requested facility not implemented", ""
- },
- {
- 0x44, "Only restricted digital information bearer capability is available", ""
- },
- {
- 0x4f, "Service or option not implemented", ""
- },
- {
- 0x51, "Invalid call reference value", ""
- },
- {
- 0x52, "Identified channel does not exist", ""
- },
- {
- 0x53, "A suspended call exists, but this call identity does not", ""
- },
- {
- 0x54, "Call identity in use", ""
- },
- {
- 0x55, "No call suspended", ""
- },
- {
- 0x56, "Call having the requested call identity has been cleared", ""
- },
- {
- 0x57, "User not member of CUG", ""
- },
- {
- 0x58, "Incompatible destination", ""
- },
- {
- 0x5a, "Non-existent CUG", ""
- },
- {
- 0x5b, "Invalid transit network selection", ""
- },
- {
- 0x5f, "Invalid message, unspecified", ""
- },
- {
- 0x60, "Mandatory information element is missing", ""
- },
- {
- 0x61, "Message type non-existent or not implemented", ""
- },
- {
- 0x62, "Message not compatible with call state or message type non-existent or not implemented ", " "
- },
- {
- 0x63, "Information element/parameter non-existent or not implemented", ""
- },
- {
- 0x64, "Invalid information element contents", ""
- },
- {
- 0x65, "Message not compatible with call state", ""
- },
- {
- 0x66, "Recovery on timer expiry", ""
- },
- {
- 0x67, "Parameter non-existent or not implemented - passed on", ""
- },
- {
- 0x6e, "Message with unrecognized parameter discarded", ""
- },
- {
- 0x6f, "Protocol error, unspecified", ""
- },
- {
- 0x7f, "Interworking, unspecified", ""
- },
-};
-
-#define CVSIZE sizeof(cvlist)/sizeof(struct CauseValue)
-
-static
-int
-prcause(char *dest, byte * p)
-{
- byte *end;
- char *dp = dest;
- int i, cause;
-
- end = p + p[1] + 1;
- p += 2;
- dp += sprintf(dp, " coding ");
- dp += prbits(dp, *p, 7, 2);
- dp += sprintf(dp, " location ");
- dp += prbits(dp, *p, 4, 4);
- *dp++ = '\n';
- p = skipext(p);
-
- cause = 0x7f & *p++;
-
- /* locate cause value */
- for (i = 0; i < CVSIZE; i++)
- if (cvlist[i].nr == cause)
- break;
-
- /* display cause value if it exists */
- if (i == CVSIZE)
- dp += sprintf(dp, "Unknown cause type %x!\n", cause);
- else
- dp += sprintf(dp, " cause value %x : %s \n", cause, cvlist[i].edescr);
-
- while (!0) {
- if (p > end)
- break;
- dp += sprintf(dp, " diag attribute %d ", *p++ & 0x7f);
- dp += sprintf(dp, " rej %d ", *p & 0x7f);
- if (*p & 0x80) {
- *dp++ = '\n';
- break;
- } else
- dp += sprintf(dp, " av %d\n", (*++p) & 0x7f);
- }
- return (dp - dest);
-
-}
-
-static
-struct MessageType cause_1tr6[] =
-{
- {CAUSE_InvCRef, "Invalid Call Reference"},
- {CAUSE_BearerNotImpl, "Bearer Service Not Implemented"},
- {CAUSE_CIDunknown, "Caller Identity unknown"},
- {CAUSE_CIDinUse, "Caller Identity in Use"},
- {CAUSE_NoChans, "No Channels available"},
- {CAUSE_FacNotImpl, "Facility Not Implemented"},
- {CAUSE_FacNotSubscr, "Facility Not Subscribed"},
- {CAUSE_OutgoingBarred, "Outgoing calls barred"},
- {CAUSE_UserAccessBusy, "User Access Busy"},
- {CAUSE_NegativeGBG, "Negative GBG"},
- {CAUSE_UnknownGBG, "Unknown GBG"},
- {CAUSE_NoSPVknown, "No SPV known"},
- {CAUSE_DestNotObtain, "Destination not obtainable"},
- {CAUSE_NumberChanged, "Number changed"},
- {CAUSE_OutOfOrder, "Out Of Order"},
- {CAUSE_NoUserResponse, "No User Response"},
- {CAUSE_UserBusy, "User Busy"},
- {CAUSE_IncomingBarred, "Incoming Barred"},
- {CAUSE_CallRejected, "Call Rejected"},
- {CAUSE_NetworkCongestion, "Network Congestion"},
- {CAUSE_RemoteUser, "Remote User initiated"},
- {CAUSE_LocalProcErr, "Local Procedure Error"},
- {CAUSE_RemoteProcErr, "Remote Procedure Error"},
- {CAUSE_RemoteUserSuspend, "Remote User Suspend"},
- {CAUSE_RemoteUserResumed, "Remote User Resumed"},
- {CAUSE_UserInfoDiscarded, "User Info Discarded"}
-};
-
-int cause_1tr6_len = (sizeof(cause_1tr6) / sizeof(struct MessageType));
-
-static int
-prcause_1tr6(char *dest, byte * p)
-{
- char *dp = dest;
- int i, cause;
-
- p++;
- if (0 == *p) {
- dp += sprintf(dp, " OK (cause length=0)\n");
- return (dp - dest);
- } else if (*p > 1) {
- dp += sprintf(dp, " coding ");
- dp += prbits(dp, p[2], 7, 2);
- dp += sprintf(dp, " location ");
- dp += prbits(dp, p[2], 4, 4);
- *dp++ = '\n';
- }
- p++;
- cause = 0x7f & *p;
-
- /* locate cause value */
- for (i = 0; i < cause_1tr6_len; i++)
- if (cause_1tr6[i].nr == cause)
- break;
-
- /* display cause value if it exists */
- if (i == cause_1tr6_len)
- dp += sprintf(dp, "Unknown cause type %x!\n", cause);
- else
- dp += sprintf(dp, " cause value %x : %s \n", cause, cause_1tr6[i].descr);
-
- return (dp - dest);
-
-}
-
-static int
-prchident(char *dest, byte * p) {
- char *dp = dest;
-
- p += 2;
- dp += sprintf(dp, " octet 3 ");
- dp += prbits(dp, *p, 8, 8);
- *dp++ = '\n';
- return (dp - dest);
-}
-
-static int
-prcalled(char *dest, byte * p) {
- int l;
- char *dp = dest;
-
- p++;
- l = *p++ - 1;
- dp += sprintf(dp, " octet 3 ");
- dp += prbits(dp, *p++, 8, 8);
- *dp++ = '\n';
- dp += sprintf(dp, " number digits ");
- while (l--)
- *dp++ = *p++;
- *dp++ = '\n';
- return (dp - dest);
-}
-static int
-prcalling(char *dest, byte * p) {
- int l;
- char *dp = dest;
-
- p++;
- l = *p++ - 1;
- dp += sprintf(dp, " octet 3 ");
- dp += prbits(dp, *p, 8, 8);
- *dp++ = '\n';
- if (!(*p & 0x80)) {
- dp += sprintf(dp, " octet 3a ");
- dp += prbits(dp, *++p, 8, 8);
- *dp++ = '\n';
- l--;
- };
- p++;
-
- dp += sprintf(dp, " number digits ");
- while (l--)
- *dp++ = *p++;
- *dp++ = '\n';
- return (dp - dest);
-}
-
-static
-int
-prbearer(char *dest, byte * p)
-{
- char *dp = dest, ch;
-
- p += 2;
- dp += sprintf(dp, " octet 3 ");
- dp += prbits(dp, *p++, 8, 8);
- *dp++ = '\n';
- dp += sprintf(dp, " octet 4 ");
- dp += prbits(dp, *p, 8, 8);
- *dp++ = '\n';
- if ((*p++ & 0x1f) == 0x18) {
- dp += sprintf(dp, " octet 4.1 ");
- dp += prbits(dp, *p++, 8, 8);
- *dp++ = '\n';
- }
- /* check for user information layer 1 */
- if ((*p & 0x60) == 0x20) {
- ch = ' ';
- do {
- dp += sprintf(dp, " octet 5%c ", ch);
- dp += prbits(dp, *p, 8, 8);
- *dp++ = '\n';
- if (ch == ' ')
- ch = 'a';
- else
- ch++;
- }
- while (!(*p++ & 0x80));
- }
- /* check for user information layer 2 */
- if ((*p & 0x60) == 0x40) {
- dp += sprintf(dp, " octet 6 ");
- dp += prbits(dp, *p++, 8, 8);
- *dp++ = '\n';
- }
- /* check for user information layer 3 */
- if ((*p & 0x60) == 0x60) {
- dp += sprintf(dp, " octet 7 ");
- dp += prbits(dp, *p++, 8, 8);
- *dp++ = '\n';
- }
- return (dp - dest);
-}
-
-static int
-general(char *dest, byte * p) {
- char *dp = dest;
- char ch = ' ';
- int l, octet = 3;
-
- p++;
- l = *p++;
- /* Iterate over all octets in the information element */
- while (l--) {
- dp += sprintf(dp, " octet %d%c ", octet, ch);
- dp += prbits(dp, *p++, 8, 8);
- *dp++ = '\n';
-
- /* last octet in group? */
- if (*p & 0x80) {
- octet++;
- ch = ' ';
- } else if (ch == ' ')
- ch = 'a';
- else
- ch++;
- }
- return (dp - dest);
-}
-
-static int
-prcharge(char *dest, byte * p) {
- char *dp = dest;
- int l;
-
- p++;
- l = *p++ - 1;
- dp += sprintf(dp, " GEA ");
- dp += prbits(dp, *p++, 8, 8);
- dp += sprintf(dp, " Anzahl: ");
- /* Iterate over all octets in the * information element */
- while (l--)
- *dp++ = *p++;
- *dp++ = '\n';
- return (dp - dest);
-}
-static int
-prtext(char *dest, byte * p) {
- char *dp = dest;
- int l;
-
- p++;
- l = *p++;
- dp += sprintf(dp, " ");
- /* Iterate over all octets in the * information element */
- while (l--)
- *dp++ = *p++;
- *dp++ = '\n';
- return (dp - dest);
-}
-static int
-display(char *dest, byte * p) {
- char *dp = dest;
- char ch = ' ';
- int l, octet = 3;
-
- p++;
- l = *p++;
- /* Iterate over all octets in the * display-information element */
- dp += sprintf(dp, " \"");
- while (l--) {
- dp += sprintf(dp, "%c", *p++);
-
- /* last octet in group? */
- if (*p & 0x80) {
- octet++;
- ch = ' ';
- } else if (ch == ' ')
- ch = 'a';
-
- else
- ch++;
- }
- *dp++ = '\"';
- *dp++ = '\n';
- return (dp - dest);
-}
-
-int
-prfacility(char *dest, byte * p)
-{
- char *dp = dest;
- int l, l2;
-
- p++;
- l = *p++;
- dp += sprintf(dp, " octet 3 ");
- dp += prbits(dp, *p++, 8, 8);
- dp += sprintf(dp, "\n");
- l -= 1;
-
- while (l > 0) {
- dp += sprintf(dp, " octet 4 ");
- dp += prbits(dp, *p++, 8, 8);
- dp += sprintf(dp, "\n");
- dp += sprintf(dp, " octet 5 %d\n", l2 = *p++ & 0x7f);
- l -= 2;
- dp += sprintf(dp, " contents ");
- while (l2--) {
- dp += sprintf(dp, "%2x ", *p++);
- l--;
- }
- dp += sprintf(dp, "\n");
- }
-
- return (dp - dest);
-}
-
-static
-struct InformationElement {
- byte nr;
- char *descr;
- int (*f) (char *, byte *);
-} ielist[] = {
-
- {
- 0x00, "Segmented message", general
- },
- {
- 0x04, "Bearer capability", prbearer
- },
- {
- 0x08, "Cause", prcause
- },
- {
- 0x10, "Call identity", general
- },
- {
- 0x14, "Call state", general
- },
- {
- 0x18, "Channel identification", prchident
- },
- {
- 0x1c, "Facility", prfacility
- },
- {
- 0x1e, "Progress indicator", general
- },
- {
- 0x20, "Network-specific facilities", general
- },
- {
- 0x27, "Notification indicator", general
- },
- {
- 0x28, "Display", display
- },
- {
- 0x29, "Date/Time", general
- },
- {
- 0x2c, "Keypad facility", general
- },
- {
- 0x34, "Signal", general
- },
- {
- 0x40, "Information rate", general
- },
- {
- 0x42, "End-to-end delay", general
- },
- {
- 0x43, "Transit delay selection and indication", general
- },
- {
- 0x44, "Packet layer binary parameters", general
- },
- {
- 0x45, "Packet layer window size", general
- },
- {
- 0x46, "Packet size", general
- },
- {
- 0x47, "Closed user group", general
- },
- {
- 0x4a, "Reverse charge indication", general
- },
- {
- 0x6c, "Calling party number", prcalling
- },
- {
- 0x6d, "Calling party subaddress", general
- },
- {
- 0x70, "Called party number", prcalled
- },
- {
- 0x71, "Called party subaddress", general
- },
- {
- 0x74, "Redirecting number", general
- },
- {
- 0x78, "Transit network selection", general
- },
- {
- 0x79, "Restart indicator", general
- },
- {
- 0x7c, "Low layer compatibility", general
- },
- {
- 0x7d, "High layer compatibility", general
- },
- {
- 0x7e, "User-user", general
- },
- {
- 0x7f, "Escape for extension", general
- },
-};
-
-
-#define IESIZE sizeof(ielist)/sizeof(struct InformationElement)
-
-static struct InformationElement we_0[] =
-{
- {WE0_cause, "Cause", prcause_1tr6},
- {WE0_connAddr, "Connecting Address", prcalled},
- {WE0_callID, "Call IDentity", general},
- {WE0_chanID, "Channel IDentity", general},
- {WE0_netSpecFac, "Network Specific Facility", general},
- {WE0_display, "Display", general},
- {WE0_keypad, "Keypad", general},
- {WE0_origAddr, "Origination Address", prcalled},
- {WE0_destAddr, "Destination Address", prcalled},
- {WE0_userInfo, "User Info", general}
-};
-
-static int we_0_len = (sizeof(we_0) / sizeof(struct InformationElement));
-
-static struct InformationElement we_6[] =
-{
- {WE6_serviceInd, "Service Indicator", general},
- {WE6_chargingInfo, "Charging Information", prcharge},
- {WE6_date, "Date", prtext},
- {WE6_facSelect, "Facility Select", general},
- {WE6_facStatus, "Facility Status", general},
- {WE6_statusCalled, "Status Called", general},
- {WE6_addTransAttr, "Additional Transmission Attributes", general}
-};
-static int we_6_len = (sizeof(we_6) / sizeof(struct InformationElement));
-
-void
-dlogframe(struct IsdnCardState *sp, byte * buf, int size, char *comment) {
- byte *bend = buf + size;
- char *dp;
- int i, cs = 0, cs_old = 0, cs_fest = 0;
-
- /* display header */
- dp = sp->dlogspace;
- dp += sprintf(dp, "%s\n", comment);
-
- {
- byte *p = buf;
- dp += sprintf(dp, "hex: ");
- while (p < bend)
- dp += sprintf(dp, "%02x ", *p++);
- dp += sprintf(dp, "\n");
- teles_putstatus(sp->dlogspace);
- dp = sp->dlogspace;
- }
- if ((0xfe & buf[0]) == PROTO_DIS_N0) { /* 1TR6 */
- /* locate message type */
- if (buf[0] == PROTO_DIS_N0) { /* N0 */
- for (i = 0; i < mt_n0_len; i++)
- if (mt_n0[i].nr == buf[3])
- break;
- /* display message type iff it exists */
- if (i == mt_n0_len)
- dp += sprintf(dp, "Unknown message type N0 %x!\n", buf[3]);
- else
- dp += sprintf(dp, "call reference %d size %d message type %s\n",
- buf[2], size, mt_n0[i].descr);
- } else { /* N1 */
- for (i = 0; i < mt_n1_len; i++)
- if (mt_n1[i].nr == buf[3])
- break;
- /* display message type iff it exists */
- if (i == mt_n1_len)
- dp += sprintf(dp, "Unknown message type N1 %x!\n", buf[3]);
- else
- dp += sprintf(dp, "call reference %d size %d message type %s\n",
- buf[2], size, mt_n1[i].descr);
- }
-
- /* display each information element */
- buf += 4;
- while (buf < bend) {
- /* Is it a single octet information element? */
- if (*buf & 0x80) {
- switch ((*buf >> 4) & 7) {
- case 1:
- dp += sprintf(dp, " Shift %x\n", *buf & 0xf);
- cs_old = cs;
- cs = *buf & 7;
- cs_fest = *buf & 8;
- break;
- case 3:
- dp += sprintf(dp, " Congestion level %x\n", *buf & 0xf);
- break;
- case 2:
- if (*buf == 0xa0) {
- dp += sprintf(dp, " More data\n");
- break;
- }
- if (*buf == 0xa1) {
- dp += sprintf(dp, " Sending complete\n");
- }
- break;
- /* fall through */
- default:
- dp += sprintf(dp, " Reserved %x\n", *buf);
- break;
- }
- buf++;
- continue;
- }
- /* No, locate it in the table */
- if (cs == 0) {
- for (i = 0; i < we_0_len; i++)
- if (*buf == we_0[i].nr)
- break;
-
- /* When found, give appropriate msg */
- if (i != we_0_len) {
- dp += sprintf(dp, " %s\n", we_0[i].descr);
- dp += we_0[i].f(dp, buf);
- } else
- dp += sprintf(dp, " Codeset %d attribute %x attribute size %d\n", cs, *buf, buf[1]);
- } else if (cs == 6) {
- for (i = 0; i < we_6_len; i++)
- if (*buf == we_6[i].nr)
- break;
-
- /* When found, give appropriate msg */
- if (i != we_6_len) {
- dp += sprintf(dp, " %s\n", we_6[i].descr);
- dp += we_6[i].f(dp, buf);
- } else
- dp += sprintf(dp, " Codeset %d attribute %x attribute size %d\n", cs, *buf, buf[1]);
- } else
- dp += sprintf(dp, " Unknown Codeset %d attribute %x attribute size %d\n", cs, *buf, buf[1]);
- /* Skip to next element */
- if (cs_fest == 8) {
- cs = cs_old;
- cs_old = 0;
- cs_fest = 0;
- }
- buf += buf[1] + 2;
- }
- } else if (buf[0]==PROTO_EURO) { /* EURO */
- /* locate message type */
- for (i = 0; i < MTSIZE; i++)
- if (mtlist[i].nr == buf[3])
- break;
-
- /* display message type iff it exists */
- if (i == MTSIZE)
- dp += sprintf(dp, "Unknown message type %x!\n", buf[3]);
- else
- dp += sprintf(dp, "call reference %d size %d message type %s\n",
- buf[2], size, mtlist[i].descr);
-
- /* display each information element */
- buf += 4;
- while (buf < bend) {
- /* Is it a single octet information element? */
- if (*buf & 0x80) {
- switch ((*buf >> 4) & 7) {
- case 1:
- dp += sprintf(dp, " Shift %x\n", *buf & 0xf);
- break;
- case 3:
- dp += sprintf(dp, " Congestion level %x\n", *buf & 0xf);
- break;
- case 5:
- dp += sprintf(dp, " Repeat indicator %x\n", *buf & 0xf);
- break;
- case 2:
- if (*buf == 0xa0) {
- dp += sprintf(dp, " More data\n");
- break;
- }
- if (*buf == 0xa1) {
- dp += sprintf(dp, " Sending complete\n");
- }
- break;
- /* fall through */
- default:
- dp += sprintf(dp, " Reserved %x\n", *buf);
- break;
- }
- buf++;
- continue;
- }
- /* No, locate it in the table */
- for (i = 0; i < IESIZE; i++)
- if (*buf == ielist[i].nr)
- break;
-
- /* When not found, give appropriate msg */
- if (i != IESIZE) {
- dp += sprintf(dp, " %s\n", ielist[i].descr);
- dp += ielist[i].f(dp, buf);
- } else
- dp += sprintf(dp, " attribute %x attribute size %d\n", *buf, buf[1]);
-
- /* Skip to next element */
- buf += buf[1] + 2;
- }
- }
- else dp += sprintf(dp,"Unnown frame type %.2x, ignored\n",buf[0]);
-
- dp += sprintf(dp, "\n");
- teles_putstatus(sp->dlogspace);
-}
diff --git a/drivers/isdn/teles/tei.c b/drivers/isdn/teles/tei.c
deleted file mode 100644
index 3ab9f3646..000000000
--- a/drivers/isdn/teles/tei.c
+++ /dev/null
@@ -1,248 +0,0 @@
-/* $Id: tei.c,v 1.1 1996/04/13 10:28:25 fritz Exp $
- *
- * $Log: tei.c,v $
- * Revision 1.1 1996/04/13 10:28:25 fritz
- * Initial revision
- *
- *
- */
-#define __NO_VERSION__
-#include "teles.h"
-
-extern struct IsdnCard cards[];
-extern int nrcards;
-
-static struct PStack *
-findces(struct PStack *st, int ces)
-{
- struct PStack *ptr = *(st->l1.stlistp);
-
- while (ptr)
- if (ptr->l2.ces == ces)
- return (ptr);
- else
- ptr = ptr->next;
- return (NULL);
-}
-
-static struct PStack *
-findtei(struct PStack *st, int tei)
-{
- struct PStack *ptr = *(st->l1.stlistp);
-
- if (tei == 127)
- return (NULL);
-
- while (ptr)
- if (ptr->l2.tei == tei)
- return (ptr);
- else
- ptr = ptr->next;
- return (NULL);
-}
-
-void
-tei_handler(struct PStack *st,
- byte pr, struct BufHeader *ibh)
-{
- byte *bp;
- unsigned int tces;
- struct PStack *otsp, *ptr;
- unsigned int data;
-
- if (st->l2.debug)
- printk(KERN_DEBUG "teihandler %d\n", pr);
-
- switch (pr) {
- case (MDL_ASSIGN):
- data = (unsigned int) ibh;
- BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 6);
- if (!ibh)
- return;
- bp = DATAPTR(ibh);
- bp += st->l2.uihsize;
- bp[0] = 0xf;
- bp[1] = data >> 8;
- bp[2] = data & 0xff;
- bp[3] = 0x1;
- bp[4] = 0xff;
- ibh->datasize = 8;
- st->l3.l3l2(st, DL_UNIT_DATA, ibh);
- break;
- case (DL_UNIT_DATA):
- bp = DATAPTR(ibh);
- bp += 3;
- if (bp[0] != 0xf)
- break;
- switch (bp[3]) {
- case (2):
- tces = (bp[1] << 8) | bp[2];
- BufPoolRelease(ibh);
- if (st->l3.debug)
- printk(KERN_DEBUG "tei identity assigned for %d=%d\n", tces,
- bp[4] >> 1);
- if ((otsp = findces(st, tces)))
- otsp->ma.teil2(otsp, MDL_ASSIGN,
- (void *)(bp[4] >> 1));
- break;
- case (4):
- if (st->l3.debug)
- printk(KERN_DEBUG "checking identity for %d\n", bp[4] >> 1);
- if (bp[4] >> 1 == 0x7f) {
- BufPoolRelease(ibh);
- ptr = *(st->l1.stlistp);
- while (ptr) {
- if ((ptr->l2.tei & 0x7f) != 0x7f) {
- if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 7))
- break;
- bp = DATAPTR(ibh);
- bp += 3;
- bp[0] = 0xf;
- bp[1] = ptr->l2.ces >> 8;
- bp[2] = ptr->l2.ces & 0xff;
- bp[3] = 0x5;
- bp[4] = (ptr->l2.tei << 1) | 1;
- ibh->datasize = 8;
- st->l3.l3l2(st, DL_UNIT_DATA, ibh);
- }
- ptr = ptr->next;
- }
- } else {
- otsp = findtei(st, bp[4] >> 1);
- BufPoolRelease(ibh);
- if (!otsp)
- break;
- if (st->l3.debug)
- printk(KERN_DEBUG "ces is %d\n", otsp->l2.ces);
- if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 7))
- break;
- bp = DATAPTR(ibh);
- bp += 3;
- bp[0] = 0xf;
- bp[1] = otsp->l2.ces >> 8;
- bp[2] = otsp->l2.ces & 0xff;
- bp[3] = 0x5;
- bp[4] = (otsp->l2.tei << 1) | 1;
- ibh->datasize = 8;
- st->l3.l3l2(st, DL_UNIT_DATA, ibh);
- }
- break;
- default:
- BufPoolRelease(ibh);
- if (st->l3.debug)
- printk(KERN_DEBUG "tei message unknown %d ai %d\n", bp[3], bp[4] >> 1);
- }
- break;
- default:
- printk(KERN_WARNING "tei handler unknown primitive %d\n", pr);
- break;
- }
-}
-
-unsigned int
-randomces(void)
-{
- int x = jiffies & 0xffff;
-
- return (x);
-}
-
-static void
-tei_man(struct PStack *sp, int i, void *v)
-{
- printk(KERN_DEBUG "tei_man\n");
-}
-
-static void
-tei_l2tei(struct PStack *st, int pr, void *arg)
-{
- struct IsdnCardState *sp = st->l1.hardware;
-
- tei_handler(sp->teistack, pr, arg);
-}
-
-void
-setstack_tei(struct PStack *st)
-{
- st->l2.l2tei = tei_l2tei;
-}
-
-static void
-init_tei(struct IsdnCardState *sp, int protocol)
-{
- struct PStack *st;
- char tmp[128];
-
-#define DIRTY_HACK_AGAINST_SIGSEGV
-
- st = (struct PStack *) Smalloc(sizeof(struct PStack), GFP_KERNEL,
- "struct PStack");
-
-#ifdef DIRTY_HACK_AGAINST_SIGSEGV
- sp->teistack = st; /* struct is not initialized yet */
- sp->teistack->protocol = protocol; /* struct is not initialized yet */
-#endif /* DIRTY_HACK_AGAINST_SIGSEGV */
-
-
- setstack_teles(st, sp);
-
- st->l2.extended = !0;
- st->l2.laptype = LAPD;
- st->l2.window = 1;
- st->l2.orig = !0;
- st->protocol = protocol;
-
-/*
- * the following is not necessary for tei mng. (broadcast only)
- */
-
- st->l2.t200 = 500; /* 500 milliseconds */
- st->l2.n200 = 4; /* try 4 times */
-
- st->l2.sap = 63;
- st->l2.tei = 127;
-
- sprintf(tmp, "Card %d tei ", sp->cardnr);
- setstack_isdnl2(st, tmp);
- st->l2.debug = 0;
- st->l3.debug = 0;
-
- st->ma.manl2(st, MDL_NOTEIPROC, NULL);
-
- st->l2.l2l3 = (void *) tei_handler;
- st->l1.l1man = tei_man;
- st->l2.l2man = tei_man;
- st->l4.l2writewakeup = NULL;
-
- teles_addlist(sp, st);
- sp->teistack = st;
-}
-
-static void
-release_tei(struct IsdnCardState *sp)
-{
- struct PStack *st = sp->teistack;
-
- teles_rmlist(sp, st);
- Sfree((void *) st);
-}
-
-void
-TeiNew(void)
-{
- int i;
-
- for (i = 0; i < nrcards; i++)
- if (cards[i].sp)
- init_tei(cards[i].sp, cards[i].protocol);
-}
-
-void
-TeiFree(void)
-{
- int i;
-
- for (i = 0; i < nrcards; i++)
- if (cards[i].sp)
- release_tei(cards[i].sp);
-}
diff --git a/drivers/isdn/teles/teles.h b/drivers/isdn/teles/teles.h
deleted file mode 100644
index 339e52d4e..000000000
--- a/drivers/isdn/teles/teles.h
+++ /dev/null
@@ -1,486 +0,0 @@
-/* $Id: teles.h,v 1.3 1997/02/11 01:40:36 keil Exp $
- *
- * $Log: teles.h,v $
- * Revision 1.3 1997/02/11 01:40:36 keil
- * New Param structure
- *
- * Revision 1.2 1996/04/30 21:52:04 isdn4dev
- * SPV for 1TR6 - Karsten
- *
- * Revision 1.1 1996/04/13 10:29:00 fritz
- * Initial revision
- *
- *
- */
-#include <linux/module.h>
-#include <linux/version.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/major.h>
-#include <asm/segment.h>
-#include <asm/io.h>
-#include <linux/delay.h>
-#include <linux/kernel.h>
-#include <linux/signal.h>
-#include <linux/malloc.h>
-#include <linux/mm.h>
-#include <linux/mman.h>
-#include <linux/ioport.h>
-#include <linux/timer.h>
-#include <linux/wait.h>
-#include <linux/isdnif.h>
-#include <linux/tty.h>
-
-#define PH_ACTIVATE 1
-#define PH_DATA 2
-#define PH_DEACTIVATE 3
-
-#define MDL_ASSIGN 4
-#define DL_UNIT_DATA 5
-#define SC_STARTUP 6
-#define CC_ESTABLISH 7
-#define DL_ESTABLISH 8
-#define DL_DATA 9
-#define CC_S_STATUS_ENQ 10
-
-#define CC_CONNECT 15
-#define CC_CONNECT_ACKNOWLEDGE 16
-#define CO_EOF 17
-#define SC_DISCONNECT 18
-#define CO_DTMF 19
-#define DL_RELEASE 20
-
-#define CO_ALARM 22
-#define CC_REJECT 23
-
-#define CC_SETUP_REQ 24
-#define CC_SETUP_CNF 25
-#define CC_SETUP_IND 26
-#define CC_SETUP_RSP 27
-#define CC_SETUP_COMPLETE_IND 28
-
-#define CC_DISCONNECT_REQ 29
-#define CC_DISCONNECT_IND 30
-
-#define CC_RELEASE_CNF 31
-#define CC_RELEASE_IND 32
-#define CC_RELEASE_REQ 33
-
-#define CC_REJECT_REQ 34
-
-#define CC_PROCEEDING_IND 35
-
-#define CC_DLRL 36
-#define CC_DLEST 37
-
-#define CC_ALERTING_REQ 38
-#define CC_ALERTING_IND 39
-
-#define DL_STOP 40
-#define DL_START 41
-
-#define MDL_NOTEIPROC 46
-
-#define LC_ESTABLISH 47
-#define LC_RELEASE 48
-
-#define PH_REQUEST_PULL 49
-#define PH_PULL_ACK 50
-#define PH_DATA_PULLED 51
-#define CC_INFO_CHARGE 52
-
-/*
- * Message-Types
- */
-
-#define MT_ALERTING 0x01
-#define MT_CALL_PROCEEDING 0x02
-#define MT_CONNECT 0x07
-#define MT_CONNECT_ACKNOWLEDGE 0x0f
-#define MT_PROGRESS 0x03
-#define MT_SETUP 0x05
-#define MT_SETUP_ACKNOWLEDGE 0x0d
-#define MT_RESUME 0x26
-#define MT_RESUME_ACKNOWLEDGE 0x2e
-#define MT_RESUME_REJECT 0x22
-#define MT_SUSPEND 0x25
-#define MT_SUSPEND_ACKNOWLEDGE 0x2d
-#define MT_SUSPEND_REJECT 0x21
-#define MT_USER_INFORMATION 0x20
-#define MT_DISCONNECT 0x45
-#define MT_RELEASE 0x4d
-#define MT_RELEASE_COMPLETE 0x5a
-#define MT_RESTART 0x46
-#define MT_RESTART_ACKNOWLEDGE 0x4e
-#define MT_SEGMENT 0x60
-#define MT_CONGESTION_CONTROL 0x79
-#define MT_INFORMATION 0x7b
-#define MT_FACILITY 0x62
-#define MT_NOTIFY 0x6e
-#define MT_STATUS 0x7d
-#define MT_STATUS_ENQUIRY 0x75
-
-#define IE_CAUSE 0x08
-
-struct HscxIoctlArg {
- int channel;
- int mode;
- int transbufsize;
-};
-
-#ifdef __KERNEL__
-
-#undef DEBUG_MAGIC
-
-#define HSCX_SBUF_ORDER 1
-#define HSCX_SBUF_BPPS 2
-#define HSCX_SBUF_MAXPAGES 3
-
-#define HSCX_RBUF_ORDER 1
-#define HSCX_RBUF_BPPS 2
-#define HSCX_RBUF_MAXPAGES 3
-
-#define HSCX_SMALLBUF_ORDER 0
-#define HSCX_SMALLBUF_BPPS 40
-#define HSCX_SMALLBUF_MAXPAGES 1
-
-#define ISAC_SBUF_ORDER 0
-#define ISAC_SBUF_BPPS 16
-#define ISAC_SBUF_MAXPAGES 1
-
-#define ISAC_RBUF_ORDER 0
-#define ISAC_RBUF_BPPS 16
-#define ISAC_RBUF_MAXPAGES 1
-
-#define ISAC_SMALLBUF_ORDER 0
-#define ISAC_SMALLBUF_BPPS 40
-#define ISAC_SMALLBUF_MAXPAGES 1
-
-#define byte unsigned char
-
-#define MAX_WINDOW 8
-
-byte *Smalloc(int size, int pr, char *why);
-void Sfree(byte * ptr);
-
-/*
- * Statemachine
- */
-struct Fsm {
- int *jumpmatrix;
- int state_count, event_count;
- char **strEvent, **strState;
-};
-
-struct FsmInst {
- struct Fsm *fsm;
- int state;
- int debug;
- void *userdata;
- int userint;
- void (*printdebug) (struct FsmInst *, char *);
-};
-
-struct FsmNode {
- int state, event;
- void (*routine) (struct FsmInst *, int, void *);
-};
-
-struct FsmTimer {
- struct FsmInst *fi;
- struct timer_list tl;
- int event;
- void *arg;
-};
-
-struct BufHeader {
-#ifdef DEBUG_MAGIC
- int magic;
-#endif
- struct BufHeader *next;
- struct BufPool *bp;
- int datasize;
- byte primitive, where;
- void *heldby;
-};
-
-struct Pages {
- struct Pages *next;
-};
-
-struct BufPool {
-#ifdef DEBUG_MAGIC
- int magic;
-#endif
- struct BufHeader *freelist;
- struct Pages *pageslist;
- int pageorder;
- int pagescount;
- int bpps;
- int bufsize;
- int maxpages;
-};
-
-struct BufQueue {
-#ifdef DEBUG_MAGIC
- int magic;
-#endif
- struct BufHeader *head, *tail;
-};
-
-struct Layer1 {
- void *hardware;
- int hscx;
- struct BufPool *sbufpool, *rbufpool, *smallpool;
- struct PStack **stlistp;
- int act_state;
- void (*l1l2) (struct PStack *, int, struct BufHeader *);
- void (*l1man) (struct PStack *, int, void *);
- int hscxmode, hscxchannel, requestpull;
-};
-
-struct Layer2 {
- int sap, tei, ces;
- int extended, laptype;
- int uihsize, ihsize;
- int vs, va, vr;
- struct BufQueue i_queue;
- int window, orig;
- int rejexp;
- int debug;
- struct BufHeader *windowar[MAX_WINDOW];
- int sow;
- struct FsmInst l2m;
- void (*l2l1) (struct PStack *, int, struct BufHeader *);
- void (*l2l1discardq) (struct PStack *, int, void *, int);
- void (*l2man) (struct PStack *, int, void *);
- void (*l2l3) (struct PStack *, int, void *);
- void (*l2tei) (struct PStack *, int, void *);
- struct FsmTimer t200_timer, t203_timer;
- int t200, n200, t203;
- int rc, t200_running;
- char debug_id[32];
-};
-
-struct Layer3 {
- void (*l3l4) (struct PStack *, int, struct BufHeader *);
- void (*l3l2) (struct PStack *, int, void *);
- int state, callref;
- int debug;
-};
-
-struct Layer4 {
- void (*l4l3) (struct PStack *, int, void *);
- void *userdata;
- void (*l1writewakeup) (struct PStack *);
- void (*l2writewakeup) (struct PStack *);
-};
-
-struct Management {
- void (*manl1) (struct PStack *, int, void *);
- void (*manl2) (struct PStack *, int, void *);
- void (*teil2) (struct PStack *, int, void *);
-};
-
-struct Param {
- int cause;
- int bchannel;
- int callref; /* TEI-Number */
- setup_parm setup; /* from isdnif.h numbers and Serviceindicator */
- int chargeinfo; /* Charge Info - only for 1tr6 in
- * the moment
- */
- int spv; /* SPV Flag */
-};
-
-struct PStack {
- struct PStack *next;
- struct Layer1 l1;
- struct Layer2 l2;
- struct Layer3 l3;
- struct Layer4 l4;
- struct Management ma;
- struct Param *pa;
- int protocol; /* EDSS1 or 1TR6 */
-};
-
-struct HscxState {
- byte *membase;
- int iobase;
- int inuse, init, active;
- struct BufPool sbufpool, rbufpool, smallpool;
- struct IsdnCardState *sp;
- int hscx, mode;
- int transbufsize, receive;
- struct BufHeader *rcvibh, *xmtibh;
- int rcvptr, sendptr;
- struct PStack *st;
- struct tq_struct tqueue;
- int event;
- struct BufQueue rq, sq;
- int releasebuf;
-#ifdef DEBUG_MAGIC
- int magic; /* 301270 */
-#endif
-};
-
-struct IsdnCardState {
-#ifdef DEBUG_MAGIC
- int magic;
-#endif
- byte *membase;
- int iobase;
- struct BufPool sbufpool, rbufpool, smallpool;
- struct PStack *stlist;
- struct BufHeader *xmtibh, *rcvibh;
- int rcvptr, sendptr;
- int event;
- struct tq_struct tqueue;
- int ph_active;
- struct BufQueue rq, sq;
-
- int cardnr, ph_state;
- struct PStack *teistack;
- struct HscxState hs[2];
-
- int dlogflag;
- char *dlogspace;
- int debug;
- int releasebuf;
-};
-
-struct IsdnCard {
- byte *membase;
- int interrupt;
- unsigned int iobase;
- int protocol; /* EDSS1 or 1TR6 */
- struct IsdnCardState *sp;
-};
-
-#define DATAPTR(x) ((byte *)x+sizeof(struct BufHeader))
-
-#define LAPD 0
-#define LAPB 1
-
-void BufPoolInit(struct BufPool *bp, int order, int bpps,
- int maxpages);
-int BufPoolAdd(struct BufPool *bp, int priority);
-void BufPoolFree(struct BufPool *bp);
-int BufPoolGet(struct BufHeader **bh,
- struct BufPool *bp, int priority, void *heldby, int where);
-void BufPoolRelease(struct BufHeader *bh);
-void BufQueueLink(struct BufQueue *bq,
- struct BufHeader *bh);
-int BufQueueUnlink(struct BufHeader **bh, struct BufQueue *bq);
-void BufQueueInit(struct BufQueue *bq);
-void BufQueueRelease(struct BufQueue *bq);
-void BufQueueDiscard(struct BufQueue *q, int pr, void *heldby,
- int releasetoo);
-int BufQueueLength(struct BufQueue *bq);
-void BufQueueLinkFront(struct BufQueue *bq,
- struct BufHeader *bh);
-
-void l2down(struct PStack *st,
- byte pr, struct BufHeader *ibh);
-void l2up(struct PStack *st,
- byte pr, struct BufHeader *ibh);
-void acceptph(struct PStack *st,
- struct BufHeader *ibh);
-void setstack_isdnl2(struct PStack *st, char *debug_id);
-int teles_inithardware(void);
-void teles_closehardware(void);
-
-void setstack_teles(struct PStack *st, struct IsdnCardState *sp);
-unsigned int randomces(void);
-void setstack_isdnl3(struct PStack *st);
-void teles_addlist(struct IsdnCardState *sp,
- struct PStack *st);
-void releasestack_isdnl2(struct PStack *st);
-void teles_rmlist(struct IsdnCardState *sp,
- struct PStack *st);
-void newcallref(struct PStack *st);
-
-int ll_init(void);
-void ll_stop(void), ll_unload(void);
-int setstack_hscx(struct PStack *st, struct HscxState *hs);
-void modehscx(struct HscxState *hs, int mode, int ichan);
-byte *findie(byte * p, int size, byte ie, int wanted_set);
-int getcallref(byte * p);
-
-void FsmNew(struct Fsm *fsm,
- struct FsmNode *fnlist, int fncount);
-void FsmFree(struct Fsm *fsm);
-int FsmEvent(struct FsmInst *fi,
- int event, void *arg);
-void FsmChangeState(struct FsmInst *fi,
- int newstate);
-void FsmInitTimer(struct FsmInst *fi, struct FsmTimer *ft);
-int FsmAddTimer(struct FsmTimer *ft,
- int millisec, int event, void *arg, int where);
-void FsmDelTimer(struct FsmTimer *ft, int where);
-int FsmTimerRunning(struct FsmTimer *ft);
-void jiftime(char *s, long mark);
-
-void CallcNew(void);
-void CallcFree(void);
-int CallcNewChan(void);
-void CallcFreeChan(void);
-int teles_command(isdn_ctrl * ic);
-int teles_writebuf(int id, int chan, const u_char * buf, int count, int user);
-void teles_putstatus(char *buf);
-void teles_reportcard(int cardnr);
-int ListLength(struct BufHeader *ibh);
-void dlogframe(struct IsdnCardState *sp, byte * p, int size, char *comment);
-void iecpy(byte * dest, byte * iestart, int ieoffset);
-void setstack_transl2(struct PStack *st);
-void releasestack_transl2(struct PStack *st);
-void close_hscxstate(struct HscxState *);
-void setstack_tei(struct PStack *st);
-
-struct LcFsm {
- struct FsmInst lcfi;
- int type;
- struct Channel *ch;
- void (*lccall) (struct LcFsm *, int, void *);
- struct PStack *st;
- int l2_establish;
- int l2_start;
- struct FsmTimer act_timer;
- char debug_id[32];
-};
-
-struct Channel {
- struct PStack ds, is;
- struct IsdnCardState *sp;
- int hscx;
- int chan;
- int incoming;
- struct FsmInst fi;
- struct LcFsm lc_d, lc_b;
- struct Param para;
- int debug;
-#ifdef DEBUG_MAGIC
- int magic; /* 301272 */
-#endif
- int l2_protocol, l2_active_protocol;
- int l2_primitive, l2_headersize;
- int data_open;
- int outcallref;
- int impair;
-};
-
-#define PART_SIZE(order,bpps) (( (PAGE_SIZE<<order) -\
- sizeof(void *))/bpps)
-#define BUFFER_SIZE(order,bpps) (PART_SIZE(order,bpps)-\
- sizeof(struct BufHeader))
-
-#endif
-
-void Isdnl2New(void);
-void Isdnl2Free(void);
-void TeiNew(void);
-void TeiFree(void);
-
-
-
-
diff --git a/drivers/net/3c501.c b/drivers/net/3c501.c
index d17ea2c93..77a5e302d 100644
--- a/drivers/net/3c501.c
+++ b/drivers/net/3c501.c
@@ -413,7 +413,7 @@ static int el_start_xmit(struct sk_buff *skb, struct device *dev)
* Avoid timer-based retransmission conflicts.
*/
- if (set_bit(0, (void*)&dev->tbusy) != 0)
+ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
{
restore_flags(flags);
printk("%s: Transmitter access conflict.\n", dev->name);
diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c
index 31a64990a..d8a7b33ce 100644
--- a/drivers/net/3c505.c
+++ b/drivers/net/3c505.c
@@ -412,7 +412,7 @@ static int send_pcb(struct device *dev, pcb_struct * pcb)
return FALSE;
/* Avoid contention */
- if (set_bit(1, &adapter->send_pcb_semaphore)) {
+ if (test_and_set_bit(1, &adapter->send_pcb_semaphore)) {
if (elp_debug >= 3) {
printk("%s: send_pcb entered while threaded\n", dev->name);
}
@@ -545,7 +545,7 @@ static int receive_pcb(struct device *dev, pcb_struct * pcb)
}
if (pcb->command == CMD_RECEIVE_PACKET_COMPLETE) {
- if (set_bit(0, (void *) &adapter->busy)) {
+ if (test_and_set_bit(0, (void *) &adapter->busy)) {
if (backlog_next(adapter->rx_backlog.in) == adapter->rx_backlog.out) {
set_hsf(dev, HSF_PCB_NAK);
printk("%s: PCB rejected, transfer in progress and backlog full\n", dev->name);
@@ -621,7 +621,7 @@ static void receive_packet(struct device *dev, int len)
}
/* if this happens, we die */
- if (set_bit(0, (void *) &adapter->dmaing))
+ if (test_and_set_bit(0, (void *) &adapter->dmaing))
printk("%s: rx blocked, DMA in progress, dir %d\n", dev->name, adapter->current_dma.direction);
skb->dev = dev;
@@ -1031,7 +1031,7 @@ static int send_packet(struct device *dev, struct sk_buff *skb)
*/
unsigned int nlen = (((skb->len < 60) ? 60 : skb->len) + 1) & (~1);
- if (set_bit(0, (void *) &adapter->busy)) {
+ if (test_and_set_bit(0, (void *) &adapter->busy)) {
if (elp_debug >= 2)
printk("%s: transmit blocked\n", dev->name);
return FALSE;
@@ -1054,7 +1054,7 @@ static int send_packet(struct device *dev, struct sk_buff *skb)
return FALSE;
}
/* if this happens, we die */
- if (set_bit(0, (void *) &adapter->dmaing))
+ if (test_and_set_bit(0, (void *) &adapter->dmaing))
printk("%s: tx: DMA %d in progress\n", dev->name, adapter->current_dma.direction);
adapter->current_dma.direction = 1;
@@ -1119,7 +1119,7 @@ static int elp_start_xmit(struct sk_buff *skb, struct device *dev)
if (elp_debug >= 3)
printk("%s: request to send packet of length %d\n", dev->name, (int) skb->len);
- if (set_bit(0, (void *) &dev->tbusy)) {
+ if (test_and_set_bit(0, (void *) &dev->tbusy)) {
printk("%s: transmitter access conflict\n", dev->name);
return 1;
}
diff --git a/drivers/net/3c507.c b/drivers/net/3c507.c
index 00038f96d..c12d6ee98 100644
--- a/drivers/net/3c507.c
+++ b/drivers/net/3c507.c
@@ -479,7 +479,7 @@ static int el16_send_packet(struct sk_buff *skb, struct device *dev)
}
/* Block a timer-based transmit from overlapping. */
- if (set_bit(0, (void*)&dev->tbusy) != 0)
+ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
printk("%s: Transmitter access conflict.\n", dev->name);
else
{
diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c
index d3d941d20..af1be0848 100644
--- a/drivers/net/3c509.c
+++ b/drivers/net/3c509.c
@@ -468,7 +468,7 @@ static int el3_start_xmit(struct sk_buff *skb, struct device *dev)
#endif
#endif
/* Avoid timer-based retransmission conflicts. */
- if (set_bit(0, (void*)&dev->tbusy) != 0)
+ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
printk("%s: Transmitter access conflict.\n", dev->name);
else {
lp->stats.tx_bytes+=skb->len;
diff --git a/drivers/net/3c523.c b/drivers/net/3c523.c
index 63c6240d3..39750860e 100644
--- a/drivers/net/3c523.c
+++ b/drivers/net/3c523.c
@@ -1137,7 +1137,7 @@ elmc_send_packet(struct sk_buff *skb, struct device *dev)
return 0;
}
- if (set_bit(0, (void*)&dev->tbusy) != 0) {
+ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
printk("%s: Transmitter access conflict.\n", dev->name);
} else {
memcpy((char *)p->xmit_cbuffs[p->xmit_count],(char *)(skb->data),skb->len);
diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c
index 69464b4e9..56541f0c2 100644
--- a/drivers/net/3c59x.c
+++ b/drivers/net/3c59x.c
@@ -799,7 +799,7 @@ vortex_start_xmit(struct sk_buff *skb, struct device *dev)
/* Block a timer-based transmit from overlapping. This could better be
done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
If this ever occurs the queue layer is doing something evil! */
- if (set_bit(0, (void*)&dev->tbusy) != 0) {
+ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
printk("%s: Transmitter access conflict.\n", dev->name);
return 1;
}
diff --git a/drivers/net/a2065.c b/drivers/net/a2065.c
index b62102e7a..8de7f28b9 100644
--- a/drivers/net/a2065.c
+++ b/drivers/net/a2065.c
@@ -599,7 +599,7 @@ static int lance_start_xmit (struct sk_buff *skb, struct device *dev)
#ifdef OLD_METHOD
dev->tbusy = 1;
#else
- if (set_bit (0, (void *) &dev->tbusy) != 0) {
+ if (test_and_set_bit (0, (void *) &dev->tbusy) != 0) {
printk ("Transmitter access conflict.\n");
return -1;
}
diff --git a/drivers/net/apricot.c b/drivers/net/apricot.c
index 2a00c4481..cc118f7e3 100644
--- a/drivers/net/apricot.c
+++ b/drivers/net/apricot.c
@@ -616,7 +616,7 @@ i596_start_xmit(struct sk_buff *skb, struct device *dev)
/* Block a timer-based transmit from overlapping. This could better be
done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
- if (set_bit(0, (void*)&dev->tbusy) != 0)
+ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
printk("%s: Transmitter access conflict.\n", dev->name);
else
{
diff --git a/drivers/net/arcnet.c b/drivers/net/arcnet.c
index b25dd02c2..7a8069fd6 100644
--- a/drivers/net/arcnet.c
+++ b/drivers/net/arcnet.c
@@ -1588,7 +1588,7 @@ arcnet_send_packet_bad(struct sk_buff *skb, struct device *dev)
/* Block a timer-based transmit from overlapping. This could better be
done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
- if (set_bit(0, (void*)&dev->tbusy) != 0)
+ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
{
BUGMSG(D_NORMAL,"transmitter called with busy bit set! (status=%Xh, inTX=%d, tickssofar=%ld)\n",
ARCSTATUS,lp->intx,jiffies-dev->trans_start);
diff --git a/drivers/net/ariadne.c b/drivers/net/ariadne.c
index 290b9761e..884398c53 100644
--- a/drivers/net/ariadne.c
+++ b/drivers/net/ariadne.c
@@ -593,12 +593,12 @@ static int ariadne_start_xmit(struct sk_buff *skb, struct device *dev)
/* Block a timer-based transmit from overlapping. This could better be
done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
- if (set_bit(0, (void*)&dev->tbusy) != 0) {
+ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
printk("%s: Transmitter access conflict.\n", dev->name);
return(1);
}
- if (set_bit(0, (void*)&priv->lock) != 0) {
+ if (test_and_set_bit(0, (void*)&priv->lock) != 0) {
if (ariadne_debug > 0)
printk("%s: tx queue lock!.\n", dev->name);
/* don't clear dev->tbusy flag. */
diff --git a/drivers/net/at1700.c b/drivers/net/at1700.c
index bd1f93846..c75274c01 100644
--- a/drivers/net/at1700.c
+++ b/drivers/net/at1700.c
@@ -395,7 +395,7 @@ net_send_packet(struct sk_buff *skb, struct device *dev)
/* Block a timer-based transmit from overlapping. This could better be
done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
- if (set_bit(0, (void*)&dev->tbusy) != 0)
+ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
printk("%s: Transmitter access conflict.\n", dev->name);
else {
short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
diff --git a/drivers/net/atarilance.c b/drivers/net/atarilance.c
index bb08b8927..764416d79 100644
--- a/drivers/net/atarilance.c
+++ b/drivers/net/atarilance.c
@@ -776,12 +776,12 @@ static int lance_start_xmit( struct sk_buff *skb, struct device *dev )
/* Block a timer-based transmit from overlapping. This could better be
done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
- if (set_bit( 0, (void*)&dev->tbusy ) != 0) {
+ if (test_and_set_bit( 0, (void*)&dev->tbusy ) != 0) {
DPRINTK( 0, ( "%s: Transmitter access conflict.\n", dev->name ));
return 1;
}
- if (set_bit( 0, (void*)&lp->lock ) != 0) {
+ if (test_and_set_bit( 0, (void*)&lp->lock ) != 0) {
DPRINTK( 0, ( "%s: tx queue lock!.\n", dev->name ));
/* don't clear dev->tbusy flag. */
return 1;
diff --git a/drivers/net/atp.c b/drivers/net/atp.c
index 411374119..997368ef4 100644
--- a/drivers/net/atp.c
+++ b/drivers/net/atp.c
@@ -437,7 +437,7 @@ net_send_packet(struct sk_buff *skb, struct device *dev)
/* Block a timer-based transmit from overlapping. This could better be
done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
- if (set_bit(0, (void*)&dev->tbusy) != 0)
+ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
printk("%s: Transmitter access conflict.\n", dev->name);
else {
short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c
index 6a38177b6..66852e388 100644
--- a/drivers/net/cs89x0.c
+++ b/drivers/net/cs89x0.c
@@ -752,7 +752,7 @@ net_send_packet(struct sk_buff *skb, struct device *dev)
/* Block a timer-based transmit from overlapping. This could better be
done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
- if (set_bit(0, (void*)&dev->tbusy) != 0)
+ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
printk("%s: Transmitter access conflict.\n", dev->name);
else {
struct net_local *lp = (struct net_local *)dev->priv;
diff --git a/drivers/net/de4x5.c b/drivers/net/de4x5.c
index aae249ed0..a199c7f8a 100644
--- a/drivers/net/de4x5.c
+++ b/drivers/net/de4x5.c
@@ -3,8 +3,30 @@
Copyright 1994, 1995 Digital Equipment Corporation.
- This software may be used and distributed according to the terms of
- the GNU Public License, incorporated herein by reference.
+ Testing resources for this driver have been made available
+ in part by NASA Ames Research Center (mjacob@nas.nasa.gov).
+
+ The author may be reached at davies@maniac.ultranet.com.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ 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.
Originally, this driver was written for the Digital Equipment
Corporation series of EtherWORKS ethernet cards:
@@ -15,8 +37,8 @@
DE450 TP/COAX/AUI PCI
DE500 10/100 PCI Fasternet
- but it will now attempt to support all cards which conform to the
- Digital Semiconductor SROM Specification. The driver currently
+ but it will now attempt to support all cards which conform to the
+ Digital Semiconductor SROM Specification. The driver currently
recognises the following chips:
DC21040 (no SROM)
@@ -32,6 +54,7 @@
SMC8432
SMC9332 (w/new SROM)
ZNYX31[45]
+ ZNYX346 10/100 4 port (can act as a 10/100 bridge!)
The driver has been tested on a relatively busy network using the DE425,
DE434, DE435 and DE500 cards and benchmarked with 'ttcp': it transferred
@@ -48,13 +71,11 @@
measurement. Their error is +/-20k on a quiet (private) network and also
depend on what load the CPU has.
- The author may be reached at davies@maniac.ultranet.com.
-
=========================================================================
- This driver has been written substantially from scratch, although its
+ This driver has been written substantially from scratch, although its
inheritance of style and stack interface from 'ewrk3.c' and in turn from
Donald Becker's 'lance.c' should be obvious. With the module autoload of
- every usable DECchip board, I pinched Donald's 'next_module' field to
+ every usable DECchip board, I pinched Donald's 'next_module' field to
link my modules together.
Upto 15 EISA cards can be supported under this driver, limited primarily
@@ -80,7 +101,7 @@
1) copy de4x5.c from the /linux/drivers/net directory to your favourite
temporary directory.
2) for fixed autoprobes (not recommended), edit the source code near
- line 4927 to reflect the I/O address you're using, or assign these when
+ line 5005 to reflect the I/O address you're using, or assign these when
loading by:
insmod de4x5 io=0xghh where g = bus number
@@ -113,7 +134,7 @@
By default, the driver will now autodetect any DECchip based card.
Should you have a need to restrict the driver to DIGITAL only cards, you
can compile with a DEC_ONLY define, or if loading as a module, use the
- 'dec_only=1' parameter.
+ 'dec_only=1' parameter.
I've changed the timing routines to use the kernel timer and scheduling
functions so that the hangs and other assorted problems that occurred
@@ -145,6 +166,19 @@
(quad 21041 MAC) cards also appear to work despite their incorrectly
wired IRQs.
+ I have added a temporary fix for interrupt problems when some SCSI cards
+ share the same interrupt as the DECchip based cards. The problem occurs
+ because the SCSI card wants to grab the interrupt as a fast interrupt
+ (runs the service routine with interrupts turned off) vs. this card
+ which really needs to run the service routine with interrupts turned on.
+ This driver will now add the interrupt service routine as a fast
+ interrupt if it is bounced from the slow interrupt. THIS IS NOT A
+ RECOMMENDED WAY TO RUN THE DRIVER and has been done for a limited time
+ until people sort out their compatibility issues and the kernel
+ interrupt service code is fixed. YOU SHOULD SEPARATE OUT THE FAST
+ INTERRUPT CARDS FROM THE SLOW INTERRUPT CARDS to ensure that they do not
+ run on the same interrupt. PCMCIA/CardBus is another can of worms...
+
TO DO:
------
@@ -234,7 +268,7 @@
0.442 9-Sep-96 Include AUI in dc21041 media printout. Bug reported
by <bhat@mundook.cs.mu.OZ.AU>
0.45 8-Dec-96 Include endian functions for PPC use, from work
- by <cort@cs.nmt.edu>.
+ by <cort@cs.nmt.edu> and <g.thomas@opengroup.org>.
0.451 28-Dec-96 Added fix to allow autoprobe for modules after
suggestion from <mjacob@feral.com>.
0.5 30-Jan-97 Added SROM decoding functions.
@@ -247,11 +281,30 @@
Added attempt to use an SMC9332 with broken SROM.
Added fix for ZYNX multi-mac cards that didn't
get their IRQs wired correctly.
+ 0.51 13-Feb-97 Added endian fixes for the SROM accesses from
+ <paubert@iram.es>
+ Fix init_connection() to remove extra device reset.
+ Fix MAC/PHY reset ordering in dc21140m_autoconf().
+ Fix initialisation problem with lp->timeout in
+ typeX_infoblock() from <paubert@iram.es>.
+ Fix MII PHY reset problem from work done by
+ <paubert@iram.es>.
+ 0.52 26-Apr-97 Some changes may not credit the right people -
+ a disk crash meant I lost some mail.
+ Change RX interrupt routine to drop rather than
+ defer packets to avoid hang reported by
+ <g.thomas@opengroup.org>.
+ Fix srom_exec() to return for COMPACT and type 1
+ infoblocks.
+ Added DC21142 and DC21143 functions.
+ Added byte counters from <phil@tazenda.demon.co.uk>
+ Added SA_INTERRUPT temporary fix from
+ <mjacob@feral.com>.
=========================================================================
*/
-static const char *version = "de4x5.c:V0.5 97/1/30 davies@maniac.ultranet.com\n";
+static const char *version = "de4x5.c:V0.52 1997/4/26 davies@maniac.ultranet.com\n";
#include <linux/module.h>
@@ -270,8 +323,8 @@ static const char *version = "de4x5.c:V0.5 97/1/30 davies@maniac.ultranet.com\n"
#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/dma.h>
-#include <asm/uaccess.h>
#include <asm/byteorder.h>
+#include <asm/unaligned.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
@@ -286,14 +339,37 @@ static const char *version = "de4x5.c:V0.5 97/1/30 davies@maniac.ultranet.com\n"
#define c_char const char
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < ((2 << 16) | (1 << 8))
+#define net_device_stats enet_statistics
+#define copy_to_user(a,b,c) memcpy_tofs(a,b,c)
+#define copy_from_user(a,b,c) memcpy_fromfs(a,b,c)
+#define le16_to_cpu(a) cpu_to_le16(a)
+#define le32_to_cpu(a) cpu_to_le32(a)
+#ifdef __powerpc__
+#define cpu_to_le16(a) ((((a) & 0x00ffU) << 8) | (((a) & 0xff00U) >> 8))
+#define cpu_to_le32(a) ((((a) & 0x000000ffU) << 24) |\
+ (((a) & 0x0000ff00U) << 8) |\
+ (((a) & 0x00ff0000U) >> 8) |\
+ (((a) & 0xff000000U) >> 24))
+#else
+#define cpu_to_le16(a) (a)
+#define cpu_to_le32(a) (a)
+#endif /* __powerpc__ */
+#include <asm/segment.h>
+#else
+#include <asm/uaccess.h>
+#endif /* LINUX_VERSION_CODE */
+#define TWIDDLE(a) (u_short)le16_to_cpu(get_unaligned((u_short *)(a)))
+
/*
** MII Information
*/
struct phy_table {
- int reset; /* Hard reset required? */
- int id; /* IEEE OUI */
+ int reset; /* Hard reset required? */
+ int id; /* IEEE OUI */
int ta; /* One cycle TA time - 802.3u is confusing here */
- struct { /* Non autonegotiation (parallel) speed det. */
+ struct { /* Non autonegotiation (parallel) speed det. */
int reg;
int mask;
int value;
@@ -301,25 +377,35 @@ struct phy_table {
};
struct mii_phy {
- int reset; /* Hard reset required? */
- int id; /* IEEE OUI */
- int ta; /* One cycle TA time */
+ int reset; /* Hard reset required? */
+ int id; /* IEEE OUI */
+ int ta; /* One cycle TA time */
struct { /* Non autonegotiation (parallel) speed det. */
int reg;
int mask;
int value;
} spd;
- int addr; /* MII address for the PHY */
- u_char *gep; /* Start of GEP sequence block in SROM */
- u_char *rst; /* Start of reset sequence in SROM */
- u_int mc; /* Media Capabilities */
- u_int ana; /* NWay Advertisement */
- u_int fdx; /* Full DupleX capabilites for each media */
- u_int ttm; /* Transmit Threshold Mode for each media */
+ int addr; /* MII address for the PHY */
+ u_char *gep; /* Start of GEP sequence block in SROM */
+ u_char *rst; /* Start of reset sequence in SROM */
+ u_int mc; /* Media Capabilities */
+ u_int ana; /* NWay Advertisement */
+ u_int fdx; /* Full DupleX capabilites for each media */
+ u_int ttm; /* Transmit Threshold Mode for each media */
};
#define DE4X5_MAX_PHY 8 /* Allow upto 8 attached PHY devices per board */
+struct sia_phy {
+ u_char mc; /* Media Code */
+ u_char ext; /* csr13-15 valid when set */
+ int csr13; /* SIA Connectivity Register */
+ int csr14; /* SIA TX/RX Register */
+ int csr15; /* SIA General Register */
+ int gepc; /* SIA GEP Control Information */
+ int gep; /* SIA GEP Data */
+};
+
/*
** Define the know universe of PHY devices that can be
** recognised by this driver
@@ -327,8 +413,8 @@ struct mii_phy {
static struct phy_table phy_info[] = {
{0, NATIONAL_TX, 1, {0x19, 0x40, 0x00}}, /* National TX */
{1, BROADCOM_T4, 1, {0x10, 0x02, 0x02}}, /* Broadcom T4 */
- {0, SEEQ_T4 , 1, {0x12, 0x10, 0x10}}, /* SEEQ T4 */
- {0, CYPRESS_T4 , 1, {0x05, 0x20, 0x20}} /* Cypress T4 */
+ {0, SEEQ_T4 , 1, {0x12, 0x10, 0x10}}, /* SEEQ T4 */
+ {0, CYPRESS_T4 , 1, {0x05, 0x20, 0x20}} /* Cypress T4 */
};
/*
@@ -354,7 +440,6 @@ static c_char srom_repair_info[][100] = {
0x00,0x18,}
};
-#undef DE4X5_VERBOSE /* define to get more verbose startup messages */
#ifdef DE4X5_DEBUG
static int de4x5_debug = DE4X5_DEBUG;
@@ -581,6 +666,7 @@ struct de4x5_private {
int setup_f; /* Setup frame filtering type */
int local_state; /* State within a 'media' state */
struct mii_phy phy[DE4X5_MAX_PHY]; /* List of attached PHY devices */
+ struct sia_phy sia; /* SIA PHY Information */
int active; /* Index to active PHY device */
int mii_cnt; /* Number of attached PHY's */
int timeout; /* Scheduling counter */
@@ -770,9 +856,6 @@ static void timeout(struct device *dev, void (*fn)(u_long data), u_long data,
static void yawn(struct device *dev, int state);
static int de4x5_dev_index(char *s);
static void link_modules(struct device *dev, struct device *tmp);
-#ifdef MODULE
-static struct device *unlink_modules(struct device *p);
-#endif
static void de4x5_dbg_open(struct device *dev);
static void de4x5_dbg_mii(struct device *dev, int k);
static void de4x5_dbg_media(struct device *dev);
@@ -794,6 +877,7 @@ static int compact_infoblock(struct device *dev, u_char count, u_char *p);
#ifdef MODULE
int init_module(void);
void cleanup_module(void);
+static struct device *unlink_modules(struct device *p);
static int autoprobed = 0, loading_module = 1;
# else
static int autoprobed = 0, loading_module = 0;
@@ -898,7 +982,7 @@ de4x5_hw_init(struct device *dev, u_long iobase))
PCI_CFDA_PSM, WAKEUP);
}
de4x5_ms_delay(10);
-
+
RESET_DE4X5;
if ((inl(DE4X5_STS) & (STS_TS | STS_RS)) != 0) {
@@ -964,6 +1048,9 @@ de4x5_hw_init(struct device *dev, u_long iobase))
lp->chipset = bus.chipset;
lp->cache.priv = tmp;
lp->cache.gepc = GEP_INIT;
+ lp->asBit = GEP_SLNK;
+ lp->asPolarity = GEP_SLNK;
+ lp->asBitValid = TRUE;
lp->timeout = -1;
lp->useSROM = useSROM;
memcpy((char *)&lp->srom,(char *)&bus.srom,sizeof(struct de4x5_srom));
@@ -1071,11 +1158,6 @@ de4x5_hw_init(struct device *dev, u_long iobase))
printk(" and requires IRQ%d (provided by %s).\n", dev->irq,
((lp->bus == PCI) ? "PCI BIOS" : "EISA CNFG"));
-
-#ifdef DE4X5_VERBOSE
- printk("%s: INFOLEAF_SIZE: %ld, COMPACT: %ld\n", dev->name,
- INFOLEAF_SIZE, COMPACT);
-#endif
}
if (de4x5_debug & DEBUG_VERSION) {
@@ -1133,18 +1215,29 @@ de4x5_open(struct device *dev)
if (request_irq(dev->irq, (void *)de4x5_interrupt, SA_SHIRQ,
lp->adapter_name, dev)) {
- printk("de4x5_open(): Requested IRQ%d is busy\n",dev->irq);
- status = -EAGAIN;
- } else {
- dev->tbusy = 0;
- dev->start = 1;
- dev->interrupt = UNMASK_INTERRUPTS;
- dev->trans_start = jiffies;
-
- START_DE4X5;
-
- de4x5_setup_intr(dev);
+ printk("de4x5_open(): Requested IRQ%d is busy - attemping FAST/SHARE...", dev->irq);
+ if (request_irq(dev->irq, de4x5_interrupt, SA_INTERRUPT | SA_SHIRQ,
+ lp->adapter_name, dev)) {
+ printk("\n Cannot get IRQ- reconfigure your hardware.\n");
+ disable_ast(dev);
+ de4x5_free_rx_buffs(dev);
+ de4x5_free_tx_buffs(dev);
+ yawn(dev, SLEEP);
+ lp->state = CLOSED;
+ return -EAGAIN;
+ } else {
+ printk("\n Succeeded, but you should reconfigure your hardware to avoid this.\n");
+ printk("WARNING: there may be IRQ related problems in heavily loaded systems.\n");
+ }
}
+ dev->tbusy = 0;
+ dev->start = 1;
+ dev->interrupt = UNMASK_INTERRUPTS;
+ dev->trans_start = jiffies;
+
+ START_DE4X5;
+
+ de4x5_setup_intr(dev);
if (de4x5_debug & DEBUG_OPEN) {
printk("\tsts: 0x%08x\n", inl(DE4X5_STS));
@@ -1287,7 +1380,7 @@ de4x5_queue_pkt(struct sk_buff *skb, struct device *dev)
sti();
/* Test if cache is already locked - requeue skb if so */
- if (set_bit(0, (void *)&lp->cache.lock) && !dev->interrupt) return -1;
+ if (test_and_set_bit(0, (void *)&lp->cache.lock) && !dev->interrupt) return -1;
/* Transmit descriptor ring full or stale skb */
if (dev->tbusy || lp->tx_skb[lp->tx_new]) {
@@ -1300,9 +1393,6 @@ de4x5_queue_pkt(struct sk_buff *skb, struct device *dev)
printk("%s: transmit busy, lost media or stale skb found:\n STS:%08x\n tbusy:%ld\n IMR:%08x\n OMR:%08x\n Stale skb: %s\n",dev->name, inl(DE4X5_STS), dev->tbusy, inl(DE4X5_IMR), inl(DE4X5_OMR), (lp->tx_skb[lp->tx_new] ? "YES" : "NO"));
}
} else if (skb->len > 0) {
- /* Update the byte counter */
- lp->stats.tx_bytes += skb->len;
-
/* If we already have stuff queued locally, use that first */
if (lp->cache.skb && !dev->interrupt) {
de4x5_put_cache(dev, skb);
@@ -1313,6 +1403,9 @@ de4x5_queue_pkt(struct sk_buff *skb, struct device *dev)
cli();
set_bit(0, (void*)&dev->tbusy);
load_packet(dev, skb->data, TD_IC | TD_LS | TD_FS | skb->len, skb);
+#if LINUX_VERSION_CODE >= ((2 << 16) | (1 << 8))
+ lp->stats.tx_bytes += skb->len;
+#endif
outl(POLL_DEMAND, DE4X5_TPD);/* Start the TX */
lp->tx_new = (++lp->tx_new) % lp->txRingSize;
@@ -1326,7 +1419,7 @@ de4x5_queue_pkt(struct sk_buff *skb, struct device *dev)
}
if (skb) de4x5_putb_cache(dev, skb);
}
-
+
lp->cache.lock = 0;
return status;
@@ -1360,9 +1453,11 @@ de4x5_interrupt(int irq, void *dev_id, struct pt_regs *regs)
if (dev->interrupt)
printk("%s: Re-entering the interrupt handler.\n", dev->name);
-
+
DISABLE_IRQs; /* Ensure non re-entrancy */
+#if LINUX_VERSION_CODE >= ((2 << 16) | (1 << 8))
synchronize_irq();
+#endif
dev->interrupt = MASK_INTERRUPTS;
for (limit=0; limit<8; limit++) {
@@ -1394,8 +1489,8 @@ de4x5_interrupt(int irq, void *dev_id, struct pt_regs *regs)
}
/* Load the TX ring with any locally stored packets */
- if (!set_bit(0, (void *)&lp->cache.lock)) {
- if (lp->cache.skb && !dev->tbusy && lp->tx_enable) {
+ if (!test_and_set_bit(0, (void *)&lp->cache.lock)) {
+ while (lp->cache.skb && !dev->tbusy && lp->tx_enable) {
de4x5_queue_pkt(de4x5_get_cache(dev), dev);
}
lp->cache.lock = 0;
@@ -1450,19 +1545,21 @@ de4x5_rx(struct device *dev)
if ((skb = de4x5_alloc_rx_buff(dev, entry, pkt_len)) == NULL) {
printk("%s: Insufficient memory; nuking packet.\n",
dev->name);
- lp->stats.rx_dropped++; /* Really, deferred. */
- break;
- }
- de4x5_dbg_rx(skb, pkt_len);
+ lp->stats.rx_dropped++;
+ } else {
+ de4x5_dbg_rx(skb, pkt_len);
- /* Push up the protocol stack */
- skb->protocol=eth_type_trans(skb,dev);
- netif_rx(skb);
+ /* Push up the protocol stack */
+ skb->protocol=eth_type_trans(skb,dev);
+ netif_rx(skb);
- /* Update stats */
- lp->stats.rx_packets++;
- lp->stats.rx_bytes += pkt_len;
- de4x5_local_stats(dev, skb->data, pkt_len);
+ /* Update stats */
+ lp->stats.rx_packets++;
+#if LINUX_VERSION_CODE >= ((2 << 16) | (1 << 8))
+ lp->stats.rx_bytes += pkt_len;
+#endif
+ de4x5_local_stats(dev, skb->data, pkt_len);
+ }
}
/* Change buffer ownership for this frame, back to the adapter */
@@ -1575,10 +1672,7 @@ de4x5_txur(struct device *dev)
if ((omr & OMR_TR) < OMR_TR) {
omr += 0x4000;
} else {
- if (omr & OMR_TTM)
- omr &= ~OMR_TTM;
- else
- omr |= OMR_SF;
+ omr |= OMR_SF;
}
outl(omr | OMR_ST | OMR_SR, DE4X5_OMR);
}
@@ -1645,7 +1739,8 @@ de4x5_close(struct device *dev)
return 0;
}
-static struct net_device_stats *de4x5_get_stats(struct device *dev)
+static struct net_device_stats *
+de4x5_get_stats(struct device *dev)
{
struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
u_long iobase = dev->base_addr;
@@ -1880,7 +1975,7 @@ pci_probe(struct device *dev, u_long ioaddr))
{
u_char irq;
u_char pb, pbus, dev_num, dnum, dev_fn;
- u_short vendor, index, status;
+ u_short dev_id, vendor, index, status;
u_int class = DE4X5_CLASS_CODE;
u_int device, iobase;
struct bus_type *lp = &bus;
@@ -1908,7 +2003,8 @@ pci_probe(struct device *dev, u_long ioaddr))
if ((!pbus && !dnum) || ((pbus == pb) && (dnum == dev_num))) {
device = 0;
pcibios_read_config_word(pb, PCI_DEVICE, PCI_VENDOR_ID, &vendor);
- pcibios_read_config_word(pb, PCI_DEVICE, PCI_DEVICE_ID, (u_short *)&device);
+ pcibios_read_config_word(pb, PCI_DEVICE, PCI_DEVICE_ID, &dev_id);
+ device = dev_id;
device <<= 8;
if (!(is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x)) {
continue;
@@ -2091,31 +2187,6 @@ link_modules(struct device *dev, struct device *tmp))
return;
}
-#ifdef MODULE
-static struct device *
-unlink_modules(struct device *p)
-{
- struct device *next = NULL;
-
- if (p->priv) { /* Private areas allocated? */
- struct de4x5_private *lp = (struct de4x5_private *)p->priv;
-
- next = lp->next_module;
- if (lp->cache.buf) { /* MAC buffers allocated? */
- kfree(lp->cache.buf); /* Free the MAC buffers */
- }
- kfree(lp->cache.priv); /* Free the private area */
- release_region(p->base_addr, (lp->bus == PCI ?
- DE4X5_PCI_TOTAL_SIZE :
- DE4X5_EISA_TOTAL_SIZE));
- }
- unregister_netdev(p);
- kfree(p); /* Free the device structure */
-
- return next;
-}
-#endif
-
/*
** Auto configure the media here rather than setting the port at compile
** time. This routine is called by de4x5_init() and when a loss of media is
@@ -2300,6 +2371,7 @@ de4x5_suspect_state(struct device *dev, int timeout, int prev_state,
lp->media = prev_state;
} else {
lp->media = INIT;
+ lp->tcount++;
}
}
@@ -2527,16 +2599,22 @@ dc21140m_autoconf(struct device *dev)
switch(lp->media) {
case INIT:
- DISABLE_IRQs;
- lp->tx_enable = FALSE;
- lp->linkOK = 0;
-/* lp->timeout = -1;*/
+ if (lp->timeout < 0) {
+ DISABLE_IRQs;
+ lp->tx_enable = FALSE;
+ lp->linkOK = 0;
+ de4x5_save_skbs(dev); /* Save non transmitted skb's */
+ }
if ((next_tick = de4x5_reset_phy(dev)) < 0) {
next_tick &= ~TIMER_CB;
} else {
- de4x5_save_skbs(dev); /* Save non transmitted skb's */
if (lp->useSROM) {
srom_map_media(dev);
+ srom_exec(dev, lp->phy[lp->active].gep);
+ if (lp->infoblock_media == ANS) {
+ ana = lp->phy[lp->active].ana | MII_ANA_CSMA;
+ mii_wr(ana, MII_ANA, lp->phy[lp->active].addr, DE4X5_MII);
+ }
} else {
lp->tmp = MII_SR_ASSC; /* Fake out the MII speed set */
SET_10Mb;
@@ -2752,9 +2830,9 @@ de4x5_init_connection(struct device *dev)
de4x5_dbg_media(dev);
lp->c_media = lp->media; /* Stop scrolling media messages */
}
- de4x5_restore_skbs(dev);
+
cli();
- de4x5_rx(dev);
+ de4x5_restore_skbs(dev);
de4x5_setup_intr(dev);
lp->tx_enable = YES;
dev->tbusy = 0;
@@ -2766,7 +2844,9 @@ de4x5_init_connection(struct device *dev)
}
/*
-** General PHY reset function.
+** General PHY reset function. Some MII devices don't reset correctly
+** since their MII address pins can float at voltages that are dependent
+** on the signal pin use. Do a double reset to ensure a reset.
*/
static int
de4x5_reset_phy(struct device *dev)
@@ -2780,8 +2860,10 @@ de4x5_reset_phy(struct device *dev)
if (lp->useSROM) {
if (lp->phy[lp->active].rst) { /* MII device specific reset */
srom_exec(dev, lp->phy[lp->active].rst);
+ srom_exec(dev, lp->phy[lp->active].rst);
} else if (lp->rst) { /* Type 5 infoblock reset */
srom_exec(dev, lp->rst);
+ srom_exec(dev, lp->rst);
}
} else {
PHY_HARD_RESET;
@@ -3151,13 +3233,26 @@ de4x5_restore_skbs(struct device *dev)
{
struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
u_long iobase = dev->base_addr;
+ int i;
s32 omr;
if (lp->cache.save_cnt) {
STOP_DE4X5;
- de4x5_cache_state(dev, DE4X5_SAVE_STATE);
- de4x5_sw_reset(dev);
- de4x5_cache_state(dev, DE4X5_RESTORE_STATE);
+ outl(virt_to_bus(lp->rx_ring), DE4X5_RRBA);
+ outl(virt_to_bus(lp->tx_ring), DE4X5_TRBA);
+
+ lp->rx_new = lp->rx_old = 0;
+ lp->tx_new = lp->tx_old = 0;
+
+ for (i = 0; i < lp->rxRingSize; i++) {
+ lp->rx_ring[i].status = cpu_to_le32(R_OWN);
+ }
+
+ for (i = 0; i < lp->txRingSize; i++) {
+ lp->tx_ring[i].status = cpu_to_le32(0);
+ }
+
+ barrier();
lp->cache.save_cnt--;
START_DE4X5;
}
@@ -3446,9 +3541,10 @@ DevicePresent(u_long aprom_addr)
if (lp->chipset == DC21040) {
outl(0, aprom_addr); /* Reset Ethernet Address ROM Pointer */
} else { /* Read new srom */
- short *p = (short *)&lp->srom;
+ u_short tmp, *p = (short *)&lp->srom;
for (i=0; i<(sizeof(struct de4x5_srom)>>1); i++) {
- *p++ = srom_rd(aprom_addr, i);
+ tmp = srom_rd(aprom_addr, i);
+ *p++ = le16_to_cpu(tmp);
}
de4x5_dbg_srom((struct de4x5_srom *)&lp->srom);
}
@@ -3756,7 +3852,7 @@ srom_infoleaf_info(struct device *dev)
}
}
- lp->infoleaf_offset = (u_short)*((u_short *)(p+1));
+ lp->infoleaf_offset = TWIDDLE(p+1);
return 0;
}
@@ -3776,14 +3872,10 @@ srom_init(struct device *dev)
u_char *p = (u_char *)&lp->srom + lp->infoleaf_offset;
u_char count;
+ p+=2;
if (lp->chipset == DC21140) {
- p+=2;
lp->cache.gepc = (*p++ | GEP_CTRL);
outl(lp->cache.gepc, DE4X5_GEP);
- } else if (lp->chipset == DC21142) {
- p+=2;
- } else if (lp->chipset == DC21143) {
- p+=2;
}
/* Block count */
@@ -3815,7 +3907,7 @@ srom_exec(struct device *dev, u_char *p)
{
struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
u_long iobase = dev->base_addr;
- u_char count = *p++;
+ u_char count = (p ? *p++ : 0);
while (count--) {
if (lp->chipset == DC21140) {
@@ -3910,7 +4002,7 @@ compact_infoblock(struct device *dev, u_char count, u_char *p)
}
}
- if (lp->media == INIT) {
+ if ((lp->media == INIT) && (lp->timeout < 0)) {
outl(lp->cache.gepc, DE4X5_GEP);
lp->infoblock_media = (*p++) & COMPACT_MC;
lp->cache.gep = *p++;
@@ -3949,7 +4041,7 @@ type0_infoblock(struct device *dev, u_char count, u_char *p)
}
}
- if (lp->media == INIT) {
+ if ((lp->media == INIT) && (lp->timeout < 0)) {
outl(lp->cache.gepc, DE4X5_GEP);
p+=2;
lp->infoblock_media = (*p++) & BLOCK0_MC;
@@ -3976,9 +4068,7 @@ static int
type1_infoblock(struct device *dev, u_char count, u_char *p)
{
struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
- u_long iobase = dev->base_addr;
u_char len = (*p & BLOCK_LEN)+1;
- int ana;
/* Recursively figure out the info blocks */
if (--count > lp->tcount) {
@@ -3989,22 +4079,20 @@ type1_infoblock(struct device *dev, u_char count, u_char *p)
}
}
+ p += 2;
if (lp->state == INITIALISED) {
- lp->ibn = 1; p += 2;
+ lp->ibn = 1;
lp->active = *p++;
lp->phy[lp->active].gep = (*p ? p : 0); p += (*p + 1);
lp->phy[lp->active].rst = (*p ? p : 0); p += (*p + 1);
- lp->phy[lp->active].mc = *(u_short *)p; p += 2;
- lp->phy[lp->active].ana = *(u_short *)p; p += 2;
- lp->phy[lp->active].fdx = *(u_short *)p; p += 2;
- lp->phy[lp->active].ttm = *(u_short *)p;
+ lp->phy[lp->active].mc = TWIDDLE(p); p += 2;
+ lp->phy[lp->active].ana = TWIDDLE(p); p += 2;
+ lp->phy[lp->active].fdx = TWIDDLE(p); p += 2;
+ lp->phy[lp->active].ttm = TWIDDLE(p);
return 0;
- } else if (lp->media == INIT) {
- if (lp->phy[lp->active].gep) {
- srom_exec(dev, lp->phy[lp->active].gep);
- }
- ana = lp->phy[lp->active].ana | MII_ANA_CSMA;
- mii_wr(ana, MII_ANA, lp->phy[lp->active].addr, DE4X5_MII);
+ } else if ((lp->media == INIT) && (lp->timeout < 0)) {
+ lp->ibn = 1;
+ lp->active = *p;
lp->infoblock_csr6 = OMR_PS | OMR_HBD;
lp->useMII = TRUE;
lp->infoblock_media = ANS;
@@ -4040,10 +4128,10 @@ type3_infoblock(struct device *dev, u_char count, u_char *p)
lp->active = *p++;
lp->phy[lp->active].gep = (*p ? p : 0); p += (*p + 1);
lp->phy[lp->active].rst = (*p ? p : 0); p += (*p + 1);
- lp->phy[lp->active].mc = *(u_short *)p; p += 2;
- lp->phy[lp->active].ana = *(u_short *)p; p += 2;
- lp->phy[lp->active].fdx = *(u_short *)p; p += 2;
- lp->phy[lp->active].ttm = *(u_short *)p;
+ lp->phy[lp->active].mc = TWIDDLE(p); p += 2;
+ lp->phy[lp->active].ana = TWIDDLE(p); p += 2;
+ lp->phy[lp->active].fdx = TWIDDLE(p); p += 2;
+ lp->phy[lp->active].ttm = TWIDDLE(p);
return 0;
} else if (lp->media == INIT) {
p+=2;
@@ -4672,18 +4760,12 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
u_long iobase = dev->base_addr;
int i, j, status = 0;
s32 omr;
- struct {
- u8 *addr;
- u16 *sval;
- u32 *lval;
+ union {
+ u8 addr[144];
+ u16 sval[72];
+ u32 lval[36];
} tmp;
-
- tmp.addr = tmp.sval = tmp.lval = kmalloc(HASH_TABLE_LEN * ETH_ALEN, GFP_KERNEL);
- if (!tmp.addr){
- printk("%s ioctl: memory squeeze.\n", dev->name);
- return -ENOMEM;
- }
-
+
switch(ioc->cmd) {
case DE4X5_GET_HWADDR: /* Get the hardware address */
ioc->len = ETH_ALEN;
@@ -4710,7 +4792,7 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
}
build_setup_frame(dev, PHYS_ADDR_ONLY);
/* Set up the descriptor and give ownership to the card */
- while (set_bit(0, (void *)&dev->tbusy) != 0);/* Wait for lock to free*/
+ while (test_and_set_bit(0, (void *)&dev->tbusy) != 0);/* Wait for lock to free*/
load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET |
SETUP_FRAME_LEN, NULL);
lp->tx_new = (++lp->tx_new) % lp->txRingSize;
@@ -4743,39 +4825,12 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
break;
case DE4X5_GET_MCA: /* Get the multicast address table */
- ioc->len = (HASH_TABLE_LEN >> 3);
- status = verify_area(VERIFY_WRITE, ioc->data, ioc->len);
- if (!status) {
- copy_to_user(ioc->data, lp->setup_frame, ioc->len);
- }
-
break;
case DE4X5_SET_MCA: /* Set a multicast address */
- if (suser()) {
- /******* FIX ME! ********/
- if (ioc->len != HASH_TABLE_LEN) { /* MCA changes */
- if (!(status = verify_area(VERIFY_READ, (void *)ioc->data, ETH_ALEN * ioc->len))) {
- copy_from_user(tmp.addr, ioc->data, ETH_ALEN * ioc->len);
- set_multicast_list(dev);
- }
- } else {
- set_multicast_list(dev);
- }
- } else {
- status = -EPERM;
- }
-
break;
case DE4X5_CLR_MCA: /* Clear all multicast addresses */
- if (suser()) {
- /******* FIX ME! ********/
- set_multicast_list(dev);
- } else {
- status = -EPERM;
- }
-
break;
- case DE4X5_MCA_EN: /* Enable pass all multicast addressing */
+ case DE4X5_MCA_EN: /* Enable pass all multicast addresses*/
if (suser()) {
omr = inl(DE4X5_OMR);
omr |= OMR_PM;
@@ -4840,7 +4895,8 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
}
break;
-#define DE4X5_DUMP 0x0f /* Dump the DE4X5 Status */
+/*
+#define DE4X5_DUMP 0x0f / * Dump the DE4X5 Status * /
case DE4X5_DUMP:
j = 0;
@@ -4931,12 +4987,11 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
}
break;
+*/
default:
status = -EOPNOTSUPP;
}
-
- kfree(tmp.addr);
-
+
return status;
}
@@ -4975,6 +5030,30 @@ cleanup_module(void)
return;
}
+
+static struct device *
+unlink_modules(struct device *p)
+{
+ struct device *next = NULL;
+
+ if (p->priv) { /* Private areas allocated? */
+ struct de4x5_private *lp = (struct de4x5_private *)p->priv;
+
+ next = lp->next_module;
+ if (lp->cache.buf) { /* MAC buffers allocated? */
+ kfree(lp->cache.buf); /* Free the MAC buffers */
+ }
+ kfree(lp->cache.priv); /* Free the private area */
+ release_region(p->base_addr, (lp->bus == PCI ?
+ DE4X5_PCI_TOTAL_SIZE :
+ DE4X5_EISA_TOTAL_SIZE));
+ }
+ unregister_netdev(p);
+ kfree(p); /* Free the device structure */
+
+ return next;
+}
+
#endif /* MODULE */
diff --git a/drivers/net/de4x5.h b/drivers/net/de4x5.h
index bda97578c..525e0122d 100644
--- a/drivers/net/de4x5.h
+++ b/drivers/net/de4x5.h
@@ -139,7 +139,7 @@
#define CFCS_DST 0x06000000 /* DEVSEL Timing (S) */
#define CFCS_DPR 0x01000000 /* Data Parity Report (S) */
#define CFCS_FBB 0x00800000 /* Fast Back-To-Back (S) */
-#define CFCS_SLE 0x00000100 /* System Error Enable (C) */
+#define CFCS_SEE 0x00000100 /* System Error Enable (C) */
#define CFCS_PER 0x00000040 /* Parity Error Response (C) */
#define CFCS_MO 0x00000004 /* Master Operation (C) */
#define CFCS_MSA 0x00000002 /* Memory Space Access (C) */
@@ -150,8 +150,8 @@
*/
#define CFRV_BC 0xff000000 /* Base Class */
#define CFRV_SC 0x00ff0000 /* Subclass */
-#define CFRV_SN 0x000000f0 /* Step Number */
-#define CFRV_RN 0x0000000f /* Revision Number */
+#define CFRV_RN 0x000000f0 /* Revision Number */
+#define CFRV_SN 0x0000000f /* Step Number */
#define BASE_CLASS 0x02000000 /* Indicates Network Controller */
#define SUB_CLASS 0x00000000 /* Indicates Ethernet Controller */
#define STEP_NUMBER 0x00000020 /* Increments for future chips */
@@ -170,12 +170,33 @@
#define CBIO_IOSI 0x00000001 /* I/O Space Indicator (RO, value is 1) */
/*
+** PCI Configuration Card Information Structure Register (PCI_CCIS)
+*/
+#define CCIS_ROMI 0xf0000000 /* ROM Image */
+#define CCIS_ASO 0x0ffffff8 /* Address Space Offset */
+#define CCIS_ASI 0x00000007 /* Address Space Indicator */
+
+/*
+** PCI Configuration Subsystem ID Register (PCI_SSID)
+*/
+#define SSID_SSID 0xffff0000 /* Subsystem ID */
+#define SSID_SVID 0x0000ffff /* Subsystem Vendor ID */
+
+/*
** PCI Configuration Expansion ROM Base Address Register (PCI_CBER)
*/
#define CBER_MASK 0xfffffc00 /* Expansion ROM Base Address Mask */
#define CBER_ROME 0x00000001 /* ROM Enable */
/*
+** PCI Configuration Interrupt Register (PCI_CFIT)
+*/
+#define CFIT_MXLT 0xff000000 /* MAX_LAT Value (0.25us periods) */
+#define CFIT_MNGT 0x00ff0000 /* MIN_GNT Value (0.25us periods) */
+#define CFIT_IRQP 0x0000ff00 /* Interrupt Pin */
+#define CFIT_IRQL 0x000000ff /* Interrupt Line */
+
+/*
** PCI Configuration Power Management Area Register (PCI_CFPM)
*/
#define SLEEP 0x80 /* Power Saving Sleep Mode */
@@ -188,6 +209,7 @@
/*
** DC21040 Bus Mode Register (DE4X5_BMR)
*/
+#define BMR_RML 0x00200000 /* [Memory] Read Multiple */
#define BMR_DBO 0x00100000 /* Descriptor Byte Ordering (Endian) */
#define BMR_TAP 0x000e0000 /* Transmit Automatic Polling */
#define BMR_DAS 0x00010000 /* Diagnostic Address Space */
@@ -198,6 +220,7 @@
#define BMR_BAR 0x00000002 /* Bus ARbitration */
#define BMR_SWR 0x00000001 /* Software Reset */
+ /* Timings here are for 10BASE-T/AUI only*/
#define TAP_NOPOLL 0x00000000 /* No automatic polling */
#define TAP_200US 0x00020000 /* TX automatic polling every 200us */
#define TAP_800US 0x00040000 /* TX automatic polling every 800us */
@@ -249,18 +272,21 @@
#define TRBA 0xfffffffc /* TX Descriptor List Start Address */
/*
-** DC21040 Status Register (DE4X5_STS)
+** Status Register (DE4X5_STS)
*/
+#define STS_GPI 0x04000000 /* General Purpose Port Interrupt */
#define STS_BE 0x03800000 /* Bus Error Bits */
#define STS_TS 0x00700000 /* Transmit Process State */
#define STS_RS 0x000e0000 /* Receive Process State */
#define STS_NIS 0x00010000 /* Normal Interrupt Summary */
#define STS_AIS 0x00008000 /* Abnormal Interrupt Summary */
#define STS_ER 0x00004000 /* Early Receive */
+#define STS_FBE 0x00002000 /* Fatal Bus Error */
#define STS_SE 0x00002000 /* System Error */
#define STS_LNF 0x00001000 /* Link Fail */
#define STS_FD 0x00000800 /* Full-Duplex Short Frame Received */
#define STS_TM 0x00000800 /* Timer Expired (DC21041) */
+#define STS_ETI 0x00000400 /* Early Transmit Interupt */
#define STS_AT 0x00000400 /* AUI/TP Pin */
#define STS_RWT 0x00000200 /* Receive Watchdog Time-Out */
#define STS_RPS 0x00000100 /* Receive Process Stopped */
@@ -268,6 +294,7 @@
#define STS_RI 0x00000040 /* Receive Interrupt */
#define STS_UNF 0x00000020 /* Transmit Underflow */
#define STS_LNP 0x00000010 /* Link Pass */
+#define STS_ANC 0x00000010 /* Autonegotiation Complete */
#define STS_TJT 0x00000008 /* Transmit Jabber Time-Out */
#define STS_TU 0x00000004 /* Transmit Buffer Unavailable */
#define STS_TPS 0x00000002 /* Transmit Process Stopped */
@@ -300,8 +327,10 @@
#define INT_CANCEL 0x0001ffff /* For zeroing all interrupt sources */
/*
-** DC21040 Operation Mode Register (DE4X5_OMR)
+** Operation Mode Register (DE4X5_OMR)
*/
+#define OMR_SC 0x80000000 /* Special Capture Effect Enable */
+#define OMR_RA 0x40000000 /* Receive All */
#define OMR_SDP 0x02000000 /* SD Polarity - MUST BE ASSERTED */
#define OMR_SCR 0x01000000 /* Scrambler Mode */
#define OMR_PCS 0x00800000 /* PCS Function */
@@ -326,27 +355,31 @@
#define OMR_SR 0x00000002 /* Start/Stop Receive */
#define OMR_HP 0x00000001 /* Hash/Perfect Receive Filtering Mode */
-#define TR_72 0x00000000 /* Threshold set to 72 bytes */
-#define TR_96 0x00004000 /* Threshold set to 96 bytes */
-#define TR_128 0x00008000 /* Threshold set to 128 bytes */
-#define TR_160 0x0000c000 /* Threshold set to 160 bytes */
+#define TR_72 0x00000000 /* Threshold set to 72 (128) bytes */
+#define TR_96 0x00004000 /* Threshold set to 96 (256) bytes */
+#define TR_128 0x00008000 /* Threshold set to 128 (512) bytes */
+#define TR_160 0x0000c000 /* Threshold set to 160 (1024) bytes */
/*
** DC21040 Interrupt Mask Register (DE4X5_IMR)
*/
+#define IMR_GPM 0x04000000 /* General Purpose Port Mask */
#define IMR_NIM 0x00010000 /* Normal Interrupt Summary Mask */
#define IMR_AIM 0x00008000 /* Abnormal Interrupt Summary Mask */
#define IMR_ERM 0x00004000 /* Early Receive Mask */
+#define IMR_FBM 0x00002000 /* Fatal Bus Error Mask */
#define IMR_SEM 0x00002000 /* System Error Mask */
#define IMR_LFM 0x00001000 /* Link Fail Mask */
#define IMR_FDM 0x00000800 /* Full-Duplex (Short Frame) Mask */
#define IMR_TMM 0x00000800 /* Timer Expired Mask (DC21041) */
+#define IMR_ETM 0x00000400 /* Early Transmit Interrupt Mask */
#define IMR_ATM 0x00000400 /* AUI/TP Switch Mask */
#define IMR_RWM 0x00000200 /* Receive Watchdog Time-Out Mask */
#define IMR_RSM 0x00000100 /* Receive Stopped Mask */
#define IMR_RUM 0x00000080 /* Receive Buffer Unavailable Mask */
#define IMR_RIM 0x00000040 /* Receive Interrupt Mask */
#define IMR_UNM 0x00000020 /* Underflow Interrupt Mask */
+#define IMR_ANM 0x00000010 /* Autonegotiation Complete Mask */
#define IMR_LPM 0x00000010 /* Link Pass */
#define IMR_TJM 0x00000008 /* Transmit Time-Out Jabber Mask */
#define IMR_TUM 0x00000004 /* Transmit Buffer Unavailable Mask */
@@ -354,13 +387,7 @@
#define IMR_TIM 0x00000001 /* Transmit Interrupt Mask */
/*
-** DC21040 Missed Frames Counter (DE4X5_MFC)
-*/
-#define MFC_OVFL 0x00010000 /* Missed Frames Counter Overflow Bit */
-#define MFC_CNTR 0x0000ffff /* Missed Frames Counter Bits */
-
-/*
-** DC21140 Missed Frames and FIFO Overflow Counters (DE4X5_MFC)
+** Missed Frames and FIFO Overflow Counters (DE4X5_MFC)
*/
#define MFC_FOCO 0x10000000 /* FIFO Overflow Counter Overflow Bit */
#define MFC_FOC 0x0ffe0000 /* FIFO Overflow Counter Bits */
@@ -461,7 +488,7 @@
** MII Management Auto Negotiation Advertisement Register
*/
#define MII_ANA_TAF 0x03e0 /* Technology Ability Field */
-#define MII_ANA_T4AM 0x0400 /* T4 Technology Ability Mask */
+#define MII_ANA_T4AM 0x0200 /* T4 Technology Ability Mask */
#define MII_ANA_TXAM 0x0180 /* TX Technology Ability Mask */
#define MII_ANA_FDAM 0x0140 /* Full Duplex Technology Ability Mask */
#define MII_ANA_HDAM 0x02a0 /* Half Duplex Technology Ability Mask */
@@ -476,7 +503,7 @@
#define MII_ANLPA_ACK 0x4000 /* Remote Acknowledge */
#define MII_ANLPA_RF 0x2000 /* Remote Fault */
#define MII_ANLPA_TAF 0x03e0 /* Technology Ability Field */
-#define MII_ANLPA_T4AM 0x0400 /* T4 Technology Ability Mask */
+#define MII_ANLPA_T4AM 0x0200 /* T4 Technology Ability Mask */
#define MII_ANLPA_TXAM 0x0180 /* TX Technology Ability Mask */
#define MII_ANLPA_FDAM 0x0140 /* Full Duplex Technology Ability Mask */
#define MII_ANLPA_HDAM 0x02a0 /* Half Duplex Technology Ability Mask */
@@ -547,6 +574,8 @@
#define SROM_100BASEFF 0x0008 /* 100BASE-FX full duplex */
#define BLOCK_LEN 0x7f /* Extended blocks length mask */
+#define EXT_FIELD 0x40 /* Extended blocks extension field bit */
+#define MEDIA_CODE 0x3f /* Extended blocks media code mask */
/*
** SROM Compact Format Block Masks
@@ -589,14 +618,18 @@
#define GEP_CTRL 0x00000100 /* GEP control bit */
/*
-** DC21040 SIA Status Register (DE4X5_SISR)
+** SIA Status Register (DE4X5_SISR)
*/
#define SISR_LPC 0xffff0000 /* Link Partner's Code Word */
#define SISR_LPN 0x00008000 /* Link Partner Negotiable */
#define SISR_ANS 0x00007000 /* Auto Negotiation Arbitration State */
-#define SISR_NSN 0x00000800 /* Non Stable NLPs Detected */
+#define SISR_NSN 0x00000800 /* Non Stable NLPs Detected (DC21041) */
+#define SISR_TRF 0x00000800 /* Transmit Remote Fault */
+#define SISR_NSND 0x00000400 /* Non Stable NLPs Detected (DC21142) */
#define SISR_ANR_FDS 0x00000400 /* Auto Negotiate Restart/Full Duplex Sel.*/
+#define SISR_TRA 0x00000200 /* 10BASE-T Receive Port Activity */
#define SISR_NRA 0x00000200 /* Non Selected Port Receive Activity */
+#define SISR_ARA 0x00000100 /* AUI Receive Port Activity */
#define SISR_SRA 0x00000100 /* Selected Port Receive Activity */
#define SISR_DAO 0x00000080 /* PLL All One */
#define SISR_DAZ 0x00000040 /* PLL All Zero */
@@ -606,7 +639,7 @@
#define SISR_LKF 0x00000004 /* Link Fail Status */
#define SISR_NCR 0x00000002 /* Network Connection Error */
#define SISR_PAUI 0x00000001 /* AUI_TP Indication */
-#define SIA_RESET 0x00000000 /* SIA Reset */
+#define SISR_MRA 0x00000001 /* MII Receive Port Activity */
#define ANS_NDIS 0x00000000 /* Nway disable */
#define ANS_TDIS 0x00001000 /* Transmit Disable */
@@ -617,7 +650,7 @@
#define ANS_LCHK 0x00006000 /* Link Check */
/*
-** DC21040 SIA Connectivity Register (DE4X5_SICR)
+** SIA Connectivity Register (DE4X5_SICR)
*/
#define SICR_SDM 0xffff0000 /* SIA Diagnostics Mode */
#define SICR_OE57 0x00008000 /* Output Enable 5 6 7 */
@@ -636,14 +669,14 @@
#define SICR_SIM 0x00000040 /* Serial Interface Input Multiplexer */
#define SICR_ENI 0x00000020 /* Encoder Input Multiplexer */
#define SICR_EDP 0x00000010 /* SIA PLL External Input Enable */
-#define SICR_AUI 0x00000008 /* 10Base-T or AUI */
+#define SICR_AUI 0x00000008 /* 10Base-T (0) or AUI (1) */
#define SICR_CAC 0x00000004 /* CSR Auto Configuration */
#define SICR_PS 0x00000002 /* Pin AUI/TP Selection */
#define SICR_SRL 0x00000001 /* SIA Reset */
-#define SICR_RESET 0xffff0000 /* Reset value for SICR */
+#define SIA_RESET 0x00000000 /* SIA Reset Value */
/*
-** DC21040 SIA Transmit and Receive Register (DE4X5_STRR)
+** SIA Transmit and Receive Register (DE4X5_STRR)
*/
#define STRR_TAS 0x00008000 /* 10Base-T/AUI Autosensing Enable */
#define STRR_SPP 0x00004000 /* Set Polarity Plus */
@@ -663,8 +696,20 @@
#define STRR_RESET 0xffffffff /* Reset value for STRR */
/*
-** DC21040 SIA General Register (DE4X5_SIGR)
-*/
+** SIA General Register (DE4X5_SIGR)
+*/
+#define SIGR_RMI 0x40000000 /* Receive Match Interrupt */
+#define SIGR_GI1 0x20000000 /* General Port Interrupt 1 */
+#define SIGR_GI0 0x10000000 /* General Port Interrupt 0 */
+#define SIGR_CWE 0x08000000 /* Control Write Enable */
+#define SIGR_RME 0x04000000 /* Receive Match Enable */
+#define SIGR_GEI1 0x02000000 /* GEP Interrupt Enable on Port 1 */
+#define SIGR_GEI0 0x01000000 /* GEP Interrupt Enable on Port 0 */
+#define SIGR_LGS3 0x00800000 /* LED/GEP3 Select */
+#define SIGR_LGS2 0x00400000 /* LED/GEP2 Select */
+#define SIGR_LGS1 0x00200000 /* LED/GEP1 Select */
+#define SIGR_LGS0 0x00100000 /* LED/GEP0 Select */
+#define SIGR_MD 0x000f0000 /* General Purpose Mode and Data */
#define SIGR_LV2 0x00008000 /* General Purpose LED2 value */
#define SIGR_LE2 0x00004000 /* General Purpose LED2 enable */
#define SIGR_FRL 0x00002000 /* Force Receiver Low */
@@ -687,7 +732,8 @@
** Receive Descriptor Bit Summary
*/
#define R_OWN 0x80000000 /* Own Bit */
-#define RD_FL 0x7fff0000 /* Frame Length */
+#define RD_FF 0x40000000 /* Filtering Fail */
+#define RD_FL 0x3fff0000 /* Frame Length */
#define RD_ES 0x00008000 /* Error Summary */
#define RD_LE 0x00004000 /* Length Error */
#define RD_DT 0x00003000 /* Data Type */
@@ -699,6 +745,7 @@
#define RD_CS 0x00000040 /* Collision Seen */
#define RD_FT 0x00000020 /* Frame Type */
#define RD_RJ 0x00000010 /* Receive Watchdog */
+#define RD_RE 0x00000008 /* Report on MII Error */
#define RD_DB 0x00000004 /* Dribbling Bit */
#define RD_CE 0x00000002 /* CRC Error */
#define RD_OF 0x00000001 /* Overflow */
@@ -734,40 +781,39 @@
#define TD_TCH 0x01000000 /* Second Address Chained */
#define TD_DPD 0x00800000 /* Disabled Padding */
#define TD_FT0 0x00400000 /* Filtering Type */
-#define TD_RBS2 0x003ff800 /* Buffer 2 Size */
-#define TD_RBS1 0x000007ff /* Buffer 1 Size */
+#define TD_TBS2 0x003ff800 /* Buffer 2 Size */
+#define TD_TBS1 0x000007ff /* Buffer 1 Size */
#define PERFECT_F 0x00000000
#define HASH_F TD_FT0
#define INVERSE_F TD_FT1
-#define HASH_O_F TD_FT1| TD_F0
+#define HASH_O_F (TD_FT1 | TD_F0)
/*
** Media / mode state machine definitions
*/
-#define NC 0x0000 /* No Connection */
-#define TP 0x0001 /* 10Base-T */
-#define TP_NW 0x0002 /* 10Base-T with Nway */
-#define BNC 0x0004 /* Thinwire */
-#define AUI 0x0008 /* Thickwire */
+#define NC 0x0000 /* No Connection */
+#define TP 0x0001 /* 10Base-T */
+#define TP_NW 0x0002 /* 10Base-T with Nway */
+#define BNC 0x0004 /* Thinwire */
+#define AUI 0x0008 /* Thickwire */
#define BNC_AUI 0x0010 /* BNC/AUI on DC21040 indistinguishable */
-#define ANS 0x0020 /* Intermediate AutoNegotiation State */
-#define ANS_1 0x0021 /* Intermediate AutoNegotiation State */
-
-#define _10Mb 0x0040 /* 10Mb/s Ethernet */
-#define _100Mb 0x0080 /* 100Mb/s Ethernet */
-#define SPD_DET 0x0100 /* Parallel speed detection */
-#define INIT 0x0200 /* Initial state */
-#define EXT_SIA 0x0400 /* External SIA for motherboard chip */
-#define ANS_SUSPECT 0x0802 /* Suspect the ANS (TP) port is down */
-#define TP_SUSPECT 0x0803 /* Suspect the TP port is down */
-#define BNC_AUI_SUSPECT 0x0804 /* Suspect the BNC or AUI port is down */
-#define EXT_SIA_SUSPECT 0x0805 /* Suspect the EXT SIA port is down */
-#define BNC_SUSPECT 0x0806 /* Suspect the BNC port is down */
-#define AUI_SUSPECT 0x0807 /* Suspect the AUI port is down */
-
-#define AUTO 0x4000 /* Auto sense the media or speed */
-#define TIMER_CB 0x80000000 /* Timer callback detection */
+#define ANS 0x0020 /* Intermediate AutoNegotiation State */
+#define _10Mb 0x0040 /* 10Mb/s Ethernet */
+#define _100Mb 0x0080 /* 100Mb/s Ethernet */
+#define SPD_DET 0x0100 /* Parallel speed detection */
+#define INIT 0x0200 /* Initial state */
+#define EXT_SIA 0x0400 /* External SIA for motherboard chip */
+#define ANS_SUSPECT 0x0802 /* Suspect the ANS (TP) port is down */
+#define TP_SUSPECT 0x0803 /* Suspect the TP port is down */
+#define BNC_AUI_SUSPECT 0x0804 /* Suspect the BNC or AUI port is down */
+#define EXT_SIA_SUSPECT 0x0805 /* Suspect the EXT SIA port is down */
+#define BNC_SUSPECT 0x0806 /* Suspect the BNC port is down */
+#define AUI_SUSPECT 0x0807 /* Suspect the AUI port is down */
+#define MII 0x1000 /* MII on the 21143 */
+
+#define AUTO 0x4000 /* Auto sense the media or speed */
+#define TIMER_CB 0x80000000 /* Timer callback detection */
/*
** DE4X5 DEBUG Options
@@ -798,7 +844,6 @@
#define POLL_DEMAND 1
#define LOST_MEDIA_THRESHOLD 3
-#define LOST_MEDIA (lp->lostMedia > LOST_MEDIA_THRESHOLD)
#define MASK_INTERRUPTS 1
#define UNMASK_INTERRUPTS 0
@@ -859,7 +904,7 @@
}\
omr |= ((lp->fdx ? OMR_FDX : 0) | OMR_TTM);\
outl(omr, DE4X5_OMR);\
- lp->cache.gep = 0;\
+ if (!lp->useSROM) lp->cache.gep = 0;\
} else if (lp->useSROM && !lp->useMII) {\
omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\
omr |= (lp->fdx ? OMR_FDX : 0);\
@@ -887,7 +932,7 @@
}\
if (fdx) omr |= OMR_FDX;\
outl(omr, DE4X5_OMR);\
- lp->cache.gep = 0;\
+ if (!lp->useSROM) lp->cache.gep = 0;\
} else if (lp->useSROM && !lp->useMII) {\
omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\
omr |= (lp->fdx ? OMR_FDX : 0);\
@@ -906,7 +951,6 @@
mii_wr(MII_CR_100|MII_CR_ASSE, MII_CR, lp->phy[lp->active].addr, DE4X5_MII);\
omr = (inl(DE4X5_OMR) & ~(OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\
outl(omr, DE4X5_OMR);\
- lp->cache.gep = 0;\
} else if (lp->useSROM && !lp->useMII) {\
omr = (inl(DE4X5_OMR) & ~(OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\
outl(omr, DE4X5_OMR);\
@@ -934,7 +978,7 @@ struct de4x5_ioctl {
** Recognised commands for the driver
*/
#define DE4X5_GET_HWADDR 0x01 /* Get the hardware address */
-#define DE4X5_SET_HWADDR 0x02 /* Get the hardware address */
+#define DE4X5_SET_HWADDR 0x02 /* Set the hardware address */
#define DE4X5_SET_PROM 0x03 /* Set Promiscuous Mode */
#define DE4X5_CLR_PROM 0x04 /* Clear Promiscuous Mode */
#define DE4X5_SAY_BOO 0x05 /* Say "Boo!" to the kernel log file */
diff --git a/drivers/net/defxx.c b/drivers/net/defxx.c
index 5e50cbfa5..659e71f32 100644
--- a/drivers/net/defxx.c
+++ b/drivers/net/defxx.c
@@ -226,6 +226,11 @@ static const char *version = "defxx.c:v1.04 09/16/96 Lawrence V. Stefani (stefa
#include "defxx.h"
+#define DYNAMIC_BUFFERS 1
+
+#define SKBUFF_RX_COPYBREAK 200
+#define NEW_SKB_SIZE (PI_RCV_DATA_K_SIZE_MAX)
+
/* Define global routines */
int dfx_probe(struct device *dev);
@@ -1083,7 +1088,9 @@ __initfunc(int dfx_driver_init(
alloc_size = sizeof(PI_DESCR_BLOCK) +
PI_CMD_REQ_K_SIZE_MAX +
PI_CMD_RSP_K_SIZE_MAX +
+#ifndef DYNAMIC_BUFFERS
(bp->rcv_bufs_to_post * PI_RCV_DATA_K_SIZE_MAX) +
+#endif
sizeof(PI_CONSUMER_BLOCK) +
(PI_ALIGN_K_DESC_BLK - 1);
top_v = (char *) kmalloc(alloc_size, GFP_KERNEL);
@@ -1135,8 +1142,11 @@ __initfunc(int dfx_driver_init(
bp->rcv_block_virt = curr_v;
bp->rcv_block_phys = curr_p;
+
+#ifndef DYNAMIC_BUFFERS
curr_v += (bp->rcv_bufs_to_post * PI_RCV_DATA_K_SIZE_MAX);
curr_p += (bp->rcv_bufs_to_post * PI_RCV_DATA_K_SIZE_MAX);
+#endif
/* Reserve space for the consumer block */
@@ -2926,6 +2936,22 @@ void dfx_rcv_init(
* driver initialization when we allocated memory for the receive buffers.
*/
+#ifdef DYNAMIC_BUFFERS
+ for (i = 0; i < (int)(bp->rcv_bufs_to_post); i++)
+ for (j = 0; (i + j) < (int)PI_RCV_DATA_K_NUM_ENTRIES; j += bp->rcv_bufs_to_post)
+ {
+ struct sk_buff *newskb;
+ bp->descr_block_virt->rcv_data[i+j].long_0 = (u32) (PI_RCV_DESCR_M_SOP |
+ ((PI_RCV_DATA_K_SIZE_MAX / PI_ALIGN_K_RCV_DATA_BUFF) << PI_RCV_DESCR_V_SEG_LEN));
+ newskb = dev_alloc_skb(NEW_SKB_SIZE);
+ bp->descr_block_virt->rcv_data[i+j].long_1 = virt_to_bus(newskb->data);
+ /*
+ * p_rcv_buff_va is only used inside the
+ * kernel so we put the skb pointer here.
+ */
+ bp->p_rcv_buff_va[i+j] = (char *) newskb;
+ }
+#else
for (i=0; i < (int)(bp->rcv_bufs_to_post); i++)
for (j=0; (i + j) < (int)PI_RCV_DATA_K_NUM_ENTRIES; j += bp->rcv_bufs_to_post)
{
@@ -2934,6 +2960,7 @@ void dfx_rcv_init(
bp->descr_block_virt->rcv_data[i+j].long_1 = (u32) (bp->rcv_block_phys + (i * PI_RCV_DATA_K_SIZE_MAX));
bp->p_rcv_buff_va[i+j] = (char *) (bp->rcv_block_virt + (i * PI_RCV_DATA_K_SIZE_MAX));
}
+#endif
/* Update receive producer and Type 2 register */
@@ -2985,6 +3012,8 @@ void dfx_rcv_queue_process(
u32 descr, pkt_len; /* FMC descriptor field and packet length */
struct sk_buff *skb; /* pointer to a sk_buff to hold incoming packet data */
+ static int testing_dyn;
+
/* Service all consumed LLC receive frames */
p_type_2_cons = (PI_TYPE_2_CONSUMER *)(&bp->cons_block_virt->xmt_rcv_data);
@@ -2992,7 +3021,14 @@ void dfx_rcv_queue_process(
{
/* Process any errors */
- p_buff = (char *) bp->p_rcv_buff_va[bp->rcv_xmt_reg.index.rcv_comp];
+ int entry;
+
+ entry = bp->rcv_xmt_reg.index.rcv_comp;
+#ifdef DYNAMIC_BUFFERS
+ p_buff = (char *) (((struct sk_buff *)bp->p_rcv_buff_va[entry])->data);
+#else
+ p_buff = (char *) bp->p_rcv_buff_va[entry];
+#endif
memcpy(&descr, p_buff + RCV_BUFF_K_DESCR, sizeof(u32));
if (descr & PI_FMC_DESCR_M_RCC_FLUSH)
@@ -3003,29 +3039,60 @@ void dfx_rcv_queue_process(
bp->rcv_frame_status_errors++;
}
else
- {
+ {
+ int rx_in_place = 0;
+
/* The frame was received without errors - verify packet length */
pkt_len = (u32)((descr & PI_FMC_DESCR_M_LEN) >> PI_FMC_DESCR_V_LEN);
pkt_len -= 4; /* subtract 4 byte CRC */
if (!IN_RANGE(pkt_len, FDDI_K_LLC_ZLEN, FDDI_K_LLC_LEN))
bp->rcv_length_errors++;
- else
- {
- skb = dev_alloc_skb(pkt_len+3); /* alloc new buffer to pass up, add room for PRH */
+ else{
+#ifdef DYNAMIC_BUFFERS
+ if (pkt_len > SKBUFF_RX_COPYBREAK) {
+ struct sk_buff *newskb;
+
+ newskb = dev_alloc_skb(NEW_SKB_SIZE);
+ if (newskb){
+ rx_in_place = 1;
+#define JES_TESTING
+#ifdef JES_TESTING
+ if(testing_dyn++ < 5)
+ printk("Skipping a memcpy\n");
+ skb = (struct sk_buff *)bp->p_rcv_buff_va[entry];
+ skb->data += RCV_BUFF_K_PADDING;
+ bp->p_rcv_buff_va[entry] = (char *)newskb;
+ bp->descr_block_virt->rcv_data[entry].long_1 = virt_to_bus(newskb->data);
+#else
+ memcpy(newskb->data, p_buff + RCV_BUFF_K_PADDING, pkt_len+3);
+ skb = newskb;
+#endif
+ } else
+ skb = 0;
+ } else
+#endif
+ skb = dev_alloc_skb(pkt_len+3); /* alloc new buffer to pass up, add room for PRH */
if (skb == NULL)
{
printk("%s: Could not allocate receive buffer. Dropping packet.\n", bp->dev->name);
bp->rcv_discards++;
+ break;
}
- else
+ else {
+#ifndef DYNAMIC_BUFFERS
+ if (! rx_in_place)
+#endif
{
- /* Receive buffer allocated, pass receive packet up */
+ /* Receive buffer allocated, pass receive packet up */
+
+ memcpy(skb->data, p_buff + RCV_BUFF_K_PADDING, pkt_len+3);
+ }
- memcpy(skb->data, p_buff + RCV_BUFF_K_PADDING, pkt_len+3);
skb->data += 3; /* adjust data field so that it points to FC byte */
skb->len = pkt_len; /* pass up packet length, NOT including CRC */
skb->dev = bp->dev; /* pass up device pointer */
+
skb->protocol = fddi_type_trans(skb, bp->dev);
netif_rx(skb);
@@ -3034,9 +3101,9 @@ void dfx_rcv_queue_process(
bp->rcv_total_frames++;
if (*(p_buff + RCV_BUFF_K_DA) & 0x01)
bp->rcv_multicast_frames++;
- }
}
}
+ }
/*
* Advance the producer (for recycling) and advance the completion
@@ -3140,6 +3207,7 @@ int dfx_xmt_queue_pkt(
dev->name, skb->len);
bp->xmt_length_errors++; /* bump error counter */
dev_tint(dev); /* dequeue packets from xmt queue and send them */
+ dev_kfree_skb(skb, FREE_WRITE);
return(0); /* return "success" */
}
/*
diff --git a/drivers/net/depca.c b/drivers/net/depca.c
index 85cf704c5..74246fa7a 100644
--- a/drivers/net/depca.c
+++ b/drivers/net/depca.c
@@ -804,7 +804,7 @@ depca_start_xmit(struct sk_buff *skb, struct device *dev)
dev_tint(dev);
} else if (skb->len > 0) {
/* Enforce 1 process per h/w access */
- if (set_bit(0, (void*)&dev->tbusy) != 0) {
+ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
printk("%s: Transmitter access conflict.\n", dev->name);
status = -1;
} else {
diff --git a/drivers/net/dlci.c b/drivers/net/dlci.c
index e42b0dcf4..08d9901ba 100644
--- a/drivers/net/dlci.c
+++ b/drivers/net/dlci.c
@@ -248,7 +248,7 @@ static int dlci_transmit(struct sk_buff *skb, struct device *dev)
dlp = dev->priv;
- if (set_bit(0, (void*)&dev->tbusy) != 0)
+ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
printk(KERN_WARNING "%s: transmitter access conflict.\n", dev->name);
else
{
diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c
index 814d798c5..877e2256e 100644
--- a/drivers/net/dummy.c
+++ b/drivers/net/dummy.c
@@ -134,7 +134,7 @@ int init_module(void)
{
/* Find a name for this unit */
int err=dev_alloc_name(&dev_dummy,"dummy%d");
- if(err)
+ if(err<0)
return err;
if (register_netdev(&dev_dummy) != 0)
return -EIO;
diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c
index 72060c53b..25167fa0b 100644
--- a/drivers/net/eepro.c
+++ b/drivers/net/eepro.c
@@ -714,7 +714,7 @@ eepro_send_packet(struct sk_buff *skb, struct device *dev)
}
/* Block a timer-based transmit from overlapping. */
- if (set_bit(0, (void*)&dev->tbusy) != 0)
+ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
printk("%s: Transmitter access conflict.\n", dev->name);
else {
short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c
index cf67f942b..af117e223 100644
--- a/drivers/net/eepro100.c
+++ b/drivers/net/eepro100.c
@@ -1033,7 +1033,7 @@ speedo_start_xmit(struct sk_buff *skb, struct device *dev)
/* Block a timer-based transmit from overlapping. This could better be
done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
If this ever occurs the queue layer is doing something evil! */
- if (set_bit(0, (void*)&dev->tbusy) != 0) {
+ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
int tickssofar = jiffies - dev->trans_start;
if (tickssofar < TX_TIMEOUT - 2)
return 1;
diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c
index f5b75bb9f..8e8852bc0 100644
--- a/drivers/net/eexpress.c
+++ b/drivers/net/eexpress.c
@@ -94,6 +94,7 @@
#include <asm/io.h>
#include <linux/delay.h>
#include <linux/errno.h>
+#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
@@ -301,7 +302,7 @@ static inline short int SHADOW(short int addr)
* checks for presence of EtherExpress card
*/
-int express_probe(struct device *dev)
+__initfunc(int express_probe(struct device *dev))
{
unsigned short *port;
static unsigned short ports[] = { 0x300,0x310,0x270,0x320,0x340,0 };
@@ -525,7 +526,7 @@ static int eexp_xmit(struct sk_buff *buf, struct device *dev)
}
}
- if (set_bit(0,(void *)&dev->tbusy))
+ if (test_and_set_bit(0,(void *)&dev->tbusy))
{
lp->stats.tx_dropped++;
}
@@ -913,7 +914,7 @@ static void eexp_hw_tx_pio(struct device *dev, unsigned short *buf,
* than one card in a machine.
*/
-static int eexp_hw_probe(struct device *dev, unsigned short ioaddr)
+__initfunc(static int eexp_hw_probe(struct device *dev, unsigned short ioaddr))
{
unsigned short hw_addr[3];
unsigned char buswidth;
@@ -1034,8 +1035,8 @@ static int eexp_hw_probe(struct device *dev, unsigned short ioaddr)
* Read a word from the EtherExpress on-board serial EEPROM.
* The EEPROM contains 64 words of 16 bits.
*/
-static unsigned short eexp_hw_readeeprom(unsigned short ioaddr,
- unsigned char location)
+__initfunc(static unsigned short eexp_hw_readeeprom(unsigned short ioaddr,
+ unsigned char location))
{
unsigned short cmd = 0x180|(location&0x7f);
unsigned short rval = 0,wval = EC_CS|i586_RST;
diff --git a/drivers/net/eth16i.c b/drivers/net/eth16i.c
index 24e449390..74cf38d50 100644
--- a/drivers/net/eth16i.c
+++ b/drivers/net/eth16i.c
@@ -932,7 +932,7 @@ static int eth16i_tx(struct sk_buff *skb, struct device *dev)
/* Turn off TX interrupts */
outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);
- if(set_bit(0, (void *)&dev->tbusy) != 0)
+ if(test_and_set_bit(0, (void *)&dev->tbusy) != 0)
printk("%s: Transmitter access conflict.\n", dev->name);
else {
short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
diff --git a/drivers/net/ewrk3.c b/drivers/net/ewrk3.c
index 3c3752251..75492e1c1 100644
--- a/drivers/net/ewrk3.c
+++ b/drivers/net/ewrk3.c
@@ -767,7 +767,7 @@ ewrk3_queue_pkt(struct sk_buff *skb, struct device *dev)
** Block a timer-based transmit from overlapping. This could better be
** done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
*/
- if (set_bit(0, (void*)&dev->tbusy) != 0)
+ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
printk("%s: Transmitter access conflict.\n", dev->name);
DISABLE_IRQs; /* So that the page # remains correct */
@@ -783,7 +783,7 @@ ewrk3_queue_pkt(struct sk_buff *skb, struct device *dev)
/*
** Set up shared memory window and pointer into the window
*/
- while (set_bit(0, (void *)&lp->lock) != 0); /* Wait for lock to free */
+ while (test_and_set_bit(0, (void *)&lp->lock) != 0); /* Wait for lock to free */
if (lp->shmem_length == IO_ONLY) {
outb(page, EWRK3_IOPR);
} else if (lp->shmem_length == SHMEM_2K) {
@@ -953,7 +953,7 @@ ewrk3_rx(struct device *dev)
** Preempt any process using the current page register. Check for
** an existing lock to reduce time taken in I/O transactions.
*/
- if ((tmpLock = set_bit(0, (void *)&lp->lock)) == 1) { /* Assert lock */
+ if ((tmpLock = test_and_set_bit(0, (void *)&lp->lock)) == 1) { /* Assert lock */
if (lp->shmem_length == IO_ONLY) { /* Get existing page */
tmpPage = inb(EWRK3_IOPR);
} else {
@@ -1217,7 +1217,7 @@ static void SetMulticastFilter(struct device *dev)
u16 hashcode;
s32 crc, poly = CRC_POLYNOMIAL_LE;
- while (set_bit(0, (void *)&lp->lock) != 0); /* Wait for lock to free */
+ while (test_and_set_bit(0, (void *)&lp->lock) != 0); /* Wait for lock to free */
if (lp->shmem_length == IO_ONLY) {
outb(0, EWRK3_IOPR);
@@ -1723,7 +1723,7 @@ static int ewrk3_ioctl(struct device *dev, struct ifreq *rq, int cmd)
break;
case EWRK3_GET_MCA: /* Get the multicast address table */
if (!(status = verify_area(VERIFY_WRITE, ioc->data, ioc->len))) {
- while (set_bit(0, (void *)&lp->lock) != 0); /* Wait for lock to free */
+ while (test_and_set_bit(0, (void *)&lp->lock) != 0); /* Wait for lock to free */
if (lp->shmem_length == IO_ONLY) {
outb(0, EWRK3_IOPR);
outw(PAGE0_HTE, EWRK3_PIR1);
diff --git a/drivers/net/fmv18x.c b/drivers/net/fmv18x.c
index 7536a7e04..59362c8fe 100644
--- a/drivers/net/fmv18x.c
+++ b/drivers/net/fmv18x.c
@@ -348,7 +348,7 @@ net_send_packet(struct sk_buff *skb, struct device *dev)
/* Block a timer-based transmit from overlapping. This could better be
done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
- if (set_bit(0, (void*)&dev->tbusy) != 0)
+ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
printk("%s: Transmitter access conflict.\n", dev->name);
else {
short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
diff --git a/drivers/net/hdlcdrv.c b/drivers/net/hdlcdrv.c
index 9098fdf2e..467980406 100644
--- a/drivers/net/hdlcdrv.c
+++ b/drivers/net/hdlcdrv.c
@@ -288,7 +288,7 @@ void hdlcdrv_receiver(struct device *dev, struct hdlcdrv_state *s)
if (!s || s->magic != HDLCDRV_MAGIC)
return;
- if (set_bit(0, &s->hdlcrx.in_hdlc_rx))
+ if (test_and_set_bit(0, &s->hdlcrx.in_hdlc_rx))
return;
while (!hdlcdrv_hbuf_empty(&s->hdlcrx.hbuf)) {
@@ -387,7 +387,7 @@ void hdlcdrv_transmitter(struct device *dev, struct hdlcdrv_state *s)
if (!s || s->magic != HDLCDRV_MAGIC)
return;
- if (set_bit(0, &s->hdlctx.in_hdlc_tx))
+ if (test_and_set_bit(0, &s->hdlctx.in_hdlc_tx))
return;
for (;;) {
if (s->hdlctx.numbits >= 16) {
diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c
index 6a599dd60..0780e038f 100644
--- a/drivers/net/hp100.c
+++ b/drivers/net/hp100.c
@@ -1,89 +1,54 @@
/*
- * hp100.c: Hewlett Packard HP10/100VG ANY LAN ethernet driver for Linux.
- *
- * Author: Jaroslav Kysela, <perex@pf.jcu.cz>
- *
- * Supports only the following Hewlett Packard cards:
- *
- * HP J2577 10/100 EISA card with REVA Cascade chip
- * HP J2573 10/100 ISA card with REVA Cascade chip
- * HP 27248B 10 only EISA card with Cascade chip
- * HP J2577 10/100 EISA card with Cascade chip
- * HP J2573 10/100 ISA card with Cascade chip
- * HP J2585 10/100 PCI card
- *
- * Other ATT2MD01 Chip based boards might be supported in the future
- * (there are some minor changes needed).
- *
- * This driver is based on the 'hpfepkt' crynwr packet driver.
- *
- * This source/code is public free; you can distribute it and/or modify
- * it under terms of the GNU General Public License (published by the
- * Free Software Foundation) either version two of this License, or any
- * later version.
- * ----------------------------------------------------------------------------
- *
- * Note: Some routines (interrupt handling, transmit) assumes that
- * there is the PERFORMANCE page selected...
- *
- * ----------------------------------------------------------------------------
- *
- * If you are going to use the module version of this driver, you may
- * change this values at the "insert time" :
- *
- * Variable Description
- *
- * hp100_rx_ratio Range 1-99 - onboard memory used for RX
- * packets in %.
- * hp100_priority_tx If this variable is nonzero - all outgoing
- * packets will be transmitted as priority.
- * hp100_port Adapter port (for example 0x380).
- *
- * ----------------------------------------------------------------------------
- * MY BEST REGARDS GOING TO:
- *
- * IPEX s.r.o which lend me two HP J2573 cards and
- * the HP AdvanceStack 100VG Hub-15 for debugging.
- *
- * Russel Nellson <nelson@crynwr.com> for help with obtaining sources
- * of the 'hpfepkt' packet driver.
- *
- * Also thanks to Abacus Electric s.r.o which let me to use their
- * motherboard for my second computer.
- *
- * ----------------------------------------------------------------------------
- *
- * TO DO:
- * ======
- * - ioctl handling - some runtime setup things
- * - 100Mb/s Voice Grade AnyLAN network adapter/hub services support
- * - 802.5 frames
- * - promiscuous mode
- * - bridge mode
- * - cascaded repeater mode
- * - 100Mbit MAC
- *
- * Revision history:
- * =================
- *
- * Version Date Description
- *
- * 0.1 14-May-95 Initial writing. ALPHA code was released.
- * Only HP J2573 on 10Mb/s (two machines) tested.
- * 0.11 14-Jun-95 Reset interface bug fixed?
- * Little bug in hp100_close function fixed.
- * 100Mb/s connection debugged.
- * 0.12 14-Jul-95 Link down is now handled better.
- * 0.20 01-Aug-95 Added PCI support for HP J2585A card.
- * Statistics bug fixed.
- * 0.21 04-Aug-95 Memory mapped access support for PCI card.
- * Added priority transmit support for 100Mb/s
- * Voice Grade AnyLAN network.
- *
- */
-
+** hp100.c
+** HP CASCADE Architecture Driver for 100VG-AnyLan Network Adapters
+**
+** $Id: hp100.c,v 1.52 1997/04/21 14:20:20 perex Exp perex $
+**
+** Based on the HP100 driver written by Jaroslav Kysela <perex@jcu.cz>
+** Extended for new busmaster capable chipsets by
+** Siegfried "Frieder" Loeffler (dg1sek) <floeff@mathematik.uni-stuttgart.de>
+**
+** Maintained by: Jaroslav Kysela <perex@jcu.cz>
+**
+** This driver has only been tested with
+** -- HP J2585B 10/100 Mbit/s PCI Busmaster
+** -- HP J2585A 10/100 Mbit/s PCI
+** -- HP J2970 10 Mbit/s PCI Combo 10base-T/BNC
+** -- HP J2973 10 Mbit/s PCI 10base-T
+** -- HP J2573 10/100 ISA
+** -- Compex ReadyLink ENET100-VG4 10/100 Mbit/s PCI / EISA
+**
+** but it should also work with the other CASCADE based adapters.
+**
+** TODO:
+** - J2573 seems to hang sometimes when in shared memory mode.
+** - Mode for Priority TX
+** - Check PCI registers, performance might be improved?
+** - To reduce interrupt load in busmaster, one could switch off
+** the interrupts that are used to refill the queues whenever the
+** queues are filled up to more than a certain threshold.
+**
+**
+** This source/code is public free; you can distribute it and/or modify
+** it under terms of the GNU General Public License (published by the
+** Free Software Foundation) either version two of this License, or any
+** later version.
+**
+*/
+
+#define HP100_DEFAULT_PRIORITY_TX 0
+
+#undef HP100_DEBUG
+#undef HP100_DEBUG_B /* Trace */
+#undef HP100_DEBUG_BM /* Debug busmaster code (PDL stuff) */
+
+#undef HP100_DEBUG_TRAINING /* Debug login-to-hub procedure */
+#undef HP100_DEBUG_TX
+#undef HP100_DEBUG_IRQ
+#undef HP100_DEBUG_RX
+
+#include <linux/version.h>
#include <linux/module.h>
-
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
@@ -102,7 +67,17 @@
#include <linux/skbuff.h>
#include <linux/types.h>
-#include <linux/config.h> /* for CONFIG_PCI */
+#include <linux/config.h> /* for CONFIG_PCI */
+#include <linux/delay.h>
+
+#if LINUX_VERSION_CODE < 0x020100
+#define ioremap vremap
+#define iounmap vfree
+typedef struct enet_statistics hp100_stats_t;
+#else
+#define LINUX_2_1
+typedef struct net_device_stats hp100_stats_t;
+#endif
#include "hp100.h"
@@ -110,18 +85,28 @@
* defines
*/
-#define HP100_BUS_ISA 0
-#define HP100_BUS_EISA 1
-#define HP100_BUS_PCI 2
+#define HP100_BUS_ISA 0
+#define HP100_BUS_EISA 1
+#define HP100_BUS_PCI 2
-#define HP100_REGION_SIZE 0x20
+#ifndef PCI_DEVICE_ID_HP_J2585B
+#define PCI_DEVICE_ID_HP_J2585B 0x1031
+#endif
+#ifndef PCI_VENDOR_ID_COMPEX
+#define PCI_VENDOR_ID_COMPEX 0x11f6
+#endif
+#ifndef PCI_DEVICE_ID_COMPEX_ENET100VG4
+#define PCI_DEVICE_ID_COMPEX_ENET100VG4 0x0112
+#endif
+
+#define HP100_REGION_SIZE 0x20 /* for ioports */
-#define HP100_MAX_PACKET_SIZE (1536+4)
-#define HP100_MIN_PACKET_SIZE 60
+#define HP100_MAX_PACKET_SIZE (1536+4)
+#define HP100_MIN_PACKET_SIZE 60
#ifndef HP100_DEFAULT_RX_RATIO
-/* default - 65% onboard memory on the card are used for RX packets */
-#define HP100_DEFAULT_RX_RATIO 65
+/* default - 75% onboard memory on the card are used for RX packets */
+#define HP100_DEFAULT_RX_RATIO 75
#endif
#ifndef HP100_DEFAULT_PRIORITY_TX
@@ -141,18 +126,37 @@ struct hp100_eisa_id {
struct hp100_private {
struct hp100_eisa_id *id;
+ u_short chip;
u_short soft_model;
- u_int memory_size;
- u_short rx_ratio; /* 1 - 99 */
- u_short priority_tx; /* != 0 - priority tx */
- short mem_mapped; /* memory mapped access */
- u_char *mem_ptr_virt; /* virtual memory mapped area, maybe NULL */
- u_char *mem_ptr_phys; /* physical memory mapped area */
- short lan_type; /* 10Mb/s, 100Mb/s or -1 (error) */
- int hub_status; /* login to hub was successful? */
+ u_int memory_size;
+ u_short rx_ratio; /* 1 - 99 */
+ u_short priority_tx; /* != 0 - priority tx */
+ u_short mode; /* PIO, Shared Mem or Busmaster */
+ u_char bus;
+ u_char pci_bus;
+ u_char pci_device_fn;
+ short mem_mapped; /* memory mapped access */
+ u_int *mem_ptr_virt; /* virtual memory mapped area, maybe NULL */
+ u_int *mem_ptr_phys; /* physical memory mapped area */
+ short lan_type; /* 10Mb/s, 100Mb/s or -1 (error) */
+ int hub_status; /* was login to hub successful? */
u_char mac1_mode;
u_char mac2_mode;
- struct net_device_stats stats;
+ hp100_stats_t stats;
+
+ /* Rings for busmaster mode: */
+ hp100_ring_t *rxrhead; /* Head (oldest) index into rxring */
+ hp100_ring_t *rxrtail; /* Tail (newest) index into rxring */
+ hp100_ring_t *txrhead; /* Head (oldest) index into txring */
+ hp100_ring_t *txrtail; /* Tail (newest) index into txring */
+
+ hp100_ring_t rxring[ MAX_RX_PDL ];
+ hp100_ring_t txring[ MAX_TX_PDL ];
+
+ u_int *page_vaddr; /* Virtual address of allocated page */
+ u_int *page_vaddr_algn; /* Aligned virtual address of allocated page */
+ int rxrcommit; /* # Rx PDLs commited to adapter */
+ int txrcommit; /* # Tx PDLs commited to adapter */
};
/*
@@ -161,78 +165,124 @@ struct hp100_private {
static struct hp100_eisa_id hp100_eisa_ids[] = {
- /* 10/100 EISA card with REVA Cascade chip */
- { 0x080F1F022, "HP J2577 rev A", HP100_BUS_EISA },
+ /* 10/100 EISA card with revision A Cascade chip */
+ { 0x80F1F022, "HP J2577 rev A", HP100_BUS_EISA },
- /* 10/100 ISA card with REVA Cascade chip */
- { 0x050F1F022, "HP J2573 rev A", HP100_BUS_ISA },
+ /* 10/100 ISA card with revision A Cascade chip */
+ { 0x50F1F022, "HP J2573 rev A", HP100_BUS_ISA },
/* 10 only EISA card with Cascade chip */
- { 0x02019F022, "HP 27248B", HP100_BUS_EISA },
+ { 0x2019F022, "HP 27248B", HP100_BUS_EISA },
/* 10/100 EISA card with Cascade chip */
- { 0x04019F022, "HP J2577", HP100_BUS_EISA },
+ { 0x4019F022, "HP J2577", HP100_BUS_EISA },
/* 10/100 ISA card with Cascade chip */
- { 0x05019F022, "HP J2573", HP100_BUS_ISA },
+ { 0x5019F022, "HP J2573", HP100_BUS_ISA },
- /* 10/100 PCI card */
- /* Note: ID for this card is same as PCI vendor/device numbers. */
- { 0x01030103c, "HP J2585", HP100_BUS_PCI },
+ /* 10/100 PCI card - old J2585A */
+ { 0x1030103c, "HP J2585A", HP100_BUS_PCI },
+
+ /* 10/100 PCI card - new J2585B - master capable */
+ { 0x1041103c, "HP J2585B", HP100_BUS_PCI },
+
+ /* 10 Mbit Combo Adapter */
+ { 0x1042103c, "HP J2970", HP100_BUS_PCI },
+
+ /* 10 Mbit 10baseT Adapter */
+ { 0x1040103c, "HP J2973", HP100_BUS_PCI },
+
+ /* 10/100 EISA card from Compex */
+ { 0x0103180e, "ReadyLink ENET100-VG4", HP100_BUS_EISA },
+
+ /* 10/100 PCI card from Compex (J2585A compatible) */
+ { 0x011211f6, "ReadyLink ENET100-VG4", HP100_BUS_PCI }
};
static int hp100_rx_ratio = HP100_DEFAULT_RX_RATIO;
static int hp100_priority_tx = HP100_DEFAULT_PRIORITY_TX;
+static int hp100_mode = 1;
+
+#ifdef LINUX_2_1
+MODULE_PARM( hp100_rx_ratio, "1i" );
+MODULE_PARM( hp100_priority_tx, "1i" );
+MODULE_PARM( hp100_mode, "1i" );
+#endif
/*
* prototypes
*/
-static int hp100_probe1( struct device *dev, int ioaddr, int bus );
-static int hp100_open( struct device *dev );
-static int hp100_close( struct device *dev );
-static int hp100_start_xmit( struct sk_buff *skb, struct device *dev );
+static int hp100_probe1( struct device *dev, int ioaddr, u_char bus, u_char pci_bus, u_char pci_device_fn );
+static int hp100_open( struct device *dev );
+static int hp100_close( struct device *dev );
+static int hp100_start_xmit( struct sk_buff *skb, struct device *dev );
+static int hp100_start_xmit_bm (struct sk_buff *skb, struct device *dev );
static void hp100_rx( struct device *dev );
-static struct net_device_stats *hp100_get_stats( struct device *dev );
+static hp100_stats_t *hp100_get_stats( struct device *dev );
static void hp100_update_stats( struct device *dev );
static void hp100_clear_stats( int ioaddr );
static void hp100_set_multicast_list( struct device *dev);
static void hp100_interrupt( int irq, void *dev_id, struct pt_regs *regs );
-
static void hp100_start_interface( struct device *dev );
static void hp100_stop_interface( struct device *dev );
static void hp100_load_eeprom( struct device *dev );
-static int hp100_sense_lan( struct device *dev );
-static int hp100_login_to_vg_hub( struct device *dev );
-static int hp100_down_vg_link( struct device *dev );
+static int hp100_sense_lan( struct device *dev );
+static int hp100_login_to_vg_hub( struct device *dev, u_short force_relogin );
+static int hp100_down_vg_link( struct device *dev );
+static void hp100_cascade_reset( struct device *dev, u_short enable );
+static void hp100_BM_shutdown( struct device *dev );
+static void hp100_mmuinit( struct device *dev );
+static void hp100_init_pdls( struct device *dev );
+static int hp100_init_rxpdl( register hp100_ring_t *ringptr, register u_int *pdlptr);
+static int hp100_init_txpdl( register hp100_ring_t *ringptr, register u_int *pdlptr);
+static void hp100_rxfill( struct device *dev );
+static void hp100_hwinit( struct device *dev );
+static void hp100_clean_txring( struct device *dev );
+#ifdef HP100_DEBUG
+static void hp100_RegisterDump( struct device *dev );
+#endif
+
+/* TODO: This function should not really be needed in a good design... */
+static void wait( void )
+{
+ udelay( 1000 );
+}
/*
* probe functions
+ * These functions should - if possible - avoid doing write operations
+ * since this could cause problems when the card is not installed.
*/
__initfunc(int hp100_probe( struct device *dev ))
{
int base_addr = dev ? dev -> base_addr : 0;
- int ioaddr;
+ int ioaddr = 0;
#ifdef CONFIG_PCI
int pci_start_index = 0;
#endif
+#ifdef HP100_DEBUG_B
+ hp100_outw( 0x4200, TRACE );
+ printk( "hp100: probe\n" );
+#endif
+
if ( base_addr > 0xff ) /* Check a single specified location. */
{
if ( check_region( base_addr, HP100_REGION_SIZE ) ) return -EINVAL;
if ( base_addr < 0x400 )
- return hp100_probe1( dev, base_addr, HP100_BUS_ISA );
- else
- return hp100_probe1( dev, base_addr, HP100_BUS_EISA );
+ return hp100_probe1( dev, base_addr, HP100_BUS_ISA, 0, 0 );
+ else
+ return hp100_probe1( dev, base_addr, HP100_BUS_EISA, 0, 0 );
}
- else
+ else
#ifdef CONFIG_PCI
- if ( base_addr > 0 && base_addr < 8 + 1 )
- pci_start_index = 0x100 | ( base_addr - 1 );
- else
+ if ( base_addr > 0 && base_addr < 8 + 1 )
+ pci_start_index = 0x100 | ( base_addr - 1 );
+ else
#endif
- if ( base_addr != 0 ) return -ENXIO;
+ if ( base_addr != 0 ) return -ENXIO;
/* at first - scan PCI bus(es) */
@@ -249,65 +299,80 @@ __initfunc(int hp100_probe( struct device *dev ))
u_char pci_bus, pci_device_fn;
u_short pci_command;
- if ( pcibios_find_device( PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585A,
- pci_index, &pci_bus,
- &pci_device_fn ) != 0 ) break;
+ if ((pcibios_find_device( PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585A,
+ pci_index, &pci_bus,
+ &pci_device_fn ) != 0 ) &&
+ (pcibios_find_device( PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585B,
+ pci_index, &pci_bus,
+ &pci_device_fn ) != 0 ) &&
+ (pcibios_find_device( PCI_VENDOR_ID_COMPEX, PCI_DEVICE_ID_COMPEX_ENET100VG4,
+ pci_index, &pci_bus,
+ &pci_device_fn ) != 0 ) ) break;
+
pcibios_read_config_dword( pci_bus, pci_device_fn,
- PCI_BASE_ADDRESS_0, &ioaddr );
+ PCI_BASE_ADDRESS_0, &ioaddr );
- ioaddr &= ~3; /* remove I/O space marker in bit 0. */
+ ioaddr &= ~3; /* remove I/O space marker in bit 0. */
if ( check_region( ioaddr, HP100_REGION_SIZE ) ) continue;
pcibios_read_config_word( pci_bus, pci_device_fn,
- PCI_COMMAND, &pci_command );
+ PCI_COMMAND, &pci_command );
if ( !( pci_command & PCI_COMMAND_MASTER ) )
{
-#ifdef HP100_DEBUG_PCI
+#ifdef HP100_DEBUG
printk( "hp100: PCI Master Bit has not been set. Setting...\n" );
#endif
pci_command |= PCI_COMMAND_MASTER;
pcibios_write_config_word( pci_bus, pci_device_fn,
- PCI_COMMAND, pci_command );
+ PCI_COMMAND, pci_command );
}
-#ifdef HP100_DEBUG_PCI
+#ifdef HP100_DEBUG
printk( "hp100: PCI adapter found at 0x%x\n", ioaddr );
#endif
- if ( hp100_probe1( dev, ioaddr, HP100_BUS_PCI ) == 0 ) return 0;
+ if ( hp100_probe1( dev, ioaddr, HP100_BUS_PCI, pci_bus, pci_device_fn ) == 0 )
+ return 0;
}
}
if ( pci_start_index > 0 ) return -ENODEV;
#endif /* CONFIG_PCI */
- /* at second - probe all EISA possible port regions (if EISA bus present) */
-
+ /* Second: Probe all EISA possible port regions (if EISA bus present) */
for ( ioaddr = 0x1c38; EISA_bus && ioaddr < 0x10000; ioaddr += 0x400 )
{
if ( check_region( ioaddr, HP100_REGION_SIZE ) ) continue;
- if ( hp100_probe1( dev, ioaddr, HP100_BUS_EISA ) == 0 ) return 0;
+ if ( hp100_probe1( dev, ioaddr, HP100_BUS_EISA, 0, 0 ) == 0 ) return 0;
}
- /* at third - probe all ISA possible port regions */
-
+ /* Third Probe all ISA possible port regions */
for ( ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x20 )
{
if ( check_region( ioaddr, HP100_REGION_SIZE ) ) continue;
- if ( hp100_probe1( dev, ioaddr, HP100_BUS_ISA ) == 0 ) return 0;
+ if ( hp100_probe1( dev, ioaddr, HP100_BUS_ISA, 0, 0 ) == 0 ) return 0;
}
return -ENODEV;
}
-__initfunc(static int hp100_probe1( struct device *dev, int ioaddr, int bus ))
+
+__initfunc(static int hp100_probe1( struct device *dev, int ioaddr, u_char bus, u_char pci_bus, u_char pci_device_fn ))
{
int i;
+
u_char uc, uc_1;
u_int eisa_id;
+ u_int chip;
+ u_int memory_size = 0;
short mem_mapped;
- u_char *mem_ptr_phys, *mem_ptr_virt;
+ u_int *mem_ptr_phys, *mem_ptr_virt;
struct hp100_private *lp;
struct hp100_eisa_id *eid;
+#ifdef HP100_DEBUG_B
+ hp100_outw( 0x4201, TRACE );
+ printk("hp100: probe1\n");
+#endif
+
if ( dev == NULL )
{
#ifdef HP100_DEBUG
@@ -315,19 +380,27 @@ __initfunc(static int hp100_probe1( struct device *dev, int ioaddr, int bus ))
#endif
return EIO;
}
+
+ if ( hp100_inw( HW_ID ) != HP100_HW_ID_CASCADE )
+ {
+ return -ENODEV;
+ }
+ else
+ {
+ chip = hp100_inw( PAGING ) & HP100_CHIPID_MASK;
+#ifdef HP100_DEBUG
+ if ( chip == HP100_CHIPID_SHASTA )
+ printk("hp100: Shasta Chip detected. (This is a pre 802.12 chip)\n");
+ else if ( chip == HP100_CHIPID_RAINIER )
+ printk("hp100: Rainier Chip detected. (This is a pre 802.12 chip)\n");
+ else if ( chip == HP100_CHIPID_LASSEN )
+ printk("hp100: Lassen Chip detected.\n");
+ else
+ printk("hp100: Warning: Unknown CASCADE chip (id=0x%.4x).\n",chip);
+#endif
+ }
- if ( bus != HP100_BUS_PCI ) /* don't check PCI cards again */
- if ( inb( ioaddr + 0 ) != HP100_HW_ID_0 ||
- inb( ioaddr + 1 ) != HP100_HW_ID_1 ||
- ( inb( ioaddr + 2 ) & 0xf0 ) != HP100_HW_ID_2_REVA ||
- inb( ioaddr + 3 ) != HP100_HW_ID_3 )
- return -ENODEV;
-
- dev -> base_addr = ioaddr;
-
-#ifdef HP100_DEBUG_PROBE1
- printk( "hp100_probe1: card found at port 0x%x\n", ioaddr );
-#endif
+ dev->base_addr = ioaddr;
hp100_page( ID_MAC_ADDR );
for ( i = uc = eisa_id = 0; i < 4; i++ )
@@ -339,17 +412,13 @@ __initfunc(static int hp100_probe1( struct device *dev, int ioaddr, int bus ))
}
uc += hp100_inb( BOARD_ID + 4 );
-#ifdef HP100_DEBUG_PROBE1
- printk( "hp100_probe1: EISA ID = 0x%08x checksum = 0x%02x\n", eisa_id, uc );
-#endif
-
- if ( uc != 0xff ) /* bad checksum? */
+ if ( uc != 0xff ) /* bad checksum? */
{
- printk( "hp100_probe: bad EISA ID checksum at base port 0x%x\n", ioaddr );
+ printk("hp100_probe: bad EISA ID checksum at base port 0x%x\n", ioaddr );
return -ENODEV;
}
- for ( i = 0; i < sizeof( hp100_eisa_ids ) / sizeof( struct hp100_eisa_id ); i++ )
+ for ( i=0; i<sizeof(hp100_eisa_ids)/sizeof(struct hp100_eisa_id); i++)
if ( ( hp100_eisa_ids[ i ].id & 0xf0ffffff ) == ( eisa_id & 0xf0ffffff ) )
break;
if ( i >= sizeof( hp100_eisa_ids ) / sizeof( struct hp100_eisa_id ) )
@@ -358,10 +427,10 @@ __initfunc(static int hp100_probe1( struct device *dev, int ioaddr, int bus ))
return -ENODEV;
}
eid = &hp100_eisa_ids[ i ];
- if ( ( eid -> id & 0x0f000000 ) < ( eisa_id & 0x0f000000 ) )
+ if ( ( eid->id & 0x0f000000 ) < ( eisa_id & 0x0f000000 ) )
{
printk( "hp100_probe1: newer version of card %s at port 0x%x - unsupported\n",
- eid -> name, ioaddr );
+ eid->name, ioaddr );
return -ENODEV;
}
@@ -369,461 +438,1592 @@ __initfunc(static int hp100_probe1( struct device *dev, int ioaddr, int bus ))
uc += hp100_inb( LAN_ADDR + i );
if ( uc != 0xff )
{
- printk( "hp100_probe1: bad lan address checksum (card %s at port 0x%x)\n",
- eid -> name, ioaddr );
+ printk("hp100_probe1: bad lan address checksum (card %s at port 0x%x)\n",
+ eid->name, ioaddr );
return -EIO;
}
-#ifndef HP100_IO_MAPPED
+ /* Determine driver operation mode
+ *
+ * Use the variable "hp100_mode" upon insmod or as kernel parameter to
+ * force driver modes:
+ * hp100_mode=1 -> default, use busmaster mode if configured.
+ * hp100_mode=2 -> enable shared memory mode
+ * hp100_mode=3 -> force use of i/o mapped mode.
+ * hp100_mode=4 -> same as 1, but re-set the enable bit on the card.
+ */
+
+ if(hp100_mode==3)
+ {
+ hp100_outw(HP100_MEM_EN|HP100_RESET_LB, OPTION_LSW);
+ hp100_outw(HP100_IO_EN|HP100_SET_LB, OPTION_LSW);
+ hp100_outw(HP100_BM_WRITE|HP100_BM_READ|HP100_RESET_HB, OPTION_LSW);
+ printk("hp100: IO mapped mode forced.\n");
+ }
+ else if(hp100_mode==2)
+ {
+ hp100_outw(HP100_MEM_EN|HP100_SET_LB, OPTION_LSW);
+ hp100_outw(HP100_IO_EN |HP100_SET_LB, OPTION_LSW);
+ hp100_outw(HP100_BM_WRITE|HP100_BM_READ|HP100_RESET_HB, OPTION_LSW);
+ printk("hp100: Shared memory mode requested.\n");
+ }
+ else if(hp100_mode==4)
+ {
+ if(chip==HP100_CHIPID_LASSEN)
+ {
+ hp100_outw(HP100_BM_WRITE|
+ HP100_BM_READ | HP100_SET_HB, OPTION_LSW);
+ hp100_outw(HP100_IO_EN |
+ HP100_MEM_EN | HP100_RESET_LB, OPTION_LSW);
+ printk("hp100: Busmaster mode requested.\n");
+ }
+ hp100_mode=1;
+ }
+
+ if(hp100_mode==1) /* default behaviour */
+ {
+ if( (hp100_inw(OPTION_LSW)&HP100_IO_EN) &&
+ (~hp100_inw(OPTION_LSW)&HP100_MEM_EN) &&
+ (~hp100_inw(OPTION_LSW)&(HP100_BM_WRITE|HP100_BM_READ))
+ )
+ {
+#ifdef HP100_DEBUG
+ printk("hp100: IO_EN bit is set on card.\n");
+#endif
+ hp100_mode=3;
+ }
+ else if( ( chip==HP100_CHIPID_LASSEN ) &&
+ ( (hp100_inw(OPTION_LSW)&(HP100_BM_WRITE|HP100_BM_READ) ) ==
+ (HP100_BM_WRITE|HP100_BM_READ) ) )
+ {
+ printk("hp100: Busmaster mode enabled.\n");
+ hp100_outw(HP100_MEM_EN|HP100_IO_EN|HP100_RESET_LB, OPTION_LSW);
+ }
+ else
+ {
+#ifdef HP100_DEBUG
+ printk("hp100: Card not configured for BM or BM not supported with this card. Trying shared memory mode.\n");
+#endif
+ /* In this case, try shared memory mode */
+ hp100_mode=2;
+ hp100_outw(HP100_MEM_EN|HP100_SET_LB, OPTION_LSW);
+ /* hp100_outw(HP100_IO_EN|HP100_RESET_LB, OPTION_LSW); */
+ }
+ }
+
+ /* Check for shared memory on the card, eventually remap it */
hp100_page( HW_MAP );
- mem_mapped = ( hp100_inw( OPTION_LSW ) &
- ( HP100_MEM_EN | HP100_BM_WRITE | HP100_BM_READ ) ) != 0;
+ mem_mapped = (( hp100_inw( OPTION_LSW ) & ( HP100_MEM_EN ) ) != 0);
mem_ptr_phys = mem_ptr_virt = NULL;
- if ( mem_mapped )
+ memory_size = (8192<<( (hp100_inb(SRAM)>>5)&0x07));
+
+ /* For memory mapped or busmaster mode, we want the memory address */
+ if ( mem_mapped || (hp100_mode==1))
{
- mem_ptr_phys = (u_char *)( hp100_inw( MEM_MAP_LSW ) |
- ( hp100_inw( MEM_MAP_MSW ) << 16 ) );
- (u_int)mem_ptr_phys &= ~0x1fff; /* 8k alignment */
+ mem_ptr_phys = (u_int *)( hp100_inw( MEM_MAP_LSW ) |
+ ( hp100_inw( MEM_MAP_MSW ) << 16 ) );
+ (u_int)mem_ptr_phys &= ~0x1fff; /* 8k alignment */
+
if ( bus == HP100_BUS_ISA && ( (u_long)mem_ptr_phys & ~0xfffff ) != 0 )
{
+ printk("hp100: Can only use programmed i/o mode.\n");
mem_ptr_phys = NULL;
mem_mapped = 0;
+ hp100_mode=3; /* Use programmed i/o */
}
- if ( mem_mapped && bus == HP100_BUS_PCI )
- {
- if ( ( mem_ptr_virt = ioremap( (u_long)mem_ptr_phys, 0x2000 ) ) == NULL )
- {
- printk( "hp100: ioremap for high PCI memory at 0x%lx failed\n", (u_long)mem_ptr_phys );
- mem_ptr_phys = NULL;
- mem_mapped = 0;
- }
- }
- }
-#else
- mem_mapped = 0;
- mem_ptr_phys = mem_ptr_virt = NULL;
+
+ /* We do not need access to shared memory in busmaster mode */
+ /* However in slave mode we need to remap high (>1GB) card memory */
+ if(hp100_mode!=1) /* = not busmaster */
+ {
+ if ( bus == HP100_BUS_PCI )
+ {
+ /* We try with smaller memory sizes, if ioremap fails */
+ for(; memory_size>16383; memory_size=memory_size/2)
+ {
+ if((mem_ptr_virt=ioremap((u_long)mem_ptr_phys,memory_size))==NULL)
+ {
+#ifdef HP100_DEBUG
+ printk( "hp100: ioremap for 0x%x bytes high PCI memory at 0x%lx failed\n", memory_size, (u_long)mem_ptr_phys );
+#endif
+ }
+ else
+ {
+#ifdef HP100_DEBUG
+ printk( "hp100: remapped 0x%x bytes high PCI memory at 0x%lx to 0x%lx.\n", memory_size, (u_long)mem_ptr_phys, (u_long)mem_ptr_virt);
#endif
+ break;
+ }
+ }
+
+ if(mem_ptr_virt==NULL) /* all ioremap tries failed */
+ {
+ printk("hp100: Failed to ioremap the PCI card memory. Will have to use i/o mapped mode.\n");
+ hp100_mode=3;
+ memory_size = (8192<<( (hp100_inb(SRAM)>>5)&0x07) );
+ }
+ }
+ }
+
+ }
- if ( ( dev -> priv = kmalloc( sizeof( struct hp100_private ), GFP_KERNEL ) ) == NULL )
- return -ENOMEM;
- memset( dev -> priv, 0, sizeof( struct hp100_private ) );
+ if(hp100_mode==3) /* io mapped forced */
+ {
+ mem_mapped = 0;
+ mem_ptr_phys = mem_ptr_virt = NULL;
+ printk("hp100: Using (slow) programmed i/o mode.\n");
+ }
- lp = (struct hp100_private *)dev -> priv;
- lp -> id = eid;
- lp -> mem_mapped = mem_mapped;
- lp -> mem_ptr_phys = mem_ptr_phys;
- lp -> mem_ptr_virt = mem_ptr_virt;
+ /* Initialise the "private" data structure for this card. */
+ if ( (dev->priv=kmalloc(sizeof(struct hp100_private), GFP_KERNEL)) == NULL)
+ return -ENOMEM;
+ memset( dev->priv, 0, sizeof(struct hp100_private) );
+
+ lp = (struct hp100_private *)dev->priv;
+ lp->id = eid;
+ lp->chip = chip;
+ lp->mode = hp100_mode;
+ lp->pci_bus = pci_bus;
+ lp->bus = bus;
+ lp->pci_device_fn = pci_device_fn;
+ lp->priority_tx = hp100_priority_tx;
+ lp->rx_ratio = hp100_rx_ratio;
+ lp->mem_ptr_phys = mem_ptr_phys;
+ lp->mem_ptr_virt = mem_ptr_virt;
hp100_page( ID_MAC_ADDR );
- lp -> soft_model = hp100_inb( SOFT_MODEL );
- lp -> mac1_mode = HP100_MAC1MODE3;
- lp -> mac2_mode = HP100_MAC2MODE3;
+ lp->soft_model = hp100_inb( SOFT_MODEL );
+ lp->mac1_mode = HP100_MAC1MODE3;
+ lp->mac2_mode = HP100_MAC2MODE3;
- dev -> base_addr = ioaddr;
- hp100_page( HW_MAP );
- dev -> irq = hp100_inb( IRQ_CHANNEL ) & HP100_IRQ_MASK;
- if ( dev -> irq == 2 ) dev -> irq = 9;
- lp -> memory_size = 0x200 << ( ( hp100_inb( SRAM ) & 0xe0 ) >> 5 );
- lp -> rx_ratio = hp100_rx_ratio;
+ dev->base_addr = ioaddr;
+
+ lp->memory_size = memory_size;
+ lp->rx_ratio = hp100_rx_ratio; /* can be conf'd with insmod */
+
+ /* memory region for programmed i/o */
+ request_region( dev->base_addr, HP100_REGION_SIZE, eid->name );
+
+ dev->open = hp100_open;
+ dev->stop = hp100_close;
- dev -> open = hp100_open;
- dev -> stop = hp100_close;
- dev -> hard_start_xmit = hp100_start_xmit;
- dev -> get_stats = hp100_get_stats;
- dev -> set_multicast_list = &hp100_set_multicast_list;
+ if (lp->mode==1) /* busmaster */
+ dev->hard_start_xmit = hp100_start_xmit_bm;
+ else
+ dev->hard_start_xmit = hp100_start_xmit;
- request_region( dev -> base_addr, HP100_REGION_SIZE, eid -> name );
+ dev->get_stats = hp100_get_stats;
+ dev->set_multicast_list = &hp100_set_multicast_list;
+ /* Ask the card for which IRQ line it is configured */
+ hp100_page( HW_MAP );
+ dev->irq = hp100_inb( IRQ_CHANNEL ) & HP100_IRQMASK;
+ if ( dev->irq == 2 )
+ dev->irq = 9;
+
+ if(lp->mode==1) /* busmaster */
+ dev->dma=4;
+
+ /* Ask the card for its MAC address and store it for later use. */
hp100_page( ID_MAC_ADDR );
for ( i = uc = 0; i < 6; i++ )
- dev -> dev_addr[ i ] = hp100_inb( LAN_ADDR + i );
+ dev->dev_addr[ i ] = hp100_inb( LAN_ADDR + i );
+ /* Reset statistics (counters) */
hp100_clear_stats( ioaddr );
ether_setup( dev );
- lp -> lan_type = hp100_sense_lan( dev );
+ /* If busmaster mode is wanted, a dma-capable memory area is needed for
+ * the rx and tx PDLs
+ * PCI cards can access the whole PC memory. Therefore GFP_DMA is not
+ * needed for the allocation of the memory area.
+ */
- printk( "%s: %s at 0x%x, IRQ %d, ",
- dev -> name, lp -> id -> name, ioaddr, dev -> irq );
+ /* TODO: We do not need this with old cards, where PDLs are stored
+ * in the cards shared memory area. But currently, busmaster has been
+ * implemented/tested only with the lassen chip anyway... */
+ if(lp->mode==1) /* busmaster */
+ {
+ /* Get physically continous memory for TX & RX PDLs */
+ if ( (lp->page_vaddr=kmalloc(MAX_RINGSIZE+0x0f,GFP_KERNEL) ) == NULL)
+ return -ENOMEM;
+ lp->page_vaddr_algn=((u_int *) ( ((u_int)(lp->page_vaddr)+0x0f) &~0x0f));
+ memset(lp->page_vaddr, 0, MAX_RINGSIZE+0x0f);
+
+#ifdef HP100_DEBUG_BM
+ printk("hp100: Reserved DMA memory from 0x%x to 0x%x\n",
+ (u_int)lp->page_vaddr_algn,
+ (u_int)lp->page_vaddr_algn+MAX_RINGSIZE);
+#endif
+ lp->rxrcommit = lp->txrcommit = 0;
+ lp->rxrhead = lp->rxrtail = &(lp->rxring[0]);
+ lp->txrhead = lp->txrtail = &(lp->txring[0]);
+ }
+
+ /* Initialise the card. */
+ /* (I'm not really sure if it's a good idea to do this during probing, but
+ * like this it's assured that the lan connection type can be sensed
+ * correctly)
+ */
+ hp100_hwinit( dev );
+
+ /* Try to find out which kind of LAN the card is connected to. */
+ lp->lan_type = hp100_sense_lan( dev );
+
+ /* Print out a message what about what we think we have probed. */
+ printk( "hp100: %s: %s at 0x%x, IRQ %d, ",
+ dev->name, lp->id->name, ioaddr, dev->irq );
switch ( bus ) {
- case HP100_BUS_EISA: printk( "EISA" ); break;
- case HP100_BUS_PCI: printk( "PCI" ); break;
- default: printk( "ISA" ); break;
+ case HP100_BUS_EISA: printk( "EISA" ); break;
+ case HP100_BUS_PCI: printk( "PCI" ); break;
+ default: printk( "ISA" ); break;
}
printk( " bus, %dk SRAM (rx/tx %d%%).\n",
- lp -> memory_size >> ( 10 - 4 ), lp -> rx_ratio );
- if ( mem_mapped )
+ lp->memory_size >> 10, lp->rx_ratio );
+
+ if ( lp->mode==2 ) /* memory mapped */
{
printk( "%s: Memory area at 0x%lx-0x%lx",
- dev -> name, (u_long)mem_ptr_phys, (u_long)mem_ptr_phys + 0x1fff );
+ dev->name,(u_long)mem_ptr_phys,(u_long)mem_ptr_phys+(u_long)lp->memory_size );
if ( mem_ptr_virt )
- printk( " (virtual base 0x%lx)", (u_long)mem_ptr_virt );
+ printk( " (virtual base 0x%lx)", (u_long)mem_ptr_virt );
printk( ".\n" );
+
+ /* Set for info when doing ifconfig */
+ dev->mem_start = (u_long)mem_ptr_phys;
+ dev->mem_end = (u_long)mem_ptr_phys+(u_long)lp->memory_size;
}
- printk( "%s: ", dev -> name );
- if ( lp -> lan_type != HP100_LAN_ERR )
+ printk( "%s: ", dev->name );
+ if ( lp->lan_type != HP100_LAN_ERR )
printk( "Adapter is attached to " );
- switch ( lp -> lan_type ) {
- case HP100_LAN_100:
- printk( "100Mb/s Voice Grade AnyLAN network.\n" );
- break;
- case HP100_LAN_10:
- printk( "10Mb/s network.\n" );
- break;
- default:
- printk( "Warning! Link down.\n" );
+ switch ( lp->lan_type ) {
+ case HP100_LAN_100:
+ printk( "100Mb/s Voice Grade AnyLAN network.\n" );
+ break;
+ case HP100_LAN_10:
+ printk( "10Mb/s network.\n" );
+ break;
+ default:
+ printk( "Warning! Link down.\n" );
}
+ return 0;
+}
- hp100_stop_interface( dev );
+
+/* This procedure puts the card into a stable init state */
+static void hp100_hwinit( struct device *dev )
+{
+ int ioaddr = dev->base_addr;
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
- return 0;
+#ifdef HP100_DEBUG_B
+ hp100_outw( 0x4202, TRACE );
+ printk("hp100: hwinit\n");
+#endif
+
+ /* Initialise the card. -------------------------------------------- */
+
+ /* Clear all pending Ints and disable Ints */
+ hp100_page( PERFORMANCE );
+ hp100_outw( 0xfefe, IRQ_MASK ); /* mask off all ints */
+ hp100_outw( 0xffff, IRQ_STATUS ); /* clear all pending ints */
+
+ hp100_outw( HP100_INT_EN | HP100_RESET_LB, OPTION_LSW );
+ hp100_outw( HP100_TRI_INT | HP100_SET_HB, OPTION_LSW );
+
+ if(lp->mode==1)
+ {
+ hp100_BM_shutdown( dev ); /* disables BM, puts cascade in reset */
+ wait();
+ }
+ else
+ {
+ hp100_outw( HP100_INT_EN | HP100_RESET_LB, OPTION_LSW );
+ hp100_cascade_reset( dev, TRUE );
+ hp100_page( MAC_CTRL );
+ hp100_andb( ~(HP100_RX_EN|HP100_TX_EN), MAC_CFG_1);
+ }
+
+ /* Initiate EEPROM reload */
+ hp100_load_eeprom( dev );
+
+ wait();
+
+ /* Go into reset again. */
+ hp100_cascade_reset( dev, TRUE );
+
+ /* Set Option Registers to a safe state */
+ hp100_outw( HP100_DEBUG_EN |
+ HP100_RX_HDR |
+ HP100_EE_EN |
+ HP100_BM_WRITE |
+ HP100_BM_READ | HP100_RESET_HB |
+ HP100_FAKE_INT |
+ HP100_INT_EN |
+ HP100_MEM_EN |
+ HP100_IO_EN | HP100_RESET_LB, OPTION_LSW);
+
+ hp100_outw( HP100_TRI_INT |
+ HP100_MMAP_DIS | HP100_SET_HB, OPTION_LSW );
+
+ hp100_outb( HP100_PRIORITY_TX |
+ HP100_ADV_NXT_PKT |
+ HP100_TX_CMD | HP100_RESET_LB, OPTION_MSW );
+
+ /* TODO: Configure MMU for Ram Test. */
+ /* TODO: Ram Test. */
+
+ /* Re-check if adapter is still at same i/o location */
+ /* (If the base i/o in eeprom has been changed but the */
+ /* registers had not been changed, a reload of the eeprom */
+ /* would move the adapter to the address stored in eeprom */
+
+ /* TODO: Code to implement. */
+
+ /* Until here it was code from HWdiscover procedure. */
+ /* Next comes code from mmuinit procedure of SCO BM driver which is
+ * called from HWconfigure in the SCO driver. */
+
+ /* Initialise MMU, eventually switch on Busmaster Mode, initialise
+ * multicast filter...
+ */
+ hp100_mmuinit( dev );
+
+ /* We don't turn the interrupts on here - this is done by start_interface. */
+ wait(); /* TODO: Do we really need this? */
+
+ /* Enable Hardware (e.g. unreset) */
+ hp100_cascade_reset( dev, FALSE );
+
+ /* ------- initialisation complete ----------- */
+
+ /* Finally try to log in the Hub if there may be a VG connection. */
+ if( lp->lan_type != HP100_LAN_10 )
+ hp100_login_to_vg_hub( dev, FALSE ); /* relogin */
}
-/*
- * open/close functions
+
+/*
+ * mmuinit - Reinitialise Cascade MMU and MAC settings.
+ * Note: Must already be in reset and leaves card in reset.
*/
-
-static int hp100_open( struct device *dev )
+static void hp100_mmuinit( struct device *dev )
{
+ int ioaddr = dev->base_addr;
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
int i;
- int ioaddr = dev -> base_addr;
- struct hp100_private *lp = (struct hp100_private *)dev -> priv;
- if ( request_irq( dev -> irq, hp100_interrupt, SA_INTERRUPT, lp -> id -> name, NULL ) )
+#ifdef HP100_DEBUG_B
+ hp100_outw( 0x4203, TRACE );
+ printk("hp100: mmuinit\n");
+#endif
+
+#ifdef HP100_DEBUG
+ if( 0!=(hp100_inw(OPTION_LSW)&HP100_HW_RST) )
{
- printk( "%s: unable to get IRQ %d\n", dev -> name, dev -> irq );
- return -EAGAIN;
+ printk("hp100: Not in reset when entering mmuinit. Fix me.\n");
+ return;
}
- irq2dev_map[ dev -> irq ] = dev;
-
- MOD_INC_USE_COUNT;
+#endif
- dev -> tbusy = 0;
- dev -> trans_start = jiffies;
- dev -> interrupt = 0;
- dev -> start = 1;
+ /* Make sure IRQs are masked off and ack'ed. */
+ hp100_page( PERFORMANCE );
+ hp100_outw( 0xfefe, IRQ_MASK ); /* mask off all ints */
+ hp100_outw( 0xffff, IRQ_STATUS ); /* ack IRQ */
+
+ /*
+ * Enable Hardware
+ * - Clear Debug En, Rx Hdr Pipe, EE En, I/O En, Fake Int and Intr En
+ * - Set Tri-State Int, Bus Master Rd/Wr, and Mem Map Disable
+ * - Clear Priority, Advance Pkt and Xmit Cmd
+ */
+
+ hp100_outw( HP100_DEBUG_EN |
+ HP100_RX_HDR |
+ HP100_EE_EN | HP100_RESET_HB |
+ HP100_IO_EN |
+ HP100_FAKE_INT |
+ HP100_INT_EN | HP100_RESET_LB, OPTION_LSW );
+
+ hp100_outw( HP100_TRI_INT | HP100_SET_HB, OPTION_LSW);
+
+ if(lp->mode==1) /* busmaster */
+ {
+ hp100_outw( HP100_BM_WRITE |
+ HP100_BM_READ |
+ HP100_MMAP_DIS | HP100_SET_HB, OPTION_LSW );
+ }
+ else if(lp->mode==2) /* memory mapped */
+ {
+ hp100_outw( HP100_BM_WRITE |
+ HP100_BM_READ | HP100_RESET_HB, OPTION_LSW );
+ hp100_outw( HP100_MMAP_DIS | HP100_RESET_HB, OPTION_LSW );
+ hp100_outw( HP100_MEM_EN | HP100_SET_LB, OPTION_LSW );
+ hp100_outw( HP100_IO_EN | HP100_SET_LB, OPTION_LSW );
+ }
+ else if( lp->mode==3 ) /* i/o mapped mode */
+ {
+ hp100_outw( HP100_MMAP_DIS | HP100_SET_HB |
+ HP100_IO_EN | HP100_SET_LB, OPTION_LSW );
+ }
- lp -> lan_type = hp100_sense_lan( dev );
- lp -> mac1_mode = HP100_MAC1MODE3;
- lp -> mac2_mode = HP100_MAC2MODE3;
+ hp100_page( HW_MAP );
+ hp100_outb( 0, EARLYRXCFG );
+ hp100_outw( 0, EARLYTXCFG );
+
+ /*
+ * Enable Bus Master mode
+ */
+ if(lp->mode==1) /* busmaster */
+ {
+ /* Experimental: Set some PCI configuration bits */
+ hp100_page( HW_MAP );
+ hp100_andb( ~HP100_PDL_USE3, MODECTRL1 ); /* BM engine read maximum */
+ hp100_andb( ~HP100_TX_DUALQ, MODECTRL1 ); /* No Queue for Priority TX */
+
+ /* PCI Bus failures should result in a Misc. Interrupt */
+ hp100_orb( HP100_EN_BUS_FAIL, MODECTRL2);
+
+ hp100_outw( HP100_BM_READ | HP100_BM_WRITE | HP100_SET_HB, OPTION_LSW );
+ hp100_page( HW_MAP );
+ /* Use Burst Mode and switch on PAGE_CK */
+ hp100_orb( HP100_BM_BURST_RD |
+ HP100_BM_BURST_WR, BM);
+ if((lp->chip==HP100_CHIPID_RAINIER)||(lp->chip==HP100_CHIPID_SHASTA))
+ hp100_orb( HP100_BM_PAGE_CK, BM );
+ hp100_orb( HP100_BM_MASTER, BM );
+ }
+ else /* not busmaster */
+ {
+ hp100_page(HW_MAP);
+ hp100_andb(~HP100_BM_MASTER, BM );
+ }
- hp100_page( MAC_CTRL );
- hp100_orw( HP100_LINK_BEAT_DIS | HP100_RESET_LB, LAN_CFG_10 );
+ /*
+ * Divide card memory into regions for Rx, Tx and, if non-ETR chip, PDLs
+ */
+ hp100_page( MMU_CFG );
+ if(lp->mode==1) /* only needed for Busmaster */
+ {
+ int xmit_stop, recv_stop;
- hp100_stop_interface( dev );
- hp100_load_eeprom( dev );
+ if((lp->chip==HP100_CHIPID_RAINIER)||(lp->chip==HP100_CHIPID_SHASTA))
+ {
+ int pdl_stop;
+
+ /*
+ * Each pdl is 508 bytes long. (63 frags * 4 bytes for address and
+ * 4 bytes for for header). We will leave NUM_RXPDLS * 508 (rounded
+ * to the next higher 1k boundary) bytes for the rx-pdl's
+ * Note: For non-etr chips the transmit stop register must be
+ * programmed on a 1k boundary, i.e. bits 9:0 must be zero.
+ */
+ pdl_stop = lp->memory_size;
+ xmit_stop = ( pdl_stop-508*(MAX_RX_PDL)-16 )& ~(0x03ff);
+ recv_stop = ( xmit_stop * (lp->rx_ratio)/100 ) &~(0x03ff);
+ hp100_outw( (pdl_stop>>4)-1, PDL_MEM_STOP );
+#ifdef HP100_DEBUG_BM
+ printk("hp100: PDL_STOP = 0x%x\n", pdl_stop);
+#endif
+ }
+ else /* ETR chip (Lassen) in busmaster mode */
+ {
+ xmit_stop = ( lp->memory_size ) - 1;
+ recv_stop = ( ( lp->memory_size * lp->rx_ratio ) / 100 ) & ~(0x03ff);
+ }
- hp100_outw( HP100_MMAP_DIS | HP100_SET_HB |
- HP100_IO_EN | HP100_SET_LB, OPTION_LSW );
- hp100_outw( HP100_DEBUG_EN | HP100_RX_HDR | HP100_EE_EN | HP100_RESET_HB |
- HP100_FAKE_INT | HP100_RESET_LB, OPTION_LSW );
- hp100_outw( HP100_ADV_NXT_PKT | HP100_TX_CMD | HP100_RESET_LB |
- HP100_PRIORITY_TX | ( hp100_priority_tx ? HP100_SET_HB : HP100_RESET_HB ),
- OPTION_MSW );
+ hp100_outw( xmit_stop>>4 , TX_MEM_STOP );
+ hp100_outw( recv_stop>>4 , RX_MEM_STOP );
+#ifdef HP100_DEBUG_BM
+ printk("hp100: TX_STOP = 0x%x\n",xmit_stop>>4);
+ printk("hp100: RX_STOP = 0x%x\n",recv_stop>>4);
+#endif
+ }
+ else /* Slave modes (memory mapped and programmed io) */
+ {
+ hp100_outw( (((lp->memory_size*lp->rx_ratio)/100)>>4), RX_MEM_STOP );
+ hp100_outw( ((lp->memory_size - 1 )>>4), TX_MEM_STOP );
+#ifdef HP100_DEBUG
+ printk("hp100: TX_MEM_STOP: 0x%x\n", hp100_inw(TX_MEM_STOP));
+ printk("hp100: RX_MEM_STOP: 0x%x\n", hp100_inw(RX_MEM_STOP));
+#endif
+ }
+ /* Write MAC address into page 1 */
hp100_page( MAC_ADDRESS );
for ( i = 0; i < 6; i++ )
- hp100_outb( dev -> dev_addr[ i ], MAC_ADDR + i );
- for ( i = 0; i < 8; i++ ) /* setup multicast filter to receive all */
- hp100_outb( 0xff, HASH_BYTE0 + i );
+ hp100_outb( dev->dev_addr[ i ], MAC_ADDR + i );
+
+ /* Zero the multicast hash registers */
+ for ( i = 0; i < 8; i++ )
+ hp100_outb( 0x0, HASH_BYTE0 + i );
+
+ /* Set up MAC defaults */
+ hp100_page( MAC_CTRL );
+
+ /* Go to LAN Page and zero all filter bits */
+ /* Zero accept error, accept multicast, accept broadcast and accept */
+ /* all directed packet bits */
+ hp100_andb( ~(HP100_RX_EN|
+ HP100_TX_EN|
+ HP100_ACC_ERRORED|
+ HP100_ACC_MC|
+ HP100_ACC_BC|
+ HP100_ACC_PHY), MAC_CFG_1 );
+
+ hp100_outb( 0x00, MAC_CFG_2 );
+
+ /* Zero the frame format bit. This works around a training bug in the */
+ /* new hubs. */
+ hp100_outb( 0x00, VG_LAN_CFG_2); /* (use 802.3) */
+
+ if(lp->priority_tx)
+ hp100_outb( HP100_PRIORITY_TX | HP100_SET_LB, OPTION_MSW );
+ else
+ hp100_outb( HP100_PRIORITY_TX | HP100_RESET_LB, OPTION_MSW );
+
+ hp100_outb( HP100_ADV_NXT_PKT |
+ HP100_TX_CMD | HP100_RESET_LB, OPTION_MSW );
+
+ /* If busmaster, initialize the PDLs */
+ if(lp->mode==1)
+ hp100_init_pdls( dev );
+
+ /* Go to performance page and initalize isr and imr registers */
hp100_page( PERFORMANCE );
- hp100_outw( 0xfefe, IRQ_MASK ); /* mask off all ints */
- hp100_outw( 0xffff, IRQ_STATUS ); /* ack IRQ */
- hp100_outw( (HP100_RX_PACKET | HP100_RX_ERROR | HP100_SET_HB) |
- (HP100_TX_ERROR | HP100_SET_LB ), IRQ_MASK );
- /* and enable few */
- hp100_reset_card();
- hp100_page( MMU_CFG );
- hp100_outw( ( lp -> memory_size * lp -> rx_ratio ) / 100, RX_MEM_STOP );
- hp100_outw( lp -> memory_size - 1, TX_MEM_STOP );
- hp100_unreset_card();
+ hp100_outw( 0xfefe, IRQ_MASK ); /* mask off all ints */
+ hp100_outw( 0xffff, IRQ_STATUS ); /* ack IRQ */
+}
+
+
+/*
+ * open/close functions
+ */
+
+static int hp100_open( struct device *dev )
+{
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
+#ifdef HP100_DEBUG_B
+ int ioaddr=dev->base_addr;
+#endif
+
+#ifdef HP100_DEBUG_B
+ hp100_outw( 0x4204, TRACE );
+ printk("hp100: open\n");
+#endif
+
+ /* New: if bus is PCI or EISA, interrupts might be shared interrupts */
+ if((lp->bus==HP100_BUS_PCI)||(lp->bus==HP100_BUS_EISA))
+ {
+ if(request_irq(dev->irq,hp100_interrupt,SA_SHIRQ,lp->id->name,dev))
+ {
+ printk( "%s: unable to get IRQ %d\n", dev->name, dev->irq );
+ return -EAGAIN;
+ }
+ }
+ else
+ if(request_irq(dev->irq, hp100_interrupt, SA_INTERRUPT, lp->id->name, NULL))
+ {
+ printk( "%s: unable to get IRQ %d\n", dev->name, dev->irq );
+ return -EAGAIN;
+ }
+
+ irq2dev_map[ dev->irq ] = dev;
+
+ MOD_INC_USE_COUNT;
- if ( lp -> lan_type == HP100_LAN_100 )
- lp -> hub_status = hp100_login_to_vg_hub( dev );
+ dev->tbusy = 0;
+ dev->trans_start = jiffies;
+ dev->interrupt = 0;
+ dev->start = 1;
- hp100_start_interface( dev );
+ lp->lan_type = hp100_sense_lan( dev );
+ lp->mac1_mode = HP100_MAC1MODE3;
+ lp->mac2_mode = HP100_MAC2MODE3;
+
+ hp100_stop_interface( dev );
+
+ hp100_hwinit( dev );
+
+ hp100_start_interface( dev ); /* sets mac modes, enables interrupts */
return 0;
}
+
+/* The close function is called when the interface is to be brought down */
static int hp100_close( struct device *dev )
{
- int ioaddr = dev -> base_addr;
- struct hp100_private *lp = (struct hp100_private *)dev -> priv;
+ int ioaddr = dev->base_addr;
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
+
+#ifdef HP100_DEBUG_B
+ hp100_outw( 0x4205, TRACE );
+ printk("hp100:close\n");
+#endif
hp100_page( PERFORMANCE );
- hp100_outw( 0xfefe, IRQ_MASK ); /* mask off all IRQs */
+ hp100_outw( 0xfefe, IRQ_MASK ); /* mask off all IRQs */
hp100_stop_interface( dev );
- if ( lp -> lan_type == HP100_LAN_100 ) /* relogin */
- hp100_login_to_vg_hub( dev );
+ if ( lp->lan_type == HP100_LAN_100 )
+ lp->hub_status=hp100_login_to_vg_hub( dev, FALSE );
- dev -> tbusy = 1;
- dev -> start = 0;
+ dev->tbusy = 1;
+ dev->start = 0;
- free_irq( dev -> irq, NULL );
- irq2dev_map[ dev -> irq ] = NULL;
+ if ((lp->bus==HP100_BUS_PCI)||(lp->bus==HP100_BUS_EISA))
+ free_irq( dev->irq, dev );
+ else
+ free_irq( dev->irq, NULL );
+ irq2dev_map[ dev->irq ] = NULL;
MOD_DEC_USE_COUNT;
return 0;
}
+
+/*
+ * Configure the PDL Rx rings and LAN
+ */
+static void hp100_init_pdls( struct device *dev )
+{
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
+ hp100_ring_t *ringptr;
+ u_int *pageptr;
+ int i;
+
+#ifdef HP100_DEBUG_B
+ int ioaddr = dev->base_addr;
+#endif
+
+#ifdef HP100_DEBUG_B
+ hp100_outw( 0x4206, TRACE );
+ printk("hp100: init pdls\n");
+#endif
+
+ if(0==lp->page_vaddr_algn)
+ printk("hp100: Warning: lp->page_vaddr_algn not initialised!\n");
+ else
+ {
+ /* pageptr shall point into the DMA accessible memory region */
+ /* we use this pointer to status the upper limit of allocated */
+ /* memory in the allocated page. */
+ /* note: align the pointers to the pci cache line size */
+ memset(lp->page_vaddr_algn, 0, MAX_RINGSIZE); /* Zero Rx/Tx ring page */
+ pageptr=lp->page_vaddr_algn;
+
+ lp->rxrcommit =0;
+ ringptr = lp->rxrhead = lp-> rxrtail = &(lp->rxring[0]);
+
+ /* Initialise Rx Ring */
+ for (i=MAX_RX_PDL-1; i>=0; i--)
+ {
+ lp->rxring[i].next = ringptr;
+ ringptr=&(lp->rxring[i]);
+ pageptr+=hp100_init_rxpdl(ringptr, pageptr);
+ }
+
+ /* Initialise Tx Ring */
+ lp->txrcommit = 0;
+ ringptr = lp->txrhead = lp->txrtail = &(lp->txring[0]);
+ for (i=MAX_TX_PDL-1; i>=0; i--)
+ {
+ lp->txring[i].next = ringptr;
+ ringptr=&(lp->txring[i]);
+ pageptr+=hp100_init_txpdl(ringptr, pageptr);
+ }
+ }
+}
+
+
+/* These functions "format" the entries in the pdl structure */
+/* They return how much memory the fragments need. */
+static int hp100_init_rxpdl( register hp100_ring_t *ringptr, register u32 *pdlptr )
+{
+ /* pdlptr is starting adress for this pdl */
+
+ if( 0!=( ((unsigned)pdlptr) & 0xf) )
+ printk("hp100: Init rxpdl: Unaligned pdlptr 0x%x.\n",(unsigned)pdlptr);
+
+ ringptr->pdl = pdlptr+1;
+ ringptr->pdl_paddr = virt_to_bus(pdlptr+1);
+ ringptr->skb = (void *) NULL;
+
+ /*
+ * Write address and length of first PDL Fragment (which is used for
+ * storing the RX-Header
+ * We use the 4 bytes _before_ the PDH in the pdl memory area to
+ * store this information. (PDH is at offset 0x04)
+ */
+ /* Note that pdlptr+1 and not pdlptr is the pointer to the PDH */
+
+ *(pdlptr+2) =(u_int) virt_to_bus(pdlptr); /* Address Frag 1 */
+ *(pdlptr+3) = 4; /* Length Frag 1 */
+
+ return( ( ((MAX_RX_FRAG*2+2)+3) /4)*4 );
+}
+
+
+static int hp100_init_txpdl( register hp100_ring_t *ringptr, register u32 *pdlptr )
+{
+ if( 0!=( ((unsigned)pdlptr) & 0xf) )
+ printk("hp100: Init txpdl: Unaligned pdlptr 0x%x.\n",(unsigned) pdlptr);
+
+ ringptr->pdl = pdlptr; /* +1; */
+ ringptr->pdl_paddr = virt_to_bus(pdlptr); /* +1 */
+ ringptr->skb = (void *) NULL;
+
+ return((((MAX_TX_FRAG*2+2)+3)/4)*4);
+}
+
+
+/*
+ * hp100_build_rx_pdl allocates an skb_buff of maximum size plus two bytes
+ * for possible odd word alignment rounding up to next dword and set PDL
+ * address for fragment#2
+ * Returns: 0 if unable to allocate skb_buff
+ * 1 if successful
+ */
+int hp100_build_rx_pdl( hp100_ring_t *ringptr, struct device *dev )
+{
+#ifdef HP100_DEBUG_B
+ int ioaddr = dev->base_addr;
+#endif
+#ifdef HP100_DEBUG_BM
+ u_int *p;
+#endif
+
+#ifdef HP100_DEBUG_B
+ hp100_outw( 0x4207, TRACE );
+ printk("hp100: build rx pdl\n");
+#endif
+
+ /* Allocate skb buffer of maximum size */
+ /* Note: This depends on the alloc_skb functions allocating more
+ * space than requested, i.e. aligning to 16bytes */
+
+ ringptr->skb = dev_alloc_skb( ((MAX_ETHER_SIZE+2+3)/4)*4 );
+
+ if(NULL!=ringptr->skb)
+ {
+ /*
+ * Reserve 2 bytes at the head of the buffer to land the IP header
+ * on a long word boundary (According to the Network Driver section
+ * in the Linux KHG, this should help to increase performance.)
+ */
+ skb_reserve(ringptr->skb, 2);
+
+ ringptr->skb->dev=dev;
+ ringptr->skb->data=(u_char *)skb_put(ringptr->skb, MAX_ETHER_SIZE );
+
+ /* ringptr->pdl points to the beginning of the PDL, i.e. the PDH */
+ /* Note: 1st Fragment is used for the 4 byte packet status
+ * (receive header). Its PDL entries are set up by init_rxpdl. So
+ * here we only have to set up the PDL fragment entries for the data
+ * part. Those 4 bytes will be stored in the DMA memory region
+ * directly before the PDL.
+ */
+#ifdef HP100_DEBUG_BM
+ printk("hp100: build_rx_pdl: PDH@0x%x, skb->data (len %d) at 0x%x\n",
+ (u_int) ringptr->pdl,
+ ((MAX_ETHER_SIZE+2+3)/4)*4,
+ (unsigned int) ringptr->skb->data);
+#endif
+
+ ringptr->pdl[0] = 0x00020000; /* Write PDH */
+ ringptr->pdl[3] = ((u_int)virt_to_bus(ringptr->skb->data));
+ ringptr->pdl[4] = MAX_ETHER_SIZE; /* Length of Data */
+
+#ifdef HP100_DEBUG_BM
+ for(p=(ringptr->pdl); p<(ringptr->pdl+5); p++)
+ printk("Adr 0x%.8x = 0x%.8x\n",(u_int) p,(u_int) *p );
+#endif
+ return(1);
+ }
+ /* else: */
+ /* alloc_skb failed (no memory) -> still can receive the header
+ * fragment into PDL memory. make PDL safe by clearing msgptr and
+ * making the PDL only 1 fragment (i.e. the 4 byte packet status)
+ */
+#ifdef HP100_DEBUG_BM
+ printk("hp100: build_rx_pdl: PDH@0x%x, No space for skb.\n",
+ (u_int) ringptr->pdl);
+#endif
+
+ ringptr->pdl[0]=0x00010000; /* PDH: Count=1 Fragment */
+
+ return(0);
+}
+
+
+/*
+ * hp100_rxfill - attempt to fill the Rx Ring will empty skb's
+ *
+ * Makes assumption that skb's are always contiguous memory areas and
+ * therefore PDLs contain only 2 physical fragments.
+ * - While the number of Rx PDLs with buffers is less than maximum
+ * a. Get a maximum packet size skb
+ * b. Put the physical address of the buffer into the PDL.
+ * c. Output physical address of PDL to adapter.
+ */
+static void hp100_rxfill( struct device *dev )
+{
+ int ioaddr=dev->base_addr;
+
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
+ hp100_ring_t *ringptr;
+
+#ifdef HP100_DEBUG_B
+ hp100_outw( 0x4208, TRACE );
+ printk("hp100: rxfill\n");
+#endif
+
+ hp100_page( PERFORMANCE );
+
+ while (lp->rxrcommit < MAX_RX_PDL)
+ {
+ /*
+ ** Attempt to get a buffer and build a Rx PDL.
+ */
+ ringptr = lp->rxrtail;
+ if (0 == hp100_build_rx_pdl( ringptr, dev ))
+ {
+ return; /* None available, return */
+ }
+
+ /* Hand this PDL over to the card */
+ /* Note: This needs performance page selected! */
+#ifdef HP100_DEBUG_BM
+ printk("hp100: rxfill: Hand to card: pdl #%d @0x%x phys:0x%x, buffer: 0x%x\n",
+ lp->rxrcommit,
+ (u_int)ringptr->pdl,
+ (u_int)ringptr->pdl_paddr,
+ (u_int)ringptr->pdl[3]);
+#endif
+
+ hp100_outl( (u32)ringptr->pdl_paddr, RX_PDA);
+
+ lp->rxrcommit += 1;
+ lp->rxrtail = ringptr->next;
+ }
+}
+
+
/*
- * transmit
+ * BM_shutdown - shutdown bus mastering and leave chip in reset state
*/
+static void hp100_BM_shutdown( struct device *dev )
+{
+ int ioaddr = dev->base_addr;
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
+ unsigned long time;
+
+#ifdef HP100_DEBUG_B
+ hp100_outw( 0x4209, TRACE );
+ printk("hp100: bm shutdown\n");
+#endif
+
+ hp100_page( PERFORMANCE );
+ hp100_outw( 0xfefe, IRQ_MASK ); /* mask off all ints */
+ hp100_outw( 0xffff, IRQ_STATUS ); /* Ack all ints */
+
+ /* Ensure Interrupts are off */
+ hp100_outw( HP100_INT_EN | HP100_RESET_LB , OPTION_LSW );
+
+ /* Disable all MAC activity */
+ hp100_page( MAC_CTRL );
+ hp100_andb( ~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1 ); /* stop rx/tx */
+
+ /* If cascade MMU is not already in reset */
+ if (0 != (hp100_inw(OPTION_LSW)&HP100_HW_RST) )
+ {
+ /* Wait 1.3ms (10Mb max packet time) to ensure MAC is idle so
+ * MMU pointers will not be reset out from underneath
+ */
+ hp100_page( MAC_CTRL );
+ for(time=0; time<5000; time++)
+ {
+ if( (hp100_inb(MAC_CFG_1)&(HP100_TX_IDLE|HP100_RX_IDLE))==
+ (HP100_TX_IDLE|HP100_RX_IDLE) ) break;
+ }
+
+ /* Shutdown algorithm depends on the generation of Cascade */
+ if( lp->chip==HP100_CHIPID_LASSEN )
+ { /* ETR shutdown/reset */
+ /* Disable Busmaster mode and wait for bit to go to zero. */
+ hp100_page(HW_MAP);
+ hp100_andb( ~HP100_BM_MASTER, BM );
+ /* 100 ms timeout */
+ for(time=0; time<32000; time++)
+ {
+ if ( 0 == (hp100_inb( BM ) & HP100_BM_MASTER) ) break;
+ }
+ }
+ else
+ { /* Shasta or Rainier Shutdown/Reset */
+ /* To ensure all bus master inloading activity has ceased,
+ * wait for no Rx PDAs or no Rx packets on card.
+ */
+ hp100_page( PERFORMANCE );
+ /* 100 ms timeout */
+ for(time=0; time<10000; time++)
+ {
+ /* RX_PDL: PDLs not executed. */
+ /* RX_PKT_CNT: RX'd packets on card. */
+ if ( (hp100_inb( RX_PDL ) == 0) &&
+ (hp100_inb( RX_PKT_CNT ) == 0) ) break;
+ }
+
+ if(time>=10000)
+ printk("hp100: BM shutdown error.\n");
+
+ /* To ensure all bus master outloading activity has ceased,
+ * wait until the Tx PDA count goes to zero or no more Tx space
+ * available in the Tx region of the card.
+ */
+ /* 100 ms timeout */
+ for(time=0; time<10000; time++) {
+ if ( (0 == hp100_inb( TX_PKT_CNT )) &&
+ (0 != (hp100_inb( TX_MEM_FREE )&HP100_AUTO_COMPARE))) break;
+ }
+
+ /* Disable Busmaster mode */
+ hp100_page(HW_MAP);
+ hp100_andb( ~HP100_BM_MASTER, BM );
+ } /* end of shutdown procedure for non-etr parts */
+
+ hp100_cascade_reset( dev, TRUE );
+ }
+ hp100_page( PERFORMANCE );
+ hp100_outw( HP100_BM_READ | HP100_BM_WRITE | HP100_RESET_HB, OPTION_LSW );
+ /* Busmaster mode should be shut down now. */
+}
+
+
+
+/*
+ * transmit functions
+ */
+
+/* tx function for busmaster mode */
+static int hp100_start_xmit_bm( struct sk_buff *skb, struct device *dev )
+{
+ int i, ok_flag;
+ int ioaddr = dev->base_addr;
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
+ hp100_ring_t *ringptr;
+
+#ifdef HP100_DEBUG_B
+ hp100_outw( 0x4210, TRACE );
+ printk("hp100: start_xmit_bm\n");
+#endif
+
+ if ( skb==NULL )
+ {
+ dev_tint( dev );
+ return 0;
+ }
+
+ if ( skb->len <= 0 ) return 0;
+
+ /* Get Tx ring tail pointer */
+ if( lp->txrtail->next==lp->txrhead )
+ {
+ /* No memory. */
+#ifdef HP100_DEBUG
+ printk("hp100: start_xmit_bm: No TX PDL available.\n");
+#endif
+ /* not waited long enough since last tx? */
+ if ( jiffies - dev->trans_start < HZ/10 ) return -EAGAIN;
+
+ if ( lp->lan_type < 0 ) /* no LAN type detected yet? */
+ {
+ hp100_stop_interface( dev );
+ if ( ( lp->lan_type = hp100_sense_lan( dev ) ) < 0 )
+ {
+ printk( "%s: no connection found - check wire\n", dev->name );
+ hp100_start_interface( dev ); /* 10Mb/s RX pkts maybe handled */
+ return -EIO;
+ }
+ if ( lp->lan_type == HP100_LAN_100 )
+ lp->hub_status = hp100_login_to_vg_hub( dev, FALSE ); /* relogin */
+ hp100_start_interface( dev );
+ }
+
+ if ( lp->lan_type == HP100_LAN_100 && lp->hub_status < 0 )
+ /* we have a 100Mb/s adapter but it isn't connected to hub */
+ {
+ printk( "%s: login to 100Mb/s hub retry\n", dev->name );
+ hp100_stop_interface( dev );
+ lp->hub_status = hp100_login_to_vg_hub( dev, FALSE );
+ hp100_start_interface( dev );
+ }
+ else
+ {
+ hp100_ints_off();
+ i = hp100_sense_lan( dev );
+ hp100_page( PERFORMANCE );
+ hp100_ints_on();
+ if ( i == HP100_LAN_ERR )
+ printk( "%s: link down detected\n", dev->name );
+ else
+ if ( lp->lan_type != i ) /* cable change! */
+ {
+ /* it's very hard - all network setting must be changed!!! */
+ printk( "%s: cable change 10Mb/s <-> 100Mb/s detected\n", dev->name );
+ lp->lan_type = i;
+ hp100_stop_interface( dev );
+ if ( lp->lan_type == HP100_LAN_100 )
+ lp->hub_status = hp100_login_to_vg_hub( dev, FALSE );
+ hp100_start_interface( dev );
+ }
+ else
+ {
+ printk( "%s: interface reset\n", dev->name );
+ hp100_stop_interface( dev );
+ hp100_start_interface( dev );
+ }
+ }
+
+ dev->trans_start = jiffies;
+ return -EAGAIN;
+ }
+
+ /*
+ * we have to turn int's off before modifying this, otherwise
+ * a tx_pdl_cleanup could occur at the same time
+ */
+ cli();
+ ringptr=lp->txrtail;
+ lp->txrtail=ringptr->next;
+
+ /* Check whether packet has minimal packet size */
+ ok_flag = skb->len >= HP100_MIN_PACKET_SIZE;
+ i = ok_flag ? skb->len : HP100_MIN_PACKET_SIZE;
+
+ ringptr->skb=skb;
+ ringptr->pdl[0]=((1<<16) | i); /* PDH: 1 Fragment & length */
+ ringptr->pdl[1]=(u32)virt_to_bus(skb->data); /* 1st Frag: Adr. of data */
+ if(lp->chip==HP100_CHIPID_SHASTA)
+ {
+ /* TODO:Could someone who has the EISA card please check if this works? */
+ ringptr->pdl[2]=i;
+ }
+ else /* Lassen */
+ {
+ /* In the PDL, don't use the padded size but the real packet size: */
+ ringptr->pdl[2]=skb->len; /* 1st Frag: Length of frag */
+ }
+
+ /* Hand this PDL to the card. */
+ hp100_outl( ringptr->pdl_paddr, TX_PDA_L ); /* Low Prio. Queue */
+
+ lp->txrcommit++;
+ sti();
+
+ /* Update statistics */
+ lp->stats.tx_packets++;
+#ifdef LINUX_2_1
+ lp->stats.tx_bytes += skb->len;
+#endif
+ dev->trans_start = jiffies;
+
+ return 0;
+}
+
+
+/* clean_txring checks if packets have been sent by the card by reading
+ * the TX_PDL register from the performance page and comparing it to the
+ * number of commited packets. It then frees the skb's of the packets that
+ * obviously have been sent to the network.
+ *
+ * Needs the PERFORMANCE page selected.
+ */
+static void hp100_clean_txring( struct device *dev )
+{
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
+ int ioaddr = dev->base_addr;
+ int donecount;
+
+#ifdef HP100_DEBUG_B
+ hp100_outw( 0x4211, TRACE );
+ printk("hp100: clean txring\n");
+#endif
+
+ /* How many PDLs have been transmitted? */
+ donecount=(lp->txrcommit)-hp100_inb(TX_PDL);
+
+#ifdef HP100_DEBUG
+ if(donecount>MAX_TX_PDL)
+ printk("hp100: Warning: More PDLs transmitted than commited to card???\n");
+#endif
+
+ for( ; 0!=donecount; donecount-- )
+ {
+#ifdef HP100_DEBUG_BM
+ printk("hp100: Free skb: data @0x%.8x txrcommit=0x%x TXPDL=0x%x, done=0x%x\n",
+ (u_int) lp->txrhead->skb->data,
+ lp->txrcommit,
+ hp100_inb(TX_PDL),
+ donecount);
+#endif
+ dev_kfree_skb( lp->txrhead->skb, FREE_WRITE );
+ lp->txrhead->skb=(void *)NULL;
+ lp->txrhead=lp->txrhead->next;
+ lp->txrcommit--;
+ }
+}
+
+
+/* tx function for slave modes */
static int hp100_start_xmit( struct sk_buff *skb, struct device *dev )
{
int i, ok_flag;
- int ioaddr = dev -> base_addr;
+ int ioaddr = dev->base_addr;
u_short val;
- struct hp100_private *lp = (struct hp100_private *)dev -> priv;
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
+
+#ifdef HP100_DEBUG_B
+ hp100_outw( 0x4212, TRACE );
+ printk("hp100: start_xmit\n");
+#endif
- if ( lp -> lan_type < 0 )
+ if ( lp->lan_type < 0 ) /* no LAN type detected yet? */
{
hp100_stop_interface( dev );
- if ( ( lp -> lan_type = hp100_sense_lan( dev ) ) < 0 )
+ if ( ( lp->lan_type = hp100_sense_lan( dev ) ) < 0 )
{
- printk( "%s: no connection found - check wire\n", dev -> name );
- hp100_start_interface( dev ); /* 10Mb/s RX packets maybe handled */
+ printk( "%s: no connection found - check wire\n", dev->name );
+ hp100_start_interface( dev ); /* 10Mb/s RX packets maybe handled */
return -EIO;
}
- if ( lp -> lan_type == HP100_LAN_100 )
- lp -> hub_status = hp100_login_to_vg_hub( dev );
+ if ( lp->lan_type == HP100_LAN_100 )
+ lp->hub_status = hp100_login_to_vg_hub( dev, FALSE ); /* relogin */
hp100_start_interface( dev );
}
- if ( ( i = ( hp100_inl( TX_MEM_FREE ) & ~0x7fffffff ) ) < skb -> len + 16 )
+ /* If there is not enough free memory on the card... */
+ i=hp100_inl(TX_MEM_FREE)&0x7fffffff;
+ if ( !(((i/2)-539)>(skb->len+16) && (hp100_inb(TX_PKT_CNT)<255)) )
{
#ifdef HP100_DEBUG
- printk( "hp100_start_xmit: rx free mem = 0x%x\n", i );
+ printk( "hp100_start_xmit: tx free mem = 0x%x\n", i );
#endif
- if ( jiffies - dev -> trans_start < 2 * HZ ) return -EAGAIN;
- if ( lp -> lan_type == HP100_LAN_100 && lp -> hub_status < 0 )
- /* 100Mb/s adapter isn't connected to hub */
+ /* not waited long enough since last failed tx try? */
+ if ( jiffies - dev->trans_start < HZ/2 )
+ {
+#ifdef HP100_DEBUG
+ printk("hp100: trans_start timing problem\n");
+#endif
+ return -EAGAIN;
+ }
+ if ( lp->lan_type == HP100_LAN_100 && lp->hub_status < 0 )
+ /* we have a 100Mb/s adapter but it isn't connected to hub */
{
- printk( "%s: login to 100Mb/s hub retry\n", dev -> name );
+ printk( "%s: login to 100Mb/s hub retry\n", dev->name );
hp100_stop_interface( dev );
- lp -> hub_status = hp100_login_to_vg_hub( dev );
+ lp->hub_status = hp100_login_to_vg_hub( dev, FALSE );
hp100_start_interface( dev );
}
- else
+ else
{
hp100_ints_off();
i = hp100_sense_lan( dev );
hp100_page( PERFORMANCE );
hp100_ints_on();
if ( i == HP100_LAN_ERR )
- printk( "%s: link down detected\n", dev -> name );
- else
- if ( lp -> lan_type != i )
- {
- /* it's very heavy - all network setting must be changed!!! */
- printk( "%s: cable change 10Mb/s <-> 100Mb/s detected\n", dev -> name );
- lp -> lan_type = i;
- hp100_stop_interface( dev );
- if ( lp -> lan_type == HP100_LAN_100 )
- lp -> hub_status = hp100_login_to_vg_hub( dev );
- hp100_start_interface( dev );
- }
- else
- {
- printk( "%s: interface reset\n", dev -> name );
- hp100_stop_interface( dev );
- hp100_start_interface( dev );
- }
+ printk( "%s: link down detected\n", dev->name );
+ else
+ if ( lp->lan_type != i ) /* cable change! */
+ {
+ /* it's very hard - all network setting must be changed!!! */
+ printk( "%s: cable change 10Mb/s <-> 100Mb/s detected\n", dev->name );
+ lp->lan_type = i;
+ hp100_stop_interface( dev );
+ if ( lp->lan_type == HP100_LAN_100 )
+ lp->hub_status = hp100_login_to_vg_hub( dev, FALSE );
+ hp100_start_interface( dev );
+ }
+ else
+ {
+ printk( "%s: interface reset\n", dev->name );
+ hp100_stop_interface( dev );
+ hp100_start_interface( dev );
+ udelay(1000);
+ }
}
- dev -> trans_start = jiffies;
+ dev->trans_start = jiffies;
return -EAGAIN;
}
- for ( i = 0; i < 6000 && ( hp100_inw( OPTION_MSW ) & HP100_TX_CMD ); i++ )
+ for ( i=0; i<6000 && ( hp100_inb( OPTION_MSW ) & HP100_TX_CMD ); i++ )
{
#ifdef HP100_DEBUG_TX
printk( "hp100_start_xmit: busy\n" );
#endif
}
-
+
hp100_ints_off();
val = hp100_inw( IRQ_STATUS );
- hp100_outw( val & HP100_TX_COMPLETE, IRQ_STATUS );
+ /* Ack / clear the interrupt TX_COMPLETE interrupt - this interrupt is set
+ * when the current packet being transmitted on the wire is completed. */
+ hp100_outw( HP100_TX_COMPLETE, IRQ_STATUS );
#ifdef HP100_DEBUG_TX
- printk( "hp100_start_xmit: irq_status = 0x%x, len = %d\n", val, (int)skb -> len );
+ printk("hp100_start_xmit: irq_status=0x%.4x, irqmask=0x%.4x, len=%d\n",val,hp100_inw(IRQ_MASK),(int)skb->len );
#endif
- ok_flag = skb -> len >= HP100_MIN_PACKET_SIZE;
- i = ok_flag ? skb -> len : HP100_MIN_PACKET_SIZE;
- hp100_outw( i, DATA32 ); /* length to memory manager */
- hp100_outw( i, FRAGMENT_LEN );
- if ( lp -> mem_mapped )
+
+ ok_flag = skb->len >= HP100_MIN_PACKET_SIZE;
+ i = ok_flag ? skb->len : HP100_MIN_PACKET_SIZE;
+
+ hp100_outw( i, DATA32 ); /* tell card the total packet length */
+ hp100_outw( i, FRAGMENT_LEN ); /* and first/only fragment length */
+
+ if ( lp->mode==2 ) /* memory mapped */
{
- if ( lp -> mem_ptr_virt )
- {
- memcpy( lp -> mem_ptr_virt, skb -> data, skb -> len );
- if ( !ok_flag )
- memset( lp -> mem_ptr_virt, 0, HP100_MIN_PACKET_SIZE - skb -> len );
- }
- else
- {
- memcpy_toio( lp -> mem_ptr_phys, skb -> data, skb -> len );
- if ( !ok_flag )
- memset_io( lp -> mem_ptr_phys, 0, HP100_MIN_PACKET_SIZE - skb -> len );
- }
+ if ( lp->mem_ptr_virt ) /* high pci memory was remapped */
+ {
+ /* Note: The J2585B needs alignment to 32bits here! */
+ memcpy( lp->mem_ptr_virt, skb->data, ( skb->len +3 ) & ~3 );
+ if ( !ok_flag )
+ memset( lp->mem_ptr_virt, 0, HP100_MIN_PACKET_SIZE - skb->len );
+ }
+ else
+ {
+ memcpy_toio( lp->mem_ptr_phys, skb->data, skb->len );
+ if ( !ok_flag )
+ memset_io( lp->mem_ptr_phys, 0, HP100_MIN_PACKET_SIZE - skb->len );
+ }
}
- else
+ else /* programmed i/o */
{
- outsl( ioaddr + HP100_REG_DATA32, skb -> data, ( skb -> len + 3 ) >> 2 );
+ outsl( ioaddr + HP100_REG_DATA32, skb->data, ( skb->len + 3 ) >> 2 );
if ( !ok_flag )
- for ( i = ( skb -> len + 3 ) & ~3; i < HP100_MIN_PACKET_SIZE; i += 4 )
- hp100_outl( 0, DATA32 );
+ for ( i = ( skb->len + 3 ) & ~3; i < HP100_MIN_PACKET_SIZE; i += 4 )
+ hp100_outl( 0, DATA32 );
}
- hp100_outw( HP100_TX_CMD | HP100_SET_LB, OPTION_MSW ); /* send packet */
- lp -> stats.tx_packets++;
- dev -> trans_start = jiffies;
+
+ hp100_outb( HP100_TX_CMD | HP100_SET_LB, OPTION_MSW ); /* send packet */
+
+ lp->stats.tx_packets++;
+#ifdef LINUX_2_1
+ lp->stats.tx_bytes += skb->len;
+#endif
+ dev->trans_start=jiffies;
hp100_ints_on();
-
+
dev_kfree_skb( skb, FREE_WRITE );
-
+
#ifdef HP100_DEBUG_TX
printk( "hp100_start_xmit: end\n" );
#endif
-
+
return 0;
}
+
/*
- * receive - called from interrupt handler
+ * Receive Function (Non-Busmaster mode)
+ * Called when an "Receive Packet" interrupt occurs, i.e. the receive
+ * packet counter is non-zero.
+ * For non-busmaster, this function does the whole work of transfering
+ * the packet to the host memory and then up to higher layers via skb
+ * and netif_rx.
*/
static void hp100_rx( struct device *dev )
{
int packets, pkt_len;
- int ioaddr = dev -> base_addr;
- struct hp100_private *lp = (struct hp100_private *)dev -> priv;
+ int ioaddr = dev->base_addr;
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
u_int header;
struct sk_buff *skb;
-#if 0
- if ( lp -> lan_type < 0 )
- {
- if ( ( lp -> lan_type = hp100_sense_lan( dev ) ) == HP100_LAN_100 )
- lp -> hub_status = hp100_login_to_vg_hub( dev );
- hp100_page( PERFORMANCE );
- }
+#ifdef DEBUG_B
+ hp100_outw( 0x4213, TRACE );
+ printk("hp100: rx\n");
#endif
+ /* First get indication of received lan packet */
+ /* RX_PKT_CND indicates the number of packets which have been fully */
+ /* received onto the card but have not been fully transfered of the card */
packets = hp100_inb( RX_PKT_CNT );
-#ifdef HP100_DEBUG
+#ifdef HP100_DEBUG_RX
if ( packets > 1 )
printk( "hp100_rx: waiting packets = %d\n", packets );
#endif
+
while ( packets-- > 0 )
{
- for ( pkt_len = 0; pkt_len < 6000 && ( hp100_inw( OPTION_MSW ) & HP100_ADV_NXT_PKT ); pkt_len++ )
+ /* If ADV_NXT_PKT is still set, we have to wait until the card has */
+ /* really advanced to the next packet. */
+ for (pkt_len=0; pkt_len<6000 &&(hp100_inb(OPTION_MSW)&HP100_ADV_NXT_PKT);
+ pkt_len++ )
{
-#ifdef HP100_DEBUG_TX
+#ifdef HP100_DEBUG_RX
printk( "hp100_rx: busy, remaining packets = %d\n", packets );
-#endif
+#endif
}
- if ( lp -> mem_mapped )
+
+ /* First we get the header, which contains information about the */
+ /* actual length of the received packet. */
+ if( lp->mode==2 ) /* memory mapped mode */
{
- if ( lp -> mem_ptr_virt )
- header = *(__u32 *)lp -> mem_ptr_virt;
- else
- header = readl( lp -> mem_ptr_phys );
+ if ( lp->mem_ptr_virt ) /* if memory was remapped */
+ header = *(__u32 *)lp->mem_ptr_virt;
+ else
+ header = readl( lp->mem_ptr_phys );
}
- else
+ else /* programmed i/o */
header = hp100_inl( DATA32 );
+
pkt_len = header & HP100_PKT_LEN_MASK;
+
#ifdef HP100_DEBUG_RX
- printk( "hp100_rx: new packet - length = %d, errors = 0x%x, dest = 0x%x\n",
- header & HP100_PKT_LEN_MASK, ( header >> 16 ) & 0xfff8, ( header >> 16 ) & 7 );
+ printk( "hp100_rx: new packet - length=%d, errors=0x%x, dest=0x%x\n",
+ header & HP100_PKT_LEN_MASK, (header>>16)&0xfff8,
+ (header>>16)&7);
#endif
- /*
- * NOTE! This (and the skb_put() below) depends on the skb-functions
+
+ /* Now we allocate the skb and transfer the data into it. */
+ /* NOTE! This (and the skb_put() below) depends on the skb-functions
* allocating more than asked (notably, aligning the request up to
* the next 16-byte length).
*/
skb = dev_alloc_skb( pkt_len );
- if ( skb == NULL )
- {
+ if ( skb == NULL ) /* Not enough memory->drop packet */
+ {
#ifdef HP100_DEBUG
- printk( "hp100_rx: couldn't allocate a sk_buff of size %d\n", pkt_len );
+ printk( "hp100_rx: couldn't allocate a sk_buff of size %d\n", pkt_len );
#endif
- lp -> stats.rx_dropped++;
- }
- else
- {
- u_char *ptr;
-
- skb -> dev = dev;
- ptr = (u_char *)skb_put( skb, pkt_len );
- if ( lp -> mem_mapped )
+ lp->stats.rx_dropped++;
+ }
+ else /* skb successfully allocated */
+ {
+ u_char *ptr;
+
+ skb->dev = dev;
+
+ /* ptr to start of the sk_buff data area */
+ ptr = (u_char *)skb_put( skb, pkt_len );
+
+ /* Now transfer the data from the card into that area */
+ if ( lp->mode==2 )
{
- if ( lp -> mem_ptr_virt )
- memcpy( ptr, lp -> mem_ptr_virt, ( pkt_len + 3 ) & ~3 );
- else
- memcpy_fromio( ptr, lp -> mem_ptr_phys, ( pkt_len + 3 ) & ~3 );
+ if ( lp->mem_ptr_virt )
+ memcpy( ptr, lp->mem_ptr_virt, ( pkt_len + 3 ) & ~3 );
+ /* Note alignment to 32bit transfers */
+ else
+ memcpy_fromio( ptr, lp->mem_ptr_phys, ( pkt_len + 3 ) & ~3 );
}
- else
- insl( ioaddr + HP100_REG_DATA32, ptr, ( pkt_len + 3 ) >> 2 );
- skb -> protocol = eth_type_trans( skb, dev );
- netif_rx( skb );
- lp -> stats.rx_packets++;
+ else /* io mapped */
+ insl( ioaddr + HP100_REG_DATA32, ptr, ( pkt_len + 3 ) >> 2 );
+
+ skb->protocol = eth_type_trans( skb, dev );
+
+ netif_rx( skb );
+ lp->stats.rx_packets++;
+#ifdef LINUX_2_1
+ lp->stats.rx_bytes += skb->len;
+#endif
+
#ifdef HP100_DEBUG_RX
- printk( "rx: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
- ptr[ 0 ], ptr[ 1 ], ptr[ 2 ], ptr[ 3 ], ptr[ 4 ], ptr[ 5 ],
- ptr[ 6 ], ptr[ 7 ], ptr[ 8 ], ptr[ 9 ], ptr[ 10 ], ptr[ 11 ] );
+ printk( "rx: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ ptr[ 0 ], ptr[ 1 ], ptr[ 2 ], ptr[ 3 ], ptr[ 4 ], ptr[ 5 ],
+ ptr[ 6 ], ptr[ 7 ], ptr[ 8 ], ptr[ 9 ], ptr[ 10 ], ptr[ 11 ] );
#endif
- }
- hp100_outw( HP100_ADV_NXT_PKT | HP100_SET_LB, OPTION_MSW );
+ }
+
+ /* Indicate the card that we have got the packet */
+ hp100_outb( HP100_ADV_NXT_PKT | HP100_SET_LB, OPTION_MSW );
+
switch ( header & 0x00070000 ) {
- case (HP100_MULTI_ADDR_HASH<<16):
- case (HP100_MULTI_ADDR_NO_HASH<<16):
- lp -> stats.multicast++; break;
+ case (HP100_MULTI_ADDR_HASH<<16):
+ case (HP100_MULTI_ADDR_NO_HASH<<16):
+ lp->stats.multicast++; break;
}
- }
+ } /* end of while(there are packets) loop */
#ifdef HP100_DEBUG_RX
- printk( "hp100_rx: end\n" );
+ printk( "hp100_rx: end\n" );
+#endif
+}
+
+
+/*
+ * Receive Function for Busmaster Mode
+ */
+static void hp100_rx_bm( struct device *dev )
+{
+ int ioaddr = dev->base_addr;
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
+ hp100_ring_t *ptr;
+ u_int header;
+ int pkt_len;
+
+#ifdef HP100_DEBUG_B
+ hp100_outw( 0x4214, TRACE );
+ printk("hp100: rx_bm\n");
+#endif
+
+#ifdef HP100_DEBUG
+ if(0==lp->rxrcommit)
+ {
+ printk("hp100: rx_bm called although no PDLs were committed to adapter?\n");
+ return;
+ }
+ else
+
+ /* RX_PKT_CNT states how many PDLs are currently formatted and available to
+ * the cards BM engine */
+ if( (hp100_inw(RX_PKT_CNT)&0x00ff) >= lp->rxrcommit)
+ {
+ printk("hp100: More packets received than commited? RX_PKT_CNT=0x%x, commit=0x%x\n", hp100_inw(RX_PKT_CNT)&0x00ff, lp->rxrcommit);
+ return;
+ }
+#endif
+
+ while( (lp->rxrcommit > hp100_inb(RX_PDL)) )
+ {
+ /*
+ * The packet was received into the pdl pointed to by lp->rxrhead (
+ * the oldest pdl in the ring
+ */
+
+ /* First we get the header, which contains information about the */
+ /* actual length of the received packet. */
+
+ ptr=lp->rxrhead;
+
+ header = *(ptr->pdl-1);
+ pkt_len = (header & HP100_PKT_LEN_MASK);
+
+#ifdef HP100_DEBUG_BM
+ printk( "hp100: rx_bm: header@0x%x=0x%x length=%d, errors=0x%x, dest=0x%x\n",
+ (u_int) (ptr->pdl-1),(u_int) header,
+ pkt_len,
+ (header>>16)&0xfff8,
+ (header>>16)&7);
+ printk( "hp100: RX_PDL_COUNT:0x%x TX_PDL_COUNT:0x%x, RX_PKT_CNT=0x%x PDH=0x%x, Data@0x%x len=0x%x\n",
+ hp100_inb( RX_PDL ),
+ hp100_inb( TX_PDL ),
+ hp100_inb( RX_PKT_CNT ),
+ (u_int) *(ptr->pdl),
+ (u_int) *(ptr->pdl+3),
+ (u_int) *(ptr->pdl+4));
+#endif
+
+ if( (pkt_len>=MIN_ETHER_SIZE) &&
+ (pkt_len<=MAX_ETHER_SIZE) )
+ {
+ if(ptr->skb==NULL)
+ {
+ printk("hp100: rx_bm: skb null\n");
+ /* can happen if we only allocated room for the pdh due to memory shortage. */
+ lp->stats.rx_dropped++;
+ }
+ else
+ {
+ skb_trim( ptr->skb, pkt_len ); /* Shorten it */
+ ptr->skb->protocol = eth_type_trans( ptr->skb, dev );
+
+ netif_rx( ptr->skb ); /* Up and away... */
+
+ lp->stats.rx_packets++;
+#ifdef LINUX_2_1
+ lp->stats.rx_bytes += ptr->skb->len;
+#endif
+ }
+
+ switch ( header & 0x00070000 ) {
+ case (HP100_MULTI_ADDR_HASH<<16):
+ case (HP100_MULTI_ADDR_NO_HASH<<16):
+ lp->stats.multicast++; break;
+ }
+ }
+ else
+ {
+#ifdef HP100_DEBUG
+ printk("hp100: rx_bm: Received bad packet (length=%d)\n",pkt_len);
+#endif
+ if(ptr->skb!=NULL)
+ dev_kfree_skb( ptr->skb, FREE_READ );
+ lp->stats.rx_errors++;
+ }
+
+ lp->rxrhead=lp->rxrhead->next;
+
+ /* Allocate a new rx PDL (so lp->rxrcommit stays the same) */
+ if (0 == hp100_build_rx_pdl( lp->rxrtail, dev ))
+ {
+ /* No space for skb, header can still be received. */
+#ifdef HP100_DEBUG
+ printk("hp100: rx_bm: No space for new PDL.\n");
#endif
+ return;
+ }
+ else
+ { /* successfully allocated new PDL - put it in ringlist at tail. */
+ hp100_outl((u32)lp->rxrtail->pdl_paddr, RX_PDA);
+ lp->rxrtail=lp->rxrtail->next;
+ }
+
+ }
}
+
+
/*
* statistics
*/
-
-static struct net_device_stats *hp100_get_stats( struct device *dev )
+static hp100_stats_t *hp100_get_stats( struct device *dev )
{
- int ioaddr = dev -> base_addr;
+ int ioaddr = dev->base_addr;
+
+#ifdef HP100_DEBUG_B
+ hp100_outw( 0x4215, TRACE );
+#endif
hp100_ints_off();
hp100_update_stats( dev );
hp100_ints_on();
- return &((struct hp100_private *)dev -> priv) -> stats;
+ return &((struct hp100_private *)dev->priv)->stats;
}
static void hp100_update_stats( struct device *dev )
{
- int ioaddr = dev -> base_addr;
+ int ioaddr = dev->base_addr;
u_short val;
- struct hp100_private *lp = (struct hp100_private *)dev -> priv;
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
+
+#ifdef HP100_DEBUG_B
+ hp100_outw( 0x4216, TRACE );
+ printk("hp100: update-stats\n");
+#endif
- hp100_page( MAC_CTRL ); /* get all statistics bytes */
+ /* Note: Statistics counters clear when read. */
+ hp100_page( MAC_CTRL );
val = hp100_inw( DROPPED ) & 0x0fff;
- lp -> stats.rx_errors += val;
- lp -> stats.rx_over_errors += val;
+ lp->stats.rx_errors += val;
+ lp->stats.rx_over_errors += val;
val = hp100_inb( CRC );
- lp -> stats.rx_errors += val;
- lp -> stats.rx_crc_errors += val;
+ lp->stats.rx_errors += val;
+ lp->stats.rx_crc_errors += val;
val = hp100_inb( ABORT );
- lp -> stats.tx_errors += val;
- lp -> stats.tx_aborted_errors += val;
+ lp->stats.tx_errors += val;
+ lp->stats.tx_aborted_errors += val;
hp100_page( PERFORMANCE );
}
static void hp100_clear_stats( int ioaddr )
{
+#ifdef HP100_DEBUG_B
+ hp100_outw( 0x4217, TRACE );
+ printk("hp100: clear_stats\n");
+#endif
+
cli();
- hp100_page( MAC_CTRL ); /* get all statistics bytes */
+ hp100_page( MAC_CTRL ); /* get all statistics bytes */
hp100_inw( DROPPED );
hp100_inb( CRC );
hp100_inb( ABORT );
@@ -831,54 +2031,73 @@ static void hp100_clear_stats( int ioaddr )
sti();
}
+
/*
* multicast setup
*/
/*
* Set or clear the multicast filter for this adapter.
+ * TODO: Currently when in multicast mode, card accepts all multicast packets
+ * for all MC addresses. Should better use the list on the card.
*/
-
+
static void hp100_set_multicast_list( struct device *dev)
{
- int ioaddr = dev -> base_addr;
- struct hp100_private *lp = (struct hp100_private *)dev -> priv;
+ int ioaddr = dev->base_addr;
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
-#ifdef HP100_DEBUG_MULTI
- printk( "hp100_set_multicast_list: num_addrs = %d\n", dev->mc_count);
+#ifdef HP100_DEBUG_B
+ hp100_outw( 0x4218, TRACE );
+ printk("hp100: set_mc_list\n");
#endif
+
cli();
hp100_ints_off();
hp100_page( MAC_CTRL );
- hp100_andb( ~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1 ); /* stop rx/tx */
+ hp100_andb( ~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1 ); /* stop rx/tx */
- if ( dev->flags&IFF_PROMISC)
+ if ( dev->flags & IFF_PROMISC )
{
- lp -> mac2_mode = HP100_MAC2MODE6; /* promiscuous mode, all good */
- lp -> mac1_mode = HP100_MAC1MODE6; /* packets on the net */
+ lp->mac2_mode = HP100_MAC2MODE6; /* promiscuous mode = get all good */
+ lp->mac1_mode = HP100_MAC1MODE6; /* packets on the net */
}
- else
- if ( dev->mc_count || dev->flags&IFF_ALLMULTI )
+ else if ( dev->mc_count || (dev->flags&IFF_ALLMULTI) )
{
- lp -> mac2_mode = HP100_MAC2MODE5; /* multicast mode, packets for me */
- lp -> mac1_mode = HP100_MAC1MODE5; /* broadcasts and all multicasts */
+ lp->mac2_mode = HP100_MAC2MODE5; /* multicast mode = get packets for */
+ lp->mac1_mode = HP100_MAC1MODE5; /* me, broadcasts and all multicasts */
}
- else
+ else
{
- lp -> mac2_mode = HP100_MAC2MODE3; /* normal mode, packets for me */
- lp -> mac1_mode = HP100_MAC1MODE3; /* and broadcasts */
+ lp->mac2_mode = HP100_MAC2MODE3; /* normal mode = get packets for me */
+ lp->mac1_mode = HP100_MAC1MODE3; /* and broadcasts */
}
- hp100_outb( lp -> mac2_mode, MAC_CFG_2 );
- hp100_andb( HP100_MAC1MODEMASK, MAC_CFG_1 );
- hp100_orb( lp -> mac1_mode |
- HP100_RX_EN | HP100_RX_IDLE | /* enable rx */
- HP100_TX_EN | HP100_TX_IDLE, MAC_CFG_1 ); /* enable tx */
+ if ( ( (hp100_inb(MAC_CFG_1) & 0x0f)!=lp->mac1_mode ) ||
+ ( hp100_inb(MAC_CFG_2)!=lp->mac2_mode ) ) {
+ hp100_outb( lp->mac2_mode, MAC_CFG_2 );
+ hp100_andb( HP100_MAC1MODEMASK, MAC_CFG_1 ); /* clear mac1 mode bits */
+ hp100_orb( lp->mac1_mode, MAC_CFG_1 ); /* and set the new mode */
+
+ if(lp->lan_type==HP100_LAN_100)
+ {
+#ifdef HP100_DEBUG
+ printk("hp100: 100VG MAC settings have changed - relogin.\n");
+#endif
+ lp->hub_status=hp100_login_to_vg_hub( dev, TRUE ); /* force a relogin to the hub */
+ }
+ }
+
+ hp100_page( MAC_CTRL );
+ hp100_orb( HP100_RX_EN | HP100_RX_IDLE | /* enable rx */
+ HP100_TX_EN | HP100_TX_IDLE, MAC_CFG_1 ); /* enable tx */
+
hp100_page( PERFORMANCE );
hp100_ints_on();
sti();
}
+
/*
* hardware interrupt handling
*/
@@ -886,249 +2105,747 @@ static void hp100_set_multicast_list( struct device *dev)
static void hp100_interrupt( int irq, void *dev_id, struct pt_regs *regs )
{
struct device *dev = (struct device *)irq2dev_map[ irq ];
- struct hp100_private *lp;
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
+
int ioaddr;
- u_short val;
+ u_int val;
if ( dev == NULL ) return;
- ioaddr = dev -> base_addr;
- if ( dev -> interrupt )
- printk( "%s: re-entering the interrupt handler\n", dev -> name );
+ ioaddr = dev->base_addr;
+
+ if ( dev->interrupt )
+ printk( "%s: re-entering the interrupt handler\n", dev->name );
hp100_ints_off();
- dev -> interrupt = 1;
- hp100_page( PERFORMANCE );
+ dev->interrupt = 1; /* mark that we are inside the handler */
+
+#ifdef HP100_DEBUG_B
+ hp100_outw( 0x4219, TRACE );
+#endif
+
+ /* hp100_page( PERFORMANCE ); */
val = hp100_inw( IRQ_STATUS );
#ifdef HP100_DEBUG_IRQ
- printk( "hp100_interrupt: irq_status = 0x%x\n", val );
+ printk( "hp100: mode=%x,IRQ_STAT=0x%.4x,RXPKTCNT=0x%.2x RXPDL=0x%.2x TXPKTCNT=0x%.2x TXPDL=0x%.2x\n",
+ lp->mode,
+ (u_int)val,
+ hp100_inb( RX_PKT_CNT ),
+ hp100_inb( RX_PDL ),
+ hp100_inb( TX_PKT_CNT ),
+ hp100_inb( TX_PDL )
+ );
#endif
- if ( val & HP100_RX_PACKET )
+
+ if(val==0) /* might be a shared interrupt */
{
- hp100_rx( dev );
- hp100_outw( HP100_RX_PACKET, IRQ_STATUS );
+ dev->interrupt=0;
+ hp100_ints_on();
+ return;
}
- if ( val & (HP100_TX_SPACE_AVAIL | HP100_TX_COMPLETE) )
+ /* We're only interested in those interrupts we really enabled. */
+ /* val &= hp100_inw( IRQ_MASK ); */
+
+ /*
+ * RX_PDL_FILL_COMPL is set whenever a RX_PDL has been executed. A RX_PDL
+ * is considered executed whenever the RX_PDL data structure is no longer
+ * needed.
+ */
+ if ( val & HP100_RX_PDL_FILL_COMPL )
{
- hp100_outw( val & (HP100_TX_SPACE_AVAIL | HP100_TX_COMPLETE), IRQ_STATUS );
+ if(lp->mode==1)
+ hp100_rx_bm( dev );
+ else
+ printk("hp100: rx_pdl_fill_compl interrupt although not busmaster?\n");
}
- if ( val & ( HP100_TX_ERROR | HP100_RX_ERROR ) )
+
+ /*
+ * The RX_PACKET interrupt is set, when the receive packet counter is
+ * non zero. We use this interrupt for receiving in slave mode. In
+ * busmaster mode, we use it to make sure we did not miss any rx_pdl_fill
+ * interrupts. If rx_pdl_fill_compl is not set and rx_packet is set, then
+ * we somehow have missed a rx_pdl_fill_compl interrupt.
+ */
+
+ if ( val & HP100_RX_PACKET ) /* Receive Packet Counter is non zero */
{
- lp = (struct hp100_private *)dev -> priv;
- hp100_update_stats( dev );
- hp100_outw( val & (HP100_TX_ERROR | HP100_RX_ERROR), IRQ_STATUS );
+ if(lp->mode!=1) /* non busmaster */
+ hp100_rx( dev );
+ else if ( !(val & HP100_RX_PDL_FILL_COMPL ))
+ {
+ /* Shouldnt happen - maybe we missed a RX_PDL_FILL Interrupt? */
+ hp100_rx_bm( dev );
+ }
}
+
+ /*
+ * Ack. that we have noticed the interrupt and thereby allow next one.
+ * Note that this is now done after the slave rx function, since first
+ * acknowledging and then setting ADV_NXT_PKT caused an extra interrupt
+ * on the J2573.
+ */
+ hp100_outw( val, IRQ_STATUS );
+
+ /*
+ * RX_ERROR is set when a packet is dropped due to no memory resources on
+ * the card or when a RCV_ERR occurs.
+ * TX_ERROR is set when a TX_ABORT condition occurs in the MAC->exists
+ * only in the 802.3 MAC and happens when 16 collisions occur during a TX
+ */
+ if ( val & ( HP100_TX_ERROR | HP100_RX_ERROR ) )
+ {
#ifdef HP100_DEBUG_IRQ
- printk( "hp100_interrupt: end\n" );
+ printk("hp100: TX/RX Error IRQ\n");
#endif
- dev -> interrupt = 0;
+ hp100_update_stats( dev );
+ if(lp->mode==1)
+ {
+ hp100_rxfill( dev );
+ hp100_clean_txring( dev );
+ }
+ }
+
+ /*
+ * RX_PDA_ZERO is set when the PDA count goes from non-zero to zero.
+ */
+ if ( (lp->mode==1)&&(val &(HP100_RX_PDA_ZERO)) )
+ hp100_rxfill( dev );
+
+ /*
+ * HP100_TX_COMPLETE interrupt occurs when packet transmitted on wire
+ * is completed
+ */
+ if ( (lp->mode==1) && ( val & ( HP100_TX_COMPLETE )) )
+ hp100_clean_txring( dev );
+
+ /*
+ * MISC_ERROR is set when either the LAN link goes down or a detected
+ * bus error occurs.
+ */
+ if ( val & HP100_MISC_ERROR ) /* New for J2585B */
+ {
+ printk("hp100: Misc. Error Interrupt - Check cabling.\n");
+ if(lp->mode==1)
+ {
+ hp100_clean_txring( dev );
+ hp100_rxfill( dev );
+ }
+ }
+
+ dev->interrupt = 0;
hp100_ints_on();
}
+
/*
* some misc functions
*/
static void hp100_start_interface( struct device *dev )
{
- int ioaddr = dev -> base_addr;
- struct hp100_private *lp = (struct hp100_private *)dev -> priv;
+ int ioaddr = dev->base_addr;
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
+
+#ifdef HP100_DEBUG_B
+ hp100_outw( 0x4220, TRACE );
+ printk("hp100: hp100_start_interface %s\n",dev->name);
+#endif
cli();
- hp100_unreset_card();
- hp100_page( MAC_CTRL );
- hp100_outb( lp -> mac2_mode, MAC_CFG_2 );
- hp100_andb( HP100_MAC1MODEMASK, MAC_CFG_1 );
- hp100_orb( lp -> mac1_mode |
- HP100_RX_EN | HP100_RX_IDLE |
- HP100_TX_EN | HP100_TX_IDLE, MAC_CFG_1 );
+
+ /* Ensure the adapter does not want to request an interrupt when */
+ /* enabling the IRQ line to be active on the bus (i.e. not tri-stated) */
hp100_page( PERFORMANCE );
- hp100_outw( HP100_INT_EN | HP100_SET_LB, OPTION_LSW );
- hp100_outw( HP100_TRI_INT | HP100_RESET_HB, OPTION_LSW );
- if ( lp -> mem_mapped )
+ hp100_outw( 0xfefe, IRQ_MASK ); /* mask off all ints */
+ hp100_outw( 0xffff, IRQ_STATUS ); /* ack all IRQs */
+ hp100_outw( HP100_FAKE_INT|HP100_INT_EN|HP100_RESET_LB, OPTION_LSW);
+ /* Un Tri-state int. TODO: Check if shared interrupts can be realised? */
+ hp100_outw( HP100_TRI_INT | HP100_RESET_HB, OPTION_LSW );
+
+ if(lp->mode==1)
+ {
+ /* Make sure BM bit is set... */
+ hp100_page(HW_MAP);
+ hp100_orb( HP100_BM_MASTER, BM );
+ hp100_rxfill( dev );
+ }
+ else if(lp->mode==2)
{
- /* enable memory mapping */
+ /* Enable memory mapping. Note: Don't do this when busmaster. */
hp100_outw( HP100_MMAP_DIS | HP100_RESET_HB, OPTION_LSW );
}
- sti();
+
+ hp100_page(PERFORMANCE);
+ hp100_outw( 0xfefe, IRQ_MASK ); /* mask off all ints */
+ hp100_outw( 0xffff, IRQ_STATUS ); /* ack IRQ */
+
+ /* enable a few interrupts: */
+ if(lp->mode==1) /* busmaster mode */
+ {
+ hp100_outw( HP100_RX_PDL_FILL_COMPL |
+ HP100_RX_PDA_ZERO |
+ HP100_RX_ERROR |
+ /* HP100_RX_PACKET | */
+ /* HP100_RX_EARLY_INT | */ HP100_SET_HB |
+ /* HP100_TX_PDA_ZERO | */
+ HP100_TX_COMPLETE |
+ /* HP100_MISC_ERROR | */
+ HP100_TX_ERROR | HP100_SET_LB, IRQ_MASK );
+ }
+ else
+ {
+ hp100_outw( HP100_RX_PACKET |
+ HP100_RX_ERROR | HP100_SET_HB |
+ HP100_TX_ERROR | HP100_SET_LB , IRQ_MASK );
+ }
+
+ /* Enable MAC Tx and RX, set MAC modes, ... */
+ /* Note: This function also turns on the interrupts. */
+ hp100_set_multicast_list( dev );
}
+
static void hp100_stop_interface( struct device *dev )
{
- int ioaddr = dev -> base_addr;
- u_short val;
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
+ int ioaddr = dev->base_addr;
+ u_int val;
- hp100_outw( HP100_INT_EN | HP100_RESET_LB |
- HP100_TRI_INT | HP100_MMAP_DIS | HP100_SET_HB, OPTION_LSW );
- val = hp100_inw( OPTION_LSW );
- hp100_page( HW_MAP );
- hp100_andb( HP100_BM_SLAVE, BM );
- hp100_page( MAC_CTRL );
- hp100_andb( ~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1 );
- if ( !(val & HP100_HW_RST) ) return;
- for ( val = 0; val < 6000; val++ )
- if ( ( hp100_inb( MAC_CFG_1 ) & (HP100_TX_IDLE | HP100_RX_IDLE) ) ==
- (HP100_TX_IDLE | HP100_RX_IDLE) )
- return;
- printk( "%s: hp100_stop_interface - timeout\n", dev -> name );
+#ifdef HP100_DEBUG_B
+ printk("hp100: hp100_stop_interface %s\n",dev->name);
+ hp100_outw( 0x4221, TRACE );
+#endif
+
+ if (lp->mode==1)
+ hp100_BM_shutdown( dev );
+ else
+ {
+ /* Note: MMAP_DIS will be reenabled by start_interface */
+ hp100_outw( HP100_INT_EN | HP100_RESET_LB |
+ HP100_TRI_INT | HP100_MMAP_DIS | HP100_SET_HB, OPTION_LSW );
+ val = hp100_inw( OPTION_LSW );
+
+ hp100_page( MAC_CTRL );
+ hp100_andb( ~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1 );
+
+ if ( !(val & HP100_HW_RST) ) return; /* If reset, imm. return ... */
+ /* ... else: busy wait until idle */
+ for ( val = 0; val < 6000; val++ )
+ if ( ( hp100_inb( MAC_CFG_1 ) & (HP100_TX_IDLE | HP100_RX_IDLE) ) ==
+ (HP100_TX_IDLE | HP100_RX_IDLE) )
+ {
+ hp100_page(PERFORMANCE);
+ return;
+ }
+ printk( "%s: hp100_stop_interface - timeout\n", dev->name );
+ hp100_page(PERFORMANCE);
+ }
}
+
static void hp100_load_eeprom( struct device *dev )
{
int i;
- int ioaddr = dev -> base_addr;
+ int ioaddr = dev->base_addr;
+
+#ifdef HP100_DEBUG_B
+ hp100_outw( 0x4222, TRACE );
+#endif
hp100_page( EEPROM_CTRL );
hp100_andw( ~HP100_EEPROM_LOAD, EEPROM_CTRL );
hp100_orw( HP100_EEPROM_LOAD, EEPROM_CTRL );
- for ( i = 0; i < 6000; i++ )
- if ( !( hp100_inw( OPTION_MSW ) & HP100_EE_LOAD ) ) return;
- printk( "%s: hp100_load_eeprom - timeout\n", dev -> name );
+ for ( i = 0; i < 10000; i++ )
+ if ( !( hp100_inb( OPTION_MSW ) & HP100_EE_LOAD ) ) return;
+ printk( "%s: hp100_load_eeprom - timeout\n", dev->name );
}
-/* return values: LAN_10, LAN_100 or LAN_ERR (not connected or hub is down)... */
-
+
+/* Sense connection status.
+ * return values: LAN_10 - Connected to 10Mbit/s network
+ * LAN_100 - Connected to 100Mbit/s network
+ * LAN_ERR - not connected or 100Mbit/s Hub down
+ */
static int hp100_sense_lan( struct device *dev )
{
- int i;
- int ioaddr = dev -> base_addr;
+ int ioaddr = dev->base_addr;
u_short val_VG, val_10;
- struct hp100_private *lp = (struct hp100_private *)dev -> priv;
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
+
+#ifdef HP100_DEBUG_B
+ hp100_outw( 0x4223, TRACE );
+#endif
hp100_page( MAC_CTRL );
- hp100_orw( HP100_VG_RESET, LAN_CFG_VG );
- val_10 = hp100_inw( LAN_CFG_10 );
- val_VG = hp100_inw( LAN_CFG_VG );
-#ifdef HP100_DEBUG_SENSE
+ /* Enable Auto Selection */
+ /* hp100_orb( HP100_VG_RESET|HP100_LINK_CMD|HP100_VG_SEL, VG_LAN_CFG_1 ); */
+ /* hp100_orb( HP100_DOT3_MAC,10_LAN_CFG_2); */
+ /* hp100_orb( HP100_AUTO_MODE,MAC_CFG_3); */
+ /* Now we have to wait a while... */
+ /* for(i=0; i<5000; i++) */
+ /* { */
+ val_10 = hp100_inb( 10_LAN_CFG_1 );
+ val_VG = hp100_inb( VG_LAN_CFG_1 );
+ /* } */
+#ifdef HP100_DEBUG
printk( "hp100_sense_lan: val_VG = 0x%04x, val_10 = 0x%04x\n", val_VG, val_10 );
#endif
if ( val_10 & HP100_LINK_BEAT_ST ) return HP100_LAN_10;
- if ( lp -> id -> id == 0x02019F022 ) /* HP J27248B doesn't have 100Mb/s interface */
- return HP100_LAN_ERR;
- for ( i = 0; i < 2500; i++ )
- {
- val_VG = hp100_inw( LAN_CFG_VG );
- if ( val_VG & HP100_LINK_CABLE_ST ) return HP100_LAN_100;
+ if ( (lp->id->id == 0x02019F022) ||
+ (lp->id->id == 0x01042103c) ||
+ (lp->id->id == 0x01040103c) )
+ {
+ hp100_page(PERFORMANCE);
+ return HP100_LAN_ERR; /* Those cards don't have a 100 Mbit connector */
}
+ /* for ( i = 0; i < 2500; i++ ) */
+ /* { */
+ val_VG = hp100_inb( VG_LAN_CFG_1 );
+ hp100_page(PERFORMANCE);
+
+ if ( val_VG & HP100_LINK_CABLE_ST ) /* Can hear the HUBs tone. */
+ return HP100_LAN_100;
+ /* } */
return HP100_LAN_ERR;
}
+
+
static int hp100_down_vg_link( struct device *dev )
{
- int ioaddr = dev -> base_addr;
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
+ int ioaddr = dev->base_addr;
unsigned long time;
- int i;
+ long savelan, newlan;
+
+#ifdef HP100_DEBUG_B
+ hp100_outw( 0x4224, TRACE );
+ printk("hp100: down_vg_link\n");
+#endif
hp100_page( MAC_CTRL );
- for ( i = 2500; i > 0; i-- )
- if ( hp100_inw( LAN_CFG_VG ) & HP100_LINK_CABLE_ST ) break;
- if ( i <= 0 ) /* not signal - not logout */
+ time=jiffies+(HZ/4);
+ do{
+ if ( hp100_inb( VG_LAN_CFG_1 ) & HP100_LINK_CABLE_ST ) break;
+ } while (time>jiffies);
+
+ if ( jiffies >= time ) /* no signal->no logout */
return 0;
- hp100_andw( ~HP100_LINK_CMD, LAN_CFG_VG );
- time = jiffies + 10*HZ/100;
- while ( time > jiffies )
- if ( !( hp100_inw( LAN_CFG_VG ) & ( HP100_LINK_UP_ST |
- HP100_LINK_CABLE_ST |
- HP100_LINK_GOOD_ST ) ) )
- return 0;
+
+ /* Drop the VG Link by clearing the link up cmd and load addr.*/
+
+ hp100_andb( ~( HP100_LOAD_ADDR| HP100_LINK_CMD), VG_LAN_CFG_1);
+ hp100_orb( HP100_VG_SEL, VG_LAN_CFG_1);
+
+ /* Conditionally stall for >250ms on Link-Up Status (to go down) */
+ time=jiffies+(HZ/2);
+ do{
+ if ( !(hp100_inb( VG_LAN_CFG_1) & HP100_LINK_UP_ST) ) break;
+ } while(time>jiffies);
+
#ifdef HP100_DEBUG
- printk( "hp100_down_vg_link: timeout\n" );
+ if (jiffies>=time)
+ printk("hp100_down_vg_link: Link does not go down?\n");
#endif
- return -EIO;
-}
-static int hp100_login_to_vg_hub( struct device *dev )
-{
- int i;
- int ioaddr = dev -> base_addr;
- u_short val;
- unsigned long time;
+ /* To prevent condition where Rev 1 VG MAC and old hubs do not complete */
+ /* logout under traffic (even though all the status bits are cleared), */
+ /* do this workaround to get the Rev 1 MAC in its idle state */
+ if ( lp->chip==HP100_CHIPID_LASSEN )
+ {
+ /* Reset VG MAC to insure it leaves the logoff state even if */
+ /* the Hub is still emitting tones */
+ hp100_andb(~HP100_VG_RESET, VG_LAN_CFG_1);
+ udelay(1500); /* wait for >1ms */
+ hp100_orb(HP100_VG_RESET, VG_LAN_CFG_1); /* Release Reset */
+ udelay(1500);
+ }
- hp100_page( MAC_CTRL );
- hp100_orw( HP100_VG_RESET, LAN_CFG_VG );
- time = jiffies + ( HZ / 2 );
+ /* New: For lassen, switch to 10 Mbps mac briefly to clear training ACK */
+ /* to get the VG mac to full reset. This is not req.d with later chips */
+ /* Note: It will take the between 1 and 2 seconds for the VG mac to be */
+ /* selected again! This will be left to the connect hub function to */
+ /* perform if desired. */
+ if (lp->chip==HP100_CHIPID_LASSEN)
+ {
+ /* Have to write to 10 and 100VG control registers simultaneously */
+ savelan=newlan=hp100_inl(10_LAN_CFG_1); /* read 10+100 LAN_CFG regs */
+ newlan &= ~(HP100_VG_SEL<<16);
+ newlan |= (HP100_DOT3_MAC)<<8;
+ hp100_andb( ~HP100_AUTO_MODE, MAC_CFG_3); /* Autosel off */
+ hp100_outl(newlan, 10_LAN_CFG_1);
+
+ /* Conditionally stall for 5sec on VG selected. */
+ time=jiffies+(HZ*5);
+ do{
+ if( !(hp100_inb(MAC_CFG_4) & HP100_MAC_SEL_ST) ) break;
+ } while(time>jiffies);
+
+ hp100_orb( HP100_AUTO_MODE, MAC_CFG_3); /* Autosel back on */
+ hp100_outl(savelan, 10_LAN_CFG_1);
+ }
+
+ time=jiffies+(3*HZ); /* Timeout 3s */
do {
- if ( hp100_inw( LAN_CFG_VG ) & HP100_LINK_CABLE_ST ) break;
- } while ( time > jiffies );
- if ( time <= jiffies )
+ if ( (hp100_inb( VG_LAN_CFG_1 )&HP100_LINK_CABLE_ST) == 0) break;
+ } while (time>jiffies);
+
+ if(time<=jiffies)
{
#ifdef HP100_DEBUG
- printk( "hp100_login_to_vg_hub: timeout for link\n" );
+ printk( "hp100_down_vg_link: timeout\n" );
#endif
return -EIO;
}
+
+ time=jiffies+(2*HZ); /* This seems to take a while.... */
+ do {} while (time>jiffies);
+
+ return 0;
+}
+
+
+static int hp100_login_to_vg_hub( struct device *dev, u_short force_relogin )
+{
+ int ioaddr = dev->base_addr;
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
+ u_short val=0;
+ unsigned long time;
+ int startst;
- if ( hp100_down_vg_link( dev ) < 0 ) /* if fail, try reset VG link */
+#ifdef HP100_DEBUG_B
+ hp100_outw( 0x4225, TRACE );
+ printk("hp100: login_to_vg_hub\n");
+#endif
+
+ /* Initiate a login sequence iff VG MAC is enabled and either Load Address
+ * bit is zero or the force relogin flag is set (e.g. due to MAC address or
+ * promiscuous mode change)
+ */
+ hp100_page( MAC_CTRL );
+ startst=hp100_inb( VG_LAN_CFG_1 );
+ if((force_relogin==TRUE)||(hp100_inb( MAC_CFG_4 )&HP100_MAC_SEL_ST))
{
- hp100_andw( ~HP100_VG_RESET, LAN_CFG_VG );
- hp100_orw( HP100_VG_RESET, LAN_CFG_VG );
+#ifdef HP100_DEBUG_TRAINING
+ printk("hp100: Start training\n");
+#endif
+
+ /* Ensure VG Reset bit is 1 (i.e., do not reset)*/
+ hp100_orb( HP100_VG_RESET , VG_LAN_CFG_1 );
+
+ /* If Lassen AND auto-select-mode AND VG tones were sensed on */
+ /* entry then temporarily put them into force 100Mbit mode */
+ if((lp->chip==HP100_CHIPID_LASSEN)&&( startst & HP100_LINK_CABLE_ST ) )
+ hp100_andb( ~HP100_DOT3_MAC, 10_LAN_CFG_2 );
+
+ /* Drop the VG link by zeroing Link Up Command and Load Address */
+ hp100_andb( ~(HP100_LINK_CMD/* |HP100_LOAD_ADDR */), VG_LAN_CFG_1);
+
+#ifdef HP100_DEBUG_TRAINING
+ printk("hp100: Bring down the link\n");
+#endif
+
+ /* Wait for link to drop */
+ time = jiffies + (HZ/10);
+ do {
+ if (~(hp100_inb( VG_LAN_CFG_1 )& HP100_LINK_UP_ST) ) break;
+ } while (time>jiffies);
+
+ /* Start an addressed training and optionally request promiscuous port */
+ if ( (dev->flags) & IFF_PROMISC )
+ {
+ hp100_orb( HP100_PROM_MODE, VG_LAN_CFG_2);
+ if(lp->chip==HP100_CHIPID_LASSEN)
+ hp100_orw( HP100_MACRQ_PROMSC, TRAIN_REQUEST );
+ }
+ else
+ {
+ hp100_andb( ~HP100_PROM_MODE, VG_LAN_CFG_2);
+ /* For ETR parts we need to reset the prom. bit in the training
+ * register, otherwise promiscious mode won't be disabled.
+ */
+ if(lp->chip==HP100_CHIPID_LASSEN)
+ {
+ hp100_andw( ~HP100_MACRQ_PROMSC, TRAIN_REQUEST );
+ }
+ }
+
+ /* With ETR parts, frame format request bits can be set. */
+ if(lp->chip==HP100_CHIPID_LASSEN)
+ hp100_orb( HP100_MACRQ_FRAMEFMT_EITHER, TRAIN_REQUEST);
+
+ hp100_orb( HP100_LINK_CMD|HP100_LOAD_ADDR|HP100_VG_RESET, VG_LAN_CFG_1);
+
+ /* Note: Next wait could be omitted for Hood and earlier chips under */
+ /* certain circumstances */
+ /* TODO: check if hood/earlier and skip wait. */
+
+ /* Wait for either short timeout for VG tones or long for login */
+ /* Wait for the card hardware to signalise link cable status ok... */
+ hp100_page( MAC_CTRL );
+ time = jiffies + ( 1*HZ ); /* 1 sec timeout for cable st */
+ do {
+ if ( hp100_inb( VG_LAN_CFG_1 ) & HP100_LINK_CABLE_ST ) break;
+ } while ( jiffies < time );
+
+ if ( jiffies >= time )
+ {
+#ifdef HP100_DEBUG_TRAINING
+ printk( "hp100: Link cable status not ok? Training aborted.\n" );
+#endif
+ }
+ else
+ {
+#ifdef HP100_DEBUG_TRAINING
+ printk( "hp100: HUB tones detected. Trying to train.\n");
+#endif
+
+ time = jiffies + ( 2*HZ ); /* again a timeout */
+ do {
+ val = hp100_inb( VG_LAN_CFG_1 );
+ if ( (val & ( HP100_LINK_UP_ST )) )
+ {
+#ifdef HP100_DEBUG_TRAINING
+ printk( "hp100: Passed training.\n");
+#endif
+ break;
+ }
+ } while ( time > jiffies );
+ }
+
+ /* If LINK_UP_ST is set, then we are logged into the hub. */
+ if ( (jiffies<=time) && (val & HP100_LINK_UP_ST) )
+ {
+#ifdef HP100_DEBUG_TRAINING
+ printk( "hp100: Successfully logged into the HUB.\n");
+ if(lp->chip==HP100_CHIPID_LASSEN)
+ {
+ val = hp100_inw(TRAIN_ALLOW);
+ printk( "hp100: Card supports 100VG MAC Version \"%s\" ",
+ (hp100_inw(TRAIN_REQUEST)&HP100_CARD_MACVER) ? "802.12" : "Pre");
+ printk( "Driver will use MAC Version \"%s\"\n",
+ ( val & HP100_HUB_MACVER) ? "802.12" : "Pre" );
+ printk( "hp100: Frame format is %s.\n",(val&HP100_MALLOW_FRAMEFMT)?"802.5":"802.3");
+ }
+#endif
+ }
+ else
+ {
+ /* If LINK_UP_ST is not set, login was not successful */
+ printk("hp100/%s: Problem logging into the HUB.\n",dev->name);
+ if(lp->chip==HP100_CHIPID_LASSEN)
+ {
+ /* Check allowed Register to find out why there is a problem. */
+ val = hp100_inw( TRAIN_ALLOW ); /* wont work on non-ETR card */
+#ifdef HP100_DEBUG_TRAINING
+ printk("hp100: MAC Configuration requested: 0x%04x, HUB allowed: 0x%04x\n", hp100_inw(TRAIN_REQUEST), val);
+#endif
+ if ( val & HP100_MALLOW_ACCDENIED )
+ printk("hp100: HUB access denied.\n");
+ if ( val & HP100_MALLOW_CONFIGURE )
+ printk("hp100: MAC Configuration is incompatible with the Network.\n");
+ if ( val & HP100_MALLOW_DUPADDR )
+ printk("hp100: Duplicate MAC Address on the Network.\n");
+ }
+ }
+
+ /* If we have put the chip into forced 100 Mbit mode earlier, go back */
+ /* to auto-select mode */
+
+ if( (lp->chip==HP100_CHIPID_LASSEN)&&(startst & HP100_LINK_CABLE_ST) )
+ {
+ hp100_page( MAC_CTRL );
+ hp100_orb( HP100_DOT3_MAC, 10_LAN_CFG_2 );
+ }
+
+ val=hp100_inb(VG_LAN_CFG_1);
+
+ /* Clear the MISC_ERROR Interrupt, which might be generated when doing the relogin */
+ hp100_page(PERFORMANCE);
+ hp100_outw( HP100_MISC_ERROR, IRQ_STATUS);
+
+ if (val&HP100_LINK_UP_ST)
+ return(0); /* login was ok */
+ else
+ {
+ printk("hp100: Training failed.\n");
+ hp100_down_vg_link( dev );
+ return -EIO;
+ }
}
- /* bring up link */
- hp100_orw( HP100_LOAD_ADDR | HP100_LINK_CMD, LAN_CFG_VG );
- for ( i = 2500; i > 0; i-- )
- if ( hp100_inw( LAN_CFG_VG ) & HP100_LINK_CABLE_ST ) break;
- if ( i <= 0 )
- {
-#ifdef HP100_DEBUG
- printk( "hp100_login_to_vg_hub: timeout for link (bring up)\n" );
+ /* no forced relogin & already link there->no training. */
+ return -EIO;
+}
+
+
+static void hp100_cascade_reset( struct device *dev, u_short enable )
+{
+ int ioaddr = dev->base_addr;
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
+ int i;
+
+#ifdef HP100_DEBUG_B
+ hp100_outw( 0x4226, TRACE );
+ printk("hp100: cascade_reset\n");
#endif
- goto down_link;
+
+ if (enable==TRUE)
+ {
+ hp100_outw( HP100_HW_RST | HP100_RESET_LB, OPTION_LSW );
+ if(lp->chip==HP100_CHIPID_LASSEN)
+ {
+ /* Lassen requires a PCI transmit fifo reset */
+ hp100_page( HW_MAP );
+ hp100_andb( ~HP100_PCI_RESET, PCICTRL2 );
+ hp100_orb( HP100_PCI_RESET, PCICTRL2 );
+ /* Wait for min. 300 ns */
+ /* we cant use jiffies here, because it may be */
+ /* that we have disabled the timer... */
+ for (i=0; i<0xffff; i++);
+ hp100_andb( ~HP100_PCI_RESET, PCICTRL2 );
+ hp100_page( PERFORMANCE );
+ }
+ }
+ else
+ { /* bring out of reset */
+ hp100_outw(HP100_HW_RST|HP100_SET_LB, OPTION_LSW);
+ for (i=0; i<0xffff; i++ );
+ hp100_page(PERFORMANCE);
}
+}
- time = jiffies + ( HZ / 2 );
- do {
- val = hp100_inw( LAN_CFG_VG );
- if ( ( val & ( HP100_LINK_UP_ST | HP100_LINK_GOOD_ST ) ) ==
- ( HP100_LINK_UP_ST | HP100_LINK_GOOD_ST ) )
- return 0; /* success */
- } while ( time > jiffies );
- if ( val & HP100_LINK_GOOD_ST )
- printk( "%s: 100Mb cable training failed, check cable.\n", dev -> name );
- else
- printk( "%s: 100Mb node not accepted by hub, check frame type or security.\n", dev -> name );
-
-down_link:
- hp100_down_vg_link( dev );
- hp100_page( MAC_CTRL );
- hp100_andw( ~( HP100_LOAD_ADDR | HP100_PROM_MODE ), LAN_CFG_VG );
- hp100_orw( HP100_LINK_CMD, LAN_CFG_VG );
- return -EIO;
+#ifdef HP100_DEBUG
+void hp100_RegisterDump( struct device *dev )
+{
+ int ioaddr=dev->base_addr;
+ int Page;
+ int Register;
+
+ /* Dump common registers */
+ printk("hp100: Cascade Register Dump\n");
+ printk("hardware id #1: 0x%.2x\n",hp100_inb(HW_ID));
+ printk("hardware id #2/paging: 0x%.2x\n",hp100_inb(PAGING));
+ printk("option #1: 0x%.4x\n",hp100_inw(OPTION_LSW));
+ printk("option #2: 0x%.4x\n",hp100_inw(OPTION_MSW));
+
+ /* Dump paged registers */
+ for (Page = 0; Page < 8; Page++)
+ {
+ /* Dump registers */
+ printk("page: 0x%.2x\n",Page);
+ outw( Page, ioaddr+0x02);
+ for (Register = 0x8; Register < 0x22; Register += 2)
+ {
+ /* Display Register contents except data port */
+ if (((Register != 0x10) && (Register != 0x12)) || (Page > 0))
+ {
+ printk("0x%.2x = 0x%.4x\n",Register,inw(ioaddr+Register));
+ }
+ }
+ }
+ hp100_page(PERFORMANCE);
}
+#endif
+
+
/*
* module section
*/
-
+
#ifdef MODULE
-static int hp100_port = -1;
-MODULE_PARM(hp100_port, "i");
+/* Parameters set by insmod */
+int hp100_port[5] = { 0, -1, -1, -1, -1 };
+#ifdef LINUX_2_1
+MODULE_PARM(hp100_port, "1-5i");
+#endif
-static char devicename[9] = { 0, };
-static struct device dev_hp100 = {
- devicename, /* device name is inserted by linux/drivers/net/net_init.c */
- 0, 0, 0, 0,
- 0, 0,
- 0, 0, 0, NULL, hp100_probe
-};
+#ifdef LINUX_2_1
+char hp100_name[5][IFNAMSIZ] = { "", "", "", "", "" };
+MODULE_PARM(hp100_name, "1-5c" __MODULE_STRING(IFNAMSIZ));
+#else
+static char devname[5][IFNAMSIZ] = { "", "", "", "", "" };
+static char *hp100_name[5] = { devname[0], devname[1],
+ devname[2], devname[3],
+ devname[4] };
+#endif
+
+/* List of devices */
+static struct device *hp100_devlist[5] = { NULL, NULL, NULL, NULL, NULL };
+
+/*
+ * Note: if you have more than five 100vg cards in your pc, feel free to
+ * increase this value
+ */
+
+/*
+ * Note: to register three eisa or pci devices, use:
+ * option hp100 hp100_port=0,0,0
+ * to register one card at io 0x280 as eth239, use:
+ * option hp100 hp100_port=0x280 hp100_name=eth239
+ */
int init_module( void )
{
- if (hp100_port == 0 && !EISA_bus)
+ int i;
+ int ret = 0;
+
+ if (hp100_port == 0 && !EISA_bus && !pcibios_present())
printk("HP100: You should not use auto-probing with insmod!\n");
- if ( hp100_port > 0 )
- dev_hp100.base_addr = hp100_port;
- if ( register_netdev( &dev_hp100 ) != 0 )
- return -EIO;
- return 0;
+
+ /* Loop on all possible base addresses */
+ i = -1;
+ while((hp100_port[++i] != -1) && (i < 5))
+ {
+ /* Create device and set basics args */
+ hp100_devlist[i] = kmalloc(sizeof(struct device), GFP_KERNEL);
+ memset(hp100_devlist[i], 0x00, sizeof(struct device));
+ hp100_devlist[i]->name = hp100_name[i];
+ hp100_devlist[i]->base_addr = hp100_port[i];
+ hp100_devlist[i]->init = &hp100_probe;
+
+ /* Try to create the device */
+ if(register_netdev(hp100_devlist[i]) != 0)
+ {
+ /* DeAllocate everything */
+ /* Note: if dev->priv is mallocated, there is no way to fail */
+ kfree_s(hp100_devlist[i], sizeof(struct device));
+ hp100_devlist[i] = (struct device *) NULL;
+ ret = -EIO;
+ }
+ } /* Loop over all devices */
+
+ return ret;
}
void cleanup_module( void )
{
- unregister_netdev( &dev_hp100 );
- release_region( dev_hp100.base_addr, HP100_REGION_SIZE );
- if ( ((struct hp100_private *)dev_hp100.priv) -> mem_ptr_virt )
- iounmap( ((struct hp100_private *)dev_hp100.priv) -> mem_ptr_virt );
- kfree_s( dev_hp100.priv, sizeof( struct hp100_private ) );
- dev_hp100.priv = NULL;
+ int i;
+
+ /* TODO: Check if all skb's are released/freed. */
+ for(i = 0; i < 5; i++)
+ if(hp100_devlist[i] != (struct device *) NULL)
+ {
+ unregister_netdev( hp100_devlist[i] );
+ release_region( hp100_devlist[i]->base_addr, HP100_REGION_SIZE );
+ if( ((struct hp100_private *)hp100_devlist[i]->priv)->mode==1 ) /* busmaster */
+ kfree_s( ((struct hp100_private *)hp100_devlist[i]->priv)->page_vaddr, MAX_RINGSIZE+0x0f);
+ if ( ((struct hp100_private *)hp100_devlist[i]->priv) -> mem_ptr_virt )
+ iounmap( ((struct hp100_private *)hp100_devlist[i]->priv) -> mem_ptr_virt );
+ kfree_s( hp100_devlist[i]->priv, sizeof( struct hp100_private ) );
+ hp100_devlist[i]->priv = NULL;
+ kfree_s(hp100_devlist[i], sizeof(struct device));
+ hp100_devlist[i] = (struct device *) NULL;
+ }
}
-#endif
+#endif /* MODULE */
+
+
+
+/*
+ * Local variables:
+ * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c hp100.c"
+ * c-indent-level: 2
+ * tab-width: 8
+ * End:
+ */
diff --git a/drivers/net/hp100.h b/drivers/net/hp100.h
index 1ebca564d..436dd3700 100644
--- a/drivers/net/hp100.h
+++ b/drivers/net/hp100.h
@@ -1,9 +1,10 @@
/*
* hp100.h: Hewlett Packard HP10/100VG ANY LAN ethernet driver for Linux.
*
- * Author: Jaroslav Kysela, <perex@pf.jcu.cz>
+ * $Id: hp100.h,v 1.51 1997/04/08 14:26:42 floeff Exp floeff $
*
- * Header file...
+ * Authors: Jaroslav Kysela, <perex@pf.jcu.cz>
+ * Siegfried Loeffler <floeff@tunix.mathematik.uni-stuttgart.de>
*
* This driver is based on the 'hpfepkt' crynwr packet driver.
*
@@ -16,9 +17,10 @@
/****************************************************************************
* Hardware Constants
****************************************************************************/
-
-/*
- * ATT2MD01 Register Page Constants
+
+/*
+ * Page Identifiers
+ * (Swap Paging Register, PAGING, bits 3:0, Offset 0x02)
*/
#define HP100_PAGE_PERFORMANCE 0x0 /* Page 0 */
@@ -30,11 +32,8 @@
#define HP100_PAGE_ID_MAC_ADDR 0x6 /* Page 6 */
#define HP100_PAGE_MMU_POINTER 0x7 /* Page 7 */
-/*
- * ATT2MD01 Register Addresses
- */
-/* Present on all pages */
+/* Registers that are present on all pages */
#define HP100_REG_HW_ID 0x00 /* R: (16) Unique card ID */
#define HP100_REG_TRACE 0x00 /* W: (16) Used for debug output */
@@ -47,14 +46,29 @@
#define HP100_REG_IRQ_STATUS 0x08 /* RW: (16) Which ints are pending */
#define HP100_REG_IRQ_MASK 0x0a /* RW: (16) Select ints to allow */
-#define HP100_REG_FRAGMENT_LEN 0x0c /* RW: (16)12:0 Current fragment len */
+#define HP100_REG_FRAGMENT_LEN 0x0c /* W: (16)12:0 Current fragment len */
+/* Note: For 32 bit systems, fragment len and offset registers are available */
+/* at offset 0x28 and 0x2c, where they can be written as 32bit values. */
#define HP100_REG_OFFSET 0x0e /* RW: (16)12:0 Offset to start read */
#define HP100_REG_DATA32 0x10 /* RW: (32) I/O mode data port */
#define HP100_REG_DATA16 0x12 /* RW: WORDs must be read from here */
#define HP100_REG_TX_MEM_FREE 0x14 /* RD: (32) Amount of free Tx mem */
+#define HP100_REG_TX_PDA_L 0x14 /* W: (32) BM: Ptr to PDL, Low Pri */
+#define HP100_REG_TX_PDA_H 0x1c /* W: (32) BM: Ptr to PDL, High Pri */
#define HP100_REG_RX_PKT_CNT 0x18 /* RD: (8) Rx count of pkts on card */
#define HP100_REG_TX_PKT_CNT 0x19 /* RD: (8) Tx count of pkts on card */
-
+#define HP100_REG_RX_PDL 0x1a /* R: (8) BM: # rx pdl not executed */
+#define HP100_REG_TX_PDL 0x1b /* R: (8) BM: # tx pdl not executed */
+#define HP100_REG_RX_PDA 0x18 /* W: (32) BM: Up to 31 addresses */
+ /* which point to a PDL */
+#define HP100_REG_SL_EARLY 0x1c /* (32) Enhanced Slave Early Rx */
+#define HP100_REG_STAT_DROPPED 0x20 /* R (12) Dropped Packet Counter */
+#define HP100_REG_STAT_ERRORED 0x22 /* R (8) Errored Packet Counter */
+#define HP100_REG_STAT_ABORT 0x23 /* R (8) Abort Counter/OW Coll. Flag */
+#define HP100_REG_RX_RING 0x24 /* W (32) Slave: RX Ring Pointers */
+#define HP100_REG_32_FRAGMENT_LEN 0x28 /* W (13) Slave: Fragment Length Reg */
+#define HP100_REG_32_OFFSET 0x2c /* W (16) Slave: Offset Register */
+
/* Page 1 - MAC Address/Hash Table */
#define HP100_REG_MAC_ADDR 0x08 /* RW: (8) Cards MAC address */
@@ -68,27 +82,46 @@
#define HP100_REG_IRQ_CHANNEL 0x0d /* RW: (8) IRQ and edge/level int */
#define HP100_REG_SRAM 0x0e /* RW: (8) How much RAM on card */
#define HP100_REG_BM 0x0f /* RW: (8) Controls BM functions */
+
+/* New on Page 2 for ETR chips: */
+#define HP100_REG_MODECTRL1 0x10 /* RW: (8) Mode Control 1 */
+#define HP100_REG_MODECTRL2 0x11 /* RW: (8) Mode Control 2 */
+#define HP100_REG_PCICTRL1 0x12 /* RW: (8) PCI Cfg 1 */
+#define HP100_REG_PCICTRL2 0x13 /* RW: (8) PCI Cfg 2 */
+#define HP100_REG_PCIBUSMLAT 0x15 /* RW: (8) PCI Bus Master Latency */
+#define HP100_REG_EARLYTXCFG 0x16 /* RW: (16) Early TX Cfg/Cntrl Reg */
+#define HP100_REG_EARLYRXCFG 0x18 /* RW: (8) Early RX Cfg/Cntrl Reg */
+#define HP100_REG_ISAPNPCFG1 0x1a /* RW: (8) ISA PnP Cfg/Cntrl Reg 1 */
+#define HP100_REG_ISAPNPCFG2 0x1b /* RW: (8) ISA PnP Cfg/Cntrl Reg 2 */
/* Page 3 - EEPROM/Boot ROM */
#define HP100_REG_EEPROM_CTRL 0x08 /* RW: (16) Used to load EEPROM */
+#define HP100_REG_BOOTROM_CTRL 0x0a
-/* Page 4 - LAN Configuration */
+/* Page 4 - LAN Configuration (MAC_CTRL) */
-#define HP100_REG_LAN_CFG_10 0x08 /* RW: (16) Set 10M XCVR functions */
-#define HP100_REG_LAN_CFG_VG 0x0a /* RW: (16) Set 100M XCVR functions */
+#define HP100_REG_10_LAN_CFG_1 0x08 /* RW: (8) Set 10M XCVR functions */
+#define HP100_REG_10_LAN_CFG_2 0x09 /* RW: (8) 10M XCVR functions */
+#define HP100_REG_VG_LAN_CFG_1 0x0a /* RW: (8) Set 100M XCVR functions */
+#define HP100_REG_VG_LAN_CFG_2 0x0b /* RW: (8) 100M LAN Training cfgregs */
#define HP100_REG_MAC_CFG_1 0x0c /* RW: (8) Types of pkts to accept */
#define HP100_REG_MAC_CFG_2 0x0d /* RW: (8) Misc MAC functions */
-/* The follow clear when read: */
+#define HP100_REG_MAC_CFG_3 0x0e /* RW: (8) Misc MAC functions */
+#define HP100_REG_MAC_CFG_4 0x0f /* R: (8) Misc MAC states */
#define HP100_REG_DROPPED 0x10 /* R: (16),11:0 Pkts cant fit in mem*/
#define HP100_REG_CRC 0x12 /* R: (8) Pkts with CRC */
#define HP100_REG_ABORT 0x13 /* R: (8) Aborted Tx pkts */
-
+#define HP100_REG_TRAIN_REQUEST 0x14 /* RW: (16) Endnode MAC register.*/
+#define HP100_REG_TRAIN_ALLOW 0x16 /* R: (16) Hub allowed register */
+
/* Page 5 - MMU */
#define HP100_REG_RX_MEM_STOP 0x0c /* RW: (16) End of Rx ring addr */
#define HP100_REG_TX_MEM_STOP 0x0e /* RW: (16) End of Tx ring addr */
-
+#define HP100_REG_PDL_MEM_STOP 0x10 /* Not used by 802.12 devices */
+#define HP100_REG_ECB_MEM_STOP 0x14 /* I've no idea what this is */
+
/* Page 6 - Card ID/Physical LAN Address */
#define HP100_REG_BOARD_ID 0x08 /* R: (8) EISA/ISA card ID */
@@ -99,32 +132,46 @@
/* Page 7 - MMU Current Pointers */
-#define HP100_REG_RX_MEM_BR 0x08 /* R: (16) Current begin of Rx ring */
-#define HP100_REG_RX_MEM_ER 0x0a /* R: (16) Current end of Rx ring */
-#define HP100_REG_TX_MEM_BR 0x0c /* R: (16) Current begin of Tx ring */
-#define HP100_REG_TX_MEM_ER 0x0e /* R: (16) Current end of Rx ring */
-#define HP100_REG_MEM_DEBUG 0x1a /* RW: (16) Used for memory tests */
-
-/*
- * HardwareIDReg bits/masks
+#define HP100_REG_PTR_RXSTART 0x08 /* R: (16) Current begin of Rx ring */
+#define HP100_REG_PTR_RXEND 0x0a /* R: (16) Current end of Rx ring */
+#define HP100_REG_PTR_TXSTART 0x0c /* R: (16) Current begin of Tx ring */
+#define HP100_REG_PTR_TXEND 0x0e /* R: (16) Current end of Rx ring */
+#define HP100_REG_PTR_RPDLSTART 0x10
+#define HP100_REG_PTR_RPDLEND 0x12
+#define HP100_REG_PTR_RINGPTRS 0x14
+#define HP100_REG_PTR_MEMDEBUG 0x1a
+/* ------------------------------------------------------------------------ */
+
+
+/*
+ * Hardware ID Register I (Always available, HW_ID, Offset 0x00)
*/
+#define HP100_HW_ID_CASCADE 0x4850 /* Identifies Cascade Chip */
-#define HP100_HW_ID_0 0x50 /* Hardware ID bytes. */
-#define HP100_HW_ID_1 0x48
-#define HP100_HW_ID_2_REVA 0x50 /* Rev. A ID. NOTE: lower nibble not used */
-#define HP100_HW_ID_3 0x53
+/*
+ * Hardware ID Register 2 & Paging Register
+ * (Always available, PAGING, Offset 0x02)
+ * Bits 15:4 are for the Chip ID
+ */
+#define HP100_CHIPID_MASK 0xFFF0
+#define HP100_CHIPID_SHASTA 0x5350 /* Not 802.12 compliant */
+ /* EISA BM/SL, MCA16/32 SL, ISA SL */
+#define HP100_CHIPID_RAINIER 0x5360 /* Not 802.12 compliant EISA BM,*/
+ /* PCI SL, MCA16/32 SL, ISA SL */
+#define HP100_CHIPID_LASSEN 0x5370 /* 802.12 compliant PCI BM, PCI SL */
+ /* LRF supported */
/*
- * OptionLSWReg bits/masks
+ * Option Registers I and II
+ * (Always available, OPTION_LSW, Offset 0x04-0x05)
*/
-
-#define HP100_DEBUG_EN 0x8000 /* 0:Disable, 1:Enable Debug Dump Pointer */
-#define HP100_RX_HDR 0x4000 /* 0:Disable, 1:Enable putting pkt into */
- /* system memory before Rx interrupt */
-#define HP100_MMAP_DIS 0x2000 /* 0:Enable, 1:Disable memory mapping. */
- /* MMAP_DIS must be 0 and MEM_EN must */
- /* be 1 for memory-mapped mode to be */
- /* enabled */
+#define HP100_DEBUG_EN 0x8000 /* 0:Dis., 1:Enable Debug Dump Ptr. */
+#define HP100_RX_HDR 0x4000 /* 0:Dis., 1:Enable putting pkt into */
+ /* system mem. before Rx interrupt */
+#define HP100_MMAP_DIS 0x2000 /* 0:Enable, 1:Disable mem.mapping. */
+ /* MMAP_DIS must be 0 and MEM_EN */
+ /* must be 1 for memory-mapped */
+ /* mode to be enabled */
#define HP100_EE_EN 0x1000 /* 0:Disable,1:Enable EEPROM writing */
#define HP100_BM_WRITE 0x0800 /* 0:Slave, 1:Bus Master for Tx data */
#define HP100_BM_READ 0x0400 /* 0:Slave, 1:Bus Master for Rx data */
@@ -132,121 +179,236 @@
#define HP100_MEM_EN 0x0040 /* Config program set this to */
/* 0:Disable, 1:Enable mem map. */
/* See MMAP_DIS. */
-#define HP100_IO_EN 0x0020 /* 0:Disable, 1:Enable I/O transfers */
-#define HP100_BOOT_EN 0x0010 /* 0:Disable, 1:Enable boot ROM access */
-#define HP100_FAKE_INT 0x0008 /* 0:No int, 1:int */
-#define HP100_INT_EN 0x0004 /* 0:Disable, 1:Enable ints from card */
+#define HP100_IO_EN 0x0020 /* 1:Enable I/O transfers */
+#define HP100_BOOT_EN 0x0010 /* 1:Enable boot ROM access */
+#define HP100_FAKE_INT 0x0008 /* 1:int */
+#define HP100_INT_EN 0x0004 /* 1:Enable ints from card */
#define HP100_HW_RST 0x0002 /* 0:Reset, 1:Out of reset */
+ /* NIC reset on 0 to 1 transition */
/*
- * OptionMSWReg bits/masks
+ * Option Register III
+ * (Always available, OPTION_MSW, Offset 0x06)
*/
-#define HP100_PRIORITY_TX 0x0080 /* 0:Don't, 1:Do all Tx pkts as priority */
+#define HP100_PRIORITY_TX 0x0080 /* 1:Do all Tx pkts as priority */
#define HP100_EE_LOAD 0x0040 /* 1:EEPROM loading, 0 when done */
-#define HP100_ADV_NXT_PKT 0x0004 /* 1:Advance to next pkt in Rx queue, */
+#define HP100_ADV_NXT_PKT 0x0004 /* 1:Advance to next pkt in Rx queue */
/* h/w will set to 0 when done */
-#define HP100_TX_CMD 0x0002 /* 1:Tell h/w download done, h/w will set */
- /* to 0 when done */
+#define HP100_TX_CMD 0x0002 /* 1:Tell h/w download done, h/w */
+ /* will set to 0 when done */
/*
- * InterruptStatusReg/InterruptMaskReg bits/masks. These bits will 0 when a 1
- * is written to them.
+ * Interrupt Status Registers I and II
+ * (Page PERFORMANCE, IRQ_STATUS, Offset 0x08-0x09)
+ * Note: With old chips, these Registers will clear when 1 is written to them
+ * with new chips this depends on setting of CLR_ISMODE
*/
+#define HP100_RX_EARLY_INT 0x2000
+#define HP100_RX_PDA_ZERO 0x1000
+#define HP100_RX_PDL_FILL_COMPL 0x0800
#define HP100_RX_PACKET 0x0400 /* 0:No, 1:Yes pkt has been Rx */
#define HP100_RX_ERROR 0x0200 /* 0:No, 1:Yes Rx pkt had error */
+#define HP100_TX_PDA_ZERO 0x0020 /* 1 when PDA count goes to zero */
#define HP100_TX_SPACE_AVAIL 0x0010 /* 0:<8192, 1:>=8192 Tx free bytes */
#define HP100_TX_COMPLETE 0x0008 /* 0:No, 1:Yes a Tx has completed */
+#define HP100_MISC_ERROR 0x0004 /* 0:No, 1:Lan Link down or bus error*/
#define HP100_TX_ERROR 0x0002 /* 0:No, 1:Yes Tx pkt had error */
-
+
/*
- * TxMemoryFreeCountReg bits/masks.
+ * Xmit Memory Free Count
+ * (Page PERFORMANCE, TX_MEM_FREE, Offset 0x14) (Read only, 32bit)
*/
-#define HP100_AUTO_COMPARE 0x8000 /* Says at least 8k is available for Tx. */
- /* NOTE: This mask is for the upper */
- /* word of the register. */
+#define HP100_AUTO_COMPARE 0x80000000 /* Tx Space avail & pkts<255 */
+#define HP100_FREE_SPACE 0x7fffffe0 /* Tx free memory */
/*
- * IRQChannelReg bits/masks.
+ * IRQ Channel
+ * (Page HW_MAP, IRQ_CHANNEL, Offset 0x0d)
*/
#define HP100_ZERO_WAIT_EN 0x80 /* 0:No, 1:Yes asserts NOWS signal */
+#define HP100_IRQ_SCRAMBLE 0x40
+#define HP100_BOND_HP 0x20
#define HP100_LEVEL_IRQ 0x10 /* 0:Edge, 1:Level type interrupts. */
- /* Only valid on EISA cards. */
-#define HP100_IRQ_MASK 0x0F /* Isolate the IRQ bits */
+ /* (Only valid on EISA cards) */
+#define HP100_IRQMASK 0x0F /* Isolate the IRQ bits */
/*
- * SRAMReg bits/masks.
+ * SRAM Parameters
+ * (Page HW_MAP, SRAM, Offset 0x0e)
*/
#define HP100_RAM_SIZE_MASK 0xe0 /* AND to get SRAM size index */
-#define HP100_RAM_SIZE_SHIFT 0x05 /* Shift count to put index in lower bits */
+#define HP100_RAM_SIZE_SHIFT 0x05 /* Shift count(put index in lwr bits)*/
+
+/*
+ * Bus Master Register
+ * (Page HW_MAP, BM, Offset 0x0f)
+ */
+#define HP100_BM_BURST_RD 0x01 /* EISA only: 1=Use burst trans. fm system */
+ /* memory to chip (tx) */
+#define HP100_BM_BURST_WR 0x02 /* EISA only: 1=Use burst trans. fm system */
+ /* memory to chip (rx) */
+#define HP100_BM_MASTER 0x04 /* 0:Slave, 1:BM mode */
+#define HP100_BM_PAGE_CK 0x08 /* This bit should be set whenever in*/
+ /* an EISA system */
+#define HP100_BM_PCI_8CLK 0x40 /* ... cycles 8 clocks apart */
+
+
+/*
+ * Mode Control Register I
+ * (Page HW_MAP, MODECTRL1, Offset0x10)
+ */
+#define HP100_TX_DUALQ 0x10
+ /* If set and BM -> dual tx pda queues*/
+#define HP100_ISR_CLRMODE 0x02 /* If set ISR will clear all pending */
+ /* interrupts on read (etr only?) */
+#define HP100_EE_NOLOAD 0x04 /* Status whether res will be loaded */
+ /* from the eeprom */
+#define HP100_TX_CNT_FLG 0x08 /* Controls Early TX Reg Cnt Field */
+#define HP100_PDL_USE3 0x10 /* If set BM engine will read only */
+ /* first three data elements of a PDL */
+ /* on the first access. */
+#define HP100_BUSTYPE_MASK 0xe0 /* Three bit bus type info */
+
+/*
+ * Mode Control Register II
+ * (Page HW_MAP, MODECTRL2, Offset0x11)
+ */
+#define HP100_EE_MASK 0x0f /* Tell EEPROM circuit not to load */
+ /* certain resources */
+#define HP100_DIS_CANCEL 0x20 /* For tx dualq mode operation */
+#define HP100_EN_PDL_WB 0x40 /* 1: Status of PDL completion may be */
+ /* written back to system mem */
+#define HP100_EN_BUS_FAIL 0x80 /* Enables bus-fail portion of misc */
+ /* interrupt */
+
+/*
+ * PCI Configuration and Control Register I
+ * (Page HW_MAP, PCICTRL1, Offset 0x12)
+ */
+#define HP100_LO_MEM 0x01 /* 1: Mapped Mem requested below 1MB */
+#define HP100_NO_MEM 0x02 /* 1: Disables Req for sysmem to PCI */
+ /* bios */
+#define HP100_USE_ISA 0x04 /* 1: isa type decodes will occur */
+ /* simultaneously with PCI decodes */
+#define HP100_IRQ_HI_MASK 0xf0 /* pgmed by pci bios */
+#define HP100_PCI_IRQ_HI_MASK 0x78 /* Isolate 4 bits for PCI IRQ */
+
+/*
+ * PCI Configuration and Control Register II
+ * (Page HW_MAP, PCICTRL2, Offset 0x13)
+ */
+#define HP100_RD_LINE_PDL 0x01 /* 1: PCI command Memory Read Line en */
+#define HP100_RD_TX_DATA_MASK 0x06 /* choose PCI memread cmds for TX */
+#define HP100_MWI 0x08 /* 1: en. PCI memory write invalidate */
+#define HP100_ARB_MODE 0x10 /* Select PCI arbitor type */
+#define HP100_STOP_EN 0x20 /* Enables PCI state machine to issue */
+ /* pci stop if cascade not ready */
+#define HP100_IGNORE_PAR 0x40 /* 1: PCI state machine ignores parity*/
+#define HP100_PCI_RESET 0x80 /* 0->1: Reset PCI block */
/*
- * BMReg bits/masks.
+ * Early TX Configuration and Control Register
+ * (Page HW_MAP, EARLYTXCFG, Offset 0x16)
*/
-#define HP100_BM_SLAVE 0x04 /* 0:Slave, 1:BM mode */
+#define HP100_EN_EARLY_TX 0x8000 /* 1=Enable Early TX */
+#define HP100_EN_ADAPTIVE 0x4000 /* 1=Enable adaptive mode */
+#define HP100_EN_TX_UR_IRQ 0x2000 /* reserved, must be 0 */
+#define HP100_EN_LOW_TX 0x1000 /* reserved, must be 0 */
+#define HP100_ET_CNT_MASK 0x0fff /* bits 11..0: ET counters */
/*
- * EEPROMControlReg bits/masks.
+ * Early RX Configuration and Control Register
+ * (Page HW_MAP, EARLYRXCFG, Offset 0x18)
*/
-#define HP100_EEPROM_LOAD 0x0001 /* 0->1 loads the EEPROM into registers. */
- /* When it goes back to 0, load is */
- /* complete. This should take ~600us. */
+#define HP100_EN_EARLY_RX 0x80 /* 1=Enable Early RX */
+#define HP100_EN_LOW_RX 0x40 /* reserved, must be 0 */
+#define HP100_RX_TRIP_MASK 0x1f /* bits 4..0: threshold at which the
+ * early rx circuit will start the
+ * dma of received packet into system
+ * memory for BM */
/*
- * LANCntrCfg10Reg bits/masks.
- */
-#define HP100_SQU_ST 0x0100 /* 0:No, 1:Yes collision signal sent */
- /* after Tx. Only used for AUI. */
-#define HP100_MAC10_SEL 0x00c0 /* Get bits to indicate MAC */
-#define HP100_AUI_SEL 0x0020 /* Status of AUI selection */
-#define HP100_LOW_TH 0x0010 /* 0:No, 1:Yes allow better cabling */
-#define HP100_LINK_BEAT_DIS 0x0008 /* 0:Enable, 1:Disable link beat */
-#define HP100_LINK_BEAT_ST 0x0004 /* 0:No, 1:Yes link beat being Rx */
-#define HP100_R_ROL_ST 0x0002 /* 0:No, 1:Yes Rx twisted pair has been */
- /* reversed */
-#define HP100_AUI_ST 0x0001 /* 0:No, 1:Yes use AUI on TP card */
-
-/* MAC Selection, use with MAC10_SEL bits */
+ * Serial Devices Control Register
+ * (Page EEPROM_CTRL, EEPROM_CTRL, Offset 0x08)
+ */
+#define HP100_EEPROM_LOAD 0x0001 /* 0->1 loads EEPROM into registers. */
+ /* When it goes back to 0, load is */
+ /* complete. This should take ~600us.*/
+
+/*
+ * 10MB LAN Control and Configuration Register I
+ * (Page MAC_CTRL, 10_LAN_CFG_1, Offset 0x08)
+ */
+#define HP100_MAC10_SEL 0xc0 /* Get bits to indicate MAC */
+#define HP100_AUI_SEL 0x20 /* Status of AUI selection */
+#define HP100_LOW_TH 0x10 /* 0:No, 1:Yes allow better cabling */
+#define HP100_LINK_BEAT_DIS 0x08 /* 0:Enable, 1:Disable link beat */
+#define HP100_LINK_BEAT_ST 0x04 /* 0:No, 1:Yes link beat being Rx */
+#define HP100_R_ROL_ST 0x02 /* 0:No, 1:Yes Rx twisted pair has */
+ /* been reversed */
+#define HP100_AUI_ST 0x01 /* 0:No, 1:Yes use AUI on TP card */
+
+/*
+ * 10 MB LAN Control and Configuration Register II
+ * (Page MAC_CTRL, 10_LAN_CFG_2, Offset 0x09)
+ */
+#define HP100_SQU_ST 0x01 /* 0:No, 1:Yes collision signal sent */
+ /* after Tx.Only used for AUI. */
+#define HP100_FULLDUP 0x02 /* 1: LXT901 XCVR fullduplx enabled */
+#define HP100_DOT3_MAC 0x04 /* 1: DOT 3 Mac sel. unless Autosel */
+
+/*
+ * MAC Selection, use with MAC10_SEL bits
+ */
#define HP100_AUTO_SEL_10 0x0 /* Auto select */
#define HP100_XCVR_LXT901_10 0x1 /* LXT901 10BaseT transceiver */
#define HP100_XCVR_7213 0x2 /* 7213 transceiver */
#define HP100_XCVR_82503 0x3 /* 82503 transceiver */
+/*
+ * 100MB LAN Training Register
+ * (Page MAC_CTRL, VG_LAN_CFG_2, Offset 0x0b) (old, pre 802.12)
+ */
+#define HP100_FRAME_FORMAT 0x08 /* 0:802.3, 1:802.5 frames */
+#define HP100_BRIDGE 0x04 /* 0:No, 1:Yes tell hub i am a bridge */
+#define HP100_PROM_MODE 0x02 /* 0:No, 1:Yes tell hub card is */
+ /* promiscuous */
+#define HP100_REPEATER 0x01 /* 0:No, 1:Yes tell hub MAC wants to */
+ /* be a cascaded repeater */
/*
- * LANCntrCfgVGReg bits/masks.
- */
-#define HP100_FRAME_FORMAT 0x0800 /* 0:802.3, 1:802.5 frames */
-#define HP100_BRIDGE 0x0400 /* 0:No, 1:Yes tell hub it's a bridge */
-#define HP100_PROM_MODE 0x0200 /* 0:No, 1:Yes tell hub card is */
- /* promiscuous */
-#define HP100_REPEATER 0x0100 /* 0:No, 1:Yes tell hub MAC wants to be */
- /* a cascaded repeater */
-#define HP100_MAC100_SEL 0x0080 /* 0:No, 1:Yes use 100 Mbit MAC */
-#define HP100_LINK_UP_ST 0x0040 /* 0:No, 1:Yes endnode logged in */
-#define HP100_LINK_CABLE_ST 0x0020 /* 0:No, 1:Yes cable can hear tones from */
- /* hub */
-#define HP100_LOAD_ADDR 0x0010 /* 0->1 card addr will be sent to hub. */
- /* 100ms later the link status bits are */
- /* valid */
-#define HP100_LINK_CMD 0x0008 /* 0->1 link will attempt to log in. */
- /* 100ms later the link status bits are */
- /* valid */
-#define HP100_LINK_GOOD_ST 0x0002 /* 0:No, 1:Yes cable passed training */
-#define HP100_VG_RESET 0x0001 /* 0:Yes, 1:No reset the 100VG MAC */
+ * 100MB LAN Control and Configuration Register
+ * (Page MAC_CTRL, VG_LAN_CFG_1, Offset 0x0a)
+ */
+#define HP100_VG_SEL 0x80 /* 0:No, 1:Yes use 100 Mbit MAC */
+#define HP100_LINK_UP_ST 0x40 /* 0:No, 1:Yes endnode logged in */
+#define HP100_LINK_CABLE_ST 0x20 /* 0:No, 1:Yes cable can hear tones */
+ /* from hub */
+#define HP100_LOAD_ADDR 0x10 /* 0->1 card addr will be sent */
+ /* 100ms later the link status */
+ /* bits are valid */
+#define HP100_LINK_CMD 0x08 /* 0->1 link will attempt to log in. */
+ /* 100ms later the link status */
+ /* bits are valid */
+#define HP100_TRN_DONE 0x04 /* NEW ETR-Chips only: Will be reset */
+ /* after LinkUp Cmd is given and set */
+ /* when training has completed. */
+#define HP100_LINK_GOOD_ST 0x02 /* 0:No, 1:Yes cable passed training */
+#define HP100_VG_RESET 0x01 /* 0:Yes, 1:No reset the 100VG MAC */
/*
- * MACConfiguration1Reg bits/masks.
+ * MAC Configuration Register I
+ * (Page MAC_CTRL, MAC_CFG_1, Offset 0x0c)
*/
#define HP100_RX_IDLE 0x80 /* 0:Yes, 1:No currently receiving pkts */
#define HP100_TX_IDLE 0x40 /* 0:Yes, 1:No currently Txing pkts */
-#define HP100_RX_EN 0x20 /* 0:No, 1:Yes allow receiving of pkts */
-#define HP100_TX_EN 0x10 /* 0:No, 1:Yes allow transmitting of pkts */
+#define HP100_RX_EN 0x20 /* 1: allow receiving of pkts */
+#define HP100_TX_EN 0x10 /* 1: allow transmitting of pkts */
#define HP100_ACC_ERRORED 0x08 /* 0:No, 1:Yes allow Rx of errored pkts */
#define HP100_ACC_MC 0x04 /* 0:No, 1:Yes allow Rx of multicast pkts */
#define HP100_ACC_BC 0x02 /* 0:No, 1:Yes allow Rx of broadcast pkts */
-#define HP100_ACC_PHY 0x01 /* 0:No, 1:Yes allow Rx of ALL physical pkts */
-
+#define HP100_ACC_PHY 0x01 /* 0:No, 1:Yes allow Rx of ALL phys. pkts */
#define HP100_MAC1MODEMASK 0xf0 /* Hide ACC bits */
#define HP100_MAC1MODE1 0x00 /* Receive nothing, must also disable RX */
#define HP100_MAC1MODE2 0x00
@@ -254,15 +416,14 @@
#define HP100_MAC1MODE4 HP100_MAC1MODE3 | HP100_ACC_MC
#define HP100_MAC1MODE5 HP100_MAC1MODE4 /* set mc hash to all ones also */
#define HP100_MAC1MODE6 HP100_MAC1MODE5 | HP100_ACC_PHY /* Promiscuous */
-
/* Note MODE6 will receive all GOOD packets on the LAN. This really needs
a mode 7 defined to be LAN Analyzer mode, which will receive errored and
runt packets, and keep the CRC bytes. */
-
-#define HP100_MAC1MODE7 MAC1MODE6 OR ACC_ERRORED
+#define HP100_MAC1MODE7 HP100_MAC1MODE6 | HP100_ACC_ERRORED
/*
- * MACConfiguration2Reg bits/masks.
+ * MAC Configuration Register II
+ * (Page MAC_CTRL, MAC_CFG_2, Offset 0x0d)
*/
#define HP100_TR_MODE 0x80 /* 0:No, 1:Yes support Token Ring formats */
#define HP100_TX_SAME 0x40 /* 0:No, 1:Yes Tx same packet continuous */
@@ -270,9 +431,12 @@
/* transceiver */
#define HP100_LBK_MAC 0x10 /* 0:No, 1:Yes loopback through MAC */
#define HP100_CRC_I 0x08 /* 0:No, 1:Yes inhibit CRC on Tx packets */
+#define HP100_ACCNA 0x04 /* 1: For 802.5: Accept only token ring
+ * group addr that maches NA mask */
#define HP100_KEEP_CRC 0x02 /* 0:No, 1:Yes keep CRC on Rx packets. */
/* The length will reflect this. */
-
+#define HP100_ACCFA 0x01 /* 1: For 802.5: Accept only functional
+ * addrs that match FA mask (page1) */
#define HP100_MAC2MODEMASK 0x02
#define HP100_MAC2MODE1 0x00
#define HP100_MAC2MODE2 0x00
@@ -283,6 +447,65 @@
#define HP100_MAC2MODE7 KEEP_CRC
/*
+ * MAC Configuration Register III
+ * (Page MAC_CTRL, MAC_CFG_3, Offset 0x0e)
+ */
+#define HP100_PACKET_PACE 0x03 /* Packet Pacing:
+ * 00: No packet pacing
+ * 01: 8 to 16 uS delay
+ * 10: 16 to 32 uS delay
+ * 11: 32 to 64 uS delay
+ */
+#define HP100_LRF_EN 0x04 /* 1: External LAN Rcv Filter and
+ * TCP/IP Checksumming enabled. */
+#define HP100_AUTO_MODE 0x10 /* 1: AutoSelect between 10/100 */
+
+/*
+ * MAC Configuration Register IV
+ * (Page MAC_CTRL, MAC_CFG_4, Offset 0x0f)
+ */
+#define HP100_MAC_SEL_ST 0x01 /* (R): Status of external VGSEL
+ * Signal, 1=100VG, 0=10Mbit sel. */
+#define HP100_LINK_FAIL_ST 0x02 /* (R): Status of Link Fail portion
+ * of the Misc. Interrupt */
+
+/*
+ * 100 MB LAN Training Request/Allowed Registers
+ * (Page MAC_CTRL, TRAIN_REQUEST and TRAIN_ALLOW, Offset 0x14-0x16)(ETR parts only)
+ */
+#define HP100_MACRQ_REPEATER 0x0001 /* 1: MAC tells HUB it wants to be
+ * a cascaded repeater
+ * 0: ... wants to be a DTE */
+#define HP100_MACRQ_PROMSC 0x0006 /* 2 bits: Promiscious mode
+ * 00: Rcv only unicast packets
+ * specifically addr to this
+ * endnode
+ * 10: Rcv all pckts fwded by
+ * the local repeater */
+#define HP100_MACRQ_FRAMEFMT_EITHER 0x0018 /* 11: either format allowed */
+#define HP100_MACRQ_FRAMEFMT_802_3 0x0000 /* 00: 802.3 is requested */
+#define HP100_MACRQ_FRAMEFMT_802_5 0x0010 /* 10: 802.5 format is requested */
+#define HP100_CARD_MACVER 0xe000 /* R: 3 bit Cards 100VG MAC version */
+#define HP100_MALLOW_REPEATER 0x0001 /* If reset, requested access as an
+ * end node is allowed */
+#define HP100_MALLOW_PROMSC 0x0004 /* 2 bits: Promiscious mode
+ * 00: Rcv only unicast packets
+ * specifically addr to this
+ * endnode
+ * 10: Rcv all pckts fwded by
+ * the local repeater */
+#define HP100_MALLOW_FRAMEFMT 0x00e0 /* 2 bits: Frame Format
+ * 00: 802.3 format will be used
+ * 10: 802.5 format will be used */
+#define HP100_MALLOW_ACCDENIED 0x0400 /* N bit */
+#define HP100_MALLOW_CONFIGURE 0x0f00 /* C bit */
+#define HP100_MALLOW_DUPADDR 0x1000 /* D bit */
+#define HP100_HUB_MACVER 0xe000 /* R: 3 bit 802.12 MAC/RMAC training */
+ /* protocol of repeater */
+
+/* ****************************************************************************** */
+
+/*
* Set/Reset bits
*/
#define HP100_SET_HB 0x0100 /* 0:Set fields to 0 whose mask is 1 */
@@ -297,20 +520,45 @@
#define HP100_LAN_10 10 /* lan_type value for 10BaseT */
#define HP100_LAN_ERR (-1) /* lan_type value for link down */
-/*
- * Receive Header Definition.
+#define TRUE 1
+#define FALSE 0
+
+
+/*
+ * Bus Master Data Structures ----------------------------------------------
*/
-struct hp100_rx_header {
- u_short rx_length; /* Pkt length is bits 12:0 */
- u_short rx_status; /* status of the packet */
-};
+#define MAX_RX_PDL 30 /* Card limit = 31 */
+#define MAX_RX_FRAG 2 /* Dont need more... */
+#define MAX_TX_PDL 29
+#define MAX_TX_FRAG 2 /* Limit = 31 */
+
+/* Define total PDL area size in bytes (should be 4096) */
+/* This is the size of kernel (dma) memory that will be allocated. */
+#define MAX_RINGSIZE ((MAX_RX_FRAG*8+4+4)*MAX_RX_PDL+(MAX_TX_FRAG*8+4+4)*MAX_TX_PDL)+16
+
+/* Ethernet Packet Sizes */
+#define MIN_ETHER_SIZE 60
+#define MAX_ETHER_SIZE 1514 /* Needed for preallocation of */
+ /* skb buffer when busmastering */
+
+/* Tx or Rx Ring Entry */
+typedef struct hp100_ring {
+ u_int *pdl; /* Address of PDLs PDH, dword before
+ * this address is used for rx hdr */
+ u_int pdl_paddr; /* Physical address of PDL */
+ struct sk_buff *skb;
+ struct hp100_ring *next;
+} hp100_ring_t;
+
+
+
+/* Mask for Header Descriptor */
+#define HP100_PKT_LEN_MASK 0x1FFF /* AND with RxLength to get length */
-#define HP100_PKT_LEN_MASK 0x1FFF /* AND with RxLength to get length bits */
/* Receive Packet Status. Note, the error bits are only valid if ACC_ERRORED
bit in the MAC Configuration Register 1 is set. */
-
#define HP100_RX_PRI 0x8000 /* 0:No, 1:Yes packet is priority */
#define HP100_SDF_ERR 0x4000 /* 0:No, 1:Yes start of frame error */
#define HP100_SKEW_ERR 0x2000 /* 0:No, 1:Yes skew out of range */
@@ -368,7 +616,11 @@ struct hp100_rx_header {
outw( HP100_MMAP_DIS | HP100_RESET_HB, ioaddr + HP100_REG_OPTION_LSW )
#define hp100_mem_map_disable() \
outw( HP100_MMAP_DIS | HP100_SET_HB, ioaddr + HP100_REG_OPTION_LSW )
-#define hp100_reset_card() \
- outw( HP100_HW_RST | HP100_RESET_LB, ioaddr + HP100_REG_OPTION_LSW )
-#define hp100_unreset_card() \
- outw( HP100_HW_RST | HP100_SET_LB, ioaddr + HP100_REG_OPTION_LSW )
+
+
+/*
+ * Local variables:
+ * c-indent-level: 2
+ * tab-width: 8
+ * End:
+*/
diff --git a/drivers/net/ibmtr.c b/drivers/net/ibmtr.c
index faedd45fa..e0d71b202 100644
--- a/drivers/net/ibmtr.c
+++ b/drivers/net/ibmtr.c
@@ -84,7 +84,7 @@
/* version and credits */
static char *version =
"ibmtr.c: v1.3.57 8/ 7/94 Peter De Schrijver and Mark Swanson\n"
-" v2.1.29 3/15/97 Paul Norton <pnorton@cts.com>\n";
+" v2.1.35 5/ 1/97 Paul Norton <pnorton@cts.com>\n";
static char pcchannelid[] = {
0x05, 0x00, 0x04, 0x09,
@@ -1013,14 +1013,15 @@ void tok_interrupt (int irq, void *dev_id, struct pt_regs *regs)
} /* ARB response */
if (status & SSB_RESP_INT) { /* SSB response */
-
+ unsigned char retcode;
switch (readb(ti->ssb)) { /* SSB command check */
-
+
case XMIT_DIR_FRAME:
case XMIT_UI_FRAME:
- if (readb(ti->ssb+2)) /* checks ret_code */
+ retcode = readb(ti->ssb+2);
+ if (retcode && (retcode != 0x22)) /* checks ret_code */
DPRINTK("xmit ret_code: %02X xmit error code: %02X\n",
- (int)readb(ti->ssb+2), (int)readb(ti->ssb+6));
+ (int)retcode, (int)readb(ti->ssb+6));
else ti->tr_stats.tx_packets++;
break;
@@ -1321,12 +1322,12 @@ static void tr_rx(struct device *dev)
__u32 rbuffer, rbufdata;
__u32 llc;
unsigned char *data;
- unsigned int rbuffer_len, lan_hdr_len, hdr_len;
- unsigned int arb_frame_len;
+ unsigned int rbuffer_len, lan_hdr_len, hdr_len, ip_len, length;
struct sk_buff *skb;
unsigned int skb_size = 0;
int is8022 = 0;
unsigned int chksum = 0;
+ struct iphdr *iph;
rbuffer=(ti->sram
+ntohs(readw(ti->arb + offsetof(struct arb_rec_req, rec_buf_addr))))+2;
@@ -1400,8 +1401,8 @@ static void tr_rx(struct device *dev)
}
#endif
- arb_frame_len=ntohs(readw(ti->arb+offsetof(struct arb_rec_req, frame_len)));
- skb_size = arb_frame_len-lan_hdr_len+sizeof(struct trh_hdr);
+ length = ntohs(readw(ti->arb+offsetof(struct arb_rec_req, frame_len)));
+ skb_size = length-lan_hdr_len+sizeof(struct trh_hdr);
if (is8022) {
skb_size += sizeof(struct trllc);
}
@@ -1429,30 +1430,42 @@ static void tr_rx(struct device *dev)
rbuffer_len=ntohs(readw(rbuffer + offsetof(struct rec_buf, buf_len)))-lan_hdr_len;
if (is8022) {
- /* create whitewashed LLC header in skb buffer (why not the real one?) */
+ /* create whitewashed LLC header in sk buffer */
struct trllc *local_llc = (struct trllc *)data;
memset(local_llc, 0, sizeof(*local_llc));
local_llc->ethertype = htons(ETH_P_TR_802_2);
hdr_len = sizeof(struct trllc);
+ /* copy the real LLC header to the sk buffer */
+ data += hdr_len;
+ memcpy_fromio(data, rbuffer+offsetof(struct rec_buf, data)+lan_hdr_len,hdr_len);
} else {
/* Copy the LLC header and the IPv4 header */
hdr_len = sizeof(struct trllc) + sizeof(struct iphdr);
memcpy_fromio(data, rbuffer+offsetof(struct rec_buf, data)+lan_hdr_len,hdr_len);
+
+ /* Watch for padded packets and bogons */
+ iph=(struct iphdr*)(data+sizeof(struct trllc));
+ ip_len = ntohs(iph->tot_len) - sizeof(struct iphdr);
+ length -= lan_hdr_len + hdr_len;
+ if ((ip_len <= length) && (ip_len > 7))
+ length = ip_len;
}
data += hdr_len;
- lan_hdr_len += hdr_len;
rbuffer_len -= hdr_len;
- rbufdata = rbuffer + offsetof(struct rec_buf,data) + lan_hdr_len;
+ rbufdata = rbuffer + offsetof(struct rec_buf,data) + lan_hdr_len + hdr_len;
/* Copy the payload... */
for (;;) {
if (is8022)
memcpy_fromio(data, rbufdata, rbuffer_len);
else
- chksum = csum_partial_copy(bus_to_virt(rbufdata), data, rbuffer_len, chksum);
+ chksum = csum_partial_copy(bus_to_virt(rbufdata), data,
+ length < rbuffer_len ? length : rbuffer_len,
+ chksum);
rbuffer = ntohs(readw(rbuffer));
if (!rbuffer)
break;
+ length -= rbuffer_len;
data += rbuffer_len;
rbuffer += ti->sram;
rbuffer_len = ntohs(readw(rbuffer + offsetof(struct rec_buf, buf_len)));
@@ -1495,7 +1508,7 @@ static int tok_send_packet(struct sk_buff *skb, struct device *dev)
return 0;
}
- if (set_bit(0,(void *)&dev->tbusy)!=0)
+ if (test_and_set_bit(0,(void *)&dev->tbusy)!=0)
DPRINTK("Transmitter access conflict\n");
else {
/* Save skb; we'll need it when the adapter asks for the data */
diff --git a/drivers/net/lance.c b/drivers/net/lance.c
index c1aa556d6..bf4061b05 100644
--- a/drivers/net/lance.c
+++ b/drivers/net/lance.c
@@ -858,12 +858,12 @@ static int lance_start_xmit(struct sk_buff *skb, struct device *dev)
/* Block a timer-based transmit from overlapping. This could better be
done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
- if (set_bit(0, (void*)&dev->tbusy) != 0) {
+ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
printk("%s: Transmitter access conflict.\n", dev->name);
return 1;
}
- if (set_bit(0, (void*)&lp->lock) != 0) {
+ if (test_and_set_bit(0, (void*)&lp->lock) != 0) {
if (lance_debug > 0)
printk("%s: tx queue lock!.\n", dev->name);
/* don't clear dev->tbusy flag. */
diff --git a/drivers/net/ltpc.c b/drivers/net/ltpc.c
index 8a4fae560..1da2ee64f 100644
--- a/drivers/net/ltpc.c
+++ b/drivers/net/ltpc.c
@@ -1259,7 +1259,7 @@ void cleanup_module(void)
if(debug&DEBUG_VERBOSE) printk("waiting\n");
/* if it's in process, wait a bit for it to finish */
timeout = jiffies+HZ;
- add_timer(&ltpc_timer)
+ add_timer(&ltpc_timer);
while(del_timer(&ltpc_timer) && (timeout > jiffies))
{
add_timer(&ltpc_timer);
diff --git a/drivers/net/mkiss.c b/drivers/net/mkiss.c
index 6f772fd68..13ebbd9b4 100644
--- a/drivers/net/mkiss.c
+++ b/drivers/net/mkiss.c
@@ -109,7 +109,7 @@ static inline struct ax_disp *ax_alloc(void)
break;
/* Not in use ? */
- if (!set_bit(AXF_INUSE, &axp->ctrl.flags))
+ if (!test_and_set_bit(AXF_INUSE, &axp->ctrl.flags))
break;
}
@@ -165,7 +165,7 @@ static inline void ax_free(struct ax_disp *ax)
if (ax->xbuff)
kfree(ax->xbuff);
ax->xbuff = NULL;
- if (!clear_bit(AXF_INUSE, &ax->flags))
+ if (!test_and_clear_bit(AXF_INUSE, &ax->flags))
printk(KERN_ERR "%s: ax_free for already free unit.\n", ax->dev->name);
}
@@ -244,7 +244,7 @@ static void ax_changedmtu(struct ax_disp *ax)
/* Set the "sending" flag. This must be atomic, hence the ASM. */
static inline void ax_lock(struct ax_disp *ax)
{
- if (set_bit(0, (void *)&ax->dev->tbusy))
+ if (test_and_set_bit(0, (void *)&ax->dev->tbusy))
printk(KERN_ERR "%s: trying to lock already locked device!\n", ax->dev->name);
}
@@ -252,7 +252,7 @@ static inline void ax_lock(struct ax_disp *ax)
/* Clear the "sending" flag. This must be atomic, hence the ASM. */
static inline void ax_unlock(struct ax_disp *ax)
{
- if (!clear_bit(0, (void *)&ax->dev->tbusy))
+ if (!test_and_clear_bit(0, (void *)&ax->dev->tbusy))
printk(KERN_ERR "%s: trying to unlock already unlocked device!\n", ax->dev->name);
}
@@ -551,7 +551,7 @@ static void ax25_receive_buf(struct tty_struct *tty, const unsigned char *cp, ch
/* Read the characters out of the buffer */
while (count--) {
if (fp != NULL && *fp++) {
- if (!set_bit(AXF_ERROR, &ax->flags))
+ if (!test_and_set_bit(AXF_ERROR, &ax->flags))
ax->rx_errors++;
cp++;
continue;
@@ -709,7 +709,7 @@ static void kiss_unesc(struct ax_disp *ax, unsigned char s)
if (test_bit(AXF_KEEPTEST, &ax->flags))
clear_bit(AXF_KEEPTEST, &ax->flags);
- if (!clear_bit(AXF_ERROR, &ax->flags) && (ax->rcount > 2))
+ if (!test_and_clear_bit(AXF_ERROR, &ax->flags) && (ax->rcount > 2))
ax_bump(ax);
clear_bit(AXF_ESCAPE, &ax->flags);
@@ -720,11 +720,11 @@ static void kiss_unesc(struct ax_disp *ax, unsigned char s)
set_bit(AXF_ESCAPE, &ax->flags);
return;
case ESC_ESC:
- if (clear_bit(AXF_ESCAPE, &ax->flags))
+ if (test_and_clear_bit(AXF_ESCAPE, &ax->flags))
s = ESC;
break;
case ESC_END:
- if (clear_bit(AXF_ESCAPE, &ax->flags))
+ if (test_and_clear_bit(AXF_ESCAPE, &ax->flags))
s = END;
break;
}
diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c
index 3d7a2587a..4ae7aa069 100644
--- a/drivers/net/myri_sbus.c
+++ b/drivers/net/myri_sbus.c
@@ -584,7 +584,7 @@ static int myri_start_xmit(struct sk_buff *skb, struct device *dev)
return 0;
}
- if(set_bit(0, (void *) &dev->tbusy) != 0) {
+ if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) {
DTX(("tbusy, maybe a race? returning 1\n"));
printk("%s: Transmitter access conflict.\n", dev->name);
return 1;
diff --git a/drivers/net/ni52.c b/drivers/net/ni52.c
index 746037adf..0935f4f0b 100644
--- a/drivers/net/ni52.c
+++ b/drivers/net/ni52.c
@@ -1171,12 +1171,12 @@ static int ni52_send_packet(struct sk_buff *skb, struct device *dev)
return 0;
}
- if (set_bit(0, (void*)&dev->tbusy)) {
+ if (test_and_set_bit(0, (void*)&dev->tbusy)) {
printk("%s: Transmitter access conflict.\n", dev->name);
return 1;
}
#if(NUM_XMIT_BUFFS > 1)
- else if(set_bit(0,(void *) &p->lock)) {
+ else if(test_and_set_bit(0,(void *) &p->lock)) {
printk("%s: Queue was locked\n",dev->name);
return 1;
}
diff --git a/drivers/net/ni65.c b/drivers/net/ni65.c
index 07a946d3b..a008a3ea7 100644
--- a/drivers/net/ni65.c
+++ b/drivers/net/ni65.c
@@ -804,7 +804,7 @@ static void ni65_interrupt(int irq, void * dev_id, struct pt_regs * regs)
return;
}
- if(set_bit(0,(int *) &dev->interrupt)) {
+ if(test_and_set_bit(0,(int *) &dev->interrupt)) {
printk("ni65: oops .. interrupt while proceeding interrupt\n");
return;
}
@@ -1087,11 +1087,11 @@ static int ni65_send_packet(struct sk_buff *skb, struct device *dev)
dev->trans_start = jiffies;
}
- if (set_bit(0, (void*)&dev->tbusy) != 0) {
+ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
printk(KERN_ERR "%s: Transmitter access conflict.\n", dev->name);
return 1;
}
- if (set_bit(0, (void*)&p->lock)) {
+ if (test_and_set_bit(0, (void*)&p->lock)) {
printk(KERN_ERR "%s: Queue was locked.\n", dev->name);
return 1;
}
diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c
index 3f34e690c..d10663ff5 100644
--- a/drivers/net/pcnet32.c
+++ b/drivers/net/pcnet32.c
@@ -613,12 +613,12 @@ pcnet32_start_xmit(struct sk_buff *skb, struct device *dev)
/* Block a timer-based transmit from overlapping. This could better be
done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
- if (set_bit(0, (void*)&dev->tbusy) != 0) {
+ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
printk("%s: Transmitter access conflict.\n", dev->name);
return 1;
}
- if (set_bit(0, (void*)&lp->lock) != 0) {
+ if (test_and_set_bit(0, (void*)&lp->lock) != 0) {
if (pcnet32_debug > 0)
printk("%s: tx queue lock!.\n", dev->name);
/* don't clear dev->tbusy flag. */
diff --git a/drivers/net/plip.c b/drivers/net/plip.c
index 25c33ab1a..f06a66afc 100644
--- a/drivers/net/plip.c
+++ b/drivers/net/plip.c
@@ -910,7 +910,7 @@ plip_tx_packet(struct sk_buff *skb, struct device *dev)
return 0;
}
- if (set_bit(0, (void*)&dev->tbusy) != 0) {
+ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
printk("%s: Transmitter access conflict.\n", dev->name);
return 1;
}
diff --git a/drivers/net/ppp.c b/drivers/net/ppp.c
index a1dbb5020..e3615534d 100644
--- a/drivers/net/ppp.c
+++ b/drivers/net/ppp.c
@@ -1291,7 +1291,7 @@ rcv_proto_unknown (struct ppp *ppp, __u16 proto,
* The total length includes the protocol data.
* Lock the user information buffer.
*/
- if (set_bit (0, &ppp->ubuf->locked)) {
+ if (test_and_set_bit (0, &ppp->ubuf->locked)) {
if (ppp->flags & SC_DEBUG)
printk (KERN_DEBUG
"ppp_us_queue: can't get lock\n");
@@ -1698,7 +1698,7 @@ ppp_tty_read (struct tty_struct *tty, struct file *file, __u8 * buf,
if (!ppp || ppp->magic != PPP_MAGIC || !ppp->inuse)
return 0;
- if (set_bit (0, &ppp->ubuf->locked) != 0) {
+ if (test_and_set_bit (0, &ppp->ubuf->locked) != 0) {
if (ppp->flags & SC_DEBUG)
printk (KERN_DEBUG
"ppp_tty_read: sleeping(ubuf)\n");
@@ -2584,7 +2584,7 @@ ppp_tty_poll (struct tty_struct *tty, struct file *filp, poll_table * wait)
poll_wait(&ppp->write_wait, wait);
/* Must lock the user buffer area while checking. */
- if(set_bit(0, &ppp->ubuf->locked) == 0) {
+ if(test_and_set_bit(0, &ppp->ubuf->locked) == 0) {
if(ppp->ubuf->head != ppp->ubuf->tail)
mask |= POLLIN | POLLRDNORM;
clear_bit(0, &ppp->ubuf->locked);
@@ -3130,7 +3130,7 @@ ppp_find (int pid_value)
while (ctl) {
ppp = ctl2ppp (ctl);
- if (!set_bit(0, &ppp->inuse)) {
+ if (!test_and_set_bit(0, &ppp->inuse)) {
if (ppp->sc_xfer == pid_value) {
ppp->sc_xfer = 0;
return (ppp);
@@ -3160,7 +3160,7 @@ ppp_alloc (void)
while (ctl) {
ppp = ctl2ppp (ctl);
- if (!set_bit(0, &ppp->inuse))
+ if (!test_and_set_bit(0, &ppp->inuse))
return (ppp);
ctl = ctl->next;
if (++if_num == max_dev)
diff --git a/drivers/net/sdla.c b/drivers/net/sdla.c
index f2762eef1..feaeef4cc 100644
--- a/drivers/net/sdla.c
+++ b/drivers/net/sdla.c
@@ -657,7 +657,7 @@ static int sdla_transmit(struct sk_buff *skb, struct device *dev)
if (skb == NULL)
return(0);
- if (set_bit(0, (void*)&dev->tbusy) != 0)
+ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
printk(KERN_WARNING "%s: transmitter access conflict.\n", dev->name);
else
{
diff --git a/drivers/net/sdla_fr.c b/drivers/net/sdla_fr.c
index 79a493c2c..d2dc0eb90 100644
--- a/drivers/net/sdla_fr.c
+++ b/drivers/net/sdla_fr.c
@@ -440,7 +440,7 @@ static int if_open (struct device* dev)
if (dev->start)
return -EBUSY /* only one open is allowed */
;
- if (set_bit(0, (void*)&card->wandev.critical))
+ if (test_and_set_bit(0, (void*)&card->wandev.critical))
return -EAGAIN;
;
if (!card->open_cnt)
@@ -489,7 +489,7 @@ static int if_close (struct device* dev)
fr_channel_t* chan = dev->priv;
sdla_t* card = chan->card;
- if (set_bit(0, (void*)&card->wandev.critical))
+ if (test_and_set_bit(0, (void*)&card->wandev.critical))
return -EAGAIN;
;
dev->start = 0;
@@ -574,7 +574,7 @@ static int if_send (struct sk_buff* skb, struct device* dev)
sdla_t* card = chan->card;
int retry = 0;
- if (set_bit(0, (void*)&card->wandev.critical))
+ if (test_and_set_bit(0, (void*)&card->wandev.critical))
{
#ifdef _DEBUG_
printk(KERN_INFO "%s: if_send() hit critical section!\n",
@@ -584,7 +584,7 @@ static int if_send (struct sk_buff* skb, struct device* dev)
return 1;
}
- if (set_bit(0, (void*)&dev->tbusy))
+ if (test_and_set_bit(0, (void*)&dev->tbusy))
{
#ifdef _DEBUG_
printk(KERN_INFO "%s: Tx collision on interface %s!\n",
diff --git a/drivers/net/sdla_ppp.c b/drivers/net/sdla_ppp.c
index c6b1ce945..c5c5ecc55 100644
--- a/drivers/net/sdla_ppp.c
+++ b/drivers/net/sdla_ppp.c
@@ -286,7 +286,7 @@ static int if_open (struct device* dev)
if (dev->start)
return -EBUSY /* only one open is allowed */
;
- if (set_bit(0, (void*)&card->wandev.critical))
+ if (test_and_set_bit(0, (void*)&card->wandev.critical))
return -EAGAIN;
;
if ((card->hw.fwid == SFID_PPP502) ? config502(card) : config508(card))
@@ -365,7 +365,7 @@ static int if_close (struct device* dev)
{
sdla_t* card = dev->priv;
- if (set_bit(0, (void*)&card->wandev.critical))
+ if (test_and_set_bit(0, (void*)&card->wandev.critical))
return -EAGAIN;
;
dev->start = 0;
@@ -441,7 +441,7 @@ static int if_send (struct sk_buff* skb, struct device* dev)
sdla_t* card = dev->priv;
int retry = 0;
- if (set_bit(0, (void*)&card->wandev.critical))
+ if (test_and_set_bit(0, (void*)&card->wandev.critical))
{
#ifdef _DEBUG_
printk(KERN_INFO "%s: if_send() hit critical section!\n",
@@ -451,7 +451,7 @@ static int if_send (struct sk_buff* skb, struct device* dev)
return 1;
}
- if (set_bit(0, (void*)&dev->tbusy))
+ if (test_and_set_bit(0, (void*)&dev->tbusy))
{
#ifdef _DEBUG_
printk(KERN_INFO "%s: Tx collision on interface %s!\n",
diff --git a/drivers/net/sdla_x25.c b/drivers/net/sdla_x25.c
index f6f540709..3296c2819 100644
--- a/drivers/net/sdla_x25.c
+++ b/drivers/net/sdla_x25.c
@@ -476,7 +476,7 @@ static int if_open (struct device* dev)
if (dev->start)
return -EBUSY /* only one open is allowed */
;
- if (set_bit(0, (void*)&card->wandev.critical))
+ if (test_and_set_bit(0, (void*)&card->wandev.critical))
return -EAGAIN;
;
@@ -503,7 +503,7 @@ static int if_close (struct device* dev)
x25_channel_t* chan = dev->priv;
sdla_t* card = chan->card;
- if (set_bit(0, (void*)&card->wandev.critical))
+ if (test_and_set_bit(0, (void*)&card->wandev.critical))
return -EAGAIN;
;
dev->start = 0;
@@ -590,7 +590,7 @@ static int if_send (struct sk_buff* skb, struct device* dev)
sdla_t* card = chan->card;
int retry = 0, queued = 0;
- if (set_bit(0, (void*)&card->wandev.critical))
+ if (test_and_set_bit(0, (void*)&card->wandev.critical))
{
#ifdef _DEBUG_
printk(KERN_INFO "%s: if_send() hit critical section!\n",
@@ -600,7 +600,7 @@ static int if_send (struct sk_buff* skb, struct device* dev)
return 1;
}
- if (set_bit(0, (void*)&dev->tbusy))
+ if (test_and_set_bit(0, (void*)&dev->tbusy))
{
#ifdef _DEBUG_
printk(KERN_INFO "%s: Tx collision on interface %s!\n",
diff --git a/drivers/net/sdlamain.c b/drivers/net/sdlamain.c
index 2ff8a4605..75d7df944 100644
--- a/drivers/net/sdlamain.c
+++ b/drivers/net/sdlamain.c
@@ -332,7 +332,7 @@ static int shutdown (wan_device_t* wandev)
if (wandev->state == WAN_UNCONFIGURED)
return 0
;
- if (set_bit(0, (void*)&wandev->critical))
+ if (test_and_set_bit(0, (void*)&wandev->critical))
return -EAGAIN
;
card = wandev->private;
@@ -364,7 +364,7 @@ static int ioctl (wan_device_t* wandev, unsigned cmd, unsigned long arg)
if (wandev->state == WAN_UNCONFIGURED)
return -ENODEV
;
- if (set_bit(0, (void*)&wandev->critical))
+ if (test_and_set_bit(0, (void*)&wandev->critical))
return -EAGAIN
;
switch (cmd)
@@ -514,7 +514,7 @@ STATIC void sdla_poll (void* data)
sdla_t* card = &card_array[i];
if ((card->wandev.state != WAN_UNCONFIGURED) && card->poll &&
- !set_bit(0, (void*)&card->wandev.critical))
+ !test_and_set_bit(0, (void*)&card->wandev.critical))
{
card->poll(card);
card->wandev.critical = 0;
diff --git a/drivers/net/seeq8005.c b/drivers/net/seeq8005.c
index 397228647..1a41960c4 100644
--- a/drivers/net/seeq8005.c
+++ b/drivers/net/seeq8005.c
@@ -392,7 +392,7 @@ seeq8005_send_packet(struct sk_buff *skb, struct device *dev)
/* Block a timer-based transmit from overlapping. This could better be
done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
- if (set_bit(0, (void*)&dev->tbusy) != 0)
+ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
printk("%s: Transmitter access conflict.\n", dev->name);
else {
short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c
index 3022e8a0b..bf85e014a 100644
--- a/drivers/net/sgiseeq.c
+++ b/drivers/net/sgiseeq.c
@@ -519,7 +519,7 @@ static inline int verify_tx(struct sgiseeq_private *sp,
return -1;
}
/* Are we getting in someone else's way? */
- if(set_bit(0, (void *) &dev->tbusy) != 0) {
+ if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) {
printk("%s: Transmitter access conflict.\n", dev->name);
return -1;
}
diff --git a/drivers/net/sk_g16.c b/drivers/net/sk_g16.c
index 1421356e3..51e8fe8ba 100644
--- a/drivers/net/sk_g16.c
+++ b/drivers/net/sk_g16.c
@@ -68,6 +68,7 @@ static const char *rcsid = "$Id: sk_g16.c,v 1.1 1994/06/30 16:25:15 root Exp $";
#include <asm/io.h>
#include <asm/bitops.h>
#include <linux/errno.h>
+#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
@@ -532,7 +533,7 @@ void SK_print_ram(struct device *dev);
* (detachable devices only).
*/
-int SK_init(struct device *dev)
+__initfunc(int SK_init(struct device *dev))
{
int ioaddr = 0; /* I/O port address used for POS regs */
int *port, ports[] = SK_IO_PORTS; /* SK_G16 supported ports */
@@ -616,7 +617,7 @@ int SK_init(struct device *dev)
* 94/06/30 pwe SK_ADDR now checked and at the correct place
-*/
-int SK_probe(struct device *dev, short ioaddr)
+__initfunc(int SK_probe(struct device *dev, short ioaddr))
{
int i,j; /* Counters */
int sk_addr_flag = 0; /* SK ADDR correct? 1 - no, 0 - yes */
@@ -1210,7 +1211,7 @@ static int SK_send_packet(struct sk_buff *skb, struct device *dev)
* This means check if we are already in.
*/
- if (set_bit(0, (void *) &dev->tbusy) != 0) /* dev->tbusy already set ? */
+ if (test_and_set_bit(0, (void *) &dev->tbusy) != 0) /* dev->tbusy already set ? */
{
printk("%s: Transmitter access conflict.\n", dev->name);
}
@@ -1740,7 +1741,7 @@ static void set_multicast_list(struct device *dev)
* YY/MM/DD uid Description
-*/
-unsigned int SK_rom_addr(void)
+__initfunc(unsigned int SK_rom_addr(void))
{
int i,j;
int rom_found = 0;
diff --git a/drivers/net/skeleton.c b/drivers/net/skeleton.c
index 115d419c9..0df5feaae 100644
--- a/drivers/net/skeleton.c
+++ b/drivers/net/skeleton.c
@@ -56,6 +56,7 @@ static const char *version =
#include <asm/io.h>
#include <asm/dma.h>
#include <linux/errno.h>
+#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
@@ -70,7 +71,7 @@ static const char* cardname = "netcard";
/* First, a few definitions that the brave might change. */
/* A zero-terminated list of I/O addresses to be probed. */
-static unsigned int netcard_portlist[] =
+static unsigned int netcard_portlist[] __initdata =
{ 0x200, 0x240, 0x280, 0x2C0, 0x300, 0x320, 0x340, 0};
/* use 0 for production, 1 for verification, >2 for debug */
@@ -126,8 +127,8 @@ extern void chipset_init(struct device *dev, int startp);
struct netdev_entry netcard_drv =
{cardname, netcard_probe1, NETCARD_IO_EXTENT, netcard_portlist};
#else
-int
-netcard_probe(struct device *dev)
+__initfunc(int
+netcard_probe(struct device *dev))
{
int i;
int base_addr = dev ? dev->base_addr : 0;
@@ -154,7 +155,7 @@ netcard_probe(struct device *dev)
* probes on the ISA bus. A good device probes avoids doing writes, and
* verifies that the correct device exists and functions.
*/
-static int netcard_probe1(struct device *dev, int ioaddr)
+__initfunc(static int netcard_probe1(struct device *dev, int ioaddr))
{
static unsigned version_printed = 0;
int i;
@@ -365,7 +366,7 @@ static int net_send_packet(struct sk_buff *skb, struct device *dev)
* Block a timer-based transmit from overlapping. This could better be
* done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
*/
- if (set_bit(0, (void*)&dev->tbusy) != 0)
+ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name);
else {
short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
diff --git a/drivers/net/slip.c b/drivers/net/slip.c
index f091e38a4..057d3c9d2 100644
--- a/drivers/net/slip.c
+++ b/drivers/net/slip.c
@@ -123,7 +123,7 @@ sl_alloc(void)
if (slp == NULL)
break;
/* Not in use ? */
- if (!set_bit(SLF_INUSE, &slp->ctrl.flags))
+ if (!test_and_set_bit(SLF_INUSE, &slp->ctrl.flags))
break;
}
/* SLP is set.. */
@@ -207,7 +207,7 @@ sl_free(struct slip *sl)
sl->slcomp = NULL;
#endif
- if (!clear_bit(SLF_INUSE, &sl->flags)) {
+ if (!test_and_clear_bit(SLF_INUSE, &sl->flags)) {
printk("%s: sl_free for already free unit.\n", sl->dev->name);
}
}
@@ -317,7 +317,7 @@ static void sl_changedmtu(struct slip *sl)
static inline void
sl_lock(struct slip *sl)
{
- if (set_bit(0, (void *) &sl->dev->tbusy)) {
+ if (test_and_set_bit(0, (void *) &sl->dev->tbusy)) {
printk("%s: trying to lock already locked device!\n", sl->dev->name);
}
}
@@ -327,7 +327,7 @@ sl_lock(struct slip *sl)
static inline void
sl_unlock(struct slip *sl)
{
- if (!clear_bit(0, (void *)&sl->dev->tbusy)) {
+ if (!test_and_clear_bit(0, (void *)&sl->dev->tbusy)) {
printk("%s: trying to unlock already unlocked device!\n", sl->dev->name);
}
}
@@ -661,7 +661,7 @@ static void slip_receive_buf(struct tty_struct *tty, const unsigned char *cp, ch
/* Read the characters out of the buffer */
while (count--) {
if (fp && *fp++) {
- if (!set_bit(SLF_ERROR, &sl->flags)) {
+ if (!test_and_set_bit(SLF_ERROR, &sl->flags)) {
sl->rx_errors++;
}
cp++;
@@ -843,7 +843,7 @@ static void slip_unesc(struct slip *sl, unsigned char s)
if (test_bit(SLF_KEEPTEST, &sl->flags))
clear_bit(SLF_KEEPTEST, &sl->flags);
- if (!clear_bit(SLF_ERROR, &sl->flags) && (sl->rcount > 2)) {
+ if (!test_and_clear_bit(SLF_ERROR, &sl->flags) && (sl->rcount > 2)) {
sl_bump(sl);
}
clear_bit(SLF_ESCAPE, &sl->flags);
@@ -854,12 +854,12 @@ static void slip_unesc(struct slip *sl, unsigned char s)
set_bit(SLF_ESCAPE, &sl->flags);
return;
case ESC_ESC:
- if (clear_bit(SLF_ESCAPE, &sl->flags)) {
+ if (test_and_clear_bit(SLF_ESCAPE, &sl->flags)) {
s = ESC;
}
break;
case ESC_END:
- if (clear_bit(SLF_ESCAPE, &sl->flags)) {
+ if (test_and_clear_bit(SLF_ESCAPE, &sl->flags)) {
s = END;
}
break;
@@ -928,7 +928,7 @@ slip_unesc6(struct slip *sl, unsigned char s)
if (test_bit(SLF_KEEPTEST, &sl->flags))
clear_bit(SLF_KEEPTEST, &sl->flags);
- if (!clear_bit(SLF_ERROR, &sl->flags) && (sl->rcount > 2)) {
+ if (!test_and_clear_bit(SLF_ERROR, &sl->flags) && (sl->rcount > 2)) {
sl_bump(sl);
}
sl->rcount = 0;
diff --git a/drivers/net/smc9194.c b/drivers/net/smc9194.c
index 5b3e9b73c..55f04121f 100644
--- a/drivers/net/smc9194.c
+++ b/drivers/net/smc9194.c
@@ -1245,7 +1245,7 @@ static int smc_send_packet(struct sk_buff *skb, struct device *dev)
/* Block a timer-based transmit from overlapping. This could better be
done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
- if (set_bit(0, (void*)&dev->tbusy) != 0) {
+ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
printk(KERN_WARNING CARDNAME": Transmitter access conflict.\n");
dev_kfree_skb (skb, FREE_WRITE);
} else {
diff --git a/drivers/net/sonic.c b/drivers/net/sonic.c
index dfa5b272c..c42450a44 100644
--- a/drivers/net/sonic.c
+++ b/drivers/net/sonic.c
@@ -28,6 +28,7 @@ static const char *version =
#include <linux/fcntl.h>
#include <linux/interrupt.h>
#include <linux/ptrace.h>
+#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/in.h>
#include <linux/malloc.h>
@@ -127,7 +128,7 @@ static int sonic_init(struct device *dev);
* Probe for a SONIC ethernet controller on a Mips Jazz board.
* Actually probing is superfluous but we're paranoid.
*/
-int sonic_probe(struct device *dev)
+__initfunc(int sonic_probe(struct device *dev))
{
unsigned int base_addr = dev ? dev->base_addr : 0;
int i;
@@ -152,8 +153,8 @@ int sonic_probe(struct device *dev)
return -ENODEV;
}
-static int
-sonic_probe1(struct device *dev, unsigned int base_addr, unsigned int irq)
+__initfunc(static int sonic_probe1(struct device *dev,
+ unsigned int base_addr, unsigned int irq))
{
static unsigned version_printed = 0;
unsigned int silicon_revision;
@@ -403,7 +404,7 @@ static int sonic_send_packet(struct sk_buff *skb, struct device *dev)
* Block a timer-based transmit from overlapping. This could better be
* done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
*/
- if (set_bit(0, (void*)&dev->tbusy) != 0) {
+ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
printk("%s: Transmitter access conflict.\n", dev->name);
return 1;
}
@@ -719,8 +720,7 @@ sonic_multicast_list(struct device *dev)
/*
* Initialize the SONIC ethernet controller.
*/
-static int
-sonic_init(struct device *dev)
+static int sonic_init(struct device *dev)
{
unsigned int base_addr = dev->base_addr;
unsigned int cmd;
diff --git a/drivers/net/soundmodem/sm.c b/drivers/net/soundmodem/sm.c
index 777b5142f..7d57dd692 100644
--- a/drivers/net/soundmodem/sm.c
+++ b/drivers/net/soundmodem/sm.c
@@ -56,6 +56,7 @@
#include <asm/bitops.h>
#include <linux/delay.h>
#include <linux/errno.h>
+#include <linux/init.h>
#include "sm.h"
/* --------------------------------------------------------------------- */
@@ -662,10 +663,7 @@ static int sm_ioctl(struct device *dev, struct ifreq *ifr,
/* --------------------------------------------------------------------- */
-#ifdef MODULE
-static
-#endif /* MODULE */
-int sm_init(void)
+__initfunc(int sm_init(void))
{
int i, j, found = 0;
char set_hw = 1;
@@ -800,7 +798,7 @@ void cleanup_module(void)
* modem: afsk1200, fsk9600
*/
-void sm_setup(char *str, int *ints)
+__initfunc(void sm_setup(char *str, int *ints))
{
int i;
diff --git a/drivers/net/strip.c b/drivers/net/strip.c
index 862a13370..32c02b4f0 100644
--- a/drivers/net/strip.c
+++ b/drivers/net/strip.c
@@ -891,7 +891,7 @@ static void strip_unlock(struct strip *strip_info)
*/
strip_info->idle_timer.expires = jiffies + HZ;
add_timer(&strip_info->idle_timer);
- if (!clear_bit(0, (void *)&strip_info->dev.tbusy))
+ if (!test_and_clear_bit(0, (void *)&strip_info->dev.tbusy))
printk(KERN_ERR "%s: trying to unlock already unlocked device!\n",
strip_info->dev.name);
}
@@ -1745,7 +1745,7 @@ static int strip_xmit(struct sk_buff *skb, struct device *dev)
printk(KERN_ERR "%s: xmit call when iface is down\n", dev->name);
return(1);
}
- if (set_bit(0, (void *) &strip_info->dev.tbusy)) return(1);
+ if (test_and_set_bit(0, (void *) &strip_info->dev.tbusy)) return(1);
del_timer(&strip_info->idle_timer);
/* See if someone has been ifconfigging */
diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c
index 66e3b0b68..7299b0f4b 100644
--- a/drivers/net/sunhme.c
+++ b/drivers/net/sunhme.c
@@ -1673,6 +1673,7 @@ static inline void happy_meal_rx(struct happy_meal *hp, struct device *dev,
netif_rx(skb);
hp->net_stats.rx_packets++;
+ hp->net_stats.rx_bytes+=len;
next:
elem = NEXT_RX(elem);
this = &rxbase[elem];
@@ -1729,6 +1730,7 @@ static inline void sun4c_happy_meal_rx(struct happy_meal *hp, struct device *dev
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
hp->net_stats.rx_packets++;
+ hp->net_stats.rx_bytes+=len;
}
}
/* Return the buffer to the Happy Meal. */
@@ -1898,7 +1900,7 @@ static int happy_meal_start_xmit(struct sk_buff *skb, struct device *dev)
}
}
- if(set_bit(0, (void *) &dev->tbusy) != 0) {
+ if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) {
printk("happy meal: Transmitter access conflict.\n");
return 1;
}
@@ -1955,7 +1957,7 @@ static int sun4c_happy_meal_start_xmit(struct sk_buff *skb, struct device *dev)
return 0;
}
- if(set_bit(0, (void *) &dev->tbusy) != 0) {
+ if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) {
printk("happy meal: Transmitter access conflict.\n");
return 1;
}
diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c
index 0485aa2d1..4e7325016 100644
--- a/drivers/net/sunlance.c
+++ b/drivers/net/sunlance.c
@@ -1,4 +1,4 @@
-/* $Id: sunlance.c,v 1.62 1997/04/16 10:27:25 jj Exp $
+/* $Id: sunlance.c,v 1.64 1997/05/14 20:46:40 davem Exp $
* lance.c: Linux/Sparc/Lance driver
*
* Written 1995, 1996 by Miguel de Icaza
@@ -673,8 +673,7 @@ static int lance_open (struct device *dev)
/* On the 4m, setup the ledma to provide the upper bits for buffers */
if (lp->ledma)
- lp->ledma->regs->dma_test = ((unsigned long) lp->init_block)
- & 0xff000000;
+ lp->ledma->regs->dma_test = ((__u32) lp->init_block_dvma) & 0xff000000;
lance_init_ring (dev);
load_csrs (lp);
@@ -758,8 +757,7 @@ static inline int lance_reset (struct device *dev)
lp->ledma->regs->cond_reg |= DMA_RST_ENET;
udelay (200);
lp->ledma->regs->cond_reg &= ~DMA_RST_ENET;
- lp->ledma->regs->dma_test = ((unsigned long) lp->init_block)
- & 0xff000000;
+ lp->ledma->regs->dma_test = ((__u32) lp->init_block_dvma) & 0xff000000;
}
lance_init_ring (dev);
load_csrs (lp);
@@ -800,7 +798,7 @@ static int lance_start_xmit (struct sk_buff *skb, struct device *dev)
}
/* Block a timer-based transmit from overlapping. */
- if (set_bit (0, (void *) &dev->tbusy) != 0) {
+ if (test_and_set_bit (0, (void *) &dev->tbusy) != 0) {
printk ("Transmitter access conflict.\n");
return -1;
}
diff --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c
index c987c5e9f..18e758c80 100644
--- a/drivers/net/sunqe.c
+++ b/drivers/net/sunqe.c
@@ -720,7 +720,7 @@ static int qe_start_xmit(struct sk_buff *skb, struct device *dev)
if(dev->tbusy)
return 1;
- if(set_bit(0, (void *) &dev->tbusy) != 0) {
+ if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) {
printk("%s: Transmitter access conflict.\n", dev->name);
return 1;
}
@@ -762,7 +762,7 @@ static int sun4c_qe_start_xmit(struct sk_buff *skb, struct device *dev)
if(dev->tbusy)
return 1;
- if(set_bit(0, (void *) &dev->tbusy) != 0) {
+ if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) {
printk("%s: Transmitter access conflict.\n", dev->name);
return 1;
}
diff --git a/drivers/net/tulip.c b/drivers/net/tulip.c
index fe4cf2662..f87beba00 100644
--- a/drivers/net/tulip.c
+++ b/drivers/net/tulip.c
@@ -863,7 +863,7 @@ tulip_start_xmit(struct sk_buff *skb, struct device *dev)
/* Block a timer-based transmit from overlapping. This could better be
done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
If this ever occurs the queue layer is doing something evil! */
- if (set_bit(0, (void*)&dev->tbusy) != 0) {
+ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
printk("%s: Transmitter access conflict.\n", dev->name);
return 1;
}
diff --git a/drivers/net/wavelan.c b/drivers/net/wavelan.c
index 0b18de7d9..336283df0 100644
--- a/drivers/net/wavelan.c
+++ b/drivers/net/wavelan.c
@@ -64,8 +64,8 @@ wv_irq_to_psa(int irq)
/*
* Translate PSA irq parameter to irq number
*/
-static int
-wv_psa_to_irq(u_char irqval)
+__initfunc(static int
+wv_psa_to_irq(u_char irqval))
{
int irq;
@@ -895,7 +895,7 @@ wv_82586_reconfig(device * dev)
net_local * lp = (net_local *)dev->priv;
/* Check if we can do it now ! */
- if(!(dev->start) || (set_bit(0, (void *)&dev->tbusy) != 0))
+ if(!(dev->start) || (test_and_set_bit(0, (void *)&dev->tbusy) != 0))
{
lp->reconfig_82586 = 1;
#ifdef DEBUG_CONFIG_INFO
@@ -2799,7 +2799,7 @@ wavelan_packet_xmit(struct sk_buff * skb,
* Block a timer-based transmit from overlapping.
* In other words, prevent reentering this routine.
*/
- if(set_bit(0, (void *)&dev->tbusy) != 0)
+ if(test_and_set_bit(0, (void *)&dev->tbusy) != 0)
#ifdef DEBUG_TX_ERROR
printk(KERN_INFO "%s: Transmitter access conflict.\n", dev->name);
#endif
@@ -3999,8 +3999,8 @@ wavelan_close(device * dev)
* device structure
* (called by wavelan_probe() & via init_module())
*/
-static int
-wavelan_config(device * dev)
+__initfunc(static int
+wavelan_config(device * dev))
{
u_long ioaddr = dev->base_addr;
u_char irq_mask;
@@ -4112,11 +4112,9 @@ wavelan_config(device * dev)
* the initial value of dev->base_addr.
* We follow the example in drivers/net/ne.c.)
* (called in "Space.c")
- * As this function is called outside the wavelan module, it should be
- * declared extern, but it seem to cause troubles...
*/
-/* extern */ int
-wavelan_probe(device * dev)
+__initfunc(int
+wavelan_probe(device * dev))
{
short base_addr;
mac_addr mac; /* Mac address (check wavelan existence) */
diff --git a/drivers/net/wavelan.p.h b/drivers/net/wavelan.p.h
index 338ef1f6f..18320dcc4 100644
--- a/drivers/net/wavelan.p.h
+++ b/drivers/net/wavelan.p.h
@@ -305,6 +305,7 @@
#include <linux/skbuff.h>
#include <linux/malloc.h>
#include <linux/timer.h>
+#include <linux/init.h>
#include <linux/wireless.h> /* Wireless extensions */
diff --git a/drivers/net/x25_asy.c b/drivers/net/x25_asy.c
index 21963477c..f6f953201 100644
--- a/drivers/net/x25_asy.c
+++ b/drivers/net/x25_asy.c
@@ -59,7 +59,7 @@ static inline struct x25_asy *x25_asy_alloc(void)
if (slp == NULL)
break;
/* Not in use ? */
- if (!set_bit(SLF_INUSE, &slp->ctrl.flags))
+ if (!test_and_set_bit(SLF_INUSE, &slp->ctrl.flags))
break;
}
/* SLP is set.. */
@@ -124,7 +124,7 @@ static inline void x25_asy_free(struct x25_asy *sl)
}
sl->xbuff = NULL;
- if (!clear_bit(SLF_INUSE, &sl->flags)) {
+ if (!test_and_clear_bit(SLF_INUSE, &sl->flags)) {
printk("%s: x25_asy_free for already free unit.\n", sl->dev->name);
}
}
@@ -201,7 +201,7 @@ static void x25_asy_changed_mtu(struct x25_asy *sl)
static inline void x25_asy_lock(struct x25_asy *sl)
{
- if (set_bit(0, (void *) &sl->dev->tbusy))
+ if (test_and_set_bit(0, (void *) &sl->dev->tbusy))
printk("%s: trying to lock already locked device!\n", sl->dev->name);
}
@@ -210,7 +210,7 @@ static inline void x25_asy_lock(struct x25_asy *sl)
static inline void x25_asy_unlock(struct x25_asy *sl)
{
- if (!clear_bit(0, (void *)&sl->dev->tbusy))
+ if (!test_and_clear_bit(0, (void *)&sl->dev->tbusy))
printk("%s: trying to unlock already unlocked device!\n", sl->dev->name);
}
@@ -587,7 +587,7 @@ static void x25_asy_receive_buf(struct tty_struct *tty, const unsigned char *cp,
/* Read the characters out of the buffer */
while (count--) {
if (fp && *fp++) {
- if (!set_bit(SLF_ERROR, &sl->flags)) {
+ if (!test_and_set_bit(SLF_ERROR, &sl->flags)) {
sl->rx_errors++;
}
cp++;
@@ -736,7 +736,7 @@ static void x25_asy_unesc(struct x25_asy *sl, unsigned char s)
switch(s)
{
case X25_END:
- if (!clear_bit(SLF_ERROR, &sl->flags) && (sl->rcount > 2))
+ if (!test_and_clear_bit(SLF_ERROR, &sl->flags) && (sl->rcount > 2))
{
x25_asy_bump(sl);
}
@@ -750,7 +750,7 @@ static void x25_asy_unesc(struct x25_asy *sl, unsigned char s)
case X25_ESCAPE(X25_ESC):
case X25_ESCAPE(X25_END):
- if (clear_bit(SLF_ESCAPE, &sl->flags))
+ if (test_and_clear_bit(SLF_ESCAPE, &sl->flags))
s = X25_UNESCAPE(s);
break;
}
diff --git a/drivers/net/znet.c b/drivers/net/znet.c
index eb198bc78..cb53120a2 100644
--- a/drivers/net/znet.c
+++ b/drivers/net/znet.c
@@ -351,7 +351,7 @@ static int znet_send_packet(struct sk_buff *skb, struct device *dev)
/* Block a timer-based transmit from overlapping. This could better be
done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
- if (set_bit(0, (void*)&dev->tbusy) != 0)
+ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name);
else {
short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 8baf90212..2aae7a2db 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -13,6 +13,7 @@
#include <linux/bios32.h>
#include <linux/pci.h>
#include <linux/string.h>
+#include <linux/init.h>
#include <asm/page.h>
@@ -149,6 +150,7 @@ struct pci_dev_info dev_info[] = {
DEVICE( CMD, CMD_646, "646"),
DEVICE( VISION, VISION_QD8500, "QD-8500"),
DEVICE( VISION, VISION_QD8580, "QD-8580"),
+ DEVICE( BROOKTREE, BT848, "Brooktree 848"),
DEVICE( SIERRA, SIERRA_STB, "STB Horizon 64"),
DEVICE( ACC, ACC_2056, "2056"),
DEVICE( WINBOND, WINBOND_83769, "W83769F"),
@@ -263,6 +265,7 @@ struct pci_dev_info dev_info[] = {
DEVICE( INTEL, INTEL_82437VX, "82437VX Triton II"),
DEVICE( INTEL, INTEL_82371AB, "82371AB 430TX PIIX4"),
DEVICE( INTEL, INTEL_P6, "Orion P6"),
+ DEVICE( INTEL, INTEL_P6_2, "82450GX Orion P6"),
DEVICE( KTI, KTI_ET32P2, "ET32P2"),
DEVICE( ADAPTEC, ADAPTEC_7850, "AIC-7850"),
DEVICE( ADAPTEC, ADAPTEC_7855, "AIC-7855"),
@@ -517,6 +520,7 @@ const char *pci_strvendor(unsigned int vendor)
case PCI_VENDOR_ID_OLICOM: return "Olicom";
case PCI_VENDOR_ID_CMD: return "CMD";
case PCI_VENDOR_ID_VISION: return "Vision";
+ case PCI_VENDOR_ID_BROOKTREE: return "Brooktree";
case PCI_VENDOR_ID_SIERRA: return "Sierra";
case PCI_VENDOR_ID_ACC: return "ACC MICROELECTRONICS";
case PCI_VENDOR_ID_WINBOND: return "Winbond";
@@ -576,8 +580,8 @@ const char *pci_strdev(unsigned int vendor, unsigned int device)
/*
* Turn on/off PCI bridge optimization. This should allow benchmarking.
*/
-static void burst_bridge(unsigned char bus, unsigned char devfn,
- unsigned char pos, int turn_on)
+__initfunc(static void burst_bridge(unsigned char bus, unsigned char devfn,
+ unsigned char pos, int turn_on))
{
#ifdef CONFIG_PCI_OPTIMIZE
struct bridge_mapping_type *bmap;
@@ -791,7 +795,7 @@ int get_pci_list(char *buf)
* pci_malloc() returns initialized memory of size SIZE. Can be
* used only while pci_init() is active.
*/
-static void *pci_malloc(long size, unsigned long *mem_startp)
+__initfunc(static void *pci_malloc(long size, unsigned long *mem_startp))
{
void *mem;
@@ -805,7 +809,7 @@ static void *pci_malloc(long size, unsigned long *mem_startp)
}
-static unsigned int scan_bus(struct pci_bus *bus, unsigned long *mem_startp)
+__initfunc(static unsigned int scan_bus(struct pci_bus *bus, unsigned long *mem_startp))
{
unsigned int devfn, l, max;
unsigned char cmd, tmp, hdr_type = 0;
@@ -980,12 +984,12 @@ static unsigned int scan_bus(struct pci_bus *bus, unsigned long *mem_startp)
}
-unsigned long pci_init (unsigned long mem_start, unsigned long mem_end)
+__initfunc(unsigned long pci_init (unsigned long mem_start, unsigned long mem_end))
{
mem_start = pcibios_init(mem_start, mem_end);
if (!pcibios_present()) {
- printk("pci_init: no BIOS32 detected\n");
+ printk("pci_init: no PCI BIOS detected\n");
return mem_start;
}
diff --git a/drivers/pnp/.cvsignore b/drivers/pnp/.cvsignore
new file mode 100644
index 000000000..4671378ae
--- /dev/null
+++ b/drivers/pnp/.cvsignore
@@ -0,0 +1 @@
+.depend
diff --git a/drivers/sbus/audio/amd7930.c b/drivers/sbus/audio/amd7930.c
index 388949d21..1134eb74e 100644
--- a/drivers/sbus/audio/amd7930.c
+++ b/drivers/sbus/audio/amd7930.c
@@ -16,6 +16,7 @@
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/malloc.h>
+#include <linux/init.h>
#include <asm/openprom.h>
#include <asm/oplib.h>
#include <asm/system.h>
diff --git a/drivers/sbus/audio/cs4231.c b/drivers/sbus/audio/cs4231.c
index ecb09a4d7..5c361a0b0 100644
--- a/drivers/sbus/audio/cs4231.c
+++ b/drivers/sbus/audio/cs4231.c
@@ -15,6 +15,7 @@
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/malloc.h>
+#include <linux/init.h>
#include <asm/openprom.h>
#include <asm/oplib.h>
#include <asm/system.h>
diff --git a/drivers/sbus/char/creator.c b/drivers/sbus/char/creator.c
index 193a26190..9bf72a3b9 100644
--- a/drivers/sbus/char/creator.c
+++ b/drivers/sbus/char/creator.c
@@ -47,52 +47,3 @@ __initfunc(void creator_setup (fbinfo_t *fb, int slot, int con_node, unsigned lo
fb->unblank = 0;
fb->type.fb_depth = 8;
}
-/*
- * creator.c: Linux/Sun Ultra Creator console support.
- *
- * Copyright (C) 1997 MIguel de Icaza (miguel@nuclecu.unam.mx)
- *
- */
-#include <linux/kd.h>
-#include <linux/tty.h>
-#include <linux/malloc.h>
-#include <linux/proc_fs.h>
-
-#include <asm/sbus.h>
-#include <asm/io.h>
-#include <asm/fbio.h>
-#include <asm/pgtable.h>
-#include <asm/uaccess.h>
-
-#include "../../char/vt_kern.h"
-#include "../../char/selection.h"
-#include "../../char/console_struct.h"
-#include "fb.h"
-
-__initfunc(void creator_setup (fbinfo_t *fb, int slot, int con_node, unsigned long creator, int creator_io))
-{
- uint bases [2];
- unsigned long *p;
-
- if (!creator) {
- prom_getproperty (con_node, "address", (char *) &bases[0], 4);
- prom_printf ("Bases: %x %x\n", bases [0], bases [1]);
- p = (unsigned long *) creator = bases[0];
- fb->base = creator;
- fb->base = 0xff168000;
- }
-
- fb->type.fb_cmsize = 256;
- fb->mmap = 0;
- fb->loadcmap = 0;
- fb->setcursor = 0;
- fb->setcursormap = 0;
- fb->setcurshape = 0;
- fb->ioctl = 0;
- fb->switch_from_graph = 0;
- fb->postsetup = sun_cg_postsetup;
- fb->reset = 0;
- fb->blank = 0;
- fb->unblank = 0;
- fb->type.fb_depth = 8;
-}
diff --git a/drivers/sbus/char/suncons.c b/drivers/sbus/char/suncons.c
index 20b65c658..d1a2dfd45 100644
--- a/drivers/sbus/char/suncons.c
+++ b/drivers/sbus/char/suncons.c
@@ -1,4 +1,4 @@
-/* $Id: suncons.c,v 1.61 1997/04/17 02:29:36 miguel Exp $
+/* $Id: suncons.c,v 1.62 1997/05/02 22:32:32 davem Exp $
*
* suncons.c: Sun SparcStation console support.
*
@@ -387,12 +387,12 @@ render_screen(void)
sun_blitc (*contents, (unsigned long) contents);
}
-__initfunc(void serial_finish_init(void (*printfunc)(const char *)))
+__initfunc(void serial_finish_init(void (*printfunc)(const char *, int)))
{
char buffer[2048];
sprintf (buffer, linux_serial_image, UTS_RELEASE);
- (*printfunc)(buffer);
+ (*printfunc)(buffer, strlen(buffer));
}
__initfunc(void con_type_init_finish(void))
diff --git a/drivers/sbus/char/sunkbd.c b/drivers/sbus/char/sunkbd.c
index 87fb0fea4..8e398f345 100644
--- a/drivers/sbus/char/sunkbd.c
+++ b/drivers/sbus/char/sunkbd.c
@@ -487,7 +487,7 @@ void sunkbd_inchar(unsigned char ch, struct pt_regs *regs)
add_timer (&auto_repeat_timer);
}
}
- rep = set_bit(keycode, key_down);
+ rep = test_and_set_bit(keycode, key_down);
}
if(raw_mode)
diff --git a/drivers/sbus/char/sunserial.c b/drivers/sbus/char/sunserial.c
index cd4fe4ee3..2fa29da26 100644
--- a/drivers/sbus/char/sunserial.c
+++ b/drivers/sbus/char/sunserial.c
@@ -1,4 +1,4 @@
-/* $Id: sunserial.c,v 1.38 1997/04/14 17:05:00 jj Exp $
+/* $Id: sunserial.c,v 1.41 1997/05/14 20:46:51 davem Exp $
* serial.c: Serial port driver for the Sparc.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -19,6 +19,8 @@
#include <linux/fcntl.h>
#include <linux/mm.h>
#include <linux/kernel.h>
+#include <linux/keyboard.h>
+#include <linux/console.h>
#include <linux/init.h>
#include <asm/io.h>
@@ -39,8 +41,6 @@ static int num_serial = 2; /* sun4/sun4c/sun4m - Two chips on board. */
#define KEYBOARD_LINE 0x2
#define MOUSE_LINE 0x3
-extern struct wait_queue * keypress_wait;
-
struct sun_zslayout **zs_chips;
struct sun_zschannel **zs_channels;
struct sun_zschannel *zs_conschan;
@@ -687,7 +687,7 @@ static void do_softint(void *private_)
if (!tty)
return;
- if (clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
+ if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
tty->ldisc.write_wakeup)
(tty->ldisc.write_wakeup)(tty);
@@ -866,10 +866,10 @@ static void change_speed(struct sun_serial *info)
i = cflag & CBAUD;
if (cflag & CBAUDEX) {
i &= ~CBAUDEX;
- if (i != 1)
+ if (i != 5)
info->tty->termios->c_cflag &= ~CBAUDEX;
else
- i += 15;
+ i = 16;
}
if (i == 15) {
if ((info->flags & ZILOG_SPD_MASK) == ZILOG_SPD_HI)
@@ -1062,20 +1062,30 @@ static void rs_fair_output(void)
/*
* zs_console_print is registered for printk.
*/
-static void zs_console_print(const char *p)
+static void zs_console_print(const char *s, int count)
{
- char c;
+ int i;
- while((c=*(p++)) != 0) {
- if(c == '\n')
+ for (i = 0; i < count; i++, s++) {
+ if(*s == '\n')
rs_put_char('\r');
- rs_put_char(c);
+ rs_put_char(*s);
}
/* Comment this if you want to have a strict interrupt-driven output */
rs_fair_output();
+}
- return;
+static void zs_console_wait_key(void)
+{
+ sleep_on(&keypress_wait);
+}
+
+static int zs_console_device(void)
+{
+ extern int serial_console;
+
+ return MKDEV(TTYAUX_MAJOR, 64 + serial_console - 1);
}
static void rs_flush_chars(struct tty_struct *tty)
@@ -1857,7 +1867,7 @@ int rs_open(struct tty_struct *tty, struct file * filp)
static void show_serial_version(void)
{
- char *revision = "$Revision: 1.38 $";
+ char *revision = "$Revision: 1.41 $";
char *version, *p;
version = strchr(revision, ' ');
@@ -2164,14 +2174,15 @@ no_options:
termios->c_cflag = cflag;
}
-extern void register_console(void (*proc)(const char *));
-
static inline void
rs_cons_check(struct sun_serial *ss, int channel)
{
int i, o, io;
static int consout_registered = 0;
static int msg_printed = 0;
+ static struct console console = {
+ zs_console_print, 0,
+ zs_console_wait_key, zs_console_device };
i = o = io = 0;
@@ -2187,10 +2198,10 @@ rs_cons_check(struct sun_serial *ss, int channel)
o = 1;
/* double whee.. */
if(!consout_registered) {
- extern void serial_finish_init (void (*)(const char *));
+ extern void serial_finish_init (void (*)(const char *, int count));
serial_finish_init (zs_console_print);
- register_console(zs_console_print);
+ register_console(&console);
consout_registered = 1;
}
}
diff --git a/drivers/sbus/char/vfc.h b/drivers/sbus/char/vfc.h
index 752bf748c..72a883cfc 100644
--- a/drivers/sbus/char/vfc.h
+++ b/drivers/sbus/char/vfc.h
@@ -157,10 +157,16 @@ void vfc_unlock_device(struct vfc_dev *);
#define VFC_STATUS_CAPTURE 0x08000000
-#ifdef VFC_DEBUG
-#define VFC_DEBUG_PRINTK(a) printk a
+#ifdef VFC_IOCTL_DEBUG
+#define VFC_IOCTL_DEBUG_PRINTK(a) printk a
#else
-#define VFC_DEBUG_PRINTK(a)
+#define VFC_IOCTL_DEBUG_PRINTK(a)
+#endif
+
+#ifdef VFC_I2C_DEBUG
+#define VFC_I2C_DEBUG_PRINTK(a) printk a
+#else
+#define VFC_I2C_DEBUG_PRINTK(a)
#endif
#endif /* _LINUX_VFC_H_ */
diff --git a/drivers/sbus/char/vfc_dev.c b/drivers/sbus/char/vfc_dev.c
index 556d06e9f..20e04258b 100644
--- a/drivers/sbus/char/vfc_dev.c
+++ b/drivers/sbus/char/vfc_dev.c
@@ -3,11 +3,11 @@
*
* Driver for the Videopix Frame Grabber.
*
- * In order to use the VFC you need to progeam the video controller
+ * In order to use the VFC you need to program the video controller
* chip. This chip is the Phillips SAA9051. You need to call their
* documentation ordering line to get the docs.
*
- * Their is very little documentation on the VFC itself. There is
+ * There is very little documentation on the VFC itself. There is
* some useful info that can be found in the manuals that come with
* the card. I will hopefully write some better docs at a later date.
*
@@ -21,6 +21,7 @@
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/fs.h>
+#include <linux/uaccess.h>
#include <asm/openprom.h>
#include <asm/oplib.h>
@@ -30,12 +31,11 @@
#include <asm/delay.h>
#include <asm/page.h>
#include <asm/pgtable.h>
-#include <asm/uaccess.h>
#define VFC_MAJOR (60)
#if 0
-#define VFC_DEBUG
+#define VFC_IOCTL_DEBUG
#endif
#include "vfc.h"
@@ -133,30 +133,27 @@ int init_vfc_devstruct(struct vfc_dev *dev, int instance)
dev->control_reg=0;
dev->poll_wait=NULL;
dev->busy=0;
- /* initialize the timer struct */
return 0;
}
int init_vfc_device(struct linux_sbus_device *sdev,struct vfc_dev *dev,
int instance) {
- struct linux_prom_registers reg;
if(!dev) {
printk(KERN_ERR "VFC: Bogus pointer passed\n");
return -ENOMEM;
}
printk("Initializing vfc%d\n",instance);
dev->regs=NULL;
- memcpy(&reg,&sdev->reg_addrs[0],sizeof(struct linux_prom_registers));
- prom_apply_sbus_ranges(sdev->my_bus, &reg, sdev->num_registers, sdev);
- dev->regs=sparc_alloc_io(reg.phys_addr, 0,
+ prom_apply_sbus_ranges(sdev->my_bus, &sdev->reg_addrs[0], sdev->num_registers, sdev);
+ dev->regs=sparc_alloc_io(sdev->reg_addrs[0].phys_addr, 0,
sizeof(struct vfc_regs), vfcstr,
- reg.which_io, 0x0);
- dev->which_io=reg.which_io;
- dev->phys_regs=(struct vfc_regs *)reg.phys_addr;
+ sdev->reg_addrs[0].which_io, 0x0);
+ dev->which_io=sdev->reg_addrs[0].which_io;
+ dev->phys_regs=(struct vfc_regs *)sdev->reg_addrs[0].phys_addr;
if(!dev->regs) return -EIO;
printk("vfc%d: registers mapped at phys_addr: 0x%lx\n virt_addr: 0x%lx\n",
- instance,(unsigned long)reg.phys_addr,(unsigned long)dev->regs);
+ instance,(unsigned long)sdev->reg_addrs[0].phys_addr,(unsigned long)dev->regs);
if(init_vfc_devstruct(dev,instance)) return -EINVAL;
if(init_vfc_hw(dev)) return -EIO;
@@ -191,52 +188,58 @@ static int vfc_open(struct inode *inode, struct file *file)
return 0;
}
-static int vfc_release(struct inode *inode,struct file *file)
+static void vfc_release(struct inode *inode,struct file *file)
{
struct vfc_dev *dev;
dev=vfc_get_dev_ptr(MINOR(inode->i_rdev));
- if(!dev) return -EINVAL;
- if(!dev->busy) return 0;
+ if(!dev) return;
+ if(!dev->busy) return;
dev->busy=0;
MOD_DEC_USE_COUNT;
- return 0;
+ return;
}
static int vfc_debug(struct vfc_dev *dev, int cmd, unsigned long arg)
{
struct vfc_debug_inout inout;
unsigned char *buffer;
+ int ret;
+
+ if(!suser()) return -EPERM;
switch(cmd) {
case VFC_I2C_SEND:
- if(copy_from_user(&inout, (void *)arg, sizeof(inout)))
+ if(copy_from_user(&inout, (void *)arg, sizeof(inout))) {
return -EFAULT;
+ }
buffer = kmalloc(inout.len*sizeof(char), GFP_KERNEL);
if (!buffer)
return -ENOMEM;
- if(copy_from_user(buffer, inout.buffer, inout.len*sizeof(char))) {
- kfree_s(buffer,inout.len);
+
+ if(copy_from_user(buffer, inout.buffer,
+ inout.len*sizeof(char));) {
+ kfree_s(buffer,inout.len*sizeof(char));
return -EFAULT;
}
+
vfc_lock_device(dev);
inout.ret=
vfc_i2c_sendbuf(dev,inout.addr & 0xff,
inout.buffer,inout.len);
- if(copy_to_user((void *)arg,&inout,sizeof(inout))) {
- kfree_s(buffer,inout.len);
+
+ if (copy_to_user((void *)arg,&inout,sizeof(inout))) {
+ kfree_s(buffer, inout.len);
return -EFAULT;
}
vfc_unlock_device(dev);
- kfree_s(buffer, inout.len);
-
break;
case VFC_I2C_RECV:
-
- if(copy_from_user(&inout, (void *)arg, sizeof(inout)))
+ if (copy_from_user(&inout, (void *)arg, sizeof(inout))) {
return -EFAULT;
+ }
buffer = kmalloc(inout.len, GFP_KERNEL);
if (!buffer)
@@ -248,11 +251,11 @@ static int vfc_debug(struct vfc_dev *dev, int cmd, unsigned long arg)
,buffer,inout.len);
vfc_unlock_device(dev);
- if(copy_to_user(inout.buffer, buffer, inout.len)) {
+ if (copy_to_user(inout.buffer, buffer, inout.len)) {
kfree_s(buffer,inout.len);
return -EFAULT;
}
- if(copy_to_user((void *)arg,&inout,sizeof(inout))) {
+ if (copy_to_user((void *)arg,&inout,sizeof(inout))) {
kfree_s(buffer,inout.len);
return -EFAULT;
}
@@ -306,12 +309,10 @@ static int vfc_set_control_ioctl(struct inode *inode, struct file *file,
struct vfc_dev *dev, unsigned long arg)
{
int setcmd,ret=0;
- if(copy_from_user(&setcmd,(void *)arg,sizeof(unsigned int)))
+ if (copy_from_user(&setcmd,(void *)arg,sizeof(unsigned int)))
return -EFAULT;
-#if 0
- VFC_DEBUG_PRINTK(("vfc%d: IOCTL(VFCSCTRL) arg=0x%x\n",
- dev->instance,setcmd));
-#endif
+ VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCSCTRL) arg=0x%x\n",
+ dev->instance,setcmd));
switch(setcmd) {
case MEMPRST:
vfc_lock_device(dev);
@@ -359,13 +360,14 @@ int vfc_port_change_ioctl(struct inode *inode, struct file *file,
{
int ret=0;
int cmd;
+
if(copy_from_user(&cmd, (void *)arg, sizeof(unsigned int))) {
- VFC_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to "
+ VFC_IOCTL_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to "
"vfc_port_change_ioctl\n",dev->instance));
return -EFAULT;
}
- VFC_DEBUG_PRINTK(("vfc%d: IOCTL(VFCPORTCHG) arg=0x%x\n",
+ VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCPORTCHG) arg=0x%x\n",
dev->instance,cmd));
switch(cmd) {
@@ -424,12 +426,12 @@ int vfc_set_video_ioctl(struct inode *inode, struct file *file,
int ret=0;
int cmd;
if(copy_from_user(&cmd, (void *)arg, sizeof(unsigned int))) {
- VFC_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to "
+ VFC_IOCTL_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to "
"vfc_set_video_ioctl\n",dev->instance));
- return -EFAULT;
+ return ret;
}
- VFC_DEBUG_PRINTK(("vfc%d: IOCTL(VFCSVID) arg=0x%x\n",
+ VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCSVID) arg=0x%x\n",
dev->instance,cmd));
switch(cmd) {
@@ -490,12 +492,12 @@ int vfc_get_video_ioctl(struct inode *inode, struct file *file,
else
status=PAL_NOCOLOR;
}
- VFC_DEBUG_PRINTK(("vfc%d: IOCTL(VFCGVID) returning status 0x%x; buf[0]=%x\n",dev->instance,
+ VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCGVID) returning status 0x%x; buf[0]=%x\n",dev->instance,
status,buf[0]));
- if(copy_to_user((void *)arg,&status,sizeof(unsigned int))) {
- VFC_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to "
+ if (copy_to_user((void *)arg,&status,sizeof(unsigned int))) {
+ VFC_IOCTL_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to "
"vfc_get_video_ioctl\n",dev->instance));
- return -EFAULT;
+ return ret;
}
return ret;
}
@@ -513,11 +515,13 @@ static int vfc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
switch(cmd & 0x0000ffff) {
case VFCGCTRL:
#if 0
- VFC_DEBUG_PRINTK(("vfc%d: IOCTL(VFCGCTRL)\n",dev->instance));
+ VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCGCTRL)\n",dev->instance));
#endif
tmp=dev->regs->control;
- if(copy_to_user((void *)arg,&tmp,sizeof(unsigned int)))
- return -EFAULT;
+ if(copy_to_user((void *)arg,&tmp, sizeof(unsigned int))) {
+ ret=-EFAULT;
+ break;
+ }
ret=0;
break;
case VFCSCTRL:
@@ -530,12 +534,9 @@ static int vfc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
ret=vfc_set_video_ioctl(inode,file,dev,arg);
break;
case VFCHUE:
-#if 0
- VFC_DEBUG_PRINTK(("vfc%d: IOCTL(VFCHUE)\n",dev->instance));
-#endif
-
+ VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCHUE)\n",dev->instance));
if(copy_from_user(&tmp,(void *)arg,sizeof(unsigned int))) {
- VFC_DEBUG_PRINTK(("vfc%d: User passed bogus pointer "
+ VFC_IOCTL_DEBUG_PRINTK(("vfc%d: User passed bogus pointer "
"to IOCTL(VFCHUE)",dev->instance));
ret=-EFAULT;
} else {
@@ -549,7 +550,7 @@ static int vfc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
break;
case VFCRDINFO:
ret=-EINVAL;
- VFC_DEBUG_PRINTK(("vfc%d: IOCTL(VFCRDINFO)\n",dev->instance));
+ VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCRDINFO)\n",dev->instance));
break;
default:
ret=vfc_debug(vfc_get_dev_ptr(MINOR(inode->i_rdev)),
@@ -584,8 +585,9 @@ static int vfc_mmap(struct inode *inode, struct file *file,
return 0;
}
-static long long vfc_lseek(struct inode *inode, struct file *file,
- long long offset, int origin)
+
+static int vfc_lseek(struct inode *inode, struct file *file,
+ off_t offset, int origin)
{
return -ESPIPE;
}
@@ -595,14 +597,13 @@ static struct file_operations vfc_fops = {
NULL, /* vfc_write */
NULL, /* vfc_read */
NULL, /* vfc_readdir */
- NULL, /* vfc_poll */
+ NULL, /* vfc_select */
vfc_ioctl,
vfc_mmap,
vfc_open,
vfc_release,
};
-
static int vfc_probe(void)
{
struct linux_sbus *bus;
diff --git a/drivers/sbus/char/vfc_i2c.c b/drivers/sbus/char/vfc_i2c.c
index 952eb9875..68cfc4405 100644
--- a/drivers/sbus/char/vfc_i2c.c
+++ b/drivers/sbus/char/vfc_i2c.c
@@ -31,8 +31,8 @@ fairly certain that the flowcharts in the phillips docs are wrong. */
#include <asm/system.h>
#include <asm/sbus.h>
-#if 0
-#define VFC_DEBUG
+#if 0
+#define VFC_I2C_DEBUG
#endif
#include "vfc.h"
@@ -72,6 +72,8 @@ int vfc_pcf8584_init(struct vfc_dev *dev)
void vfc_i2c_delay_wakeup(struct vfc_dev *dev)
{
+ /* Used to profile code and eliminate too many delays */
+ VFC_I2C_DEBUG_PRINTK(("vfc%d: Delaying\n",dev->instance));
wake_up(&dev->poll_wait);
}
@@ -95,14 +97,14 @@ void inline vfc_i2c_delay(struct vfc_dev *dev)
int vfc_init_i2c_bus(struct vfc_dev *dev)
{
- dev->regs->i2c_s1= ENABLE_SERIAL | ACK;
+ dev->regs->i2c_s1= ENABLE_SERIAL | SELECT(S0) | ACK;
vfc_i2c_reset_bus(dev);
return 0;
}
int vfc_i2c_reset_bus(struct vfc_dev *dev)
{
- VFC_DEBUG_PRINTK((KERN_DEBUG "vfc%d: Resetting the i2c bus\n",
+ VFC_I2C_DEBUG_PRINTK((KERN_DEBUG "vfc%d: Resetting the i2c bus\n",
dev->instance));
if(!dev) return -EINVAL;
if(!dev->regs) return -EINVAL;
@@ -110,7 +112,7 @@ int vfc_i2c_reset_bus(struct vfc_dev *dev)
dev->regs->i2c_s1=SEND_I2C_STOP | ACK;
vfc_i2c_delay(dev);
dev->regs->i2c_s1=CLEAR_I2C_BUS;
- VFC_DEBUG_PRINTK((KERN_DEBUG "vfc%d: I2C status %x\n",
+ VFC_I2C_DEBUG_PRINTK((KERN_DEBUG "vfc%d: I2C status %x\n",
dev->instance, dev->regs->i2c_s1));
return 0;
}
@@ -146,7 +148,7 @@ int vfc_i2c_xmit_addr(struct vfc_dev *dev, unsigned char addr, char mode)
{
int ret,raddr;
#if 1
- dev->regs->i2c_s1=SEND_I2C_STOP;
+ dev->regs->i2c_s1=SEND_I2C_STOP | ACK;
dev->regs->i2c_s1=SELECT(S0) | ENABLE_SERIAL;
vfc_i2c_delay(dev);
#endif
@@ -154,12 +156,12 @@ int vfc_i2c_xmit_addr(struct vfc_dev *dev, unsigned char addr, char mode)
switch(mode) {
case VFC_I2C_READ:
dev->regs->i2c_reg=raddr=SHIFT((unsigned int)addr | 0x1);
- VFC_DEBUG_PRINTK(("vfc%d: recieving from i2c addr 0x%x\n",
+ VFC_I2C_DEBUG_PRINTK(("vfc%d: recieving from i2c addr 0x%x\n",
dev->instance,addr | 0x1));
break;
case VFC_I2C_WRITE:
dev->regs->i2c_reg=raddr=SHIFT((unsigned int)addr & ~0x1);
- VFC_DEBUG_PRINTK(("vfc%d: sending to i2c addr 0x%x\n",
+ VFC_I2C_DEBUG_PRINTK(("vfc%d: sending to i2c addr 0x%x\n",
dev->instance,addr & ~0x1));
break;
default:
@@ -215,7 +217,7 @@ int vfc_i2c_recv_byte(struct vfc_dev *dev, unsigned char *byte, int last)
int ret;
if(last) {
dev->regs->i2c_reg=NEGATIVE_ACK;
- VFC_DEBUG_PRINTK((KERN_DEBUG "vfc%d: sending negative ack\n",
+ VFC_I2C_DEBUG_PRINTK(("vfc%d: sending negative ack\n",
dev->instance));
} else {
dev->regs->i2c_s1=ACK;
@@ -255,6 +257,8 @@ int vfc_i2c_recvbuf(struct vfc_dev *dev, unsigned char addr,
printk(KERN_ERR "vfc%d: "
"VFC error while recieving byte\n",
dev->instance);
+ dev->regs->i2c_s1=SEND_I2C_STOP;
+ ret=-EINVAL;
}
buf++;
}
@@ -286,7 +290,7 @@ int vfc_i2c_sendbuf(struct vfc_dev *dev, unsigned char addr,
ret=vfc_i2c_xmit_byte(dev,buf);
switch(ret) {
case XMIT_LAST_BYTE:
- VFC_DEBUG_PRINTK(("vfc%d: "
+ VFC_I2C_DEBUG_PRINTK(("vfc%d: "
"Reciever ended transmission with "
" %d bytes remaining\n",
dev->instance,count));
diff --git a/drivers/scsi/53c7,8xx.c b/drivers/scsi/53c7,8xx.c
index 3691108e6..44a78b12c 100644
--- a/drivers/scsi/53c7,8xx.c
+++ b/drivers/scsi/53c7,8xx.c
@@ -254,7 +254,6 @@ typedef unsigned int u32;
#include <linux/time.h>
#include <linux/blk.h>
#include <linux/init.h>
-#undef current
#include "scsi.h"
#include "hosts.h"
@@ -783,7 +782,7 @@ NCR53c7x0_driver_init (struct Scsi_Host *host) {
struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
host->hostdata;
int i, j;
- u32 *current;
+ u32 *curr;
for (i = 0; i < 16; ++i) {
hostdata->request_sense[i] = 0;
for (j = 0; j < 8; ++j)
@@ -792,14 +791,14 @@ NCR53c7x0_driver_init (struct Scsi_Host *host) {
}
hostdata->issue_queue = NULL;
hostdata->running_list = hostdata->finished_queue =
- hostdata->current = NULL;
- for (i = 0, current = (u32 *) hostdata->schedule;
- i < host->can_queue; ++i, current += 2) {
- current[0] = hostdata->NOP_insn;
- current[1] = 0xdeadbeef;
+ hostdata->curr = NULL;
+ for (i = 0, curr = (u32 *) hostdata->schedule;
+ i < host->can_queue; ++i, curr += 2) {
+ curr[0] = hostdata->NOP_insn;
+ curr[1] = 0xdeadbeef;
}
- current[0] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24) | DBC_TCI_TRUE;
- current[1] = (u32) virt_to_bus (hostdata->script) +
+ curr[0] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24) | DBC_TCI_TRUE;
+ curr[1] = (u32) virt_to_bus (hostdata->script) +
hostdata->E_wait_reselect;
hostdata->reconnect_dsa_head = 0;
hostdata->addr_reconnect_dsa_head = (u32)
@@ -2104,7 +2103,7 @@ abnormal_finished (struct NCR53c7x0_cmd *cmd, int result) {
int left, found;
volatile struct NCR53c7x0_cmd * linux_search;
volatile struct NCR53c7x0_cmd * volatile *linux_prev;
- volatile u32 *ncr_prev, *current, ncr_search;
+ volatile u32 *ncr_prev, *curr, ncr_search;
#if 0
printk ("scsi%d: abnormal finished\n", host->host_no);
@@ -2120,13 +2119,13 @@ abnormal_finished (struct NCR53c7x0_cmd *cmd, int result) {
*/
- for (found = 0, left = host->can_queue, current = hostdata->schedule;
- left > 0; --left, current += 2)
+ for (found = 0, left = host->can_queue, curr = hostdata->schedule;
+ left > 0; --left, curr += 2)
{
- if (issue_to_cmd (host, hostdata, (u32 *) current) == cmd)
+ if (issue_to_cmd (host, hostdata, (u32 *) curr) == cmd)
{
- current[0] = hostdata->NOP_insn;
- current[1] = 0xdeadbeef;
+ curr[0] = hostdata->NOP_insn;
+ curr[1] = 0xdeadbeef;
++found;
break;
}
@@ -3964,7 +3963,7 @@ to_schedule_list (struct Scsi_Host *host, struct NCR53c7x0_hostdata *hostdata,
Scsi_Cmnd *tmp = cmd->cmd;
unsigned long flags;
/* dsa start is negative, so subtraction is used */
- volatile u32 *current;
+ volatile u32 *curr;
int i;
NCR53c7x0_local_setup(host);
@@ -3991,9 +3990,9 @@ to_schedule_list (struct Scsi_Host *host, struct NCR53c7x0_hostdata *hostdata,
return;
}
- for (i = host->can_queue, current = hostdata->schedule;
- i > 0 && current[0] != hostdata->NOP_insn;
- --i, current += 2 /* JUMP instructions are two words */);
+ for (i = host->can_queue, curr = hostdata->schedule;
+ i > 0 && curr[0] != hostdata->NOP_insn;
+ --i, curr += 2 /* JUMP instructions are two words */);
if (i > 0) {
++hostdata->busy[tmp->target][tmp->lun];
@@ -4002,13 +4001,13 @@ to_schedule_list (struct Scsi_Host *host, struct NCR53c7x0_hostdata *hostdata,
/* Restore this instruction to a NOP once the command starts */
cmd->dsa [(hostdata->dsa_jump_dest - hostdata->dsa_start) /
- sizeof(u32)] = (u32) virt_to_bus ((void *)current);
+ sizeof(u32)] = (u32) virt_to_bus ((void *)curr);
/* Replace the current jump operand. */
- current[1] =
+ curr[1] =
virt_to_bus ((void *) cmd->dsa) + hostdata->E_dsa_code_begin -
hostdata->E_dsa_code_template;
/* Replace the NOP instruction with a JUMP */
- current[0] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24) |
+ curr[0] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24) |
DBC_TCI_TRUE;
} else {
printk ("scsi%d: no free slot\n", host->host_no);
@@ -4510,8 +4509,8 @@ restart:
/*
* NCR53c700 and NCR53c700-66 change the current SCSI
- * process, hostdata->current, in the Linux driver so
- * cmd = hostdata->current.
+ * process, hostdata->curr, in the Linux driver so
+ * cmd = hostdata->curr.
*
* With other chips, we must look through the commands
* executing and find the command structure which
@@ -4519,7 +4518,7 @@ restart:
*/
if (hostdata->options & OPTION_700) {
- cmd = (struct NCR53c7x0_cmd *) hostdata->current;
+ cmd = (struct NCR53c7x0_cmd *) hostdata->curr;
} else {
dsa = bus_to_virt(NCR53c7x0_read32(DSA_REG));
for (cmd = (struct NCR53c7x0_cmd *)
@@ -5872,7 +5871,7 @@ print_queues (struct Scsi_Host *host) {
struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
host->hostdata;
u32 *dsa, *next_dsa;
- volatile u32 *current;
+ volatile u32 *curr;
int left;
Scsi_Cmnd *cmd, *next_cmd;
unsigned long flags;
@@ -5914,11 +5913,11 @@ print_queues (struct Scsi_Host *host) {
*/
printk ("scsi%d : schedule dsa array :\n", host->host_no);
- for (left = host->can_queue, current = hostdata->schedule;
- left > 0; current += 2, --left)
- if (current[0] != hostdata->NOP_insn)
+ for (left = host->can_queue, curr = hostdata->schedule;
+ left > 0; curr += 2, --left)
+ if (curr[0] != hostdata->NOP_insn)
/* FIXME : convert pointer to dsa_begin to pointer to dsa. */
- print_dsa (host, bus_to_virt (current[1] -
+ print_dsa (host, bus_to_virt (curr[1] -
(hostdata->E_dsa_code_begin -
hostdata->E_dsa_code_template)), "");
printk ("scsi%d : end schedule dsa array\n", host->host_no);
@@ -6108,7 +6107,7 @@ return_outstanding_commands (struct Scsi_Host *host, int free, int issue) {
host->hostdata;
struct NCR53c7x0_cmd *c;
int i;
- u32 *current;
+ u32 *curr;
Scsi_Cmnd *list = NULL, *tmp;
for (c = (struct NCR53c7x0_cmd *) hostdata->running_list; c;
c = (struct NCR53c7x0_cmd *) c->next) {
@@ -6129,12 +6128,12 @@ return_outstanding_commands (struct Scsi_Host *host, int free, int issue) {
}
if (free) {
- for (i = 0, current = (u32 *) hostdata->schedule;
- i < host->can_queue; ++i, current += 2) {
- current[0] = hostdata->NOP_insn;
- current[1] = 0xdeadbeef;
+ for (i = 0, curr = (u32 *) hostdata->schedule;
+ i < host->can_queue; ++i, curr += 2) {
+ curr[0] = hostdata->NOP_insn;
+ curr[1] = 0xdeadbeef;
}
- hostdata->current = NULL;
+ hostdata->curr = NULL;
}
if (issue) {
diff --git a/drivers/scsi/53c7,8xx.h b/drivers/scsi/53c7,8xx.h
index 80fbad3b5..cfddfa681 100644
--- a/drivers/scsi/53c7,8xx.h
+++ b/drivers/scsi/53c7,8xx.h
@@ -1394,7 +1394,7 @@ struct NCR53c7x0_hostdata {
/* commands running, maintained
by Linux driver */
- volatile struct NCR53c7x0_cmd *current; /* currently connected
+ volatile struct NCR53c7x0_cmd *curr; /* currently connected
nexus, ONLY valid for
NCR53c700/NCR53c700-66
*/
diff --git a/drivers/scsi/53c7xx.c b/drivers/scsi/53c7xx.c
new file mode 100644
index 000000000..a8cd93828
--- /dev/null
+++ b/drivers/scsi/53c7xx.c
@@ -0,0 +1,6107 @@
+/*
+ * 53c710 driver. Modified from Drew Eckhardts driver
+ * for 53c810 by Richard Hirst [richard@sleepie.demon.co.uk]
+ * Check out PERM_OPTIONS and EXPECTED_CLOCK, which may be defined in the
+ * relevant machine specific file (eg. mvme166.[ch], amiga7xx.[ch]).
+ * There are also currently some defines at the top of 53c7xx.scr.
+ * The chip type is #defined in script_asm.pl, as well as the Makefile.
+ * Host scsi ID expected to be 7 - see NCR53c7x0_init().
+ *
+ * I have removed the PCI code and some of the 53c8xx specific code -
+ * simply to make this file smaller and easier to manage.
+ *
+ * MVME166 issues:
+ * Problems trying to read any chip registers in NCR53c7x0_init(), as they
+ * may never have been set by 166Bug (eg. If kernel has come in over tftp).
+ */
+
+/*
+ * Adapted for Linux/m68k Amiga platforms for the A4000T/A4091 and
+ * WarpEngine SCSI controllers.
+ * By Alan Hourihane <alanh@fairlite.demon.co.uk>
+ * Thanks to Richard Hirst for making it possible with the MVME additions
+ */
+
+/*
+ * 53c710 rev 0 doesn't support add with carry. Rev 1 and 2 does. To
+ * overcome this problem you can define FORCE_DSA_ALIGNMENT, which ensures
+ * that the DSA address is always xxxxxx00. If disconnection is not allowed,
+ * then the script only ever tries to add small (< 256) positive offsets to
+ * DSA, so lack of carry isn't a problem. FORCE_DSA_ALIGNMENT can, of course,
+ * be defined for all chip revisions at a small cost in memory usage.
+ */
+
+#define FORCE_DSA_ALIGNMENT
+
+/*
+ * Selection timer does not always work on the 53c710, depending on the
+ * timing at the last disconnect, if this is a problem for you, try
+ * using validids as detailed below.
+ *
+ * Options for the NCR7xx driver
+ *
+ * nosync:0 - disables synchronous negotiation
+ * nodisconnect:0 - disables disconnection
+ * validids:0x?? - Bitmask field that disallows certain ID's.
+ * - e.g. 0x03 allows ID 0,1
+ * - 0x1F allows ID 0,1,2,3,4
+ */
+
+/*
+ * PERM_OPTIONS are driver options which will be enabled for all NCR boards
+ * in the system at driver initialization time.
+ *
+ * Don't THINK about touching these in PERM_OPTIONS :
+ * OPTION_MEMORY_MAPPED
+ * 680x0 doesn't have an IO map!
+ *
+ * OPTION_DEBUG_TEST1
+ * Test 1 does bus mastering and interrupt tests, which will help weed
+ * out brain damaged main boards.
+ *
+ * Other PERM_OPTIONS settings are listed below. Note the actual options
+ * required are set in the relevant file (mvme166.c, amiga7xx.c, etc):
+ *
+ * OPTION_NO_ASYNC
+ * Don't negotiate for asynchronous transfers on the first command
+ * when OPTION_ALWAYS_SYNCHRONOUS is set. Useful for dain bramaged
+ * devices which do something bad rather than sending a MESSAGE
+ * REJECT back to us like they should if they can't cope.
+ *
+ * OPTION_SYNCHRONOUS
+ * Enable support for synchronous transfers. Target negotiated
+ * synchronous transfers will be responded to. To initiate
+ * a synchronous transfer request, call
+ *
+ * request_synchronous (hostno, target)
+ *
+ * from within KGDB.
+ *
+ * OPTION_ALWAYS_SYNCHRONOUS
+ * Negotiate for synchronous transfers with every target after
+ * driver initialization or a SCSI bus reset. This is a bit dangerous,
+ * since there are some dain bramaged SCSI devices which will accept
+ * SDTR messages but keep talking asynchronously.
+ *
+ * OPTION_DISCONNECT
+ * Enable support for disconnect/reconnect. To change the
+ * default setting on a given host adapter, call
+ *
+ * request_disconnect (hostno, allow)
+ *
+ * where allow is non-zero to allow, 0 to disallow.
+ *
+ * If you really want to run 10MHz FAST SCSI-II transfers, you should
+ * know that the NCR driver currently ignores parity information. Most
+ * systems do 5MHz SCSI fine. I've seen a lot that have problems faster
+ * than 8MHz. To play it safe, we only request 5MHz transfers.
+ *
+ * If you'd rather get 10MHz transfers, edit sdtr_message and change
+ * the fourth byte from 50 to 25.
+ */
+
+#include <linux/config.h>
+
+/*
+ * Sponsored by
+ * iX Multiuser Multitasking Magazine
+ * Hannover, Germany
+ * hm@ix.de
+ *
+ * Copyright 1993, 1994, 1995 Drew Eckhardt
+ * Visionary Computing
+ * (Unix and Linux consulting and custom programming)
+ * drew@PoohSticks.ORG
+ * +1 (303) 786-7975
+ *
+ * TolerANT and SCSI SCRIPTS are registered trademarks of NCR Corporation.
+ *
+ * For more information, please consult
+ *
+ * NCR53C810
+ * SCSI I/O Processor
+ * Programmer's Guide
+ *
+ * NCR 53C810
+ * PCI-SCSI I/O Processor
+ * Data Manual
+ *
+ * NCR 53C810/53C820
+ * PCI-SCSI I/O Processor Design In Guide
+ *
+ * For literature on Symbios Logic Inc. formerly NCR, SCSI,
+ * and Communication products please call (800) 334-5454 or
+ * (719) 536-3300.
+ *
+ * PCI BIOS Specification Revision
+ * PCI Local Bus Specification
+ * PCI System Design Guide
+ *
+ * PCI Special Interest Group
+ * M/S HF3-15A
+ * 5200 N.E. Elam Young Parkway
+ * Hillsboro, Oregon 97124-6497
+ * +1 (503) 696-2000
+ * +1 (800) 433-5177
+ */
+
+/*
+ * Design issues :
+ * The cumulative latency needed to propagate a read/write request
+ * through the file system, buffer cache, driver stacks, SCSI host, and
+ * SCSI device is ultimately the limiting factor in throughput once we
+ * have a sufficiently fast host adapter.
+ *
+ * So, to maximize performance we want to keep the ratio of latency to data
+ * transfer time to a minimum by
+ * 1. Minimizing the total number of commands sent (typical command latency
+ * including drive and bus mastering host overhead is as high as 4.5ms)
+ * to transfer a given amount of data.
+ *
+ * This is accomplished by placing no arbitrary limit on the number
+ * of scatter/gather buffers supported, since we can transfer 1K
+ * per scatter/gather buffer without Eric's cluster patches,
+ * 4K with.
+ *
+ * 2. Minimizing the number of fatal interrupts serviced, since
+ * fatal interrupts halt the SCSI I/O processor. Basically,
+ * this means offloading the practical maximum amount of processing
+ * to the SCSI chip.
+ *
+ * On the NCR53c810/820/720, this is accomplished by using
+ * interrupt-on-the-fly signals when commands complete,
+ * and only handling fatal errors and SDTR / WDTR messages
+ * in the host code.
+ *
+ * On the NCR53c710, interrupts are generated as on the NCR53c8x0,
+ * only the lack of a interrupt-on-the-fly facility complicates
+ * things. Also, SCSI ID registers and commands are
+ * bit fielded rather than binary encoded.
+ *
+ * On the NCR53c700 and NCR53c700-66, operations that are done via
+ * indirect, table mode on the more advanced chips must be
+ * replaced by calls through a jump table which
+ * acts as a surrogate for the DSA. Unfortunately, this
+ * will mean that we must service an interrupt for each
+ * disconnect/reconnect.
+ *
+ * 3. Eliminating latency by pipelining operations at the different levels.
+ *
+ * This driver allows a configurable number of commands to be enqueued
+ * for each target/lun combination (experimentally, I have discovered
+ * that two seems to work best) and will ultimately allow for
+ * SCSI-II tagged queuing.
+ *
+ *
+ * Architecture :
+ * This driver is built around a Linux queue of commands waiting to
+ * be executed, and a shared Linux/NCR array of commands to start. Commands
+ * are transfered to the array by the run_process_issue_queue() function
+ * which is called whenever a command completes.
+ *
+ * As commands are completed, the interrupt routine is triggered,
+ * looks for commands in the linked list of completed commands with
+ * valid status, removes these commands from a list of running commands,
+ * calls the done routine, and flags their target/luns as not busy.
+ *
+ * Due to limitations in the intelligence of the NCR chips, certain
+ * concessions are made. In many cases, it is easier to dynamically
+ * generate/fix-up code rather than calculate on the NCR at run time.
+ * So, code is generated or fixed up for
+ *
+ * - Handling data transfers, using a variable number of MOVE instructions
+ * interspersed with CALL MSG_IN, WHEN MSGIN instructions.
+ *
+ * The DATAIN and DATAOUT routines are separate, so that an incorrect
+ * direction can be trapped, and space isn't wasted.
+ *
+ * It may turn out that we're better off using some sort
+ * of table indirect instruction in a loop with a variable
+ * sized table on the NCR53c710 and newer chips.
+ *
+ * - Checking for reselection (NCR53c710 and better)
+ *
+ * - Handling the details of SCSI context switches (NCR53c710 and better),
+ * such as reprogramming appropriate synchronous parameters,
+ * removing the dsa structure from the NCR's queue of outstanding
+ * commands, etc.
+ *
+ */
+
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
+#include <linux/config.h>
+
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <linux/delay.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/bios32.h>
+#include <linux/pci.h>
+#include <linux/proc_fs.h>
+#include <linux/string.h>
+#include <linux/malloc.h>
+#include <linux/vmalloc.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/time.h>
+#include <linux/blk.h>
+
+#ifdef CONFIG_AMIGA
+#include <asm/pgtable.h>
+#include <asm/amigahw.h>
+#include <asm/amigaints.h>
+#include <asm/irq.h>
+
+#define BIG_ENDIAN
+#define NO_IO_SPACE
+#endif
+
+#ifdef CONFIG_MVME166
+#include <asm/mvme166hw.h>
+
+#define BIG_ENDIAN
+#define NO_IO_SPACE
+#endif
+
+#include "scsi.h"
+#include "hosts.h"
+#include "53c7xx.h"
+#include "constants.h"
+#include "sd.h"
+#include <linux/stat.h>
+#include <linux/stddef.h>
+
+#ifdef NO_IO_SPACE
+/*
+ * The following make the definitions in 53c7xx.h (write8, etc) smaller,
+ * we don't have seperate i/o space anyway.
+ */
+#undef inb
+#undef outb
+#define inb(x) 1
+#define inw(x) 1
+#define inl(x) 1
+#define outb(x,y) 1
+#define outw(x,y) 1
+#define outl(x,y) 1
+#endif
+
+static int check_address (unsigned long addr, int size);
+static void dump_events (struct Scsi_Host *host, int count);
+static Scsi_Cmnd * return_outstanding_commands (struct Scsi_Host *host,
+ int free, int issue);
+static void hard_reset (struct Scsi_Host *host);
+static void ncr_scsi_reset (struct Scsi_Host *host);
+static void print_lots (struct Scsi_Host *host);
+static void set_synchronous (struct Scsi_Host *host, int target, int sxfer,
+ int scntl3, int now_connected);
+static int datapath_residual (struct Scsi_Host *host);
+static const char * sbcl_to_phase (int sbcl);
+static void print_progress (Scsi_Cmnd *cmd);
+static void print_queues (struct Scsi_Host *host);
+static void process_issue_queue (unsigned long flags);
+static int shutdown (struct Scsi_Host *host);
+static void abnormal_finished (struct NCR53c7x0_cmd *cmd, int result);
+static int disable (struct Scsi_Host *host);
+static int NCR53c7xx_run_tests (struct Scsi_Host *host);
+void NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs);
+static int ncr_halt (struct Scsi_Host *host);
+static void intr_phase_mismatch (struct Scsi_Host *host, struct NCR53c7x0_cmd
+ *cmd);
+static void intr_dma (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd);
+static void print_dsa (struct Scsi_Host *host, u32 *dsa,
+ const char *prefix);
+static int print_insn (struct Scsi_Host *host, const u32 *insn,
+ const char *prefix, int kernel);
+
+static void NCR53c7xx_dsa_fixup (struct NCR53c7x0_cmd *cmd);
+static void NCR53c7x0_init_fixup (struct Scsi_Host *host);
+static int NCR53c7x0_dstat_sir_intr (struct Scsi_Host *host, struct
+ NCR53c7x0_cmd *cmd);
+static void NCR53c7x0_soft_reset (struct Scsi_Host *host);
+
+/* Size of event list (per host adapter) */
+static int track_events = 0;
+static struct Scsi_Host *first_host = NULL; /* Head of list of NCR boards */
+static Scsi_Host_Template *the_template = NULL;
+
+/* NCR53c710 script handling code */
+
+#include "53c7xx_d.h"
+#ifdef A_int_debug_sync
+#define DEBUG_SYNC_INTR A_int_debug_sync
+#endif
+int NCR53c7xx_script_len = sizeof (SCRIPT);
+int NCR53c7xx_dsa_len = A_dsa_end + Ent_dsa_zero - Ent_dsa_code_template;
+#ifdef FORCE_DSA_ALIGNMENT
+int CmdPageStart = (0 - Ent_dsa_zero - sizeof(struct NCR53c7x0_cmd)) & 0xff;
+#endif
+int flushsize;
+
+static char *setup_strings[] =
+ {"","","","","","","",""};
+
+#define MAX_SETUP_STRINGS (sizeof(setup_strings) / sizeof(char *))
+#define SETUP_BUFFER_SIZE 200
+static char setup_buffer[SETUP_BUFFER_SIZE];
+static char setup_used[MAX_SETUP_STRINGS];
+
+void ncr53c7xx_setup (char *str, int *ints)
+{
+ int i;
+ char *p1, *p2;
+
+ p1 = setup_buffer;
+ *p1 = '\0';
+ if (str)
+ strncpy(p1, str, SETUP_BUFFER_SIZE - strlen(setup_buffer));
+ setup_buffer[SETUP_BUFFER_SIZE - 1] = '\0';
+ p1 = setup_buffer;
+ i = 0;
+ while (*p1 && (i < MAX_SETUP_STRINGS)) {
+ p2 = strchr(p1, ',');
+ if (p2) {
+ *p2 = '\0';
+ if (p1 != p2)
+ setup_strings[i] = p1;
+ p1 = p2 + 1;
+ i++;
+ }
+ else {
+ setup_strings[i] = p1;
+ break;
+ }
+ }
+ for (i=0; i<MAX_SETUP_STRINGS; i++)
+ setup_used[i] = 0;
+}
+
+
+/* check_setup_strings() returns index if key found, 0 if not
+ */
+
+static int check_setup_strings(char *key, int *flags, int *val, char *buf)
+{
+int x;
+char *cp;
+
+ for (x=0; x<MAX_SETUP_STRINGS; x++) {
+ if (setup_used[x])
+ continue;
+ if (!strncmp(setup_strings[x], key, strlen(key)))
+ break;
+ if (!strncmp(setup_strings[x], "next", strlen("next")))
+ return 0;
+ }
+ if (x == MAX_SETUP_STRINGS)
+ return 0;
+ setup_used[x] = 1;
+ cp = setup_strings[x] + strlen(key);
+ *val = -1;
+ if (*cp != ':')
+ return ++x;
+ cp++;
+ if ((*cp >= '0') && (*cp <= '9')) {
+ *val = simple_strtoul(cp,NULL,0);
+ }
+ return ++x;
+}
+
+
+
+/*
+ * KNOWN BUGS :
+ * - There is some sort of conflict when the PPP driver is compiled with
+ * support for 16 channels?
+ *
+ * - On systems which predate the 1.3.x initialization order change,
+ * the NCR driver will cause Cannot get free page messages to appear.
+ * These are harmless, but I don't know of an easy way to avoid them.
+ *
+ * - With OPTION_DISCONNECT, on two systems under unknown circumstances,
+ * we get a PHASE MISMATCH with DSA set to zero (suggests that we
+ * are occurring somewhere in the reselection code) where
+ * DSP=some value DCMD|DBC=same value.
+ *
+ * Closer inspection suggests that we may be trying to execute
+ * some portion of the DSA?
+ * scsi0 : handling residual transfer (+ 0 bytes from DMA FIFO)
+ * scsi0 : handling residual transfer (+ 0 bytes from DMA FIFO)
+ * scsi0 : no current command : unexpected phase MSGIN.
+ * DSP=0x1c46cc, DCMD|DBC=0x1c46ac, DSA=0x0
+ * DSPS=0x0, TEMP=0x1c3e70, DMODE=0x80
+ * scsi0 : DSP->
+ * 001c46cc : 0x001c46cc 0x00000000
+ * 001c46d4 : 0x001c5ea0 0x000011f8
+ *
+ * Changed the print code in the phase_mismatch handler so
+ * that we call print_lots to try to diagnose this.
+ *
+ */
+
+/*
+ * Possible future direction of architecture for max performance :
+ *
+ * We're using a single start array for the NCR chip. This is
+ * sub-optimal, because we cannot add a command which would conflict with
+ * an executing command to this start queue, and therefore must insert the
+ * next command for a given I/T/L combination after the first has completed;
+ * incurring our interrupt latency between SCSI commands.
+ *
+ * To allow further pipelining of the NCR and host CPU operation, we want
+ * to set things up so that immediately on termination of a command destined
+ * for a given LUN, we get that LUN busy again.
+ *
+ * To do this, we need to add a 32 bit pointer to which is jumped to
+ * on completion of a command. If no new command is available, this
+ * would point to the usual DSA issue queue select routine.
+ *
+ * If one were, it would point to a per-NCR53c7x0_cmd select routine
+ * which starts execution immediately, inserting the command at the head
+ * of the start queue if the NCR chip is selected or reselected.
+ *
+ * We would change so that we keep a list of outstanding commands
+ * for each unit, rather than a single running_list. We'd insert
+ * a new command into the right running list; if the NCR didn't
+ * have something running for that yet, we'd put it in the
+ * start queue as well. Some magic needs to happen to handle the
+ * race condition between the first command terminating before the
+ * new one is written.
+ *
+ * Potential for profiling :
+ * Call do_gettimeofday(struct timeval *tv) to get 800ns resolution.
+ */
+
+
+/*
+ * TODO :
+ * 1. To support WIDE transfers, not much needs to happen. We
+ * should do CHMOVE instructions instead of MOVEs when
+ * we have scatter/gather segments of uneven length. When
+ * we do this, we need to handle the case where we disconnect
+ * between segments.
+ *
+ * 2. Currently, when Icky things happen we do a FATAL(). Instead,
+ * we want to do an integrity check on the parts of the NCR hostdata
+ * structure which were initialized at boot time; FATAL() if that
+ * fails, and otherwise try to recover. Keep track of how many
+ * times this has happened within a single SCSI command; if it
+ * gets excessive, then FATAL().
+ *
+ * 3. Parity checking is currently disabled, and a few things should
+ * happen here now that we support synchronous SCSI transfers :
+ * 1. On soft-reset, we shoould set the EPC (Enable Parity Checking)
+ * and AAP (Assert SATN/ on parity error) bits in SCNTL0.
+ *
+ * 2. We should enable the parity interrupt in the SIEN0 register.
+ *
+ * 3. intr_phase_mismatch() needs to believe that message out is
+ * always an "acceptable" phase to have a mismatch in. If
+ * the old phase was MSG_IN, we should send a MESSAGE PARITY
+ * error. If the old phase was something else, we should send
+ * a INITIATOR_DETECTED_ERROR message. Note that this could
+ * cause a RESTORE POINTERS message; so we should handle that
+ * correctly first. Instead, we should probably do an
+ * initiator_abort.
+ *
+ * 4. MPEE bit of CTEST4 should be set so we get interrupted if
+ * we detect an error.
+ *
+ *
+ * 5. The initial code has been tested on the NCR53c810. I don't
+ * have access to NCR53c700, 700-66 (Forex boards), NCR53c710
+ * (NCR Pentium systems), NCR53c720, NCR53c820, or NCR53c825 boards to
+ * finish development on those platforms.
+ *
+ * NCR53c820/825/720 - need to add wide transfer support, including WDTR
+ * negotiation, programming of wide transfer capabilities
+ * on reselection and table indirect selection.
+ *
+ * NCR53c710 - need to add fatal interrupt or GEN code for
+ * command completion signaling. Need to modify all
+ * SDID, SCID, etc. registers, and table indirect select code
+ * since these use bit fielded (ie 1<<target) instead of
+ * binary encoded target ids. Need to accommodate
+ * different register mappings, probably scan through
+ * the SCRIPT code and change the non SFBR register operand
+ * of all MOVE instructions.
+ *
+ * It is rather worse than this actually, the 710 corrupts
+ * both TEMP and DSA when you do a MOVE MEMORY. This
+ * screws you up all over the place. MOVE MEMORY 4 with a
+ * destination of DSA seems to work OK, which helps some.
+ * Richard Hirst richard@sleepie.demon.co.uk
+ *
+ * NCR53c700/700-66 - need to add code to refix addresses on
+ * every nexus change, eliminate all table indirect code,
+ * very messy.
+ *
+ * 6. The NCR53c7x0 series is very popular on other platforms that
+ * could be running Linux - ie, some high performance AMIGA SCSI
+ * boards use it.
+ *
+ * So, I should include #ifdef'd code so that it is
+ * compatible with these systems.
+ *
+ * Specifically, the little Endian assumptions I made in my
+ * bit fields need to change, and if the NCR doesn't see memory
+ * the right way, we need to provide options to reverse words
+ * when the scripts are relocated.
+ *
+ * 7. Use vremap() to access memory mapped boards.
+ */
+
+/*
+ * Allow for simultaneous existence of multiple SCSI scripts so we
+ * can have a single driver binary for all of the family.
+ *
+ * - one for NCR53c700 and NCR53c700-66 chips (not yet supported)
+ * - one for rest (only the NCR53c810, 815, 820, and 825 are currently
+ * supported)
+ *
+ * So that we only need two SCSI scripts, we need to modify things so
+ * that we fixup register accesses in READ/WRITE instructions, and
+ * we'll also have to accommodate the bit vs. binary encoding of IDs
+ * with the 7xx chips.
+ */
+
+#define ROUNDUP(adr,type) \
+ ((void *) (((long) (adr) + sizeof(type) - 1) & ~(sizeof(type) - 1)))
+
+
+/*
+ * Function: issue_to_cmd
+ *
+ * Purpose: convert jump instruction in issue array to NCR53c7x0_cmd
+ * structure pointer.
+ *
+ * Inputs; issue - pointer to start of NOP or JUMP instruction
+ * in issue array.
+ *
+ * Returns: pointer to command on success; 0 if opcode is NOP.
+ */
+
+static inline struct NCR53c7x0_cmd *
+issue_to_cmd (struct Scsi_Host *host, struct NCR53c7x0_hostdata *hostdata,
+ u32 *issue)
+{
+ return (issue[0] != hostdata->NOP_insn) ?
+ /*
+ * If the IF TRUE bit is set, it's a JUMP instruction. The
+ * operand is a bus pointer to the dsa_begin routine for this DSA. The
+ * dsa field of the NCR53c7x0_cmd structure starts with the
+ * DSA code template. By converting to a virtual address,
+ * subtracting the code template size, and offset of the
+ * dsa field, we end up with a pointer to the start of the
+ * structure (alternatively, we could use the
+ * dsa_cmnd field, an anachronism from when we weren't
+ * sure what the relationship between the NCR structures
+ * and host structures were going to be.
+ */
+ (struct NCR53c7x0_cmd *) ((char *) bus_to_virt (issue[1]) -
+ (hostdata->E_dsa_code_begin - hostdata->E_dsa_code_template) -
+ offsetof(struct NCR53c7x0_cmd, dsa))
+ /* If the IF TRUE bit is not set, it's a NOP */
+ : NULL;
+}
+
+
+/*
+ * FIXME: we should junk these, in favor of synchronous_want and
+ * wide_want in the NCR53c7x0_hostdata structure.
+ */
+
+/* Template for "preferred" synchronous transfer parameters. */
+
+static const unsigned char sdtr_message[] = {
+#ifdef CONFIG_SCSI_NCR53C7xx_FAST
+ EXTENDED_MESSAGE, 3 /* length */, EXTENDED_SDTR, 25 /* *4ns */, 8 /* off */
+#else
+ EXTENDED_MESSAGE, 3 /* length */, EXTENDED_SDTR, 50 /* *4ns */, 8 /* off */
+#endif
+};
+
+/* Template to request asynchronous transfers */
+
+static const unsigned char async_message[] = {
+ EXTENDED_MESSAGE, 3 /* length */, EXTENDED_SDTR, 0, 0 /* asynchronous */
+};
+
+/* Template for "preferred" WIDE transfer parameters */
+
+static const unsigned char wdtr_message[] = {
+ EXTENDED_MESSAGE, 2 /* length */, EXTENDED_WDTR, 1 /* 2^1 bytes */
+};
+
+/*
+ * Function : struct Scsi_Host *find_host (int host)
+ *
+ * Purpose : KGDB support function which translates a host number
+ * to a host structure.
+ *
+ * Inputs : host - number of SCSI host
+ *
+ * Returns : NULL on failure, pointer to host structure on success.
+ */
+
+static struct Scsi_Host *
+find_host (int host) {
+ struct Scsi_Host *h;
+ for (h = first_host; h && h->host_no != host; h = h->next);
+ if (!h) {
+ printk (KERN_ALERT "scsi%d not found\n", host);
+ return NULL;
+ } else if (h->hostt != the_template) {
+ printk (KERN_ALERT "scsi%d is not a NCR board\n", host);
+ return NULL;
+ }
+ return h;
+}
+
+/*
+ * Function : request_synchronous (int host, int target)
+ *
+ * Purpose : KGDB interface which will allow us to negotiate for
+ * synchronous transfers. This ill be replaced with a more
+ * integrated function; perhaps a new entry in the scsi_host
+ * structure, accessible via an ioctl() or perhaps /proc/scsi.
+ *
+ * Inputs : host - number of SCSI host; target - number of target.
+ *
+ * Returns : 0 when negotiation has been setup for next SCSI command,
+ * -1 on failure.
+ */
+
+static int
+request_synchronous (int host, int target) {
+ struct Scsi_Host *h;
+ struct NCR53c7x0_hostdata *hostdata;
+ unsigned long flags;
+ if (target < 0) {
+ printk (KERN_ALERT "target %d is bogus\n", target);
+ return -1;
+ }
+ if (!(h = find_host (host)))
+ return -1;
+ else if (h->this_id == target) {
+ printk (KERN_ALERT "target %d is host ID\n", target);
+ return -1;
+ }
+ else if (target > h->max_id) {
+ printk (KERN_ALERT "target %d exceeds maximum of %d\n", target,
+ h->max_id);
+ return -1;
+ }
+ hostdata = (struct NCR53c7x0_hostdata *)h->hostdata;
+
+ save_flags(flags);
+ cli();
+ if (hostdata->initiate_sdtr & (1 << target)) {
+ restore_flags(flags);
+ printk (KERN_ALERT "target %d already doing SDTR\n", target);
+ return -1;
+ }
+ hostdata->initiate_sdtr |= (1 << target);
+ restore_flags(flags);
+ return 0;
+}
+
+/*
+ * Function : request_disconnect (int host, int on_or_off)
+ *
+ * Purpose : KGDB support function, tells us to allow or disallow
+ * disconnections.
+ *
+ * Inputs : host - number of SCSI host; on_or_off - non-zero to allow,
+ * zero to disallow.
+ *
+ * Returns : 0 on success, * -1 on failure.
+ */
+
+static int
+request_disconnect (int host, int on_or_off) {
+ struct Scsi_Host *h;
+ struct NCR53c7x0_hostdata *hostdata;
+ if (!(h = find_host (host)))
+ return -1;
+ hostdata = (struct NCR53c7x0_hostdata *) h->hostdata;
+ if (on_or_off)
+ hostdata->options |= OPTION_DISCONNECT;
+ else
+ hostdata->options &= ~OPTION_DISCONNECT;
+ return 0;
+}
+
+/*
+ * Function : static void NCR53c7x0_driver_init (struct Scsi_Host *host)
+ *
+ * Purpose : Initialize internal structures, as required on startup, or
+ * after a SCSI bus reset.
+ *
+ * Inputs : host - pointer to this host adapter's structure
+ */
+
+static void
+NCR53c7x0_driver_init (struct Scsi_Host *host) {
+ struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+ host->hostdata;
+ int i, j;
+ u32 *ncrcurrent;
+
+flush_cache_all();
+cache_push(virt_to_bus(hostdata->script), flushsize);
+cache_clear(virt_to_bus(hostdata->script), flushsize);
+
+ for (i = 0; i < 16; ++i) {
+ hostdata->request_sense[i] = 0;
+ for (j = 0; j < 8; ++j)
+ hostdata->busy[i][j] = 0;
+ set_synchronous (host, i, /* sxfer */ 0, hostdata->saved_scntl3, 0);
+ }
+ hostdata->issue_queue = NULL;
+ hostdata->running_list = hostdata->finished_queue =
+ hostdata->ncrcurrent = NULL;
+ for (i = 0, ncrcurrent = (u32 *) hostdata->schedule;
+ i < host->can_queue; ++i, ncrcurrent += 2) {
+ ncrcurrent[0] = hostdata->NOP_insn;
+ ncrcurrent[1] = 0xdeadbeef;
+ }
+ ncrcurrent[0] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24) | DBC_TCI_TRUE;
+ ncrcurrent[1] = (u32) virt_to_bus (hostdata->script) +
+ hostdata->E_wait_reselect;
+ hostdata->reconnect_dsa_head = 0;
+ hostdata->addr_reconnect_dsa_head = (u32)
+ virt_to_bus((void *) &(hostdata->reconnect_dsa_head));
+ hostdata->expecting_iid = 0;
+ hostdata->expecting_sto = 0;
+ if (hostdata->options & OPTION_ALWAYS_SYNCHRONOUS)
+ hostdata->initiate_sdtr = 0xffff;
+ else
+ hostdata->initiate_sdtr = 0;
+ hostdata->talked_to = 0;
+ hostdata->idle = 1;
+flush_cache_all();
+cache_push(virt_to_bus(hostdata->script), flushsize);
+cache_clear(virt_to_bus(hostdata->script), flushsize);
+}
+
+/*
+ * Function : static int clock_to_ccf_710 (int clock)
+ *
+ * Purpose : Return the clock conversion factor for a given SCSI clock.
+ *
+ * Inputs : clock - SCSI clock expressed in Hz.
+ *
+ * Returns : ccf on success, -1 on failure.
+ */
+
+static int
+clock_to_ccf_710 (int clock) {
+ if (clock <= 16666666)
+ return -1;
+ if (clock <= 25000000)
+ return 2; /* Divide by 1.0 */
+ else if (clock <= 37500000)
+ return 1; /* Divide by 1.5 */
+ else if (clock <= 50000000)
+ return 0; /* Divide by 2.0 */
+ else if (clock <= 66000000)
+ return 3; /* Divide by 3.0 */
+ else
+ return -1;
+}
+
+/*
+ * Function : static int NCR53c7x0_init (struct Scsi_Host *host)
+ *
+ * Purpose : initialize the internal structures for a given SCSI host
+ *
+ * Inputs : host - pointer to this host adapter's structure
+ *
+ * Preconditions : when this function is called, the chip_type
+ * field of the hostdata structure MUST have been set.
+ *
+ * Returns : 0 on success, -1 on failure.
+ */
+
+int
+NCR53c7x0_init (struct Scsi_Host *host) {
+ NCR53c7x0_local_declare();
+ int i, ccf;
+ unsigned char revision;
+ struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+ host->hostdata;
+ struct Scsi_Host *search;
+ /*
+ * There are some things which we need to know about in order to provide
+ * a semblance of support. Print 'em if they aren't what we expect,
+ * otherwise don't add to the noise.
+ *
+ * -1 means we don't know what to expect.
+ */
+ int val, flags;
+ char buf[32];
+ int expected_id = -1;
+ int expected_clock = -1;
+ int uninitialized = 0;
+#ifdef NO_IO_SPACE
+ int expected_mapping = OPTION_MEMORY_MAPPED;
+#else
+ int expected_mapping = OPTION_IO_MAPPED;
+#endif
+ for (i=0;i<7;i++)
+ hostdata->valid_ids[i] = 1; /* Default all ID's to scan */
+
+ /* Parse commandline flags */
+ if (check_setup_strings("nosync",&flags,&val,buf))
+ {
+ hostdata->options |= OPTION_NO_ASYNC;
+ hostdata->options &= ~(OPTION_SYNCHRONOUS | OPTION_ALWAYS_SYNCHRONOUS);
+ }
+
+ if (check_setup_strings("nodisconnect",&flags,&val,buf))
+ hostdata->options &= ~OPTION_DISCONNECT;
+
+ if (check_setup_strings("validids",&flags,&val,buf))
+ {
+ for (i=0;i<7;i++)
+ hostdata->valid_ids[i] = val & (1<<i);
+ }
+
+ if ((i = check_setup_strings("next",&flags,&val,buf)))
+ {
+ while (i)
+ setup_used[--i] = 1;
+ }
+
+
+ NCR53c7x0_local_setup(host);
+
+ switch (hostdata->chip) {
+ case 710:
+ hostdata->dstat_sir_intr = NCR53c7x0_dstat_sir_intr;
+ hostdata->init_save_regs = NULL;
+ hostdata->dsa_fixup = NCR53c7xx_dsa_fixup;
+ hostdata->init_fixup = NCR53c7x0_init_fixup;
+ hostdata->soft_reset = NCR53c7x0_soft_reset;
+ hostdata->run_tests = NCR53c7xx_run_tests;
+ expected_clock = hostdata->scsi_clock = 50000000;
+ expected_id = 7;
+ break;
+ default:
+ printk ("scsi%d : chip type of %d is not supported yet, detaching.\n",
+ host->host_no, hostdata->chip);
+ scsi_unregister (host);
+ return -1;
+ }
+
+ /* Assign constants accessed by NCR */
+ hostdata->NCR53c7xx_zero = 0;
+ hostdata->NCR53c7xx_msg_reject = MESSAGE_REJECT;
+ hostdata->NCR53c7xx_msg_abort = ABORT;
+ hostdata->NCR53c7xx_msg_nop = NOP;
+ hostdata->NOP_insn = (DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24;
+
+ if (expected_mapping == -1 ||
+ (hostdata->options & (OPTION_MEMORY_MAPPED)) !=
+ (expected_mapping & OPTION_MEMORY_MAPPED))
+ printk ("scsi%d : using %s mapped access\n", host->host_no,
+ (hostdata->options & OPTION_MEMORY_MAPPED) ? "memory" :
+ "io");
+
+ hostdata->dmode = (hostdata->chip == 700 || hostdata->chip == 70066) ?
+ DMODE_REG_00 : DMODE_REG_10;
+ hostdata->istat = ((hostdata->chip / 100) == 8) ?
+ ISTAT_REG_800 : ISTAT_REG_700;
+
+/* Only the ISTAT register is readable when the NCR is running, so make
+ sure it's halted. */
+ ncr_halt(host);
+
+/*
+ * XXX - the NCR53c700 uses bitfielded registers for SCID, SDID, etc,
+ * as does the 710 with one bit per SCSI ID. Conversely, the NCR
+ * uses a normal, 3 bit binary representation of these values.
+ *
+ * Get the rest of the NCR documentation, and FIND OUT where the change
+ * was.
+ */
+
+#if 0
+ /* May not be able to do this - chip my not have been set up yet */
+ tmp = hostdata->this_id_mask = NCR53c7x0_read8(SCID_REG);
+ for (host->this_id = 0; tmp != 1; tmp >>=1, ++host->this_id);
+#else
+ host->this_id = 7;
+#endif
+
+/*
+ * Note : we should never encounter a board setup for ID0. So,
+ * if we see ID0, assume that it was uninitialized and set it
+ * to the industry standard 7.
+ */
+ if (!host->this_id) {
+ printk("scsi%d : initiator ID was %d, changing to 7\n",
+ host->host_no, host->this_id);
+ host->this_id = 7;
+ hostdata->this_id_mask = 1 << 7;
+ uninitialized = 1;
+ };
+
+ if (expected_id == -1 || host->this_id != expected_id)
+ printk("scsi%d : using initiator ID %d\n", host->host_no,
+ host->this_id);
+
+ /*
+ * Save important registers to allow a soft reset.
+ */
+
+ /*
+ * CTEST7 controls cache snooping, burst mode, and support for
+ * external differential drivers. This isn't currently used - the
+ * default value may not be optimal anyway.
+ * Even worse, it may never have been set up since reset.
+ */
+ hostdata->saved_ctest7 = NCR53c7x0_read8(CTEST7_REG) & CTEST7_SAVE;
+ revision = (NCR53c7x0_read8(CTEST8_REG) & 0xF0) >> 4;
+ switch (revision) {
+ case 1:
+ revision = 0;
+ break;
+ case 2:
+ revision = 1;
+ break;
+ case 4:
+ revision = 2;
+ break;
+ case 8:
+ revision = 3;
+ break;
+ default:
+ revision = 255;
+ break;
+ }
+ printk("scsi%d: Revision 0x%x\n",host->host_no,revision);
+
+ /*
+ * On NCR53c700 series chips, DCNTL controls the SCSI clock divisor,
+ * on 800 series chips, it allows for a totem-pole IRQ driver.
+ * NOTE saved_dcntl currently overwritten in init function.
+ * The value read here may be garbage anyway, MVME166 board at least
+ * does not initialise chip if kernel arrived via tftp.
+ */
+
+ hostdata->saved_dcntl = NCR53c7x0_read8(DCNTL_REG);
+
+ /*
+ * DMODE controls DMA burst length, and on 700 series chips,
+ * 286 mode and bus width
+ * NOTE: On MVME166, chip may have been reset, so this could be a
+ * power-on/reset default value.
+ */
+ hostdata->saved_dmode = NCR53c7x0_read8(hostdata->dmode);
+
+ /*
+ * Now that burst length and enabled/disabled status is known,
+ * clue the user in on it.
+ */
+
+ ccf = clock_to_ccf_710 (expected_clock);
+
+ for (i = 0; i < 16; ++i)
+ hostdata->cmd_allocated[i] = 0;
+
+ if (hostdata->init_save_regs)
+ hostdata->init_save_regs (host);
+ if (hostdata->init_fixup)
+ hostdata->init_fixup (host);
+
+ if (!the_template) {
+ the_template = host->hostt;
+ first_host = host;
+ }
+
+ /*
+ * Linux SCSI drivers have always been plagued with initialization
+ * problems - some didn't work with the BIOS disabled since they expected
+ * initialization from it, some didn't work when the networking code
+ * was enabled and registers got scrambled, etc.
+ *
+ * To avoid problems like this, in the future, we will do a soft
+ * reset on the SCSI chip, taking it back to a sane state.
+ */
+
+ hostdata->soft_reset (host);
+
+#if 1
+ hostdata->debug_count_limit = -1;
+#else
+ hostdata->debug_count_limit = 1;
+#endif
+ hostdata->intrs = -1;
+ hostdata->resets = -1;
+ memcpy ((void *) hostdata->synchronous_want, (void *) sdtr_message,
+ sizeof (hostdata->synchronous_want));
+
+ NCR53c7x0_driver_init (host);
+
+ /*
+ * Set up an interrupt handler if we aren't already sharing an IRQ
+ * with another board.
+ */
+
+#ifdef CONFIG_MVME166
+ if (request_irq(IRQ_MVME166_SCSI, NCR53c7x0_intr, 0, "SCSI-script", NULL))
+ panic ("Couldn't get SCSI IRQ");
+#ifdef MVME166_INTFLY
+ else if (request_irq(IRQ_MVME166_FLY, NCR53c7x0_intr, 0, "SCSI-intfly", NULL))
+ panic ("Couldn't get INT_FLY IRQ");
+#endif
+#else
+ for (search = first_host; search && !(search->hostt == the_template &&
+ search->irq == host->irq && search != host); search=search->next);
+
+ if (!search) {
+#ifdef CONFIG_AMIGA
+ if (request_irq(IRQ_AMIGA_PORTS, NCR53c7x0_intr, 0, "53c7xx", NCR53c7x0_intr)) {
+#else
+ if (request_irq(host->irq, NCR53c7x0_intr, SA_INTERRUPT, "53c7xx", NULL)) {
+#endif
+ printk("scsi%d : IRQ%d not free, detaching\n"
+ " You have either a configuration problem, or a\n"
+ " broken BIOS. You may wish to manually assign\n"
+ " an interrupt to the NCR board rather than using\n"
+ " an automatic setting.\n",
+ host->host_no, host->irq);
+ scsi_unregister (host);
+ return -1;
+ }
+ } else {
+ printk("scsi%d : using interrupt handler previously installed for scsi%d\n",
+ host->host_no, search->host_no);
+ }
+#endif
+
+ if ((hostdata->run_tests && hostdata->run_tests(host) == -1) ||
+ (hostdata->options & OPTION_DEBUG_TESTS_ONLY)) {
+ /* XXX Should disable interrupts, etc. here */
+ scsi_unregister (host);
+ return -1;
+ } else {
+ if (host->io_port) {
+ host->n_io_port = 128;
+ request_region (host->io_port, host->n_io_port, "ncr53c7xx");
+ }
+ }
+
+ if (NCR53c7x0_read8 (SBCL_REG) & SBCL_BSY) {
+ printk ("scsi%d : bus wedge, doing SCSI reset\n", host->host_no);
+ hard_reset (host);
+ }
+ return 0;
+}
+
+/*
+ * Function : static int normal_init(Scsi_Host_Template *tpnt, int board,
+ * int chip, u32 base, int io_port, int irq, int dma, int pcivalid,
+ * unsigned char pci_bus, unsigned char pci_device_fn,
+ * long long options);
+ *
+ * Purpose : initializes a NCR53c7,8x0 based on base addresses,
+ * IRQ, and DMA channel.
+ *
+ * Useful where a new NCR chip is backwards compatible with
+ * a supported chip, but the DEVICE ID has changed so it
+ * doesn't show up when the autoprobe does a pcibios_find_device.
+ *
+ * Inputs : tpnt - Template for this SCSI adapter, board - board level
+ * product, chip - 710
+ *
+ * Returns : 0 on success, -1 on failure.
+ *
+ */
+
+int
+ncr53c7xx_init (Scsi_Host_Template *tpnt, int board, int chip,
+ u32 base, int io_port, int irq, int dma, long long options, int clock)
+{
+ struct Scsi_Host *instance;
+ struct NCR53c7x0_hostdata *hostdata;
+ char chip_str[80];
+ int script_len = 0, dsa_len = 0, size = 0, max_cmd_size = 0,
+ schedule_size = 0, ok = 0;
+ void *tmp;
+
+ switch (chip) {
+ case 710:
+ schedule_size = (tpnt->can_queue + 1) * 8 /* JUMP instruction size */;
+ script_len = NCR53c7xx_script_len;
+ dsa_len = NCR53c7xx_dsa_len;
+ options |= OPTION_INTFLY;
+ sprintf (chip_str, "NCR53c%d", chip);
+ break;
+ default:
+ printk("scsi-ncr53c7xx : unsupported SCSI chip %d\n", chip);
+ return -1;
+ }
+
+ printk("scsi-ncr53c7xx : %s at memory 0x%x, io 0x%x, irq %d",
+ chip_str, (unsigned) base, io_port, irq);
+ if (dma == DMA_NONE)
+ printk("\n");
+ else
+ printk(", dma %d\n", dma);
+
+ if (options & OPTION_DEBUG_PROBE_ONLY) {
+ printk ("scsi-ncr53c7xx : probe only enabled, aborting initialization\n");
+ return -1;
+ }
+
+ max_cmd_size = sizeof(struct NCR53c7x0_cmd) + dsa_len +
+ /* Size of dynamic part of command structure : */
+ 2 * /* Worst case : we don't know if we need DATA IN or DATA out */
+ ( 2 * /* Current instructions per scatter/gather segment */
+ tpnt->sg_tablesize +
+ 3 /* Current startup / termination required per phase */
+ ) *
+ 8 /* Each instruction is eight bytes */;
+
+ /* Allocate fixed part of hostdata, dynamic part to hold appropriate
+ SCSI SCRIPT(tm) plus a single, maximum-sized NCR53c7x0_cmd structure.
+
+ We need a NCR53c7x0_cmd structure for scan_scsis() when we are
+ not loaded as a module, and when we're loaded as a module, we
+ can't use a non-dynamically allocated structure because modules
+ are vmalloc()'d, which can allow structures to cross page
+ boundaries and breaks our physical/virtual address assumptions
+ for DMA.
+
+ So, we stick it past the end of our hostdata structure.
+
+ ASSUMPTION :
+ Regardless of how many simultaneous SCSI commands we allow,
+ the probe code only executes a _single_ instruction at a time,
+ so we only need one here, and don't need to allocate NCR53c7x0_cmd
+ structures for each target until we are no longer in scan_scsis
+ and kmalloc() has become functional (memory_init() happens
+ after all device driver initialization).
+ */
+
+ size = sizeof(struct NCR53c7x0_hostdata) + script_len +
+ /* Note that alignment will be guaranteed, since we put the command
+ allocated at probe time after the fixed-up SCSI script, which
+ consists of 32 bit words, aligned on a 32 bit boundary. But
+ on a 64bit machine we need 8 byte alignment for hostdata->free, so
+ we add in another 4 bytes to take care of potential misalignment
+ */
+ (sizeof(void *) - sizeof(u32)) + max_cmd_size + schedule_size;
+
+#ifdef FORCE_DSA_ALIGNMENT
+ /*
+ * 53c710 rev.0 doesn't have an add-with-carry instruction.
+ * Ensure we allocate enough memory to force DSA alignment.
+ */
+ size += 256;
+#endif
+ flushsize = size;
+ instance = scsi_register (tpnt, size);
+ if (!instance)
+ return -1;
+
+ /* FIXME : if we ever support an ISA NCR53c7xx based board, we
+ need to check if the chip is running in a 16 bit mode, and if so
+ unregister it if it is past the 16M (0x1000000) mark */
+
+ hostdata = (struct NCR53c7x0_hostdata *)
+ instance->hostdata;
+ hostdata->size = size;
+ hostdata->script_count = script_len / sizeof(u32);
+ hostdata = (struct NCR53c7x0_hostdata *) instance->hostdata;
+ hostdata->board = board;
+ hostdata->chip = chip;
+
+ /*
+ * Being memory mapped is more desirable, since
+ *
+ * - Memory accesses may be faster.
+ *
+ * - The destination and source address spaces are the same for
+ * all instructions, meaning we don't have to twiddle dmode or
+ * any other registers.
+ *
+ * So, we try for memory mapped, and if we don't get it,
+ * we go for port mapped, and that failing we tell the user
+ * it can't work.
+ */
+
+ if (base) {
+ instance->base = (unsigned char *) (unsigned long) base;
+ /* Check for forced I/O mapping */
+ if (!(options & OPTION_IO_MAPPED)) {
+ options |= OPTION_MEMORY_MAPPED;
+ ok = 1;
+ }
+ } else {
+ options &= ~OPTION_MEMORY_MAPPED;
+ }
+
+ if (io_port) {
+ instance->io_port = io_port;
+ options |= OPTION_IO_MAPPED;
+ ok = 1;
+ } else {
+ options &= ~OPTION_IO_MAPPED;
+ }
+
+ if (!ok) {
+ printk ("scsi%d : not initializing, no I/O or memory mapping known \n",
+ instance->host_no);
+ scsi_unregister (instance);
+ return -1;
+ }
+ instance->irq = irq;
+ instance->dma_channel = dma;
+
+ hostdata->options = options;
+ hostdata->dsa_len = dsa_len;
+ hostdata->max_cmd_size = max_cmd_size;
+ hostdata->num_cmds = 1;
+ /* Initialize single command */
+ tmp = (hostdata->script + hostdata->script_count);
+#ifdef FORCE_DSA_ALIGNMENT
+ {
+ void *t = ROUNDUP(tmp, void *);
+ if (((u32)t & 0xff) > CmdPageStart)
+ t = (void *)((u32)t + 255);
+ t = (void *)(((u32)t & ~0xff) + CmdPageStart);
+ hostdata->free = t;
+ printk ("scsi: Registered size increased by 256 to %d\n", size);
+ printk ("scsi: CmdPageStart = 0x%02x\n", CmdPageStart);
+ printk ("scsi: tmp = 0x%08x, hostdata->free set to 0x%08x\n",
+ (u32)tmp, (u32)t);
+ }
+#else
+ hostdata->free = ROUNDUP(tmp, void *);
+#endif
+ hostdata->free->real = tmp;
+ hostdata->free->size = max_cmd_size;
+ hostdata->free->free = NULL;
+ hostdata->free->next = NULL;
+ hostdata->extra_allocate = 0;
+
+ /* Allocate command start code space */
+ hostdata->schedule = (chip == 700 || chip == 70066) ?
+ NULL : (u32 *) ((char *)hostdata->free + max_cmd_size);
+
+/*
+ * For diagnostic purposes, we don't really care how fast things blaze.
+ * For profiling, we want to access the 800ns resolution system clock,
+ * using a 'C' call on the host processor.
+ *
+ * Therefore, there's no need for the NCR chip to directly manipulate
+ * this data, and we should put it wherever is most convenient for
+ * Linux.
+ */
+ if (track_events)
+ hostdata->events = (struct NCR53c7x0_event *) (track_events ?
+ vmalloc (sizeof (struct NCR53c7x0_event) * track_events) : NULL);
+ else
+ hostdata->events = NULL;
+
+ if (hostdata->events) {
+ memset ((void *) hostdata->events, 0, sizeof(struct NCR53c7x0_event) *
+ track_events);
+ hostdata->event_size = track_events;
+ hostdata->event_index = 0;
+ } else
+ hostdata->event_size = 0;
+
+ return NCR53c7x0_init(instance);
+}
+
+
+/*
+ * Function : static void NCR53c7x0_init_fixup (struct Scsi_Host *host)
+ *
+ * Purpose : copy and fixup the SCSI SCRIPTS(tm) code for this device.
+ *
+ * Inputs : host - pointer to this host adapter's structure
+ *
+ */
+
+static void
+NCR53c7x0_init_fixup (struct Scsi_Host *host) {
+ NCR53c7x0_local_declare();
+ struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+ host->hostdata;
+ unsigned char tmp;
+ int i, ncr_to_memory, memory_to_ncr;
+ u32 base;
+ NCR53c7x0_local_setup(host);
+
+
+ /* XXX - NOTE : this code MUST be made endian aware */
+ /* Copy code into buffer that was allocated at detection time. */
+ memcpy ((void *) hostdata->script, (void *) SCRIPT,
+ sizeof(SCRIPT));
+ /* Fixup labels */
+ for (i = 0; i < PATCHES; ++i)
+ hostdata->script[LABELPATCHES[i]] +=
+ virt_to_bus(hostdata->script);
+ /* Fixup addresses of constants that used to be EXTERNAL */
+
+ patch_abs_32 (hostdata->script, 0, NCR53c7xx_msg_abort,
+ virt_to_bus(&(hostdata->NCR53c7xx_msg_abort)));
+ patch_abs_32 (hostdata->script, 0, NCR53c7xx_msg_reject,
+ virt_to_bus(&(hostdata->NCR53c7xx_msg_reject)));
+ patch_abs_32 (hostdata->script, 0, NCR53c7xx_zero,
+ virt_to_bus(&(hostdata->NCR53c7xx_zero)));
+ patch_abs_32 (hostdata->script, 0, NCR53c7xx_sink,
+ virt_to_bus(&(hostdata->NCR53c7xx_sink)));
+ patch_abs_32 (hostdata->script, 0, NOP_insn,
+ virt_to_bus(&(hostdata->NOP_insn)));
+ patch_abs_32 (hostdata->script, 0, schedule,
+ virt_to_bus((void *) hostdata->schedule));
+
+ /* Fixup references to external variables: */
+ for (i = 0; i < EXTERNAL_PATCHES_LEN; ++i)
+ hostdata->script[EXTERNAL_PATCHES[i].offset] +=
+ virt_to_bus(EXTERNAL_PATCHES[i].address);
+
+ /*
+ * Fixup absolutes set at boot-time.
+ *
+ * All non-code absolute variables suffixed with "dsa_" and "int_"
+ * are constants, and need no fixup provided the assembler has done
+ * it for us (I don't know what the "real" NCR assembler does in
+ * this case, my assembler does the right magic).
+ */
+
+ patch_abs_rwri_data (hostdata->script, 0, dsa_save_data_pointer,
+ Ent_dsa_code_save_data_pointer - Ent_dsa_zero);
+ patch_abs_rwri_data (hostdata->script, 0, dsa_restore_pointers,
+ Ent_dsa_code_restore_pointers - Ent_dsa_zero);
+ patch_abs_rwri_data (hostdata->script, 0, dsa_check_reselect,
+ Ent_dsa_code_check_reselect - Ent_dsa_zero);
+
+ /*
+ * Just for the hell of it, preserve the settings of
+ * Burst Length and Enable Read Line bits from the DMODE
+ * register. Make sure SCRIPTS start automagically.
+ */
+
+#if defined(CONFIG_MVME166)
+ /* We know better what we want than 166Bug does! */
+ tmp = DMODE_10_BL_8 | DMODE_10_FC2;
+#else
+ tmp = NCR53c7x0_read8(DMODE_REG_10);
+ tmp &= (DMODE_BL_MASK | DMODE_10_FC2 | DMODE_10_FC1 | DMODE_710_PD |
+ DMODE_710_UO);
+#endif
+
+ if (!(hostdata->options & OPTION_MEMORY_MAPPED)) {
+ base = (u32) host->io_port;
+ memory_to_ncr = tmp|DMODE_800_DIOM;
+ ncr_to_memory = tmp|DMODE_800_SIOM;
+ } else {
+ base = virt_to_bus(host->base);
+ memory_to_ncr = ncr_to_memory = tmp;
+ }
+
+ /* SCRATCHB_REG_10 == SCRATCHA_REG_800, as it happens */
+ patch_abs_32 (hostdata->script, 0, addr_scratch, base + SCRATCHA_REG_800);
+ patch_abs_32 (hostdata->script, 0, addr_temp, base + TEMP_REG);
+ patch_abs_32 (hostdata->script, 0, addr_dsa, base + DSA_REG);
+
+ /*
+ * I needed some variables in the script to be accessible to
+ * both the NCR chip and the host processor. For these variables,
+ * I made the arbitrary decision to store them directly in the
+ * hostdata structure rather than in the RELATIVE area of the
+ * SCRIPTS.
+ */
+
+
+ patch_abs_rwri_data (hostdata->script, 0, dmode_memory_to_memory, tmp);
+ patch_abs_rwri_data (hostdata->script, 0, dmode_memory_to_ncr, memory_to_ncr);
+ patch_abs_rwri_data (hostdata->script, 0, dmode_ncr_to_memory, ncr_to_memory);
+
+ patch_abs_32 (hostdata->script, 0, msg_buf,
+ virt_to_bus((void *)&(hostdata->msg_buf)));
+ patch_abs_32 (hostdata->script, 0, reconnect_dsa_head,
+ virt_to_bus((void *)&(hostdata->reconnect_dsa_head)));
+ patch_abs_32 (hostdata->script, 0, addr_reconnect_dsa_head,
+ virt_to_bus((void *)&(hostdata->addr_reconnect_dsa_head)));
+ patch_abs_32 (hostdata->script, 0, reselected_identify,
+ virt_to_bus((void *)&(hostdata->reselected_identify)));
+/* reselected_tag is currently unused */
+#if 0
+ patch_abs_32 (hostdata->script, 0, reselected_tag,
+ virt_to_bus((void *)&(hostdata->reselected_tag)));
+#endif
+
+ patch_abs_32 (hostdata->script, 0, test_dest,
+ virt_to_bus((void*)&hostdata->test_dest));
+ patch_abs_32 (hostdata->script, 0, test_src,
+ virt_to_bus(&hostdata->test_source));
+ patch_abs_32 (hostdata->script, 0, saved_dsa,
+ virt_to_bus(&hostdata->saved2_dsa));
+ patch_abs_32 (hostdata->script, 0, emulfly,
+ virt_to_bus(&hostdata->emulated_intfly));
+
+ patch_abs_rwri_data (hostdata->script, 0, dsa_check_reselect,
+ (unsigned char)(Ent_dsa_code_check_reselect - Ent_dsa_zero));
+
+/* These are for event logging; the ncr_event enum contains the
+ actual interrupt numbers. */
+#ifdef A_int_EVENT_SELECT
+ patch_abs_32 (hostdata->script, 0, int_EVENT_SELECT, (u32) EVENT_SELECT);
+#endif
+#ifdef A_int_EVENT_DISCONNECT
+ patch_abs_32 (hostdata->script, 0, int_EVENT_DISCONNECT, (u32) EVENT_DISCONNECT);
+#endif
+#ifdef A_int_EVENT_RESELECT
+ patch_abs_32 (hostdata->script, 0, int_EVENT_RESELECT, (u32) EVENT_RESELECT);
+#endif
+#ifdef A_int_EVENT_COMPLETE
+ patch_abs_32 (hostdata->script, 0, int_EVENT_COMPLETE, (u32) EVENT_COMPLETE);
+#endif
+#ifdef A_int_EVENT_IDLE
+ patch_abs_32 (hostdata->script, 0, int_EVENT_IDLE, (u32) EVENT_IDLE);
+#endif
+#ifdef A_int_EVENT_SELECT_FAILED
+ patch_abs_32 (hostdata->script, 0, int_EVENT_SELECT_FAILED,
+ (u32) EVENT_SELECT_FAILED);
+#endif
+#ifdef A_int_EVENT_BEFORE_SELECT
+ patch_abs_32 (hostdata->script, 0, int_EVENT_BEFORE_SELECT,
+ (u32) EVENT_BEFORE_SELECT);
+#endif
+#ifdef A_int_EVENT_RESELECT_FAILED
+ patch_abs_32 (hostdata->script, 0, int_EVENT_RESELECT_FAILED,
+ (u32) EVENT_RESELECT_FAILED);
+#endif
+
+ /*
+ * Make sure the NCR and Linux code agree on the location of
+ * certain fields.
+ */
+
+ hostdata->E_accept_message = Ent_accept_message;
+ hostdata->E_command_complete = Ent_command_complete;
+ hostdata->E_cmdout_cmdout = Ent_cmdout_cmdout;
+ hostdata->E_data_transfer = Ent_data_transfer;
+ hostdata->E_debug_break = Ent_debug_break;
+ hostdata->E_dsa_code_template = Ent_dsa_code_template;
+ hostdata->E_dsa_code_template_end = Ent_dsa_code_template_end;
+ hostdata->E_end_data_transfer = Ent_end_data_transfer;
+ hostdata->E_initiator_abort = Ent_initiator_abort;
+ hostdata->E_msg_in = Ent_msg_in;
+ hostdata->E_other_transfer = Ent_other_transfer;
+ hostdata->E_other_in = Ent_other_in;
+ hostdata->E_other_out = Ent_other_out;
+ hostdata->E_reject_message = Ent_reject_message;
+ hostdata->E_respond_message = Ent_respond_message;
+ hostdata->E_select = Ent_select;
+ hostdata->E_select_msgout = Ent_select_msgout;
+ hostdata->E_target_abort = Ent_target_abort;
+#ifdef Ent_test_0
+ hostdata->E_test_0 = Ent_test_0;
+#endif
+ hostdata->E_test_1 = Ent_test_1;
+ hostdata->E_test_2 = Ent_test_2;
+#ifdef Ent_test_3
+ hostdata->E_test_3 = Ent_test_3;
+#endif
+ hostdata->E_wait_reselect = Ent_wait_reselect;
+ hostdata->E_dsa_code_begin = Ent_dsa_code_begin;
+
+ hostdata->dsa_cmdout = A_dsa_cmdout;
+ hostdata->dsa_cmnd = A_dsa_cmnd;
+ hostdata->dsa_datain = A_dsa_datain;
+ hostdata->dsa_dataout = A_dsa_dataout;
+ hostdata->dsa_end = A_dsa_end;
+ hostdata->dsa_msgin = A_dsa_msgin;
+ hostdata->dsa_msgout = A_dsa_msgout;
+ hostdata->dsa_msgout_other = A_dsa_msgout_other;
+ hostdata->dsa_next = A_dsa_next;
+ hostdata->dsa_select = A_dsa_select;
+ hostdata->dsa_start = Ent_dsa_code_template - Ent_dsa_zero;
+ hostdata->dsa_status = A_dsa_status;
+ hostdata->dsa_jump_dest = Ent_dsa_code_fix_jump - Ent_dsa_zero +
+ 8 /* destination operand */;
+
+ /* sanity check */
+ if (A_dsa_fields_start != Ent_dsa_code_template_end -
+ Ent_dsa_zero)
+ printk("scsi%d : NCR dsa_fields start is %d not %d\n",
+ host->host_no, A_dsa_fields_start, Ent_dsa_code_template_end -
+ Ent_dsa_zero);
+
+ printk("scsi%d : NCR code relocated to 0x%lx (virt 0x%p)\n", host->host_no,
+ virt_to_bus(hostdata->script), hostdata->script);
+flush_cache_all();
+cache_push(virt_to_bus(hostdata->script), flushsize);
+cache_clear(virt_to_bus(hostdata->script), flushsize);
+}
+
+/*
+ * Function : static int NCR53c7xx_run_tests (struct Scsi_Host *host)
+ *
+ * Purpose : run various verification tests on the NCR chip,
+ * including interrupt generation, and proper bus mastering
+ * operation.
+ *
+ * Inputs : host - a properly initialized Scsi_Host structure
+ *
+ * Preconditions : the NCR chip must be in a halted state.
+ *
+ * Returns : 0 if all tests were successful, -1 on error.
+ *
+ */
+
+static int
+NCR53c7xx_run_tests (struct Scsi_Host *host) {
+ NCR53c7x0_local_declare();
+ struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+ host->hostdata;
+ unsigned long timeout;
+ u32 start;
+ int failed, i;
+ unsigned long flags;
+ NCR53c7x0_local_setup(host);
+
+ /* The NCR chip _must_ be idle to run the test scripts */
+
+ save_flags(flags);
+ cli();
+ if (!hostdata->idle) {
+ printk ("scsi%d : chip not idle, aborting tests\n", host->host_no);
+ restore_flags(flags);
+ return -1;
+ }
+
+ /*
+ * Check for functional interrupts, this could work as an
+ * autoprobe routine.
+ */
+
+ if ((hostdata->options & OPTION_DEBUG_TEST1) &&
+ hostdata->state != STATE_DISABLED) {
+ hostdata->idle = 0;
+ hostdata->test_running = 1;
+ hostdata->test_completed = -1;
+ hostdata->test_dest = 0;
+ hostdata->test_source = 0xdeadbeef;
+ start = virt_to_bus (hostdata->script) + hostdata->E_test_1;
+ hostdata->state = STATE_RUNNING;
+ printk ("scsi%d : test 1", host->host_no);
+ flush_cache_all();
+ cache_push(virt_to_bus(hostdata->script), flushsize);
+ cache_clear(virt_to_bus(hostdata->script), flushsize);
+ NCR53c7x0_write32 (DSP_REG, start);
+ if (hostdata->options & OPTION_DEBUG_TRACE)
+ NCR53c7x0_write8 (DCNTL_REG, hostdata->saved_dcntl | DCNTL_SSM |
+ DCNTL_STD);
+ printk (" started\n");
+ sti();
+
+ /*
+ * This is currently a .5 second timeout, since (in theory) no slow
+ * board will take that long. In practice, we've seen one
+ * pentium which occassionally fails with this, but works with
+ * 10 times as much?
+ */
+
+ timeout = jiffies + 5 * HZ / 10;
+ while ((hostdata->test_completed == -1) && jiffies < timeout)
+ barrier();
+
+ failed = 1;
+ if (hostdata->test_completed == -1)
+ printk ("scsi%d : driver test 1 timed out%s\n",host->host_no ,
+ (hostdata->test_dest == 0xdeadbeef) ?
+ " due to lost interrupt.\n"
+ " Please verify that the correct IRQ is being used for your board,\n"
+ : "");
+ else if (hostdata->test_completed != 1)
+ printk ("scsi%d : test 1 bad interrupt value (%d)\n",
+ host->host_no, hostdata->test_completed);
+ else
+ failed = (hostdata->test_dest != 0xdeadbeef);
+
+ if (hostdata->test_dest != 0xdeadbeef) {
+ printk ("scsi%d : driver test 1 read 0x%x instead of 0xdeadbeef indicating a\n"
+ " probable cache invalidation problem. Please configure caching\n"
+ " as write-through or disabled\n",
+ host->host_no, hostdata->test_dest);
+ }
+
+ if (failed) {
+ printk ("scsi%d : DSP = 0x%p (script at 0x%p, start at 0x%x)\n",
+ host->host_no, bus_to_virt(NCR53c7x0_read32(DSP_REG)),
+ hostdata->script, start);
+ printk ("scsi%d : DSPS = 0x%x\n", host->host_no,
+ NCR53c7x0_read32(DSPS_REG));
+ restore_flags(flags);
+ return -1;
+ }
+ hostdata->test_running = 0;
+ }
+
+ if ((hostdata->options & OPTION_DEBUG_TEST2) &&
+ hostdata->state != STATE_DISABLED) {
+ u32 dsa[48];
+ unsigned char identify = IDENTIFY(0, 0);
+ unsigned char cmd[6];
+ unsigned char data[36];
+ unsigned char status = 0xff;
+ unsigned char msg = 0xff;
+
+ cmd[0] = INQUIRY;
+ cmd[1] = cmd[2] = cmd[3] = cmd[5] = 0;
+ cmd[4] = sizeof(data);
+
+ dsa[2] = 1;
+ dsa[3] = virt_to_bus(&identify);
+ dsa[4] = 6;
+ dsa[5] = virt_to_bus(&cmd);
+ dsa[6] = sizeof(data);
+ dsa[7] = virt_to_bus(&data);
+ dsa[8] = 1;
+ dsa[9] = virt_to_bus(&status);
+ dsa[10] = 1;
+ dsa[11] = virt_to_bus(&msg);
+
+ for (i = 0; i < 6; ++i) {
+#ifdef VALID_IDS
+ if (!hostdata->valid_ids[i])
+ continue;
+#endif
+ cli();
+ if (!hostdata->idle) {
+ printk ("scsi%d : chip not idle, aborting tests\n", host->host_no);
+ restore_flags(flags);
+ return -1;
+ }
+
+ /* 710: bit mapped scsi ID, async */
+ dsa[0] = (1 << i) << 16;
+ hostdata->idle = 0;
+ hostdata->test_running = 2;
+ hostdata->test_completed = -1;
+ start = virt_to_bus(hostdata->script) + hostdata->E_test_2;
+ hostdata->state = STATE_RUNNING;
+ flush_cache_all();
+ cache_clear(virt_to_bus(hostdata->script), flushsize);
+ NCR53c7x0_write32 (DSA_REG, virt_to_bus(dsa));
+ NCR53c7x0_write32 (DSP_REG, start);
+ if (hostdata->options & OPTION_DEBUG_TRACE)
+ NCR53c7x0_write8 (DCNTL_REG, hostdata->saved_dcntl |
+ DCNTL_SSM | DCNTL_STD);
+ sti();
+
+ timeout = jiffies + 5 * HZ; /* arbitrary */
+ while ((hostdata->test_completed == -1) && jiffies < timeout)
+ barrier();
+
+ NCR53c7x0_write32 (DSA_REG, 0);
+
+ if (hostdata->test_completed == 2) {
+ data[35] = 0;
+ printk ("scsi%d : test 2 INQUIRY to target %d, lun 0 : %s\n",
+ host->host_no, i, data + 8);
+ printk ("scsi%d : status ", host->host_no);
+ print_status (status);
+ printk ("\nscsi%d : message ", host->host_no);
+ print_msg (&msg);
+ printk ("\n");
+ } else if (hostdata->test_completed == 3) {
+ printk("scsi%d : test 2 no connection with target %d\n",
+ host->host_no, i);
+ if (!hostdata->idle) {
+ printk("scsi%d : not idle\n", host->host_no);
+ restore_flags(flags);
+ return -1;
+ }
+ } else if (hostdata->test_completed == -1) {
+ printk ("scsi%d : test 2 timed out\n", host->host_no);
+ restore_flags(flags);
+ return -1;
+ }
+ hostdata->test_running = 0;
+ }
+ }
+
+ restore_flags(flags);
+ return 0;
+}
+
+/*
+ * Function : static void NCR53c7xx_dsa_fixup (struct NCR53c7x0_cmd *cmd)
+ *
+ * Purpose : copy the NCR53c8xx dsa structure into cmd's dsa buffer,
+ * performing all necessary relocation.
+ *
+ * Inputs : cmd, a NCR53c7x0_cmd structure with a dsa area large
+ * enough to hold the NCR53c8xx dsa.
+ */
+
+static void
+NCR53c7xx_dsa_fixup (struct NCR53c7x0_cmd *cmd) {
+ Scsi_Cmnd *c = cmd->cmd;
+ struct Scsi_Host *host = c->host;
+ struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+ host->hostdata;
+ int i;
+
+ memcpy (cmd->dsa, hostdata->script + (hostdata->E_dsa_code_template / 4),
+ hostdata->E_dsa_code_template_end - hostdata->E_dsa_code_template);
+
+ /*
+ * Note : within the NCR 'C' code, dsa points to the _start_
+ * of the DSA structure, and _not_ the offset of dsa_zero within
+ * that structure used to facilitate shorter signed offsets
+ * for the 8 bit ALU.
+ *
+ * The implications of this are that
+ *
+ * - 32 bit A_dsa_* absolute values require an additional
+ * dsa_zero added to their value to be correct, since they are
+ * relative to dsa_zero which is in essentially a separate
+ * space from the code symbols.
+ *
+ * - All other symbols require no special treatment.
+ */
+
+ patch_abs_tci_data (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
+ dsa_temp_lun, c->lun);
+ patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
+ dsa_temp_addr_next, virt_to_bus(&cmd->dsa_next_addr));
+ patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
+ dsa_temp_next, virt_to_bus(cmd->dsa) + Ent_dsa_zero -
+ Ent_dsa_code_template + A_dsa_next);
+ patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
+ dsa_temp_sync, virt_to_bus((void *)hostdata->sync[c->target].script));
+ patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
+ dsa_sscf_710, virt_to_bus((void *)&hostdata->sync[c->target].sscf_710));
+ patch_abs_tci_data (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
+ dsa_temp_target, 1 << c->target);
+ /* XXX - new pointer stuff */
+ patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
+ dsa_temp_addr_saved_pointer, virt_to_bus(&cmd->saved_data_pointer));
+ patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
+ dsa_temp_addr_saved_residual, virt_to_bus(&cmd->saved_residual));
+ patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
+ dsa_temp_addr_residual, virt_to_bus(&cmd->residual));
+
+ /* XXX - new start stuff */
+
+ patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
+ dsa_temp_addr_dsa_value, virt_to_bus(&cmd->dsa_addr));
+
+flush_cache_all();
+cache_push(virt_to_bus(hostdata->script), flushsize);
+cache_clear(virt_to_bus(hostdata->script), flushsize);
+}
+
+/*
+ * Function : run_process_issue_queue (void)
+ *
+ * Purpose : insure that the coroutine is running and will process our
+ * request. process_issue_queue_running is checked/set here (in an
+ * inline function) rather than in process_issue_queue itself to reduce
+ * the chances of stack overflow.
+ *
+ */
+
+static volatile int process_issue_queue_running = 0;
+
+static __inline__ void
+run_process_issue_queue(void) {
+ unsigned long flags;
+ save_flags (flags);
+ cli();
+ if (!process_issue_queue_running) {
+ process_issue_queue_running = 1;
+ process_issue_queue(flags);
+ /*
+ * process_issue_queue_running is cleared in process_issue_queue
+ * once it can't do more work, and process_issue_queue exits with
+ * interrupts disabled.
+ */
+ }
+ restore_flags (flags);
+}
+
+/*
+ * Function : static void abnormal_finished (struct NCR53c7x0_cmd *cmd, int
+ * result)
+ *
+ * Purpose : mark SCSI command as finished, OR'ing the host portion
+ * of the result word into the result field of the corresponding
+ * Scsi_Cmnd structure, and removing it from the internal queues.
+ *
+ * Inputs : cmd - command, result - entire result field
+ *
+ * Preconditions : the NCR chip should be in a halted state when
+ * abnormal_finished is run, since it modifies structures which
+ * the NCR expects to have exclusive access to.
+ */
+
+static void
+abnormal_finished (struct NCR53c7x0_cmd *cmd, int result) {
+ Scsi_Cmnd *c = cmd->cmd;
+ struct Scsi_Host *host = c->host;
+ struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+ host->hostdata;
+ unsigned long flags;
+ int left, found;
+ volatile struct NCR53c7x0_cmd * linux_search;
+ volatile struct NCR53c7x0_cmd * volatile *linux_prev;
+ volatile u32 *ncr_prev, *ncrcurrent, ncr_search;
+
+#if 0
+ printk ("scsi%d: abnormal finished\n", host->host_no);
+#endif
+
+ save_flags(flags);
+ cli();
+ found = 0;
+ /*
+ * Traverse the NCR issue array until we find a match or run out
+ * of instructions. Instructions in the NCR issue array are
+ * either JUMP or NOP instructions, which are 2 words in length.
+ */
+
+
+ for (found = 0, left = host->can_queue, ncrcurrent = hostdata->schedule;
+ left > 0; --left, ncrcurrent += 2)
+ {
+ if (issue_to_cmd (host, hostdata, (u32 *) ncrcurrent) == cmd)
+ {
+ ncrcurrent[0] = hostdata->NOP_insn;
+ ncrcurrent[1] = 0xdeadbeef;
+ ++found;
+ break;
+ }
+ }
+
+ /*
+ * Traverse the NCR reconnect list of DSA structures until we find
+ * a pointer to this dsa or have found too many command structures.
+ * We let prev point at the next field of the previous element or
+ * head of the list, so we don't do anything different for removing
+ * the head element.
+ */
+
+ for (left = host->can_queue,
+ ncr_search = hostdata->reconnect_dsa_head,
+ ncr_prev = &hostdata->reconnect_dsa_head;
+ left >= 0 && ncr_search &&
+ ((char*)bus_to_virt(ncr_search) + hostdata->dsa_start)
+ != (char *) cmd->dsa;
+ ncr_prev = (u32*) ((char*)bus_to_virt(ncr_search) +
+ hostdata->dsa_next), ncr_search = *ncr_prev, --left);
+
+ if (left < 0)
+ printk("scsi%d: loop detected in ncr reconncect list\n",
+ host->host_no);
+ else if (ncr_search)
+ if (found)
+ printk("scsi%d: scsi %ld in ncr issue array and reconnect lists\n",
+ host->host_no, c->pid);
+ else {
+ volatile u32 * next = (u32 *)
+ ((char *)bus_to_virt(ncr_search) + hostdata->dsa_next);
+ *ncr_prev = *next;
+/* If we're at the tail end of the issue queue, update that pointer too. */
+ found = 1;
+ }
+
+ /*
+ * Traverse the host running list until we find this command or discover
+ * we have too many elements, pointing linux_prev at the next field of the
+ * linux_previous element or head of the list, search at this element.
+ */
+
+ for (left = host->can_queue, linux_search = hostdata->running_list,
+ linux_prev = &hostdata->running_list;
+ left >= 0 && linux_search && linux_search != cmd;
+ linux_prev = &(linux_search->next),
+ linux_search = linux_search->next, --left);
+
+ if (left < 0)
+ printk ("scsi%d: loop detected in host running list for scsi pid %ld\n",
+ host->host_no, c->pid);
+ else if (linux_search) {
+ *linux_prev = linux_search->next;
+ --hostdata->busy[c->target][c->lun];
+ }
+
+ /* Return the NCR command structure to the free list */
+ cmd->next = hostdata->free;
+ hostdata->free = cmd;
+ c->host_scribble = NULL;
+
+ /* And return */
+ c->result = result;
+ c->scsi_done(c);
+
+ restore_flags(flags);
+ run_process_issue_queue();
+}
+
+/*
+ * Function : static void intr_break (struct Scsi_Host *host,
+ * struct NCR53c7x0_cmd *cmd)
+ *
+ * Purpose : Handler for breakpoint interrupts from a SCSI script
+ *
+ * Inputs : host - pointer to this host adapter's structure,
+ * cmd - pointer to the command (if any) dsa was pointing
+ * to.
+ *
+ */
+
+static void
+intr_break (struct Scsi_Host *host, struct
+ NCR53c7x0_cmd *cmd) {
+ NCR53c7x0_local_declare();
+ struct NCR53c7x0_break *bp;
+#if 0
+ Scsi_Cmnd *c = cmd ? cmd->cmd : NULL;
+#endif
+ u32 *dsp;
+ struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+ host->hostdata;
+ unsigned long flags;
+ NCR53c7x0_local_setup(host);
+
+ /*
+ * Find the break point corresponding to this address, and
+ * dump the appropriate debugging information to standard
+ * output.
+ */
+ save_flags(flags);
+ cli();
+ flush_cache_all();
+ cache_push(virt_to_bus(hostdata->script), flushsize);
+ dsp = (u32 *) bus_to_virt(NCR53c7x0_read32(DSP_REG));
+ for (bp = hostdata->breakpoints; bp && bp->address != dsp;
+ bp = bp->next);
+ if (!bp)
+ panic("scsi%d : break point interrupt from %p with no breakpoint!",
+ host->host_no, dsp);
+
+ /*
+ * Configure the NCR chip for manual start mode, so that we can
+ * point the DSP register at the instruction that follows the
+ * INT int_debug_break instruction.
+ */
+
+ NCR53c7x0_write8 (hostdata->dmode,
+ NCR53c7x0_read8(hostdata->dmode)|DMODE_MAN);
+
+ /*
+ * And update the DSP register, using the size of the old
+ * instruction in bytes.
+ */
+
+ restore_flags(flags);
+}
+/*
+ * Function : static void print_synchronous (const char *prefix,
+ * const unsigned char *msg)
+ *
+ * Purpose : print a pretty, user and machine parsable representation
+ * of a SDTR message, including the "real" parameters, data
+ * clock so we can tell transfer rate at a glance.
+ *
+ * Inputs ; prefix - text to prepend, msg - SDTR message (5 bytes)
+ */
+
+static void
+print_synchronous (const char *prefix, const unsigned char *msg) {
+ if (msg[4]) {
+ int Hz = 1000000000 / (msg[3] * 4);
+ int integer = Hz / 1000000;
+ int fraction = (Hz - (integer * 1000000)) / 10000;
+ printk ("%speriod %dns offset %d %d.%02dMHz %s SCSI%s\n",
+ prefix, (int) msg[3] * 4, (int) msg[4], integer, fraction,
+ (((msg[3] * 4) < 200) ? "FAST" : "synchronous"),
+ (((msg[3] * 4) < 200) ? "-II" : ""));
+ } else
+ printk ("%sasynchronous SCSI\n", prefix);
+}
+
+/*
+ * Function : static void set_synchronous (struct Scsi_Host *host,
+ * int target, int sxfer, int scntl3, int now_connected)
+ *
+ * Purpose : reprogram transfers between the selected SCSI initiator and
+ * target with the given register values; in the indirect
+ * select operand, reselection script, and chip registers.
+ *
+ * Inputs : host - NCR53c7,8xx SCSI host, target - number SCSI target id,
+ * sxfer and scntl3 - NCR registers. now_connected - if non-zero,
+ * we should reprogram the registers now too.
+ *
+ * NOTE: For 53c710, scntl3 is actually used for SCF bits from
+ * SBCL, as we don't have a SCNTL3.
+ */
+
+static void
+set_synchronous (struct Scsi_Host *host, int target, int sxfer, int scntl3,
+ int now_connected) {
+ NCR53c7x0_local_declare();
+ struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+ host->hostdata;
+ u32 *script;
+ NCR53c7x0_local_setup(host);
+
+ /* These are eight bit registers */
+ sxfer &= 0xff;
+ scntl3 &= 0xff;
+
+ hostdata->sync[target].sxfer_sanity = sxfer;
+ hostdata->sync[target].scntl3_sanity = scntl3;
+
+/*
+ * HARD CODED : synchronous script is EIGHT words long. This
+ * must agree with 53c7.8xx.h
+ */
+
+ if ((hostdata->chip != 700) && (hostdata->chip != 70066)) {
+ hostdata->sync[target].select_indirect = (1 << target) << 16 |
+ (sxfer << 8);
+ hostdata->sync[target].sscf_710 = scntl3;
+
+ script = (u32 *) hostdata->sync[target].script;
+
+ /* XXX - add NCR53c7x0 code to reprogram SCF bits if we want to */
+ script[0] = ((DCMD_TYPE_RWRI | DCMD_RWRI_OPC_MODIFY |
+ DCMD_RWRI_OP_MOVE) << 24) |
+ (SBCL_REG << 16) | (scntl3 << 8);
+ script[1] = 0;
+ script += 2;
+
+ script[0] = ((DCMD_TYPE_RWRI | DCMD_RWRI_OPC_MODIFY |
+ DCMD_RWRI_OP_MOVE) << 24) |
+ (SXFER_REG << 16) | (sxfer << 8);
+ script[1] = 0;
+ script += 2;
+
+#ifdef DEBUG_SYNC_INTR
+ if (hostdata->options & OPTION_DEBUG_DISCONNECT) {
+ script[0] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_INT) << 24) | DBC_TCI_TRUE;
+ script[1] = DEBUG_SYNC_INTR;
+ script += 2;
+ }
+#endif
+
+ script[0] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_RETURN) << 24) | DBC_TCI_TRUE;
+ script[1] = 0;
+ script += 2;
+ }
+
+ if (hostdata->options & OPTION_DEBUG_SYNCHRONOUS)
+ printk ("scsi%d : target %d sync parameters are sxfer=0x%x, scntl3=0x%x\n",
+ host->host_no, target, sxfer, scntl3);
+
+ if (now_connected) {
+ NCR53c7x0_write8(SBCL_REG, scntl3);
+ NCR53c7x0_write8(SXFER_REG, sxfer);
+ }
+}
+
+
+/*
+ * Function : static int asynchronous (struct Scsi_Host *host, int target)
+ *
+ * Purpose : reprogram between the selected SCSI Host adapter and target
+ * (assumed to be currently connected) for asynchronous transfers.
+ *
+ * Inputs : host - SCSI host structure, target - numeric target ID.
+ *
+ * Preconditions : the NCR chip should be in one of the halted states
+ */
+
+static void
+asynchronous (struct Scsi_Host *host, int target) {
+ NCR53c7x0_local_declare();
+ struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+ host->hostdata;
+ NCR53c7x0_local_setup(host);
+ set_synchronous (host, target, /* no offset */ 0, hostdata->saved_scntl3,
+ 1);
+ printk ("scsi%d : setting target %d to asynchronous SCSI\n",
+ host->host_no, target);
+}
+
+/*
+ * XXX - do we want to go out of our way (ie, add extra code to selection
+ * in the NCR53c710/NCR53c720 script) to reprogram the synchronous
+ * conversion bits, or can we be content in just setting the
+ * sxfer bits? I chose to do so [richard@sleepie.demon.co.uk]
+ */
+
+/* Table for NCR53c8xx synchronous values */
+
+/* This table is also correct for 710, allowing that scf=4 is equivalent
+ * of SSCF=0 (ie use DCNTL, divide by 3) for a 50.01-66.00MHz clock.
+ * For any other clock values, we cannot use entries with SCF values of
+ * 4. I guess that for a 66MHz clock, the slowest it will set is 2MHz,
+ * and for a 50MHz clock, the slowest will be 2.27Mhz. Should check
+ * that a device doesn't try and negotiate sync below these limits!
+ */
+
+static const struct {
+ int div; /* Total clock divisor * 10 */
+ unsigned char scf; /* */
+ unsigned char tp; /* 4 + tp = xferp divisor */
+} syncs[] = {
+/* div scf tp div scf tp div scf tp */
+ { 40, 1, 0}, { 50, 1, 1}, { 60, 1, 2},
+ { 70, 1, 3}, { 75, 2, 1}, { 80, 1, 4},
+ { 90, 1, 5}, { 100, 1, 6}, { 105, 2, 3},
+ { 110, 1, 7}, { 120, 2, 4}, { 135, 2, 5},
+ { 140, 3, 3}, { 150, 2, 6}, { 160, 3, 4},
+ { 165, 2, 7}, { 180, 3, 5}, { 200, 3, 6},
+ { 210, 4, 3}, { 220, 3, 7}, { 240, 4, 4},
+ { 270, 4, 5}, { 300, 4, 6}, { 330, 4, 7}
+};
+
+/*
+ * Function : static void synchronous (struct Scsi_Host *host, int target,
+ * char *msg)
+ *
+ * Purpose : reprogram transfers between the selected SCSI initiator and
+ * target for synchronous SCSI transfers such that the synchronous
+ * offset is less than that requested and period at least as long
+ * as that requested. Also modify *msg such that it contains
+ * an appropriate response.
+ *
+ * Inputs : host - NCR53c7,8xx SCSI host, target - number SCSI target id,
+ * msg - synchronous transfer request.
+ */
+
+
+static void
+synchronous (struct Scsi_Host *host, int target, char *msg) {
+ struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+ host->hostdata;
+ int desire, divisor, i, limit;
+ unsigned char scntl3, sxfer;
+/* The diagnostic message fits on one line, even with max. width integers */
+ char buf[80];
+
+/* Desired transfer clock in Hz */
+ desire = 1000000000L / (msg[3] * 4);
+/* Scale the available SCSI clock by 10 so we get tenths */
+ divisor = (hostdata->scsi_clock * 10) / desire;
+
+/* NCR chips can handle at most an offset of 8 */
+ if (msg[4] > 8)
+ msg[4] = 8;
+
+ if (hostdata->options & OPTION_DEBUG_SDTR)
+ printk("scsi%d : optimal synchronous divisor of %d.%01d\n",
+ host->host_no, divisor / 10, divisor % 10);
+
+ limit = (sizeof(syncs) / sizeof(syncs[0]) -1);
+ for (i = 0; (i < limit) && (divisor > syncs[i].div); ++i);
+
+ if (hostdata->options & OPTION_DEBUG_SDTR)
+ printk("scsi%d : selected synchronous divisor of %d.%01d\n",
+ host->host_no, syncs[i].div / 10, syncs[i].div % 10);
+
+ msg[3] = ((1000000000L / hostdata->scsi_clock) * syncs[i].div / 10 / 4);
+
+ if (hostdata->options & OPTION_DEBUG_SDTR)
+ printk("scsi%d : selected synchronous period of %dns\n", host->host_no,
+ msg[3] * 4);
+
+ scntl3 = syncs[i].scf;
+ sxfer = (msg[4] << SXFER_MO_SHIFT) | (syncs[i].tp << 4);
+ if (hostdata->options & OPTION_DEBUG_SDTR)
+ printk ("scsi%d : sxfer=0x%x scntl3=0x%x\n",
+ host->host_no, (int) sxfer, (int) scntl3);
+ set_synchronous (host, target, sxfer, scntl3, 1);
+ sprintf (buf, "scsi%d : setting target %d to ", host->host_no, target);
+ print_synchronous (buf, msg);
+}
+
+/*
+ * Function : static int NCR53c7x0_dstat_sir_intr (struct Scsi_Host *host,
+ * struct NCR53c7x0_cmd *cmd)
+ *
+ * Purpose : Handler for INT generated instructions for the
+ * NCR53c810/820 SCSI SCRIPT
+ *
+ * Inputs : host - pointer to this host adapter's structure,
+ * cmd - pointer to the command (if any) dsa was pointing
+ * to.
+ *
+ */
+
+static int
+NCR53c7x0_dstat_sir_intr (struct Scsi_Host *host, struct
+ NCR53c7x0_cmd *cmd) {
+ NCR53c7x0_local_declare();
+ int print;
+ Scsi_Cmnd *c = cmd ? cmd->cmd : NULL;
+ struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+ host->hostdata;
+ u32 dsps,*dsp; /* Argument of the INT instruction */
+
+flush_cache_all();
+cache_push(virt_to_bus(hostdata->script), flushsize);
+cache_clear(virt_to_bus(hostdata->script), flushsize);
+
+ NCR53c7x0_local_setup(host);
+ dsps = NCR53c7x0_read32(DSPS_REG);
+ dsp = (u32 *) bus_to_virt(NCR53c7x0_read32(DSP_REG));
+
+ if (hostdata->options & OPTION_DEBUG_INTR)
+ printk ("scsi%d : DSPS = 0x%x\n", host->host_no, dsps);
+
+ switch (dsps) {
+ case A_int_msg_1:
+ print = 1;
+ switch (hostdata->msg_buf[0]) {
+ /*
+ * Unless we've initiated synchronous negotiation, I don't
+ * think that this should happen.
+ */
+ case MESSAGE_REJECT:
+ hostdata->dsp = hostdata->script + hostdata->E_accept_message /
+ sizeof(u32);
+ hostdata->dsp_changed = 1;
+ if (cmd && (cmd->flags & CMD_FLAG_SDTR)) {
+ printk ("scsi%d : target %d rejected SDTR\n", host->host_no,
+ c->target);
+ cmd->flags &= ~CMD_FLAG_SDTR;
+ asynchronous (host, c->target);
+ print = 0;
+ }
+ break;
+ case INITIATE_RECOVERY:
+ printk ("scsi%d : extended contingent allegiance not supported yet, rejecting\n",
+ host->host_no);
+ /* Fall through to default */
+ hostdata->dsp = hostdata->script + hostdata->E_reject_message /
+ sizeof(u32);
+ hostdata->dsp_changed = 1;
+ break;
+ default:
+ printk ("scsi%d : unsupported message, rejecting\n",
+ host->host_no);
+ hostdata->dsp = hostdata->script + hostdata->E_reject_message /
+ sizeof(u32);
+ hostdata->dsp_changed = 1;
+ }
+ if (print) {
+ printk ("scsi%d : received message", host->host_no);
+ if (c)
+ printk (" from target %d lun %d ", c->target, c->lun);
+ print_msg ((unsigned char *) hostdata->msg_buf);
+ printk("\n");
+ }
+
+ return SPECIFIC_INT_NOTHING;
+
+
+ case A_int_msg_sdtr:
+/*
+ * At this point, hostdata->msg_buf contains
+ * 0 EXTENDED MESSAGE
+ * 1 length
+ * 2 SDTR
+ * 3 period * 4ns
+ * 4 offset
+ */
+
+ if (cmd) {
+ char buf[80];
+ sprintf (buf, "scsi%d : target %d %s ", host->host_no, c->target,
+ (cmd->flags & CMD_FLAG_SDTR) ? "accepting" : "requesting");
+ print_synchronous (buf, (unsigned char *) hostdata->msg_buf);
+
+ /*
+ * Initiator initiated, won't happen unless synchronous
+ * transfers are enabled. If we get a SDTR message in
+ * response to our SDTR, we should program our parameters
+ * such that
+ * offset <= requested offset
+ * period >= requested period
+ */
+ if (cmd->flags & CMD_FLAG_SDTR) {
+ cmd->flags &= ~CMD_FLAG_SDTR;
+ if (hostdata->msg_buf[4])
+ synchronous (host, c->target, (unsigned char *)
+ hostdata->msg_buf);
+ else
+ asynchronous (host, c->target);
+ hostdata->dsp = hostdata->script + hostdata->E_accept_message /
+ sizeof(u32);
+ hostdata->dsp_changed = 1;
+ return SPECIFIC_INT_NOTHING;
+ } else {
+ if (hostdata->options & OPTION_SYNCHRONOUS) {
+ cmd->flags |= CMD_FLAG_DID_SDTR;
+ synchronous (host, c->target, (unsigned char *)
+ hostdata->msg_buf);
+ } else {
+ hostdata->msg_buf[4] = 0; /* 0 offset = async */
+ asynchronous (host, c->target);
+ }
+ patch_dsa_32 (cmd->dsa, dsa_msgout_other, 0, 5);
+ patch_dsa_32 (cmd->dsa, dsa_msgout_other, 1, (u32)
+ virt_to_bus ((void *)&hostdata->msg_buf));
+ hostdata->dsp = hostdata->script +
+ hostdata->E_respond_message / sizeof(u32);
+ hostdata->dsp_changed = 1;
+ }
+ return SPECIFIC_INT_NOTHING;
+ }
+ /* Fall through to abort if we couldn't find a cmd, and
+ therefore a dsa structure to twiddle */
+ case A_int_msg_wdtr:
+ hostdata->dsp = hostdata->script + hostdata->E_reject_message /
+ sizeof(u32);
+ hostdata->dsp_changed = 1;
+ return SPECIFIC_INT_NOTHING;
+ case A_int_err_unexpected_phase:
+ if (hostdata->options & OPTION_DEBUG_INTR)
+ printk ("scsi%d : unexpected phase\n", host->host_no);
+ return SPECIFIC_INT_ABORT;
+ case A_int_err_selected:
+ if ((hostdata->chip / 100) == 8)
+ printk ("scsi%d : selected by target %d\n", host->host_no,
+ (int) NCR53c7x0_read8(SDID_REG_800) &7);
+ else
+ printk ("scsi%d : selected by target LCRC=0x%02x\n", host->host_no,
+ (int) NCR53c7x0_read8(LCRC_REG_10));
+ hostdata->dsp = hostdata->script + hostdata->E_target_abort /
+ sizeof(u32);
+ hostdata->dsp_changed = 1;
+ return SPECIFIC_INT_NOTHING;
+ case A_int_err_unexpected_reselect:
+ if ((hostdata->chip / 100) == 8)
+ printk ("scsi%d : unexpected reselect by target %d lun %d\n",
+ host->host_no, (int) NCR53c7x0_read8(SDID_REG_800) & 7,
+ hostdata->reselected_identify & 7);
+ else
+ printk ("scsi%d : unexpected reselect LCRC=0x%02x\n", host->host_no,
+ (int) NCR53c7x0_read8(LCRC_REG_10));
+ hostdata->dsp = hostdata->script + hostdata->E_initiator_abort /
+ sizeof(u32);
+ hostdata->dsp_changed = 1;
+ return SPECIFIC_INT_NOTHING;
+/*
+ * Since contingent allegiance conditions are cleared by the next
+ * command issued to a target, we must issue a REQUEST SENSE
+ * command after receiving a CHECK CONDITION status, before
+ * another command is issued.
+ *
+ * Since this NCR53c7x0_cmd will be freed after use, we don't
+ * care if we step on the various fields, so modify a few things.
+ */
+ case A_int_err_check_condition:
+#if 0
+ if (hostdata->options & OPTION_DEBUG_INTR)
+#endif
+ printk ("scsi%d : CHECK CONDITION\n", host->host_no);
+ if (!c) {
+ printk("scsi%d : CHECK CONDITION with no SCSI command\n",
+ host->host_no);
+ return SPECIFIC_INT_PANIC;
+ }
+
+ /*
+ * FIXME : this uses the normal one-byte selection message.
+ * We may want to renegotiate for synchronous & WIDE transfers
+ * since these could be the crux of our problem.
+ *
+ hostdata->NOP_insn* FIXME : once SCSI-II tagged queuing is implemented, we'll
+ * have to set this up so that the rest of the DSA
+ * agrees with this being an untagged queue'd command.
+ */
+
+ patch_dsa_32 (cmd->dsa, dsa_msgout, 0, 1);
+
+ /*
+ * Modify the table indirect for COMMAND OUT phase, since
+ * Request Sense is a six byte command.
+ */
+
+ patch_dsa_32 (cmd->dsa, dsa_cmdout, 0, 6);
+
+ c->cmnd[0] = REQUEST_SENSE;
+ c->cmnd[1] &= 0xe0; /* Zero all but LUN */
+ c->cmnd[2] = 0;
+ c->cmnd[3] = 0;
+ c->cmnd[4] = sizeof(c->sense_buffer);
+ c->cmnd[5] = 0;
+
+ /*
+ * Disable dataout phase, and program datain to transfer to the
+ * sense buffer, and add a jump to other_transfer after the
+ * command so overflow/underrun conditions are detected.
+ */
+
+ patch_dsa_32 (cmd->dsa, dsa_dataout, 0,
+ virt_to_bus(hostdata->script) + hostdata->E_other_transfer);
+ patch_dsa_32 (cmd->dsa, dsa_datain, 0,
+ virt_to_bus(cmd->data_transfer_start));
+ cmd->data_transfer_start[0] = (((DCMD_TYPE_BMI | DCMD_BMI_OP_MOVE_I |
+ DCMD_BMI_IO)) << 24) | sizeof(c->sense_buffer);
+ cmd->data_transfer_start[1] = (u32) virt_to_bus(c->sense_buffer);
+
+ cmd->data_transfer_start[2] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_JUMP)
+ << 24) | DBC_TCI_TRUE;
+ cmd->data_transfer_start[3] = (u32) virt_to_bus(hostdata->script) +
+ hostdata->E_other_transfer;
+
+ /*
+ * Currently, this command is flagged as completed, ie
+ * it has valid status and message data. Reflag it as
+ * incomplete. Q - need to do something so that original
+ * status, etc are used.
+ */
+
+ cmd->cmd->result = 0xffff;
+
+ /*
+ * Restart command as a REQUEST SENSE.
+ */
+ hostdata->dsp = (u32 *) hostdata->script + hostdata->E_select /
+ sizeof(u32);
+ hostdata->dsp_changed = 1;
+ return SPECIFIC_INT_NOTHING;
+ case A_int_debug_break:
+ return SPECIFIC_INT_BREAK;
+ case A_int_norm_aborted:
+ hostdata->dsp = (u32 *) hostdata->schedule;
+ hostdata->dsp_changed = 1;
+ if (cmd)
+ abnormal_finished (cmd, DID_ERROR << 16);
+ return SPECIFIC_INT_NOTHING;
+ case A_int_norm_emulateintfly:
+ /* I'm not sure this is the right ! thing to do, but it works
+ * with the A4000T when copyback is disabled, and also the
+ * WarpEngine with copyback enabled, so it looks as though
+ * it does work to some extent.
+ *
+ * RGH: I don't really like it - You get an interrupt which
+ * calls NCR53c7x0_intr(), which calls this function (via
+ * intr_dma()), which calls NCR53c7x0_intr().....
+ * Anyway lets see how it goes for now.
+ */
+ hostdata->emulated_intfly = 1;
+ NCR53c7x0_intr(host->irq, NULL, NULL);
+ return SPECIFIC_INT_NOTHING;
+ case A_int_test_1:
+ case A_int_test_2:
+ hostdata->idle = 1;
+ hostdata->test_completed = (dsps - A_int_test_1) / 0x00010000 + 1;
+ if (hostdata->options & OPTION_DEBUG_INTR)
+ printk("scsi%d : test%d complete\n", host->host_no,
+ hostdata->test_completed);
+ return SPECIFIC_INT_NOTHING;
+#ifdef A_int_debug_reselected_ok
+ case A_int_debug_reselected_ok:
+ if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR|
+ OPTION_DEBUG_DISCONNECT)) {
+ /*
+ * Note - this dsa is not based on location relative to
+ * the command structure, but to location relative to the
+ * DSA register
+ */
+ u32 *dsa;
+ dsa = (u32 *) bus_to_virt (NCR53c7x0_read32(DSA_REG));
+
+ printk("scsi%d : reselected_ok (DSA = 0x%x (virt 0x%p)\n",
+ host->host_no, NCR53c7x0_read32(DSA_REG), dsa);
+ printk("scsi%d : resume address is 0x%x (virt 0x%p)\n",
+ host->host_no, cmd->saved_data_pointer,
+ bus_to_virt(cmd->saved_data_pointer));
+ print_insn (host, hostdata->script + Ent_reselected_ok /
+ sizeof(u32), "", 1);
+ if ((hostdata->chip / 100) == 8)
+ printk ("scsi%d : sxfer=0x%x, scntl3=0x%x\n",
+ host->host_no, NCR53c7x0_read8(SXFER_REG),
+ NCR53c7x0_read8(SCNTL3_REG_800));
+ else
+ printk ("scsi%d : sxfer=0x%x, cannot read SBCL\n",
+ host->host_no, NCR53c7x0_read8(SXFER_REG));
+ if (c) {
+ print_insn (host, (u32 *)
+ hostdata->sync[c->target].script, "", 1);
+ print_insn (host, (u32 *)
+ hostdata->sync[c->target].script + 2, "", 1);
+ }
+ }
+ return SPECIFIC_INT_RESTART;
+#endif
+#ifdef A_int_debug_reselect_check
+ case A_int_debug_reselect_check:
+ if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR)) {
+ u32 *dsa;
+#if 0
+ u32 *code;
+#endif
+ /*
+ * Note - this dsa is not based on location relative to
+ * the command structure, but to location relative to the
+ * DSA register
+ */
+ dsa = bus_to_virt (NCR53c7x0_read32(DSA_REG));
+ printk("scsi%d : reselected_check_next (DSA = 0x%lx (virt 0x%p))\n",
+ host->host_no, virt_to_bus(dsa), dsa);
+ if (dsa) {
+ printk("scsi%d : resume address is 0x%x (virt 0x%p)\n",
+ host->host_no, cmd->saved_data_pointer,
+ bus_to_virt (cmd->saved_data_pointer));
+#if 0
+ printk("scsi%d : template code :\n", host->host_no);
+ for (code = dsa + (Ent_dsa_code_check_reselect - Ent_dsa_zero)
+ / sizeof(u32); code < (dsa + Ent_dsa_zero / sizeof(u32));
+ code += print_insn (host, code, "", 1));
+#endif
+ }
+ print_insn (host, hostdata->script + Ent_reselected_ok /
+ sizeof(u32), "", 1);
+ }
+ return SPECIFIC_INT_RESTART;
+#endif
+#ifdef A_int_debug_dsa_schedule
+ case A_int_debug_dsa_schedule:
+ if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR)) {
+ u32 *dsa;
+ /*
+ * Note - this dsa is not based on location relative to
+ * the command structure, but to location relative to the
+ * DSA register
+ */
+ dsa = (u32 *) bus_to_virt (NCR53c7x0_read32(DSA_REG));
+ printk("scsi%d : dsa_schedule (old DSA = 0x%lx (virt 0x%p))\n",
+ host->host_no, virt_to_bus(dsa), dsa);
+ if (dsa)
+ printk("scsi%d : resume address is 0x%x (virt 0x%p)\n"
+ " (temp was 0x%x (virt 0x%p))\n",
+ host->host_no, cmd->saved_data_pointer,
+ bus_to_virt (cmd->saved_data_pointer),
+ NCR53c7x0_read32 (TEMP_REG),
+ bus_to_virt (NCR53c7x0_read32(TEMP_REG)));
+ }
+ return SPECIFIC_INT_RESTART;
+#endif
+#ifdef A_int_debug_scheduled
+ case A_int_debug_scheduled:
+ if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR)) {
+ printk("scsi%d : new I/O 0x%x (virt 0x%p) scheduled\n",
+ host->host_no, NCR53c7x0_read32(DSA_REG),
+ bus_to_virt(NCR53c7x0_read32(DSA_REG)));
+ }
+ return SPECIFIC_INT_RESTART;
+#endif
+#ifdef A_int_debug_idle
+ case A_int_debug_idle:
+ if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR)) {
+ printk("scsi%d : idle\n", host->host_no);
+ }
+ return SPECIFIC_INT_RESTART;
+#endif
+#ifdef A_int_debug_cmd
+ case A_int_debug_cmd:
+ if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR)) {
+ printk("scsi%d : command sent\n");
+ }
+ return SPECIFIC_INT_RESTART;
+#endif
+#ifdef A_int_debug_dsa_loaded
+ case A_int_debug_dsa_loaded:
+ if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR)) {
+ printk("scsi%d : DSA loaded with 0x%x (virt 0x%p)\n", host->host_no,
+ NCR53c7x0_read32(DSA_REG),
+ bus_to_virt(NCR53c7x0_read32(DSA_REG)));
+ }
+ return SPECIFIC_INT_RESTART;
+#endif
+#ifdef A_int_debug_reselected
+ case A_int_debug_reselected:
+ if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR|
+ OPTION_DEBUG_DISCONNECT)) {
+ if ((hostdata->chip / 100) == 8)
+ printk("scsi%d : reselected by target %d lun %d\n",
+ host->host_no, (int) NCR53c7x0_read8(SDID_REG_800) & ~0x80,
+ (int) hostdata->reselected_identify & 7);
+ else
+ printk("scsi%d : reselected by LCRC=0x%02x lun %d\n",
+ host->host_no, (int) NCR53c7x0_read8(LCRC_REG_10),
+ (int) hostdata->reselected_identify & 7);
+ print_queues(host);
+ }
+ return SPECIFIC_INT_RESTART;
+#endif
+#ifdef A_int_debug_disconnect_msg
+ case A_int_debug_disconnect_msg:
+ if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR)) {
+ if (c)
+ printk("scsi%d : target %d lun %d disconnecting\n",
+ host->host_no, c->target, c->lun);
+ else
+ printk("scsi%d : unknown target disconnecting\n",
+ host->host_no);
+ }
+ return SPECIFIC_INT_RESTART;
+#endif
+#ifdef A_int_debug_disconnected
+ case A_int_debug_disconnected:
+ if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR|
+ OPTION_DEBUG_DISCONNECT)) {
+ printk ("scsi%d : disconnected, new queues are\n",
+ host->host_no);
+ print_queues(host);
+#if 0
+ /* Not valid on ncr53c710! */
+ printk ("scsi%d : sxfer=0x%x, scntl3=0x%x\n",
+ host->host_no, NCR53c7x0_read8(SXFER_REG),
+ NCR53c7x0_read8(SCNTL3_REG_800));
+#endif
+ if (c) {
+ print_insn (host, (u32 *)
+ hostdata->sync[c->target].script, "", 1);
+ print_insn (host, (u32 *)
+ hostdata->sync[c->target].script + 2, "", 1);
+ }
+ }
+ return SPECIFIC_INT_RESTART;
+#endif
+#ifdef A_int_debug_panic
+ case A_int_debug_panic:
+ printk("scsi%d : int_debug_panic received\n", host->host_no);
+ print_lots (host);
+ return SPECIFIC_INT_PANIC;
+#endif
+#ifdef A_int_debug_saved
+ case A_int_debug_saved:
+ if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR|
+ OPTION_DEBUG_DISCONNECT)) {
+ printk ("scsi%d : saved data pointer 0x%x (virt 0x%p)\n",
+ host->host_no, cmd->saved_data_pointer,
+ bus_to_virt (cmd->saved_data_pointer));
+ print_progress (c);
+ }
+ return SPECIFIC_INT_RESTART;
+#endif
+#ifdef A_int_debug_restored
+ case A_int_debug_restored:
+ if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR|
+ OPTION_DEBUG_DISCONNECT)) {
+ if (cmd) {
+ int size;
+ printk ("scsi%d : restored data pointer 0x%x (virt 0x%p)\n",
+ host->host_no, cmd->saved_data_pointer, bus_to_virt (
+ cmd->saved_data_pointer));
+ size = print_insn (host, (u32 *)
+ bus_to_virt(cmd->saved_data_pointer), "", 1);
+ size = print_insn (host, (u32 *)
+ bus_to_virt(cmd->saved_data_pointer) + size, "", 1);
+ print_progress (c);
+ }
+#if 0
+ printk ("scsi%d : datapath residual %d\n",
+ host->host_no, datapath_residual (host)) ;
+#endif
+ }
+ return SPECIFIC_INT_RESTART;
+#endif
+#ifdef A_int_debug_sync
+ case A_int_debug_sync:
+ if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR|
+ OPTION_DEBUG_DISCONNECT|OPTION_DEBUG_SDTR)) {
+ unsigned char sxfer = NCR53c7x0_read8 (SXFER_REG), scntl3;
+ if ((hostdata->chip / 100) == 8) {
+ scntl3 = NCR53c7x0_read8 (SCNTL3_REG_800);
+ if (c) {
+ if (sxfer != hostdata->sync[c->target].sxfer_sanity ||
+ scntl3 != hostdata->sync[c->target].scntl3_sanity) {
+ printk ("scsi%d : sync sanity check failed sxfer=0x%x, scntl3=0x%x",
+ host->host_no, sxfer, scntl3);
+ NCR53c7x0_write8 (SXFER_REG, sxfer);
+ NCR53c7x0_write8 (SCNTL3_REG_800, scntl3);
+ }
+ } else
+ printk ("scsi%d : unknown command sxfer=0x%x, scntl3=0x%x\n",
+ host->host_no, (int) sxfer, (int) scntl3);
+ } else {
+ if (c) {
+ if (sxfer != hostdata->sync[c->target].sxfer_sanity) {
+ printk ("scsi%d : sync sanity check failed sxfer=0x%x",
+ host->host_no, sxfer);
+ NCR53c7x0_write8 (SXFER_REG, sxfer);
+ NCR53c7x0_write8 (SBCL_REG,
+ hostdata->sync[c->target].sscf_710);
+ }
+ } else
+ printk ("scsi%d : unknown command sxfer=0x%x\n",
+ host->host_no, (int) sxfer);
+ }
+ }
+ return SPECIFIC_INT_RESTART;
+#endif
+#ifdef A_int_debug_datain
+ case A_int_debug_datain:
+ if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR|
+ OPTION_DEBUG_DISCONNECT|OPTION_DEBUG_SDTR)) {
+ int size;
+ if ((hostdata->chip / 100) == 8)
+ printk ("scsi%d : In do_datain (%s) sxfer=0x%x, scntl3=0x%x\n"
+ " datapath residual=%d\n",
+ host->host_no, sbcl_to_phase (NCR53c7x0_read8 (SBCL_REG)),
+ (int) NCR53c7x0_read8(SXFER_REG),
+ (int) NCR53c7x0_read8(SCNTL3_REG_800),
+ datapath_residual (host)) ;
+ else
+ printk ("scsi%d : In do_datain (%s) sxfer=0x%x\n"
+ " datapath residual=%d\n",
+ host->host_no, sbcl_to_phase (NCR53c7x0_read8 (SBCL_REG)),
+ (int) NCR53c7x0_read8(SXFER_REG),
+ datapath_residual (host)) ;
+ print_insn (host, dsp, "", 1);
+ size = print_insn (host, (u32 *) bus_to_virt(dsp[1]), "", 1);
+ print_insn (host, (u32 *) bus_to_virt(dsp[1]) + size, "", 1);
+ }
+ return SPECIFIC_INT_RESTART;
+#endif
+#ifdef A_int_debug_check_dsa
+ case A_int_debug_check_dsa:
+ if (NCR53c7x0_read8 (SCNTL1_REG) & SCNTL1_CON) {
+ int sdid;
+ int tmp;
+ char *where;
+ if (hostdata->chip / 100 == 8)
+ sdid = NCR53c7x0_read8 (SDID_REG_800) & 15;
+ else {
+ tmp = NCR53c7x0_read8 (SDID_REG_700);
+ if (!tmp)
+ panic ("SDID_REG_700 = 0");
+ tmp >>= 1;
+ sdid = 0;
+ while (tmp) {
+ tmp >>= 1;
+ sdid++;
+ }
+ }
+ where = dsp - NCR53c7x0_insn_size(NCR53c7x0_read8
+ (DCMD_REG)) == hostdata->script +
+ Ent_select_check_dsa / sizeof(u32) ?
+ "selection" : "reselection";
+ if (c && sdid != c->target) {
+ printk ("scsi%d : SDID target %d != DSA target %d at %s\n",
+ host->host_no, sdid, c->target, where);
+ print_lots(host);
+ dump_events (host, 20);
+ return SPECIFIC_INT_PANIC;
+ }
+ }
+ return SPECIFIC_INT_RESTART;
+#endif
+ default:
+ if ((dsps & 0xff000000) == 0x03000000) {
+ printk ("scsi%d : misc debug interrupt 0x%x\n",
+ host->host_no, dsps);
+ return SPECIFIC_INT_RESTART;
+ } else if ((dsps & 0xff000000) == 0x05000000) {
+ if (hostdata->events) {
+ struct NCR53c7x0_event *event;
+ ++hostdata->event_index;
+ if (hostdata->event_index >= hostdata->event_size)
+ hostdata->event_index = 0;
+ event = (struct NCR53c7x0_event *) hostdata->events +
+ hostdata->event_index;
+ event->event = (enum ncr_event) dsps;
+ event->dsa = bus_to_virt(NCR53c7x0_read32(DSA_REG));
+ if (NCR53c7x0_read8 (SCNTL1_REG) & SCNTL1_CON) {
+ if (hostdata->chip / 100 == 8)
+ event->target = NCR53c7x0_read8(SSID_REG_800);
+ else {
+ unsigned char tmp, sdid;
+ tmp = NCR53c7x0_read8 (SDID_REG_700);
+ if (!tmp)
+ panic ("SDID_REG_700 = 0");
+ tmp >>= 1;
+ sdid = 0;
+ while (tmp) {
+ tmp >>= 1;
+ sdid++;
+ }
+ event->target = sdid;
+ }
+ }
+ else
+ event->target = 255;
+
+ if (event->event == EVENT_RESELECT)
+ event->lun = hostdata->reselected_identify & 0xf;
+ else if (c)
+ event->lun = c->lun;
+ else
+ event->lun = 255;
+ do_gettimeofday(&(event->time));
+ if (c) {
+ event->pid = c->pid;
+ memcpy ((void *) event->cmnd, (void *) c->cmnd,
+ sizeof (event->cmnd));
+ } else {
+ event->pid = -1;
+ }
+ }
+ return SPECIFIC_INT_RESTART;
+ }
+
+ printk ("scsi%d : unknown user interrupt 0x%x\n",
+ host->host_no, (unsigned) dsps);
+ return SPECIFIC_INT_PANIC;
+ }
+flush_cache_all();
+cache_push(virt_to_bus(hostdata->script), flushsize);
+cache_clear(virt_to_bus(hostdata->script), flushsize);
+}
+
+/*
+ * XXX - the stock NCR assembler won't output the scriptu.h file,
+ * which undefine's all #define'd CPP symbols from the script.h
+ * file, which will create problems if you use multiple scripts
+ * with the same symbol names.
+ *
+ * If you insist on using NCR's assembler, you could generate
+ * scriptu.h from script.h using something like
+ *
+ * grep #define script.h | \
+ * sed 's/#define[ ][ ]*\([_a-zA-Z][_a-zA-Z0-9]*\).*$/#undefine \1/' \
+ * > scriptu.h
+ */
+
+#include "53c7xx_u.h"
+
+/* XXX - add alternate script handling code here */
+
+
+/*
+ * Function : static void NCR537xx_soft_reset (struct Scsi_Host *host)
+ *
+ * Purpose : perform a soft reset of the NCR53c7xx chip
+ *
+ * Inputs : host - pointer to this host adapter's structure
+ *
+ * Preconditions : NCR53c7x0_init must have been called for this
+ * host.
+ *
+ */
+
+static void
+NCR53c7x0_soft_reset (struct Scsi_Host *host) {
+ NCR53c7x0_local_declare();
+ unsigned long flags;
+#ifdef CONFIG_MVME166
+ volatile unsigned long v;
+#endif
+ struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+ host->hostdata;
+ NCR53c7x0_local_setup(host);
+
+ save_flags(flags);
+ cli();
+
+ /* Disable scsi chip and s/w level 7 ints */
+
+#ifdef CONFIG_MVME166
+ v = *(volatile unsigned long *)0xfff4006c;
+ v &= ~0x8000;
+ *(volatile unsigned long *)0xfff4006c = v;
+ v = *(volatile unsigned long *)0xfff4202c;
+ v &= ~0x10;
+ *(volatile unsigned long *)0xfff4202c = v;
+#else
+ /* Anything specific for your hardware? */
+#endif
+
+ /*
+ * Do a soft reset of the chip so that everything is
+ * reinitialized to the power-on state.
+ *
+ * Basically follow the procedure outlined in the NCR53c700
+ * data manual under Chapter Six, How to Use, Steps Necessary to
+ * Start SCRIPTS, with the exception of actually starting the
+ * script and setting up the synchronous transfer gunk.
+ */
+
+ /* Should we reset the scsi bus here??????????????????? */
+
+ NCR53c7x0_write8(ISTAT_REG_700, ISTAT_10_SRST);
+ NCR53c7x0_write8(ISTAT_REG_700, 0);
+
+ /*
+ * saved_dcntl is set up in NCR53c7x0_init() before it is overwritten
+ * here. We should have some better way of working out the CF bit
+ * setting..
+ */
+
+ hostdata->saved_dcntl = DCNTL_10_EA|DCNTL_10_COM;
+ if (hostdata->scsi_clock > 50000000)
+ hostdata->saved_dcntl |= DCNTL_700_CF_3;
+ else
+ if (hostdata->scsi_clock > 37500000)
+ hostdata->saved_dcntl |= DCNTL_700_CF_2;
+#if 0
+ else
+ /* Any clocks less than 37.5MHz? */
+#endif
+
+ if (hostdata->options & OPTION_DEBUG_TRACE)
+ NCR53c7x0_write8(DCNTL_REG, hostdata->saved_dcntl | DCNTL_SSM);
+ else
+ NCR53c7x0_write8(DCNTL_REG, hostdata->saved_dcntl);
+#if 0
+ /* Following disables snooping - run with caches disabled at first */
+ NCR53c7x0_write8(CTEST7_REG, CTEST7_10_TT1|CTEST7_STD);
+#else
+ /* Setup CTEST7 for SC1=0, SC0=1 - sink/source data without invalidating
+ * cache lines. */
+ NCR53c7x0_write8(CTEST7_REG, CTEST7_10_TT1|CTEST7_STD|CTEST7_10_SC0);
+#endif
+ /* Actually burst of eight, according to my 53c710 databook */
+ NCR53c7x0_write8(hostdata->dmode, DMODE_10_BL_8 | DMODE_10_FC2);
+ NCR53c7x0_write8(SCID_REG, 1 << host->this_id);
+ NCR53c7x0_write8(SBCL_REG, 0);
+ NCR53c7x0_write8(SCNTL1_REG, SCNTL1_ESR_700);
+ NCR53c7x0_write8(SCNTL0_REG, ((hostdata->options & OPTION_PARITY) ?
+ SCNTL0_EPC : 0) | SCNTL0_EPG_700 | SCNTL0_ARB1 | SCNTL0_ARB2);
+
+ /*
+ * Enable all interrupts, except parity which we only want when
+ * the user requests it.
+ */
+
+ NCR53c7x0_write8(DIEN_REG, DIEN_700_BF |
+ DIEN_ABRT | DIEN_SSI | DIEN_SIR | DIEN_700_OPC);
+
+ NCR53c7x0_write8(SIEN_REG_700, ((hostdata->options & OPTION_PARITY) ?
+ SIEN_PAR : 0) | SIEN_700_STO | SIEN_RST | SIEN_UDC |
+ SIEN_SGE | SIEN_MA);
+
+#ifdef CONFIG_MVME166
+ /* Enable scsi chip and s/w level 7 ints */
+
+ v = *(volatile unsigned long *)0xfff40080;
+ v = (v & ~(0xf << 28)) | (4 << 28);
+ *(volatile unsigned long *)0xfff40080 = v;
+ v = *(volatile unsigned long *)0xfff4006c;
+ v |= 0x8000;
+ *(volatile unsigned long *)0xfff4006c = v;
+ v = *(volatile unsigned long *)0xfff4202c;
+ v = (v & ~0xff) | 0x10 | 4;
+ *(volatile unsigned long *)0xfff4202c = v;
+#else
+ /* Anything needed for your hardware */
+#endif
+ restore_flags(flags);
+}
+
+
+/*
+ * Function static struct NCR53c7x0_cmd *allocate_cmd (Scsi_Cmnd *cmd)
+ *
+ * Purpose : Return the first free NCR53c7x0_cmd structure (which are
+ * reused in a LIFO manner to minimize cache thrashing).
+ *
+ * Side effects : If we haven't yet scheduled allocation of NCR53c7x0_cmd
+ * structures for this device, do so. Attempt to complete all scheduled
+ * allocations using kmalloc(), putting NCR53c7x0_cmd structures on
+ * the free list. Teach programmers not to drink and hack.
+ *
+ * Inputs : cmd - SCSI command
+ *
+ * Returns : NCR53c7x0_cmd structure allocated on behalf of cmd;
+ * NULL on failure.
+ */
+
+static struct NCR53c7x0_cmd *
+allocate_cmd (Scsi_Cmnd *cmd) {
+ struct Scsi_Host *host = cmd->host;
+ struct NCR53c7x0_hostdata *hostdata =
+ (struct NCR53c7x0_hostdata *) host->hostdata;
+ void *real; /* Real address */
+ int size; /* Size of *tmp */
+ struct NCR53c7x0_cmd *tmp;
+ unsigned long flags;
+
+ if (hostdata->options & OPTION_DEBUG_ALLOCATION)
+ printk ("scsi%d : num_cmds = %d, can_queue = %d\n"
+ " target = %d, lun = %d, %s\n",
+ host->host_no, hostdata->num_cmds, host->can_queue,
+ cmd->target, cmd->lun, (hostdata->cmd_allocated[cmd->target] &
+ (1 << cmd->lun)) ? "already allocated" : "not allocated");
+
+/*
+ * If we have not yet reserved commands for this I_T_L nexus, and
+ * the device exists (as indicated by permanent Scsi_Cmnd structures
+ * being allocated under 1.3.x, or being outside of scan_scsis in
+ * 1.2.x), do so now.
+ */
+ if (!(hostdata->cmd_allocated[cmd->target] & (1 << cmd->lun)) &&
+ cmd->device && cmd->device->has_cmdblocks) {
+ if ((hostdata->extra_allocate + hostdata->num_cmds) < host->can_queue)
+ hostdata->extra_allocate += host->cmd_per_lun;
+ hostdata->cmd_allocated[cmd->target] |= (1 << cmd->lun);
+ }
+
+ for (; hostdata->extra_allocate > 0 ; --hostdata->extra_allocate,
+ ++hostdata->num_cmds) {
+ /* historically, kmalloc has returned unaligned addresses; pad so we
+ have enough room to ROUNDUP */
+ size = hostdata->max_cmd_size + sizeof (void *);
+#ifdef FORCE_DSA_ALIGNMENT
+ /*
+ * 53c710 rev.0 doesn't have an add-with-carry instruction.
+ * Ensure we allocate enough memory to force alignment.
+ */
+ size += 256;
+#endif
+/* FIXME: for ISA bus '7xx chips, we need to or GFP_DMA in here */
+ real = kmalloc (size, GFP_ATOMIC);
+ if (!real) {
+ if (hostdata->options & OPTION_DEBUG_ALLOCATION)
+ printk ("scsi%d : kmalloc(%d) failed\n",
+ host->host_no, size);
+ break;
+ }
+ tmp = ROUNDUP(real, void *);
+#ifdef FORCE_DSA_ALIGNMENT
+ {
+ if (((u32)tmp & 0xff) > CmdPageStart)
+ tmp = (struct NCR53c7x0_cmd *)((u32)tmp + 255);
+ tmp = (struct NCR53c7x0_cmd *)(((u32)tmp & ~0xff) + CmdPageStart);
+#ifdef DEBUG
+ printk ("scsi: size = %d, real = 0x%08x, tmp set to 0x%08x\n",
+ size, (u32)real, (u32)tmp);
+#endif
+ }
+#endif
+ tmp->real = real;
+ tmp->size = size;
+ tmp->free = ((void (*)(void *, int)) kfree);
+ save_flags (flags);
+ cli();
+ tmp->next = hostdata->free;
+ hostdata->free = tmp;
+ restore_flags (flags);
+ }
+ save_flags(flags);
+ cli();
+ tmp = (struct NCR53c7x0_cmd *) hostdata->free;
+ if (tmp) {
+ hostdata->free = tmp->next;
+ }
+ restore_flags(flags);
+ if (!tmp)
+ printk ("scsi%d : can't allocate command for target %d lun %d\n",
+ host->host_no, cmd->target, cmd->lun);
+ return tmp;
+}
+
+/*
+ * Function static struct NCR53c7x0_cmd *create_cmd (Scsi_Cmnd *cmd)
+ *
+ *
+ * Purpose : allocate a NCR53c7x0_cmd structure, initialize it based on the
+ * Scsi_Cmnd structure passed in cmd, including dsa and Linux field
+ * initialization, and dsa code relocation.
+ *
+ * Inputs : cmd - SCSI command
+ *
+ * Returns : NCR53c7x0_cmd structure corresponding to cmd,
+ * NULL on failure.
+ */
+static struct NCR53c7x0_cmd *
+create_cmd (Scsi_Cmnd *cmd) {
+ NCR53c7x0_local_declare();
+ struct Scsi_Host *host = cmd->host;
+ struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+ host->hostdata;
+ struct NCR53c7x0_cmd *tmp; /* NCR53c7x0_cmd structure for this command */
+ int datain, /* Number of instructions per phase */
+ dataout;
+ int data_transfer_instructions, /* Count of dynamic instructions */
+ i; /* Counter */
+ u32 *cmd_datain, /* Address of datain/dataout code */
+ *cmd_dataout; /* Incremented as we assemble */
+#ifdef notyet
+ unsigned char *msgptr; /* Current byte in select message */
+ int msglen; /* Length of whole select message */
+#endif
+ unsigned long flags;
+ u32 exp_select_indirect; /* Used in sanity check */
+ NCR53c7x0_local_setup(cmd->host);
+
+ if (!(tmp = allocate_cmd (cmd)))
+ return NULL;
+
+
+ /*
+ * Decide whether we need to generate commands for DATA IN,
+ * DATA OUT, neither, or both based on the SCSI command
+ */
+
+ switch (cmd->cmnd[0]) {
+ /* These commands do DATA IN */
+ case INQUIRY:
+ case MODE_SENSE:
+ case READ_6:
+ case READ_10:
+ case READ_CAPACITY:
+ case REQUEST_SENSE:
+ datain = 2 * (cmd->use_sg ? cmd->use_sg : 1) + 3;
+ dataout = 0;
+ break;
+ /* These commands do DATA OUT */
+ case MODE_SELECT:
+ case WRITE_6:
+ case WRITE_10:
+ case START_STOP: /* also SCAN, which may do DATA OUT */
+#if 0
+ printk("scsi%d : command is ", host->host_no);
+ print_command(cmd->cmnd);
+#endif
+#if 0
+ printk ("scsi%d : %d scatter/gather segments\n", host->host_no,
+ cmd->use_sg);
+#endif
+ datain = 0;
+ dataout = 2 * (cmd->use_sg ? cmd->use_sg : 1) + 3;
+#if 0
+ hostdata->options |= OPTION_DEBUG_INTR;
+#endif
+ break;
+ /*
+ * These commands do no data transfer, we should force an
+ * interrupt if a data phase is attempted on them.
+ */
+ case TEST_UNIT_READY:
+ datain = dataout = 0;
+ break;
+ /*
+ * We don't know about these commands, so generate code to handle
+ * both DATA IN and DATA OUT phases.
+ */
+ default:
+ datain = dataout = 2 * (cmd->use_sg ? cmd->use_sg : 1) + 3;
+ }
+
+ /*
+ * New code : so that active pointers work correctly regardless
+ * of where the saved data pointer is at, we want to immediately
+ * enter the dynamic code after selection, and on a non-data
+ * phase perform a CALL to the non-data phase handler, with
+ * returns back to this address.
+ *
+ * If a phase mismatch is encountered in the middle of a
+ * Block MOVE instruction, we want to _leave_ that instruction
+ * unchanged as the current case is, modify a temporary buffer,
+ * and point the active pointer (TEMP) at that.
+ *
+ * Furthermore, we want to implement a saved data pointer,
+ * set by the SAVE_DATA_POINTERs message.
+ *
+ * So, the data transfer segments will change to
+ * CALL data_transfer, WHEN NOT data phase
+ * MOVE x, x, WHEN data phase
+ * ( repeat )
+ * JUMP other_transfer
+ */
+
+ data_transfer_instructions = datain + dataout;
+
+ /*
+ * When we perform a request sense, we overwrite various things,
+ * including the data transfer code. Make sure we have enough
+ * space to do that.
+ */
+
+ if (data_transfer_instructions < 2)
+ data_transfer_instructions = 2;
+
+
+ /*
+ * The saved data pointer is set up so that a RESTORE POINTERS message
+ * will start the data transfer over at the begining.
+ */
+
+ tmp->saved_data_pointer = virt_to_bus (hostdata->script) +
+ hostdata->E_data_transfer;
+
+ /*
+ * Initialize Linux specific fields.
+ */
+
+ tmp->cmd = cmd;
+ tmp->next = NULL;
+ tmp->flags = 0;
+ tmp->dsa_next_addr = virt_to_bus(tmp->dsa) + hostdata->dsa_next -
+ hostdata->dsa_start;
+ tmp->dsa_addr = virt_to_bus(tmp->dsa) - hostdata->dsa_start;
+
+ /*
+ * Calculate addresses of dynamic code to fill in DSA
+ */
+
+ tmp->data_transfer_start = tmp->dsa + (hostdata->dsa_end -
+ hostdata->dsa_start) / sizeof(u32);
+ tmp->data_transfer_end = tmp->data_transfer_start +
+ 2 * data_transfer_instructions;
+
+ cmd_datain = datain ? tmp->data_transfer_start : NULL;
+ cmd_dataout = dataout ? (datain ? cmd_datain + 2 * datain : tmp->
+ data_transfer_start) : NULL;
+
+ /*
+ * Fill in the NCR53c7x0_cmd structure as follows
+ * dsa, with fixed up DSA code
+ * datain code
+ * dataout code
+ */
+
+ /* Copy template code into dsa and perform all necessary fixups */
+ if (hostdata->dsa_fixup)
+ hostdata->dsa_fixup(tmp);
+
+ patch_dsa_32(tmp->dsa, dsa_next, 0, 0);
+ patch_dsa_32(tmp->dsa, dsa_cmnd, 0, virt_to_bus(cmd));
+
+flush_cache_all();
+cache_push(virt_to_bus(hostdata->script), flushsize);
+cache_clear(virt_to_bus(hostdata->script), flushsize);
+
+ if (hostdata->options & OPTION_DEBUG_SYNCHRONOUS) {
+
+ exp_select_indirect = ((1 << cmd->target) << 16) |
+ (hostdata->sync[cmd->target].sxfer_sanity << 8);
+
+ if (hostdata->sync[cmd->target].select_indirect !=
+ exp_select_indirect) {
+ printk ("scsi%d : sanity check failed select_indirect=0x%x\n",
+ host->host_no, hostdata->sync[cmd->target].select_indirect);
+ FATAL(host);
+
+ }
+ }
+
+ patch_dsa_32(tmp->dsa, dsa_select, 0,
+ hostdata->sync[cmd->target].select_indirect);
+
+
+flush_cache_all();
+cache_push(virt_to_bus(hostdata->script), flushsize);
+cache_clear(virt_to_bus(hostdata->script), flushsize);
+
+ /*
+ * Right now, we'll do the WIDE and SYNCHRONOUS negotiations on
+ * different commands; although it should be trivial to do them
+ * both at the same time.
+ */
+ if (hostdata->initiate_wdtr & (1 << cmd->target)) {
+ memcpy ((void *) (tmp->select + 1), (void *) wdtr_message,
+ sizeof(wdtr_message));
+ patch_dsa_32(tmp->dsa, dsa_msgout, 0, 1 + sizeof(wdtr_message));
+ save_flags(flags);
+ cli();
+ hostdata->initiate_wdtr &= ~(1 << cmd->target);
+ restore_flags(flags);
+ } else if (hostdata->initiate_sdtr & (1 << cmd->target)) {
+ memcpy ((void *) (tmp->select + 1), (void *) sdtr_message,
+ sizeof(sdtr_message));
+ patch_dsa_32(tmp->dsa, dsa_msgout, 0, 1 + sizeof(sdtr_message));
+ tmp->flags |= CMD_FLAG_SDTR;
+ save_flags(flags);
+ cli();
+ hostdata->initiate_sdtr &= ~(1 << cmd->target);
+ restore_flags(flags);
+
+ }
+#if 1
+ else if (!(hostdata->talked_to & (1 << cmd->target)) &&
+ !(hostdata->options & OPTION_NO_ASYNC)) {
+
+flush_cache_all();
+cache_push(virt_to_bus(hostdata->script), flushsize);
+cache_clear(virt_to_bus(hostdata->script), flushsize);
+
+ memcpy ((void *) (tmp->select + 1), (void *) async_message,
+ sizeof(async_message));
+ patch_dsa_32(tmp->dsa, dsa_msgout, 0, 1 + sizeof(async_message));
+ tmp->flags |= CMD_FLAG_SDTR;
+ }
+#endif
+ else
+ patch_dsa_32(tmp->dsa, dsa_msgout, 0, 1);
+
+flush_cache_all();
+cache_push(virt_to_bus(hostdata->script), flushsize);
+cache_clear(virt_to_bus(hostdata->script), flushsize);
+
+ hostdata->talked_to |= (1 << cmd->target);
+ tmp->select[0] = (hostdata->options & OPTION_DISCONNECT) ?
+ IDENTIFY (1, cmd->lun) : IDENTIFY (0, cmd->lun);
+ patch_dsa_32(tmp->dsa, dsa_msgout, 1, virt_to_bus(tmp->select));
+ patch_dsa_32(tmp->dsa, dsa_cmdout, 0, cmd->cmd_len);
+ patch_dsa_32(tmp->dsa, dsa_cmdout, 1, virt_to_bus(cmd->cmnd));
+ patch_dsa_32(tmp->dsa, dsa_dataout, 0, cmd_dataout ?
+ virt_to_bus (cmd_dataout)
+ : virt_to_bus (hostdata->script) + hostdata->E_other_transfer);
+ patch_dsa_32(tmp->dsa, dsa_datain, 0, cmd_datain ?
+ virt_to_bus (cmd_datain)
+ : virt_to_bus (hostdata->script) + hostdata->E_other_transfer);
+ /*
+ * XXX - need to make endian aware, should use separate variables
+ * for both status and message bytes.
+ */
+ patch_dsa_32(tmp->dsa, dsa_msgin, 0, 1);
+/*
+ * FIXME : these only works for little endian. We probably want to
+ * provide message and status fields in the NCR53c7x0_cmd
+ * structure, and assign them to cmd->result when we're done.
+ */
+#ifdef BIG_ENDIAN
+ patch_dsa_32(tmp->dsa, dsa_msgin, 1, virt_to_bus(&cmd->result) + 2);
+ patch_dsa_32(tmp->dsa, dsa_status, 0, 1);
+ patch_dsa_32(tmp->dsa, dsa_status, 1, virt_to_bus(&cmd->result) + 3);
+#else
+ patch_dsa_32(tmp->dsa, dsa_msgin, 1, virt_to_bus(&cmd->result) + 1);
+ patch_dsa_32(tmp->dsa, dsa_status, 0, 1);
+ patch_dsa_32(tmp->dsa, dsa_status, 1, virt_to_bus(&cmd->result));
+#endif
+ patch_dsa_32(tmp->dsa, dsa_msgout_other, 0, 1);
+ patch_dsa_32(tmp->dsa, dsa_msgout_other, 1,
+ virt_to_bus(&(hostdata->NCR53c7xx_msg_nop)));
+
+ /*
+ * Generate code for zero or more of the DATA IN, DATA OUT phases
+ * in the format
+ *
+ * CALL data_transfer, WHEN NOT phase
+ * MOVE first buffer length, first buffer address, WHEN phase
+ * ...
+ * MOVE last buffer length, last buffer address, WHEN phase
+ * JUMP other_transfer
+ */
+
+/*
+ * See if we're getting to data transfer by generating an unconditional
+ * interrupt.
+ */
+#if 0
+ if (datain) {
+ cmd_datain[0] = 0x98080000;
+ cmd_datain[1] = 0x03ffd00d;
+ cmd_datain += 2;
+ }
+#endif
+
+/*
+ * XXX - I'm undecided whether all of this nonsense is faster
+ * in the long run, or whether I should just go and implement a loop
+ * on the NCR chip using table indirect mode?
+ *
+ * In any case, this is how it _must_ be done for 53c700/700-66 chips,
+ * so this stays even when we come up with something better.
+ *
+ * When we're limited to 1 simultaneous command, no overlapping processing,
+ * we're seeing 630K/sec, with 7% CPU usage on a slow Syquest 45M
+ * drive.
+ *
+ * Not bad, not good. We'll see.
+ */
+
+flush_cache_all();
+cache_push(virt_to_bus(hostdata->script), flushsize);
+cache_clear(virt_to_bus(hostdata->script), flushsize);
+
+
+ for (i = 0; cmd->use_sg ? (i < cmd->use_sg) : !i; cmd_datain += 4,
+ cmd_dataout += 4, ++i) {
+ u32 buf = cmd->use_sg ?
+ virt_to_bus(((struct scatterlist *)cmd->buffer)[i].address) :
+ virt_to_bus(cmd->request_buffer);
+ u32 count = cmd->use_sg ?
+ ((struct scatterlist *)cmd->buffer)[i].length :
+ cmd->request_bufflen;
+
+ if (datain) {
+ /* CALL other_in, WHEN NOT DATA_IN */
+ cmd_datain[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_CALL |
+ DCMD_TCI_IO) << 24) |
+ DBC_TCI_WAIT_FOR_VALID | DBC_TCI_COMPARE_PHASE;
+ cmd_datain[1] = virt_to_bus (hostdata->script) +
+ hostdata->E_other_in;
+ /* MOVE count, buf, WHEN DATA_IN */
+ cmd_datain[2] = ((DCMD_TYPE_BMI | DCMD_BMI_OP_MOVE_I | DCMD_BMI_IO)
+ << 24) | count;
+ cmd_datain[3] = buf;
+#if 0
+ print_insn (host, cmd_datain, "dynamic ", 1);
+ print_insn (host, cmd_datain + 2, "dynamic ", 1);
+#endif
+ }
+ if (dataout) {
+ /* CALL other_out, WHEN NOT DATA_OUT */
+ cmd_dataout[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_CALL) << 24) |
+ DBC_TCI_WAIT_FOR_VALID | DBC_TCI_COMPARE_PHASE;
+ cmd_dataout[1] = virt_to_bus(hostdata->script) +
+ hostdata->E_other_out;
+ /* MOVE count, buf, WHEN DATA+OUT */
+ cmd_dataout[2] = ((DCMD_TYPE_BMI | DCMD_BMI_OP_MOVE_I) << 24)
+ | count;
+ cmd_dataout[3] = buf;
+#if 0
+ print_insn (host, cmd_dataout, "dynamic ", 1);
+ print_insn (host, cmd_dataout + 2, "dynamic ", 1);
+#endif
+ }
+ }
+
+flush_cache_all();
+cache_push(virt_to_bus(hostdata->script), flushsize);
+cache_clear(virt_to_bus(hostdata->script), flushsize);
+
+
+ /*
+ * Install JUMP instructions after the data transfer routines to return
+ * control to the do_other_transfer routines.
+ */
+
+
+ if (datain) {
+ cmd_datain[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_JUMP) << 24) |
+ DBC_TCI_TRUE;
+ cmd_datain[1] = virt_to_bus(hostdata->script) +
+ hostdata->E_other_transfer;
+#if 0
+ print_insn (host, cmd_datain, "dynamic jump ", 1);
+#endif
+ cmd_datain += 2;
+ }
+#if 0
+ if (datain) {
+ cmd_datain[0] = 0x98080000;
+ cmd_datain[1] = 0x03ffdeed;
+ cmd_datain += 2;
+ }
+#endif
+ if (dataout) {
+ cmd_dataout[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_JUMP) << 24) |
+ DBC_TCI_TRUE;
+ cmd_dataout[1] = virt_to_bus(hostdata->script) +
+ hostdata->E_other_transfer;
+#if 0
+ print_insn (host, cmd_dataout, "dynamic jump ", 1);
+#endif
+ cmd_dataout += 2;
+ }
+
+flush_cache_all();
+cache_push(virt_to_bus(hostdata->script), flushsize);
+cache_clear(virt_to_bus(hostdata->script), flushsize);
+
+ return tmp;
+}
+
+/*
+ * Function : int NCR53c7xx_queue_command (Scsi_Cmnd *cmd,
+ * void (*done)(Scsi_Cmnd *))
+ *
+ * Purpose : enqueues a SCSI command
+ *
+ * Inputs : cmd - SCSI command, done - function called on completion, with
+ * a pointer to the command descriptor.
+ *
+ * Returns : 0
+ *
+ * Side effects :
+ * cmd is added to the per instance driver issue_queue, with major
+ * twiddling done to the host specific fields of cmd. If the
+ * process_issue_queue coroutine isn't running, it is restarted.
+ *
+ * NOTE : we use the host_scribble field of the Scsi_Cmnd structure to
+ * hold our own data, and pervert the ptr field of the SCp field
+ * to create a linked list.
+ */
+
+int
+NCR53c7xx_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)) {
+ struct Scsi_Host *host = cmd->host;
+ struct NCR53c7x0_hostdata *hostdata =
+ (struct NCR53c7x0_hostdata *) host->hostdata;
+ unsigned long flags;
+ Scsi_Cmnd *tmp;
+
+ cmd->scsi_done = done;
+ cmd->host_scribble = NULL;
+ cmd->SCp.ptr = NULL;
+ cmd->SCp.buffer = NULL;
+
+#ifdef VALID_IDS
+ /* Ignore commands on invalid IDs */
+ if (!hostdata->valid_ids[cmd->target]) {
+ printk("scsi%d : ignoring target %d lun %d\n", host->host_no,
+ cmd->target, cmd->lun);
+ cmd->result = (DID_BAD_TARGET << 16);
+ done(cmd);
+ return 0;
+ }
+#endif
+
+ save_flags(flags);
+ cli();
+ if ((hostdata->options & (OPTION_DEBUG_INIT_ONLY|OPTION_DEBUG_PROBE_ONLY))
+ || ((hostdata->options & OPTION_DEBUG_TARGET_LIMIT) &&
+ !(hostdata->debug_lun_limit[cmd->target] & (1 << cmd->lun)))
+#ifdef LINUX_1_2
+ || cmd->target > 7
+#else
+ || cmd->target > host->max_id
+#endif
+ || cmd->target == host->this_id
+ || hostdata->state == STATE_DISABLED) {
+ printk("scsi%d : disabled or bad target %d lun %d\n", host->host_no,
+ cmd->target, cmd->lun);
+ cmd->result = (DID_BAD_TARGET << 16);
+ done(cmd);
+ restore_flags (flags);
+ return 0;
+ }
+
+ if ((hostdata->options & OPTION_DEBUG_NCOMMANDS_LIMIT) &&
+ (hostdata->debug_count_limit == 0)) {
+ printk("scsi%d : maximum commands exceeded\n", host->host_no);
+ cmd->result = (DID_BAD_TARGET << 16);
+ done(cmd);
+ restore_flags (flags);
+ return 0;
+ }
+
+ if (hostdata->options & OPTION_DEBUG_READ_ONLY) {
+ switch (cmd->cmnd[0]) {
+ case WRITE_6:
+ case WRITE_10:
+ printk("scsi%d : WRITE attempted with NO_WRITE debugging flag set\n",
+ host->host_no);
+ cmd->result = (DID_BAD_TARGET << 16);
+ done(cmd);
+ restore_flags (flags);
+ return 0;
+ }
+ }
+
+ if ((hostdata->options & OPTION_DEBUG_TARGET_LIMIT) &&
+ hostdata->debug_count_limit != -1)
+ --hostdata->debug_count_limit;
+
+ cmd->result = 0xffff; /* The NCR will overwrite message
+ and status with valid data */
+ cmd->host_scribble = (unsigned char *) tmp = create_cmd (cmd);
+
+ /*
+ * REQUEST SENSE commands are inserted at the head of the queue
+ * so that we do not clear the contingent allegiance condition
+ * they may be looking at.
+ */
+
+ if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) {
+ cmd->SCp.ptr = (unsigned char *) hostdata->issue_queue;
+ hostdata->issue_queue = cmd;
+ } else {
+ for (tmp = (Scsi_Cmnd *) hostdata->issue_queue; tmp->SCp.ptr;
+ tmp = (Scsi_Cmnd *) tmp->SCp.ptr);
+ tmp->SCp.ptr = (unsigned char *) cmd;
+ }
+ restore_flags (flags);
+ run_process_issue_queue();
+ return 0;
+}
+
+/*
+ * Function : void to_schedule_list (struct Scsi_Host *host,
+ * struct NCR53c7x0_hostdata * hostdata, Scsi_Cmnd *cmd)
+ *
+ * Purpose : takes a SCSI command which was just removed from the
+ * issue queue, and deals with it by inserting it in the first
+ * free slot in the schedule list or by terminating it immediately.
+ *
+ * Inputs :
+ * host - SCSI host adapter; hostdata - hostdata structure for
+ * this adapter; cmd - a pointer to the command; should have
+ * the host_scribble field initialized to point to a valid
+ *
+ * Side effects :
+ * cmd is added to the per instance schedule list, with minor
+ * twiddling done to the host specific fields of cmd.
+ *
+ */
+
+static __inline__ void
+to_schedule_list (struct Scsi_Host *host, struct NCR53c7x0_hostdata *hostdata,
+ struct NCR53c7x0_cmd *cmd) {
+ NCR53c7x0_local_declare();
+ Scsi_Cmnd *tmp = cmd->cmd;
+ unsigned long flags;
+ /* dsa start is negative, so subtraction is used */
+ volatile u32 *ncrcurrent;
+
+ int i;
+ NCR53c7x0_local_setup(host);
+#if 0
+ printk("scsi%d : new dsa is 0x%lx (virt 0x%p)\n", host->host_no,
+ virt_to_bus(hostdata->dsa), hostdata->dsa);
+#endif
+
+ save_flags(flags);
+ cli();
+
+ /*
+ * Work around race condition : if an interrupt fired and we
+ * got disabled forget about this command.
+ */
+
+ if (hostdata->state == STATE_DISABLED) {
+ printk("scsi%d : driver disabled\n", host->host_no);
+ tmp->result = (DID_BAD_TARGET << 16);
+ cmd->next = (struct NCR53c7x0_cmd *) hostdata->free;
+ hostdata->free = cmd;
+ tmp->scsi_done(tmp);
+ restore_flags (flags);
+ return;
+ }
+
+ for (i = host->can_queue, ncrcurrent = hostdata->schedule;
+ i > 0 && ncrcurrent[0] != hostdata->NOP_insn;
+ --i, ncrcurrent += 2 /* JUMP instructions are two words */);
+
+
+flush_cache_all();
+cache_push(virt_to_bus(hostdata->script), flushsize);
+cache_clear(virt_to_bus(hostdata->script), flushsize);
+
+ if (i > 0) {
+ ++hostdata->busy[tmp->target][tmp->lun];
+ cmd->next = hostdata->running_list;
+ hostdata->running_list = cmd;
+
+ /* Restore this instruction to a NOP once the command starts */
+ cmd->dsa [(hostdata->dsa_jump_dest - hostdata->dsa_start) /
+ sizeof(u32)] = (u32) virt_to_bus ((void *)ncrcurrent);
+ /* Replace the current jump operand. */
+ ncrcurrent[1] =
+ virt_to_bus ((void *) cmd->dsa) + hostdata->E_dsa_code_begin -
+ hostdata->E_dsa_code_template;
+ /* Replace the NOP instruction with a JUMP */
+ ncrcurrent[0] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24) |
+ DBC_TCI_TRUE;
+ } else {
+ printk ("scsi%d: no free slot\n", host->host_no);
+ disable(host);
+ tmp->result = (DID_ERROR << 16);
+ cmd->next = (struct NCR53c7x0_cmd *) hostdata->free;
+ hostdata->free = cmd;
+ tmp->scsi_done(tmp);
+ restore_flags (flags);
+ return;
+ }
+
+ cache_push(virt_to_bus(cmd->dsa), hostdata->dsa_len);
+ cache_push(virt_to_bus(ncrcurrent), sizeof(ncrcurrent));
+
+ /*
+ * If the NCR chip is in an idle state, start it running the scheduler
+ * immediately. Otherwise, signal the chip to jump to schedule as
+ * soon as it is idle.
+ */
+
+ if (hostdata->idle) {
+ hostdata->idle = 0;
+ hostdata->state = STATE_RUNNING;
+ NCR53c7x0_write32 (DSP_REG, virt_to_bus ((void *)hostdata->schedule));
+ if (hostdata->options & OPTION_DEBUG_TRACE)
+ NCR53c7x0_write8 (DCNTL_REG, hostdata->saved_dcntl |
+ DCNTL_SSM | DCNTL_STD);
+ } else {
+ NCR53c7x0_write8(hostdata->istat, ISTAT_10_SIGP);
+ }
+
+ restore_flags(flags);
+}
+
+/*
+ * Function : busyp (struct Scsi_Host *host, struct NCR53c7x0_hostdata
+ * *hostdata, Scsi_Cmnd *cmd)
+ *
+ * Purpose : decide if we can pass the given SCSI command on to the
+ * device in question or not.
+ *
+ * Returns : non-zero when we're busy, 0 when we aren't.
+ */
+
+static __inline__ int
+busyp (struct Scsi_Host *host, struct NCR53c7x0_hostdata *hostdata,
+ Scsi_Cmnd *cmd) {
+ /* FIXME : in the future, this needs to accommodate SCSI-II tagged
+ queuing, and we may be able to play with fairness here a bit.
+ */
+ return hostdata->busy[cmd->target][cmd->lun];
+}
+
+/*
+ * Function : process_issue_queue (void)
+ *
+ * Purpose : transfer commands from the issue queue to NCR start queue
+ * of each NCR53c7/8xx in the system, avoiding kernel stack
+ * overflows when the scsi_done() function is invoked recursively.
+ *
+ * NOTE : process_issue_queue exits with interrupts *disabled*, so the
+ * caller must reenable them if it desires.
+ *
+ * NOTE : process_issue_queue should be called from both
+ * NCR53c7x0_queue_command() and from the interrupt handler
+ * after command completion in case NCR53c7x0_queue_command()
+ * isn't invoked again but we've freed up resources that are
+ * needed.
+ */
+
+static void
+process_issue_queue (unsigned long flags) {
+ Scsi_Cmnd *tmp, *prev;
+ struct Scsi_Host *host;
+ struct NCR53c7x0_hostdata *hostdata;
+ int done;
+
+ /*
+ * We run (with interrupts disabled) until we're sure that none of
+ * the host adapters have anything that can be done, at which point
+ * we set process_issue_queue_running to 0 and exit.
+ *
+ * Interrupts are enabled before doing various other internal
+ * instructions, after we've decided that we need to run through
+ * the loop again.
+ *
+ */
+
+ do {
+ cli(); /* Freeze request queues */
+ done = 1;
+ for (host = first_host; host && host->hostt == the_template;
+ host = host->next) {
+ hostdata = (struct NCR53c7x0_hostdata *) host->hostdata;
+ cli();
+ if (hostdata->issue_queue) {
+ if (hostdata->state == STATE_DISABLED) {
+ tmp = (Scsi_Cmnd *) hostdata->issue_queue;
+ hostdata->issue_queue = (Scsi_Cmnd *) tmp->SCp.ptr;
+ tmp->result = (DID_BAD_TARGET << 16);
+ if (tmp->host_scribble) {
+ ((struct NCR53c7x0_cmd *)tmp->host_scribble)->next =
+ hostdata->free;
+ hostdata->free =
+ (struct NCR53c7x0_cmd *)tmp->host_scribble;
+ tmp->host_scribble = NULL;
+ }
+ tmp->scsi_done (tmp);
+ done = 0;
+ } else
+ for (tmp = (Scsi_Cmnd *) hostdata->issue_queue,
+ prev = NULL; tmp; prev = tmp, tmp = (Scsi_Cmnd *)
+ tmp->SCp.ptr)
+ if (!tmp->host_scribble ||
+ !busyp (host, hostdata, tmp)) {
+ if (prev)
+ prev->SCp.ptr = tmp->SCp.ptr;
+ else
+ hostdata->issue_queue = (Scsi_Cmnd *)
+ tmp->SCp.ptr;
+ tmp->SCp.ptr = NULL;
+ if (tmp->host_scribble) {
+ if (hostdata->options & OPTION_DEBUG_QUEUES)
+ printk ("scsi%d : moving command for target %d lun %d to start list\n",
+ host->host_no, tmp->target, tmp->lun);
+
+
+ to_schedule_list (host, hostdata,
+ (struct NCR53c7x0_cmd *)
+ tmp->host_scribble);
+ } else {
+ if (((tmp->result & 0xff) == 0xff) ||
+ ((tmp->result & 0xff00) == 0xff00)) {
+ printk ("scsi%d : danger Will Robinson!\n",
+ host->host_no);
+ tmp->result = DID_ERROR << 16;
+ disable (host);
+ }
+ tmp->scsi_done(tmp);
+ }
+ done = 0;
+ } /* if target/lun is not busy */
+ } /* if hostdata->issue_queue */
+ if (!done)
+ restore_flags (flags);
+ } /* for host */
+ } while (!done);
+ process_issue_queue_running = 0;
+}
+
+/*
+ * Function : static void intr_scsi (struct Scsi_Host *host,
+ * struct NCR53c7x0_cmd *cmd)
+ *
+ * Purpose : handle all SCSI interrupts, indicated by the setting
+ * of the SIP bit in the ISTAT register.
+ *
+ * Inputs : host, cmd - host and NCR command causing the interrupt, cmd
+ * may be NULL.
+ */
+
+static void
+intr_scsi (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
+ NCR53c7x0_local_declare();
+ struct NCR53c7x0_hostdata *hostdata =
+ (struct NCR53c7x0_hostdata *) host->hostdata;
+ unsigned char sstat0_sist0, sist1, /* Registers */
+ fatal; /* Did a fatal interrupt
+ occur ? */
+
+ NCR53c7x0_local_setup(host);
+
+ fatal = 0;
+
+ sstat0_sist0 = NCR53c7x0_read8(SSTAT0_REG);
+ sist1 = 0;
+
+ if (hostdata->options & OPTION_DEBUG_INTR)
+ printk ("scsi%d : SIST0 0x%0x, SIST1 0x%0x\n", host->host_no,
+ sstat0_sist0, sist1);
+
+ /* 250ms selection timeout */
+ if (sstat0_sist0 & SSTAT0_700_STO) {
+ fatal = 1;
+ if (hostdata->options & OPTION_DEBUG_INTR) {
+ printk ("scsi%d : Selection Timeout\n", host->host_no);
+ if (cmd) {
+ printk("scsi%d : target %d, lun %d, command ",
+ host->host_no, cmd->cmd->target, cmd->cmd->lun);
+ print_command (cmd->cmd->cmnd);
+ printk("scsi%d : dsp = 0x%x (virt 0x%p)\n", host->host_no,
+ NCR53c7x0_read32(DSP_REG),
+ bus_to_virt(NCR53c7x0_read32(DSP_REG)));
+ } else {
+ printk("scsi%d : no command\n", host->host_no);
+ }
+ }
+/*
+ * XXX - question : how do we want to handle the Illegal Instruction
+ * interrupt, which may occur before or after the Selection Timeout
+ * interrupt?
+ */
+
+ if (1) {
+ hostdata->idle = 1;
+ hostdata->expecting_sto = 0;
+
+ if (hostdata->test_running) {
+ hostdata->test_running = 0;
+ hostdata->test_completed = 3;
+ } else if (cmd) {
+ abnormal_finished(cmd, DID_BAD_TARGET << 16);
+ }
+#if 0
+ hostdata->intrs = 0;
+#endif
+ }
+ }
+
+/*
+ * FIXME : in theory, we can also get a UDC when a STO occurs.
+ */
+ if (sstat0_sist0 & SSTAT0_UDC) {
+ fatal = 1;
+ if (cmd) {
+ printk("scsi%d : target %d lun %d unexpected disconnect\n",
+ host->host_no, cmd->cmd->target, cmd->cmd->lun);
+ print_lots (host);
+ abnormal_finished(cmd, DID_ERROR << 16);
+ } else
+ printk("scsi%d : unexpected disconnect (no command)\n",
+ host->host_no);
+
+ hostdata->dsp = (u32 *) hostdata->schedule;
+ hostdata->dsp_changed = 1;
+ }
+
+ /* SCSI PARITY error */
+ if (sstat0_sist0 & SSTAT0_PAR) {
+ fatal = 1;
+ if (cmd && cmd->cmd) {
+ printk("scsi%d : target %d lun %d parity error.\n",
+ host->host_no, cmd->cmd->target, cmd->cmd->lun);
+ abnormal_finished (cmd, DID_PARITY << 16);
+ } else
+ printk("scsi%d : parity error\n", host->host_no);
+ /* Should send message out, parity error */
+
+ /* XXX - Reduce synchronous transfer rate! */
+ hostdata->dsp = hostdata->script + hostdata->E_initiator_abort /
+ sizeof(u32);
+ hostdata->dsp_changed = 1;
+ /* SCSI GROSS error */
+ }
+
+ if (sstat0_sist0 & SSTAT0_SGE) {
+ fatal = 1;
+ printk("scsi%d : gross error, saved2_dsa = 0x%x\n", host->host_no,
+ (unsigned int)hostdata->saved2_dsa);
+ print_lots (host);
+
+ /*
+ * A SCSI gross error may occur when we have
+ *
+ * - A synchronous offset which causes the SCSI FIFO to be overwritten.
+ *
+ * - A REQ which causes the maximum synchronous offset programmed in
+ * the SXFER register to be exceeded.
+ *
+ * - A phase change with an outstanding synchronous offset.
+ *
+ * - Residual data in the synchronous data FIFO, with a transfer
+ * other than a synchronous receive is started.$#
+ */
+
+
+ /* XXX Should deduce synchronous transfer rate! */
+ hostdata->dsp = hostdata->script + hostdata->E_initiator_abort /
+ sizeof(u32);
+ hostdata->dsp_changed = 1;
+ /* Phase mismatch */
+ }
+
+ if (sstat0_sist0 & SSTAT0_MA) {
+ fatal = 1;
+ if (hostdata->options & OPTION_DEBUG_INTR)
+ printk ("scsi%d : SSTAT0_MA\n", host->host_no);
+ intr_phase_mismatch (host, cmd);
+ }
+
+#if 0
+ if (sstat0_sist0 & SIST0_800_RSL)
+ printk ("scsi%d : Oh no Mr. Bill!\n", host->host_no);
+#endif
+
+/*
+ * If a fatal SCSI interrupt occurs, we must insure that the DMA and
+ * SCSI FIFOs were flushed.
+ */
+
+ if (fatal) {
+ if (!hostdata->dstat_valid) {
+ hostdata->dstat = NCR53c7x0_read8(DSTAT_REG);
+ hostdata->dstat_valid = 1;
+ }
+
+ if (!(hostdata->dstat & DSTAT_DFE)) {
+ printk ("scsi%d : DMA FIFO not empty\n", host->host_no);
+ /*
+ * Really need to check this code for 710 RGH.
+ * Havn't seen any problems, but maybe we should FLUSH before
+ * clearing sometimes.
+ */
+ NCR53c7x0_write8 (CTEST8_REG, CTEST8_10_CLF);
+ while (NCR53c7x0_read8 (CTEST8_REG) & CTEST8_10_CLF)
+ ;
+ hostdata->dstat |= DSTAT_DFE;
+ }
+ }
+}
+
+#ifdef CYCLIC_TRACE
+
+/*
+ * The following implements a cyclic log of instructions executed, if you turn
+ * TRACE on. It will also print the log for you. Very useful when debugging
+ * 53c710 support, possibly not really needed any more.
+ */
+
+u32 insn_log[4096];
+u32 insn_log_index = 0;
+
+void log1 (u32 i)
+{
+ insn_log[insn_log_index++] = i;
+ if (insn_log_index == 4096)
+ insn_log_index = 0;
+}
+
+void log_insn (u32 *ip)
+{
+ log1 ((u32)ip);
+ log1 (*ip);
+ log1 (*(ip+1));
+ if (((*ip >> 24) & DCMD_TYPE_MASK) == DCMD_TYPE_MMI)
+ log1 (*(ip+2));
+}
+
+void dump_log(void)
+{
+ int cnt = 0;
+ int i = insn_log_index;
+ int size;
+ struct Scsi_Host *host = first_host;
+
+ while (cnt < 4096) {
+ printk ("%08x (+%6x): ", insn_log[i], (insn_log[i] - (u32)&(((struct NCR53c7x0_hostdata *)host->hostdata)->script))/4);
+ if (++i == 4096)
+ i = 0;
+ cnt++;
+ if (((insn_log[i] >> 24) & DCMD_TYPE_MASK) == DCMD_TYPE_MMI)
+ size = 3;
+ else
+ size = 2;
+ while (size--) {
+ printk ("%08x ", insn_log[i]);
+ if (++i == 4096)
+ i = 0;
+ cnt++;
+ }
+ printk ("\n");
+ }
+}
+#endif
+
+/*
+ * Function : static void NCR53c7x0_intr (int irq, void *dev_id, struct pt_regs * regs)
+ *
+ * Purpose : handle NCR53c7x0 interrupts for all NCR devices sharing
+ * the same IRQ line.
+ *
+ * Inputs : Since we're using the SA_INTERRUPT interrupt handler
+ * semantics, irq indicates the interrupt which invoked
+ * this handler.
+ *
+ * On the 710 we simualte an INTFLY with a script interrupt, and the
+ * script interrupt handler will call back to this function.
+ */
+
+void
+NCR53c7x0_intr (int irq, void *dev_id, struct pt_regs * regs) {
+ NCR53c7x0_local_declare();
+ struct Scsi_Host *host; /* Host we are looking at */
+ unsigned char istat; /* Values of interrupt regs */
+ struct NCR53c7x0_hostdata *hostdata; /* host->hostdata */
+ struct NCR53c7x0_cmd *cmd, /* command which halted */
+ **cmd_prev_ptr;
+ u32 *dsa; /* DSA */
+ int done = 1; /* Indicates when handler
+ should terminate */
+ int interrupted = 0; /* This HA generated
+ an interrupt */
+ int have_intfly; /* Don't print warning
+ messages when we stack
+ INTFLYs */
+ unsigned long flags;
+
+#ifdef NCR_DEBUG
+ char buf[80]; /* Debugging sprintf buffer */
+ size_t buflen; /* Length of same */
+#endif
+
+#if defined(CONFIG_AMIGA)
+ custom.intena = IF_PORTS;
+#endif
+
+ do {
+ done = 1;
+ for (host = first_host; host; host = host->next)
+ if (host->hostt == the_template
+#if defined(MVME166_INTFLY)
+ /* We have two different interrupts pointing
+ * at this routine, so remove this check */
+#else
+ && host->irq == irq
+#endif
+ ) {
+ NCR53c7x0_local_setup(host);
+
+ hostdata = (struct NCR53c7x0_hostdata *) host->hostdata;
+ hostdata->dsp_changed = 0;
+ interrupted = 0;
+ have_intfly = 0;
+
+ do {
+ hostdata->dstat_valid = 0;
+ interrupted = 0;
+ /*
+ * Only read istat once, since reading it again will unstack
+ * interrupts?
+ */
+ istat = NCR53c7x0_read8(hostdata->istat);
+
+ if ((hostdata->options & OPTION_INTFLY) &&
+#ifdef MVME166_INTFLY
+ /* the bit is set which indicates an on-the-fly int */
+ (*(volatile unsigned long *)0xfff40068 & 0x8000))
+#else
+ (hostdata->emulated_intfly != 0))
+#endif
+ {
+ char search_found = 0; /* Got at least one ? */
+ done = 0;
+ interrupted = 1;
+
+#ifdef MVME166_INTFLY
+ /* clear the INTFLY bit */
+ *(volatile unsigned long *)0xfff40074 = 0x8000;
+#endif
+
+ if (hostdata->options & OPTION_DEBUG_INTR)
+ printk ("scsi%d : INTFLY\n", host->host_no);
+
+ /*
+ * Traverse our list of running commands, and look
+ * for those with valid (non-0xff ff) status and message
+ * bytes encoded in the result which signify command
+ * completion.
+ */
+
+
+ save_flags(flags);
+ cli();
+restart:
+ for (cmd_prev_ptr = (struct NCR53c7x0_cmd **)
+ &(hostdata->running_list), cmd =
+ (struct NCR53c7x0_cmd *) hostdata->running_list; cmd ;
+ cmd_prev_ptr = (struct NCR53c7x0_cmd **) &(cmd->next),
+ cmd = (struct NCR53c7x0_cmd *) cmd->next) {
+ Scsi_Cmnd *tmp;
+
+ if (!cmd) {
+ printk("scsi%d : very weird.\n", host->host_no);
+ break;
+ }
+
+ if (!(tmp = cmd->cmd)) {
+ printk("scsi%d : weird. NCR53c7x0_cmd has no Scsi_Cmnd\n",
+ host->host_no);
+ continue;
+ }
+#if 0
+ printk ("scsi%d : looking at result of 0x%x\n",
+ host->host_no, cmd->cmd->result);
+#endif
+
+ if (((tmp->result & 0xff) == 0xff) ||
+ ((tmp->result & 0xff00) == 0xff00))
+ continue;
+
+ search_found = 1;
+
+ /* Important - remove from list _before_ done is called */
+ if (cmd_prev_ptr)
+ *cmd_prev_ptr = (struct NCR53c7x0_cmd *) cmd->next;
+
+ --hostdata->busy[tmp->target][tmp->lun];
+ cmd->next = hostdata->free;
+ hostdata->free = cmd;
+
+ tmp->host_scribble = NULL;
+
+ if (hostdata->options & OPTION_DEBUG_INTR) {
+ printk ("scsi%d : command complete : pid %lu, id %d,lun %d result 0x%x ",
+ host->host_no, tmp->pid, tmp->target, tmp->lun, tmp->result);
+ print_command (tmp->cmnd);
+ }
+
+#if 0
+ hostdata->options &= ~OPTION_DEBUG_INTR;
+#endif
+ tmp->scsi_done(tmp);
+ goto restart;
+
+ }
+ restore_flags(flags);
+
+ if (!search_found && !have_intfly) {
+ printk ("scsi%d : WARNING : INTFLY with no completed commands.\n",
+ host->host_no);
+ } else if (!have_intfly) {
+ have_intfly = 1;
+ run_process_issue_queue();
+ }
+ }
+
+ if (hostdata->emulated_intfly)
+ {
+ hostdata->emulated_intfly = 0;
+ return;
+ }
+
+ if (istat & (ISTAT_SIP|ISTAT_DIP)) {
+ done = 0;
+ interrupted = 1;
+ hostdata->state = STATE_HALTED;
+
+ if (NCR53c7x0_read8 (SSTAT2_REG) & SSTAT2_FF_MASK)
+ printk ("scsi%d : SCSI FIFO not empty\n",
+ host->host_no);
+
+ /*
+ * NCR53c700 and NCR53c700-66 change the current SCSI
+ * process, hostdata->ncrcurrent, in the Linux driver so
+ * cmd = hostdata->ncrcurrent.
+ *
+ * With other chips, we must look through the commands
+ * executing and find the command structure which
+ * corresponds to the DSA register.
+ */
+
+ if (hostdata->options & OPTION_700) {
+ cmd = (struct NCR53c7x0_cmd *) hostdata->ncrcurrent;
+ } else {
+ dsa = bus_to_virt(NCR53c7x0_read32(DSA_REG));
+ for (cmd = (struct NCR53c7x0_cmd *)
+ hostdata->running_list; cmd &&
+ (dsa + (hostdata->dsa_start / sizeof(u32))) !=
+ cmd->dsa;
+ cmd = (struct NCR53c7x0_cmd *)(cmd->next));
+ }
+ if (hostdata->options & OPTION_DEBUG_INTR) {
+ if (cmd) {
+ printk("scsi%d : interrupt for pid %lu, id %d, lun %d ",
+ host->host_no, cmd->cmd->pid, (int) cmd->cmd->target,
+ (int) cmd->cmd->lun);
+ print_command (cmd->cmd->cmnd);
+ } else {
+ printk("scsi%d : no active command\n", host->host_no);
+ }
+ }
+
+ if (istat & ISTAT_SIP) {
+ if (hostdata->options & OPTION_DEBUG_INTR)
+ printk ("scsi%d : ISTAT_SIP\n", host->host_no);
+ intr_scsi (host, cmd);
+ }
+
+ if (istat & ISTAT_DIP) {
+ if (hostdata->options & OPTION_DEBUG_INTR)
+ printk ("scsi%d : ISTAT_DIP\n", host->host_no);
+ intr_dma (host, cmd);
+ }
+
+ if (!hostdata->dstat_valid) {
+ hostdata->dstat = NCR53c7x0_read8(DSTAT_REG);
+ hostdata->dstat_valid = 1;
+ }
+
+ if (!(hostdata->dstat & DSTAT_DFE)) {
+ printk ("scsi%d : DMA FIFO not empty\n", host->host_no);
+ /* Really need to check this out for 710 RGH */
+ NCR53c7x0_write8 (CTEST8_REG, CTEST8_10_CLF);
+ while (NCR53c7x0_read8 (CTEST8_REG) & CTEST8_10_CLF);
+ hostdata->dstat |= DSTAT_DFE;
+ }
+ }
+ } while (interrupted);
+
+
+
+ if (hostdata->intrs != -1)
+ hostdata->intrs++;
+#if 0
+ if (hostdata->intrs > 40) {
+ printk("scsi%d : too many interrupts, halting", host->host_no);
+ disable(host);
+ }
+#endif
+
+ if (!hostdata->idle && hostdata->state == STATE_HALTED) {
+ if (!hostdata->dsp_changed) {
+ hostdata->dsp = (u32 *)
+ bus_to_virt(NCR53c7x0_read32(DSP_REG));
+ }
+
+#if 0
+ printk("scsi%d : new dsp is 0x%lx (virt 0x%p)\n",
+ host->host_no, virt_to_bus(hostdata->dsp), hostdata->dsp);
+#endif
+
+ hostdata->state = STATE_RUNNING;
+ NCR53c7x0_write32 (DSP_REG, virt_to_bus(hostdata->dsp));
+ if (hostdata->options & OPTION_DEBUG_TRACE) {
+#ifdef CYCLIC_TRACE
+ log_insn (hostdata->dsp);
+#else
+ print_insn (host, hostdata->dsp, "t ", 1);
+#endif
+ NCR53c7x0_write8 (DCNTL_REG, hostdata->saved_dcntl |
+ DCNTL_SSM | DCNTL_STD);
+ }
+ }
+ }
+ } while (!done);
+#ifdef CONFIG_AMIGA
+ custom.intena = IF_SETCLR | IF_PORTS;
+#endif
+}
+
+
+/*
+ * Function : static int abort_connected (struct Scsi_Host *host)
+ *
+ * Purpose : Assuming that the NCR SCSI processor is currently
+ * halted, break the currently established nexus. Clean
+ * up of the NCR53c7x0_cmd and Scsi_Cmnd structures should
+ * be done on receipt of the abort interrupt.
+ *
+ * Inputs : host - SCSI host
+ *
+ */
+
+static int
+abort_connected (struct Scsi_Host *host) {
+#ifdef NEW_ABORT
+ NCR53c7x0_local_declare();
+#endif
+ struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+ host->hostdata;
+/* FIXME : this probably should change for production kernels; at the
+ least, counter should move to a per-host structure. */
+ static int counter = 5;
+#ifdef NEW_ABORT
+ int sstat, phase, offset;
+ u32 *script;
+ NCR53c7x0_local_setup(host);
+#endif
+
+ if (--counter <= 0) {
+ disable(host);
+ return 0;
+ }
+
+ printk ("scsi%d : DANGER : abort_connected() called \n",
+ host->host_no);
+
+#ifdef NEW_ABORT
+
+/*
+ * New strategy : Rather than using a generic abort routine,
+ * we'll specifically try to source or sink the appropriate
+ * amount of data for the phase we're currently in (taking into
+ * account the current synchronous offset)
+ */
+
+ sstat = (NCR53c8x0_read8 (SSTAT2_REG);
+ offset = OFFSET (sstat & SSTAT2_FF_MASK) >> SSTAT2_FF_SHIFT;
+ phase = sstat & SSTAT2_PHASE_MASK;
+
+/*
+ * SET ATN
+ * MOVE source_or_sink, WHEN CURRENT PHASE
+ * < repeat for each outstanding byte >
+ * JUMP send_abort_message
+ */
+
+ script = hostdata->abort_script = kmalloc (
+ 8 /* instruction size */ * (
+ 1 /* set ATN */ +
+ (!offset ? 1 : offset) /* One transfer per outstanding byte */ +
+ 1 /* send abort message */),
+ GFP_ATOMIC);
+
+
+#else /* def NEW_ABORT */
+ hostdata->dsp = hostdata->script + hostdata->E_initiator_abort /
+ sizeof(u32);
+#endif /* def NEW_ABORT */
+ hostdata->dsp_changed = 1;
+
+/* XXX - need to flag the command as aborted after the abort_connected
+ code runs
+ */
+ return 0;
+}
+
+/*
+ * Function : static int datapath_residual (Scsi_Host *host)
+ *
+ * Purpose : return residual data count of what's in the chip.
+ *
+ * Inputs : host - SCSI host
+ */
+
+static int
+datapath_residual (struct Scsi_Host *host) {
+ NCR53c7x0_local_declare();
+ int count, synchronous, sstat;
+ unsigned int ddir;
+
+ NCR53c7x0_local_setup(host);
+ /* COMPAT : the 700 and 700-66 need to use DFIFO_00_BO_MASK */
+ count = ((NCR53c7x0_read8 (DFIFO_REG) & DFIFO_10_BO_MASK) -
+ (NCR53c7x0_read32 (DBC_REG) & DFIFO_10_BO_MASK)) & DFIFO_10_BO_MASK;
+ synchronous = NCR53c7x0_read8 (SXFER_REG) & SXFER_MO_MASK;
+ /* COMPAT : DDIR is elsewhere on non-'8xx chips. */
+ ddir = NCR53c7x0_read8 (CTEST0_REG_700) & CTEST0_700_DDIR;
+
+ if (ddir) {
+ /* Receive */
+ if (synchronous)
+ count += (NCR53c7x0_read8 (SSTAT2_REG) & SSTAT2_FF_MASK) >> SSTAT2_FF_SHIFT;
+ else
+ if (NCR53c7x0_read8 (SSTAT1_REG) & SSTAT1_ILF)
+ ++count;
+ } else {
+ /* Send */
+ sstat = NCR53c7x0_read8 (SSTAT1_REG);
+ if (sstat & SSTAT1_OLF)
+ ++count;
+ if (synchronous && (sstat & SSTAT1_ORF))
+ ++count;
+ }
+ return count;
+}
+
+/*
+ * Function : static const char * sbcl_to_phase (int sbcl)_
+ *
+ * Purpose : Convert SBCL register to user-parsable phase representation
+ *
+ * Inputs : sbcl - value of sbcl register
+ */
+
+
+static const char *
+sbcl_to_phase (int sbcl) {
+ switch (sbcl & SBCL_PHASE_MASK) {
+ case SBCL_PHASE_DATAIN:
+ return "DATAIN";
+ case SBCL_PHASE_DATAOUT:
+ return "DATAOUT";
+ case SBCL_PHASE_MSGIN:
+ return "MSGIN";
+ case SBCL_PHASE_MSGOUT:
+ return "MSGOUT";
+ case SBCL_PHASE_CMDOUT:
+ return "CMDOUT";
+ case SBCL_PHASE_STATIN:
+ return "STATUSIN";
+ default:
+ return "unknown";
+ }
+}
+
+/*
+ * Function : static const char * sstat2_to_phase (int sstat)_
+ *
+ * Purpose : Convert SSTAT2 register to user-parsable phase representation
+ *
+ * Inputs : sstat - value of sstat register
+ */
+
+
+static const char *
+sstat2_to_phase (int sstat) {
+ switch (sstat & SSTAT2_PHASE_MASK) {
+ case SSTAT2_PHASE_DATAIN:
+ return "DATAIN";
+ case SSTAT2_PHASE_DATAOUT:
+ return "DATAOUT";
+ case SSTAT2_PHASE_MSGIN:
+ return "MSGIN";
+ case SSTAT2_PHASE_MSGOUT:
+ return "MSGOUT";
+ case SSTAT2_PHASE_CMDOUT:
+ return "CMDOUT";
+ case SSTAT2_PHASE_STATIN:
+ return "STATUSIN";
+ default:
+ return "unknown";
+ }
+}
+
+/*
+ * Function : static void intr_phase_mismatch (struct Scsi_Host *host,
+ * struct NCR53c7x0_cmd *cmd)
+ *
+ * Purpose : Handle phase mismatch interrupts
+ *
+ * Inputs : host, cmd - host and NCR command causing the interrupt, cmd
+ * may be NULL.
+ *
+ * Side effects : The abort_connected() routine is called or the NCR chip
+ * is restarted, jumping to the command_complete entry point, or
+ * patching the address and transfer count of the current instruction
+ * and calling the msg_in entry point as appropriate.
+ */
+
+static void
+intr_phase_mismatch (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
+ NCR53c7x0_local_declare();
+ u32 dbc_dcmd, *dsp, *dsp_next;
+ unsigned char dcmd, sbcl;
+ struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+ host->hostdata;
+ int residual;
+ enum {ACTION_ABORT, ACTION_ABORT_PRINT, ACTION_CONTINUE} action =
+ ACTION_ABORT_PRINT;
+ const char *where = NULL;
+
+ NCR53c7x0_local_setup(host);
+
+ /*
+ * Corrective action is based on where in the SCSI SCRIPT(tm) the error
+ * occurred, as well as which SCSI phase we are currently in.
+ */
+ dsp_next = bus_to_virt(NCR53c7x0_read32(DSP_REG));
+
+ /*
+ * Fetch the current instruction, and remove the operands for easier
+ * interpretation.
+ */
+ dbc_dcmd = NCR53c7x0_read32(DBC_REG);
+ dcmd = (dbc_dcmd & 0xff000000) >> 24;
+ /*
+ * Like other processors, the NCR adjusts the instruction pointer before
+ * instruction decode. Set the DSP address back to what it should
+ * be for this instruction based on its size (2 or 3 32 bit words).
+ */
+ dsp = dsp_next - NCR53c7x0_insn_size(dcmd);
+
+
+ /*
+ * Read new SCSI phase from the SBCL lines. Since all of our code uses
+ * a WHEN conditional instead of an IF conditional, we don't need to
+ * wait for a new REQ.
+ */
+ sbcl = NCR53c7x0_read8(SBCL_REG) & SBCL_PHASE_MASK;
+
+ if (!cmd) {
+ action = ACTION_ABORT_PRINT;
+ where = "no current command";
+ /*
+ * The way my SCSI SCRIPTS(tm) are architected, recoverable phase
+ * mismatches should only occur where we're doing a multi-byte
+ * BMI instruction. Specifically, this means
+ *
+ * - select messages (a SCSI-I target may ignore additional messages
+ * after the IDENTIFY; any target may reject a SDTR or WDTR)
+ *
+ * - command out (targets may send a message to signal an error
+ * condition, or go into STATUSIN after they've decided
+ * they don't like the command.
+ *
+ * - reply_message (targets may reject a multi-byte message in the
+ * middle)
+ *
+ * - data transfer routines (command completion with buffer space
+ * left, disconnect message, or error message)
+ */
+ } else if (((dsp >= cmd->data_transfer_start &&
+ dsp < cmd->data_transfer_end)) || dsp == (cmd->residual + 2)) {
+ if ((dcmd & (DCMD_TYPE_MASK|DCMD_BMI_OP_MASK|DCMD_BMI_INDIRECT|
+ DCMD_BMI_MSG|DCMD_BMI_CD)) == (DCMD_TYPE_BMI|
+ DCMD_BMI_OP_MOVE_I)) {
+ residual = datapath_residual (host);
+ if (hostdata->options & OPTION_DEBUG_DISCONNECT)
+ printk ("scsi%d : handling residual transfer (+ %d bytes from DMA FIFO)\n",
+ host->host_no, residual);
+
+ /*
+ * The first instruction is a CALL to the alternate handler for
+ * this data transfer phase, so we can do calls to
+ * munge_msg_restart as we would if control were passed
+ * from normal dynamic code.
+ */
+ if (dsp != cmd->residual + 2) {
+ cmd->residual[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_CALL |
+ ((dcmd & DCMD_BMI_IO) ? DCMD_TCI_IO : 0)) << 24) |
+ DBC_TCI_WAIT_FOR_VALID | DBC_TCI_COMPARE_PHASE;
+ cmd->residual[1] = virt_to_bus(hostdata->script)
+ + ((dcmd & DCMD_BMI_IO)
+ ? hostdata->E_other_in : hostdata->E_other_out);
+ }
+
+ /*
+ * The second instruction is the a data transfer block
+ * move instruction, reflecting the pointer and count at the
+ * time of the phase mismatch.
+ */
+ cmd->residual[2] = dbc_dcmd + residual;
+ cmd->residual[3] = NCR53c7x0_read32(DNAD_REG) - residual;
+
+ /*
+ * The third and final instruction is a jump to the instruction
+ * which follows the instruction which had to be 'split'
+ */
+ if (dsp != cmd->residual + 2) {
+ cmd->residual[4] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP)
+ << 24) | DBC_TCI_TRUE;
+ cmd->residual[5] = virt_to_bus(dsp_next);
+ }
+
+ /*
+ * For the sake of simplicity, transfer control to the
+ * conditional CALL at the start of the residual buffer.
+ */
+ hostdata->dsp = cmd->residual;
+ hostdata->dsp_changed = 1;
+ action = ACTION_CONTINUE;
+ } else {
+ where = "non-BMI dynamic DSA code";
+ action = ACTION_ABORT_PRINT;
+ }
+ } else if (dsp == (hostdata->script + hostdata->E_select_msgout / 4)) {
+ /* Release ATN */
+ NCR53c7x0_write8 (SOCL_REG, 0);
+ switch (sbcl) {
+ /*
+ * Some devices (SQ555 come to mind) grab the IDENTIFY message
+ * sent on selection, and decide to go into COMMAND OUT phase
+ * rather than accepting the rest of the messages or rejecting
+ * them. Handle these devices gracefully.
+ */
+ case SBCL_PHASE_CMDOUT:
+ hostdata->dsp = dsp + 2 /* two _words_ */;
+ hostdata->dsp_changed = 1;
+ printk ("scsi%d : target %d ignored SDTR and went into COMMAND OUT\n",
+ host->host_no, cmd->cmd->target);
+ cmd->flags &= ~CMD_FLAG_SDTR;
+ action = ACTION_CONTINUE;
+ break;
+ case SBCL_PHASE_MSGIN:
+ hostdata->dsp = hostdata->script + hostdata->E_msg_in /
+ sizeof(u32);
+ hostdata->dsp_changed = 1;
+ action = ACTION_CONTINUE;
+ break;
+ default:
+ where="select message out";
+ action = ACTION_ABORT_PRINT;
+ }
+ /*
+ * Some SCSI devices will interpret a command as they read the bytes
+ * off the SCSI bus, and may decide that the command is Bogus before
+ * they've read the entire command off the bus.
+ */
+ } else if (dsp == hostdata->script + hostdata->E_cmdout_cmdout / sizeof
+ (u32)) {
+ hostdata->dsp = hostdata->script + hostdata->E_data_transfer /
+ sizeof (u32);
+ hostdata->dsp_changed = 1;
+ action = ACTION_CONTINUE;
+ /* FIXME : we need to handle message reject, etc. within msg_respond. */
+#ifdef notyet
+ } else if (dsp == hostdata->script + hostdata->E_reply_message) {
+ switch (sbcl) {
+ /* Any other phase mismatches abort the currently executing command. */
+#endif
+ } else {
+ where = "unknown location";
+ action = ACTION_ABORT_PRINT;
+ }
+
+ /* Flush DMA FIFO */
+ if (!hostdata->dstat_valid) {
+ hostdata->dstat = NCR53c7x0_read8(DSTAT_REG);
+ hostdata->dstat_valid = 1;
+ }
+ if (!(hostdata->dstat & DSTAT_DFE)) {
+ /* Really need to check this out for 710 RGH */
+ NCR53c7x0_write8 (CTEST8_REG, CTEST8_10_CLF);
+ while (NCR53c7x0_read8 (CTEST8_REG) & CTEST8_10_CLF);
+ hostdata->dstat |= DSTAT_DFE;
+ }
+
+ switch (action) {
+ case ACTION_ABORT_PRINT:
+ printk("scsi%d : %s : unexpected phase %s.\n",
+ host->host_no, where ? where : "unknown location",
+ sbcl_to_phase(sbcl));
+ print_lots (host);
+ /* Fall through to ACTION_ABORT */
+ case ACTION_ABORT:
+ abort_connected (host);
+ break;
+ case ACTION_CONTINUE:
+ break;
+ }
+
+#if 0
+ if (hostdata->dsp_changed) {
+ printk("scsi%d: new dsp 0x%p\n", host->host_no, hostdata->dsp);
+ print_insn (host, hostdata->dsp, "", 1);
+ }
+#endif
+
+ cache_push(virt_to_bus(hostdata->script), flushsize);
+}
+
+/*
+ * Function : static void intr_bf (struct Scsi_Host *host,
+ * struct NCR53c7x0_cmd *cmd)
+ *
+ * Purpose : handle BUS FAULT interrupts
+ *
+ * Inputs : host, cmd - host and NCR command causing the interrupt, cmd
+ * may be NULL.
+ */
+
+static void
+intr_bf (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
+ NCR53c7x0_local_declare();
+ u32 *dsp,
+ *next_dsp, /* Current dsp */
+ *dsa,
+ dbc_dcmd; /* DCMD (high eight bits) + DBC */
+ char *reason = NULL;
+ /* Default behavior is for a silent error, with a retry until we've
+ exhausted retries. */
+ enum {MAYBE, ALWAYS, NEVER} retry = MAYBE;
+ int report = 0;
+ NCR53c7x0_local_setup(host);
+
+ dbc_dcmd = NCR53c7x0_read32 (DBC_REG);
+ next_dsp = bus_to_virt (NCR53c7x0_read32(DSP_REG));
+ dsp = next_dsp - NCR53c7x0_insn_size ((dbc_dcmd >> 24) & 0xff);
+/* FIXME - check chip type */
+ dsa = bus_to_virt (NCR53c7x0_read32(DSA_REG));
+
+ /*
+ * Bus faults can be caused by either a Bad Address or
+ * Target Abort. We should check the Received Target Abort
+ * bit of the PCI status register and Master Abort Bit.
+ *
+ * - Master Abort bit indicates that no device claimed
+ * the address with DEVSEL within five clocks
+ *
+ * - Target Abort bit indicates that a target claimed it,
+ * but changed its mind once it saw the byte enables.
+ *
+ */
+
+ /* 53c710, not PCI system */
+ report = 1;
+ reason = "Unknown";
+
+#ifndef notyet
+ report = 1;
+#endif
+ if (report && reason)
+ {
+ printk(KERN_ALERT "scsi%d : BUS FAULT reason = %s\n",
+ host->host_no, reason ? reason : "unknown");
+ print_lots (host);
+ }
+
+#ifndef notyet
+ retry = NEVER;
+#endif
+
+ /*
+ * TODO : we should attempt to recover from any spurious bus
+ * faults. After X retries, we should figure that things are
+ * sufficiently wedged, and call NCR53c7xx_reset.
+ *
+ * This code should only get executed once we've decided that we
+ * cannot retry.
+ */
+
+ if (retry == NEVER) {
+ printk(KERN_ALERT " mail drew@PoohSticks.ORG\n");
+ FATAL (host);
+ }
+}
+
+/*
+ * Function : static void intr_dma (struct Scsi_Host *host,
+ * struct NCR53c7x0_cmd *cmd)
+ *
+ * Purpose : handle all DMA interrupts, indicated by the setting
+ * of the DIP bit in the ISTAT register.
+ *
+ * Inputs : host, cmd - host and NCR command causing the interrupt, cmd
+ * may be NULL.
+ */
+
+static void
+intr_dma (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
+ NCR53c7x0_local_declare();
+ struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+ host->hostdata;
+ unsigned char dstat; /* DSTAT */
+ u32 *dsp,
+ *next_dsp, /* Current dsp */
+ *dsa,
+ dbc_dcmd; /* DCMD (high eight bits) + DBC */
+ int tmp;
+ unsigned long flags;
+ NCR53c7x0_local_setup(host);
+
+ if (!hostdata->dstat_valid) {
+ hostdata->dstat = NCR53c7x0_read8(DSTAT_REG);
+ hostdata->dstat_valid = 1;
+ }
+
+ dstat = hostdata->dstat;
+
+ if (hostdata->options & OPTION_DEBUG_INTR)
+ printk("scsi%d : DSTAT=0x%x\n", host->host_no, (int) dstat);
+
+ dbc_dcmd = NCR53c7x0_read32 (DBC_REG);
+ next_dsp = bus_to_virt(NCR53c7x0_read32(DSP_REG));
+ dsp = next_dsp - NCR53c7x0_insn_size ((dbc_dcmd >> 24) & 0xff);
+/* XXX - check chip type */
+ dsa = bus_to_virt(NCR53c7x0_read32(DSA_REG));
+
+ /*
+ * DSTAT_ABRT is the aborted interrupt. This is set whenever the
+ * SCSI chip is aborted.
+ *
+ * With NCR53c700 and NCR53c700-66 style chips, we should only
+ * get this when the chip is currently running the accept
+ * reselect/select code and we have set the abort bit in the
+ * ISTAT register.
+ *
+ */
+
+ if (dstat & DSTAT_ABRT) {
+#if 0
+ /* XXX - add code here to deal with normal abort */
+ if ((hostdata->options & OPTION_700) && (hostdata->state ==
+ STATE_ABORTING)) {
+ } else
+#endif
+ {
+ printk(KERN_ALERT "scsi%d : unexpected abort interrupt at\n"
+ " ", host->host_no);
+ print_insn (host, dsp, KERN_ALERT "s ", 1);
+ FATAL (host);
+ }
+ }
+
+ /*
+ * DSTAT_SSI is the single step interrupt. Should be generated
+ * whenever we have single stepped or are tracing.
+ */
+
+ if (dstat & DSTAT_SSI) {
+ if (hostdata->options & OPTION_DEBUG_TRACE) {
+ /* Don't print instr. until we write DSP at end of intr function */
+ } else if (hostdata->options & OPTION_DEBUG_SINGLE) {
+ print_insn (host, dsp, "s ", 0);
+ save_flags(flags);
+ cli();
+/* XXX - should we do this, or can we get away with writing dsp? */
+
+ NCR53c7x0_write8 (DCNTL_REG, (NCR53c7x0_read8(DCNTL_REG) &
+ ~DCNTL_SSM) | DCNTL_STD);
+ restore_flags(flags);
+ } else {
+ printk(KERN_ALERT "scsi%d : unexpected single step interrupt at\n"
+ " ", host->host_no);
+ print_insn (host, dsp, KERN_ALERT "", 1);
+ printk(KERN_ALERT " mail drew@PoohSticks.ORG\n");
+ FATAL (host);
+ }
+ }
+
+ /*
+ * DSTAT_IID / DSTAT_OPC (same bit, same meaning, only the name
+ * is different) is generated whenever an illegal instruction is
+ * encountered.
+ *
+ * XXX - we may want to emulate INTFLY here, so we can use
+ * the same SCSI SCRIPT (tm) for NCR53c710 through NCR53c810
+ * chips.
+ */
+
+ if (dstat & DSTAT_OPC) {
+ /*
+ * Ascertain if this IID interrupts occurred before or after a STO
+ * interrupt. Since the interrupt handling code now leaves
+ * DSP unmodified until _after_ all stacked interrupts have been
+ * processed, reading the DSP returns the original DSP register.
+ * This means that if dsp lies between the select code, and
+ * message out following the selection code (where the IID interrupt
+ * would have to have occurred by due to the implicit wait for REQ),
+ * we have an IID interrupt resulting from a STO condition and
+ * can ignore it.
+ */
+
+ if (((dsp >= (hostdata->script + hostdata->E_select / sizeof(u32))) &&
+ (dsp <= (hostdata->script + hostdata->E_select_msgout /
+ sizeof(u32) + 8))) || (hostdata->test_running == 2)) {
+ if (hostdata->options & OPTION_DEBUG_INTR)
+ printk ("scsi%d : ignoring DSTAT_IID for SSTAT_STO\n",
+ host->host_no);
+ if (hostdata->expecting_iid) {
+ hostdata->expecting_iid = 0;
+ hostdata->idle = 1;
+ if (hostdata->test_running == 2) {
+ hostdata->test_running = 0;
+ hostdata->test_completed = 3;
+ } else if (cmd)
+ abnormal_finished (cmd, DID_BAD_TARGET << 16);
+ } else {
+ hostdata->expecting_sto = 1;
+ }
+ /*
+ * We can't guarantee we'll be able to execute the WAIT DISCONNECT
+ * instruction within the 3.4us of bus free and arbitration delay
+ * that a target can RESELECT in and assert REQ after we've dropped
+ * ACK. If this happens, we'll get an illegal instruction interrupt.
+ * Doing away with the WAIT DISCONNECT instructions broke everything,
+ * so instead I'll settle for moving one WAIT DISCONNECT a few
+ * instructions closer to the CLEAR ACK before it to minimize the
+ * chances of this happening, and handle it if it occurs anyway.
+ *
+ * Simply continue with what we were doing, and control should
+ * be transfered to the schedule routine which will ultimately
+ * pass control onto the reselection or selection (not yet)
+ * code.
+ */
+ } else if (dbc_dcmd == 0x48000000 && (NCR53c7x0_read8 (SBCL_REG) &
+ SBCL_REQ)) {
+ if (!(hostdata->options & OPTION_NO_PRINT_RACE))
+ {
+ printk("scsi%d: REQ before WAIT DISCONNECT IID\n",
+ host->host_no);
+ hostdata->options |= OPTION_NO_PRINT_RACE;
+ }
+ } else {
+ printk(KERN_ALERT "scsi%d : illegal instruction\n", host->host_no);
+ print_lots (host);
+ printk(KERN_ALERT " mail Richard@sleepie.demon.co.uk with ALL\n"
+ " boot messages and diagnostic output\n");
+ FATAL (host);
+ }
+ }
+
+ /*
+ * DSTAT_BF are bus fault errors. DSTAT_800_BF is valid for 710 also.
+ */
+
+ if (dstat & DSTAT_800_BF) {
+ intr_bf (host, cmd);
+ }
+
+
+ /*
+ * DSTAT_SIR interrupts are generated by the execution of
+ * the INT instruction. Since the exact values available
+ * are determined entirely by the SCSI script running,
+ * and are local to a particular script, a unique handler
+ * is called for each script.
+ */
+
+ if (dstat & DSTAT_SIR) {
+ if (hostdata->options & OPTION_DEBUG_INTR)
+ printk ("scsi%d : DSTAT_SIR\n", host->host_no);
+ switch ((tmp = hostdata->dstat_sir_intr (host, cmd))) {
+ case SPECIFIC_INT_NOTHING:
+ case SPECIFIC_INT_RESTART:
+ break;
+ case SPECIFIC_INT_ABORT:
+ abort_connected(host);
+ break;
+ case SPECIFIC_INT_PANIC:
+ printk(KERN_ALERT "scsi%d : failure at ", host->host_no);
+ print_insn (host, dsp, KERN_ALERT "", 1);
+ printk(KERN_ALERT " dstat_sir_intr() returned SPECIFIC_INT_PANIC\n");
+ FATAL (host);
+ break;
+ case SPECIFIC_INT_BREAK:
+ intr_break (host, cmd);
+ break;
+ default:
+ printk(KERN_ALERT "scsi%d : failure at ", host->host_no);
+ print_insn (host, dsp, KERN_ALERT "", 1);
+ printk(KERN_ALERT" dstat_sir_intr() returned unknown value %d\n",
+ tmp);
+ FATAL (host);
+ }
+ }
+}
+
+/*
+ * Function : static int print_insn (struct Scsi_Host *host,
+ * u32 *insn, int kernel)
+ *
+ * Purpose : print numeric representation of the instruction pointed
+ * to by insn to the debugging or kernel message buffer
+ * as appropriate.
+ *
+ * If desired, a user level program can interpret this
+ * information.
+ *
+ * Inputs : host, insn - host, pointer to instruction, prefix -
+ * string to prepend, kernel - use printk instead of debugging buffer.
+ *
+ * Returns : size, in u32s, of instruction printed.
+ */
+
+/*
+ * FIXME: should change kernel parameter so that it takes an ENUM
+ * specifying severity - either KERN_ALERT or KERN_PANIC so
+ * all panic messages are output with the same severity.
+ */
+
+static int
+print_insn (struct Scsi_Host *host, const u32 *insn,
+ const char *prefix, int kernel) {
+ char buf[160], /* Temporary buffer and pointer. ICKY
+ arbitrary length. */
+
+
+ *tmp;
+ unsigned char dcmd; /* dcmd register for *insn */
+ int size;
+
+ /*
+ * Check to see if the instruction pointer is not bogus before
+ * indirecting through it; avoiding red-zone at start of
+ * memory.
+ *
+ * FIXME: icky magic needs to happen here on non-intel boxes which
+ * don't have kernel memory mapped in like this. Might be reasonable
+ * to use vverify()?
+ */
+
+ if (MAP_NR(insn) < 1 || MAP_NR(insn + 8) > MAP_NR(high_memory) ||
+ ((((dcmd = (insn[0] >> 24) & 0xff) & DCMD_TYPE_MMI) == DCMD_TYPE_MMI) &&
+ MAP_NR(insn + 12) > MAP_NR(high_memory))) {
+ size = 0;
+ sprintf (buf, "%s%p: address out of range\n",
+ prefix, insn);
+ } else {
+/*
+ * FIXME : (void *) cast in virt_to_bus should be unnecessary, because
+ * it should take const void * as argument.
+ */
+#ifndef CONFIG_MVME166
+ sprintf(buf, "%s0x%lx (virt 0x%p) : 0x%08x 0x%08x (virt 0x%p)",
+ (prefix ? prefix : ""), virt_to_bus((void *) insn), insn,
+ insn[0], insn[1], bus_to_virt (insn[1]));
+#else
+ /* Remove virtual addresses to reduce output, as they are the same */
+ sprintf(buf, "%s0x%x (+%x) : 0x%08x 0x%08x",
+ (prefix ? prefix : ""), (u32)insn, ((u32)insn -
+ (u32)&(((struct NCR53c7x0_hostdata *)host->hostdata)->script))/4,
+ insn[0], insn[1]);
+#endif
+ tmp = buf + strlen(buf);
+ if ((dcmd & DCMD_TYPE_MASK) == DCMD_TYPE_MMI) {
+#ifndef CONFIG_MVME166
+ sprintf (tmp, " 0x%08x (virt 0x%p)\n", insn[2],
+ bus_to_virt(insn[2]));
+#else
+ /* Remove virtual addr to reduce output, as it is the same */
+ sprintf (tmp, " 0x%08x\n", insn[2]);
+#endif
+ size = 3;
+ } else {
+ sprintf (tmp, "\n");
+ size = 2;
+ }
+ }
+
+ if (kernel)
+ printk ("%s", buf);
+#ifdef NCR_DEBUG
+ else {
+ size_t len = strlen(buf);
+ debugger_kernel_write(host, buf, len);
+ }
+#endif
+ return size;
+}
+
+/*
+ * Function : int NCR53c7xx_abort (Scsi_Cmnd *cmd)
+ *
+ * Purpose : Abort an errant SCSI command, doing all necessary
+ * cleanup of the issue_queue, running_list, shared Linux/NCR
+ * dsa issue and reconnect queues.
+ *
+ * Inputs : cmd - command to abort, code - entire result field
+ *
+ * Returns : 0 on success, -1 on failure.
+ */
+
+int
+NCR53c7xx_abort (Scsi_Cmnd *cmd) {
+ NCR53c7x0_local_declare();
+ struct Scsi_Host *host = cmd->host;
+ struct NCR53c7x0_hostdata *hostdata = host ? (struct NCR53c7x0_hostdata *)
+ host->hostdata : NULL;
+ unsigned long flags;
+ struct NCR53c7x0_cmd *curr, **prev;
+ Scsi_Cmnd *me, **last;
+#if 0
+ static long cache_pid = -1;
+#endif
+
+
+ if (!host) {
+ printk ("Bogus SCSI command pid %ld; no host structure\n",
+ cmd->pid);
+ return SCSI_ABORT_ERROR;
+ } else if (!hostdata) {
+ printk ("Bogus SCSI host %d; no hostdata\n", host->host_no);
+ return SCSI_ABORT_ERROR;
+ }
+ NCR53c7x0_local_setup(host);
+
+/*
+ * CHECK : I don't think that reading ISTAT will unstack any interrupts,
+ * since we need to write the INTF bit to clear it, and SCSI/DMA
+ * interrupts don't clear until we read SSTAT/SIST and DSTAT registers.
+ *
+ * See that this is the case. Appears to be correct on the 710, at least.
+ *
+ * I suspect that several of our failures may be coming from a new fatal
+ * interrupt (possibly due to a phase mismatch) happening after we've left
+ * the interrupt handler, but before the PIC has had the interrupt condition
+ * cleared.
+ */
+
+ if (NCR53c7x0_read8(hostdata->istat) & (ISTAT_DIP|ISTAT_SIP)) {
+ printk ("scsi%d : dropped interrupt for command %ld\n", host->host_no,
+ cmd->pid);
+ NCR53c7x0_intr (host->irq, NULL, NULL);
+ return SCSI_ABORT_BUSY;
+ }
+
+ save_flags(flags);
+ cli();
+#if 0
+ if (cache_pid == cmd->pid)
+ panic ("scsi%d : bloody fetus %d\n", host->host_no, cmd->pid);
+ else
+ cache_pid = cmd->pid;
+#endif
+
+
+/*
+ * The command could be hiding in the issue_queue. This would be very
+ * nice, as commands can't be moved from the high level driver's issue queue
+ * into the shared queue until an interrupt routine is serviced, and this
+ * moving is atomic.
+ *
+ * If this is the case, we don't have to worry about anything - we simply
+ * pull the command out of the old queue, and call it aborted.
+ */
+
+ for (me = (Scsi_Cmnd *) hostdata->issue_queue,
+ last = (Scsi_Cmnd **) &(hostdata->issue_queue);
+ me && me != cmd; last = (Scsi_Cmnd **)&(me->SCp.ptr),
+ me = (Scsi_Cmnd *)me->SCp.ptr);
+
+ if (me) {
+ *last = (Scsi_Cmnd *) me->SCp.ptr;
+ if (me->host_scribble) {
+ ((struct NCR53c7x0_cmd *)me->host_scribble)->next = hostdata->free;
+ hostdata->free = (struct NCR53c7x0_cmd *) me->host_scribble;
+ me->host_scribble = NULL;
+ }
+ cmd->result = DID_ABORT << 16;
+ cmd->scsi_done(cmd);
+ printk ("scsi%d : found command %ld in Linux issue queue\n",
+ host->host_no, me->pid);
+ restore_flags(flags);
+ run_process_issue_queue();
+ return SCSI_ABORT_SUCCESS;
+ }
+
+/*
+ * That failing, the command could be in our list of already executing
+ * commands. If this is the case, drastic measures are called for.
+ */
+
+ for (curr = (struct NCR53c7x0_cmd *) hostdata->running_list,
+ prev = (struct NCR53c7x0_cmd **) &(hostdata->running_list);
+ curr && curr->cmd != cmd; prev = (struct NCR53c7x0_cmd **)
+ &(curr->next), curr = (struct NCR53c7x0_cmd *) curr->next);
+
+ if (curr) {
+ if ((cmd->result & 0xff) != 0xff && (cmd->result & 0xff00) != 0xff00) {
+ if (prev)
+ *prev = (struct NCR53c7x0_cmd *) curr->next;
+ curr->next = (struct NCR53c7x0_cmd *) hostdata->free;
+ cmd->host_scribble = NULL;
+ hostdata->free = curr;
+ cmd->scsi_done(cmd);
+ printk ("scsi%d : found finished command %ld in running list\n",
+ host->host_no, cmd->pid);
+ restore_flags(flags);
+ return SCSI_ABORT_NOT_RUNNING;
+ } else {
+ printk ("scsi%d : DANGER : command running, can not abort.\n",
+ cmd->host->host_no);
+ restore_flags(flags);
+ return SCSI_ABORT_BUSY;
+ }
+ }
+
+/*
+ * And if we couldn't find it in any of our queues, it must have been
+ * a dropped interrupt.
+ */
+
+ curr = (struct NCR53c7x0_cmd *) cmd->host_scribble;
+ if (curr) {
+ curr->next = hostdata->free;
+ hostdata->free = curr;
+ cmd->host_scribble = NULL;
+ }
+
+ if (((cmd->result & 0xff00) == 0xff00) ||
+ ((cmd->result & 0xff) == 0xff)) {
+ printk ("scsi%d : did this command ever run?\n", host->host_no);
+ cmd->result = DID_ABORT << 16;
+ } else {
+ printk ("scsi%d : probably lost INTFLY, normal completion\n",
+ host->host_no);
+/*
+ * FIXME : We need to add an additional flag which indicates if a
+ * command was ever counted as BUSY, so if we end up here we can
+ * decrement the busy count if and only if it is necessary.
+ */
+ --hostdata->busy[cmd->target][cmd->lun];
+ }
+ restore_flags(flags);
+ cmd->scsi_done(cmd);
+
+/*
+ * We need to run process_issue_queue since termination of this command
+ * may allow another queued command to execute first?
+ */
+ return SCSI_ABORT_NOT_RUNNING;
+}
+
+/*
+ * Function : int NCR53c7xx_reset (Scsi_Cmnd *cmd)
+ *
+ * Purpose : perform a hard reset of the SCSI bus and NCR
+ * chip.
+ *
+ * Inputs : cmd - command which caused the SCSI RESET
+ *
+ * Returns : 0 on success.
+ */
+
+int
+NCR53c7xx_reset (Scsi_Cmnd *cmd, unsigned int reset_flags) {
+ NCR53c7x0_local_declare();
+ unsigned long flags;
+ int found = 0;
+ struct NCR53c7x0_cmd * c;
+ Scsi_Cmnd *tmp;
+ /*
+ * When we call scsi_done(), it's going to wake up anything sleeping on the
+ * resources which were in use by the aborted commands, and we'll start to
+ * get new commands.
+ *
+ * We can't let this happen until after we've re-initialized the driver
+ * structures, and can't reinitialize those structures until after we've
+ * dealt with their contents.
+ *
+ * So, we need to find all of the commands which were running, stick
+ * them on a linked list of completed commands (we'll use the host_scribble
+ * pointer), do our reinitialization, and then call the done function for
+ * each command.
+ */
+ Scsi_Cmnd *nuke_list = NULL;
+ struct Scsi_Host *host = cmd->host;
+ struct NCR53c7x0_hostdata *hostdata =
+ (struct NCR53c7x0_hostdata *) host->hostdata;
+
+ NCR53c7x0_local_setup(host);
+ save_flags(flags);
+ cli();
+ ncr_halt (host);
+ print_lots (host);
+ dump_events (host, 30);
+ ncr_scsi_reset (host);
+ for (tmp = nuke_list = return_outstanding_commands (host, 1 /* free */,
+ 0 /* issue */ ); tmp; tmp = (Scsi_Cmnd *) tmp->SCp.buffer)
+ if (tmp == cmd) {
+ found = 1;
+ break;
+ }
+
+ /*
+ * If we didn't find the command which caused this reset in our running
+ * list, then we've lost it. See that it terminates normally anyway.
+ */
+ if (!found) {
+ c = (struct NCR53c7x0_cmd *) cmd->host_scribble;
+ if (c) {
+ cmd->host_scribble = NULL;
+ c->next = hostdata->free;
+ hostdata->free = c;
+ } else
+ printk ("scsi%d: lost command %ld\n", host->host_no, cmd->pid);
+ cmd->SCp.buffer = (struct scatterlist *) nuke_list;
+ nuke_list = cmd;
+ }
+
+ NCR53c7x0_driver_init (host);
+ hostdata->soft_reset (host);
+ if (hostdata->resets == 0)
+ disable(host);
+ else if (hostdata->resets != -1)
+ --hostdata->resets;
+ sti();
+ for (; nuke_list; nuke_list = tmp) {
+ tmp = (Scsi_Cmnd *) nuke_list->SCp.buffer;
+ nuke_list->result = DID_RESET << 16;
+ nuke_list->scsi_done (nuke_list);
+ }
+ restore_flags(flags);
+ return SCSI_RESET_SUCCESS;
+}
+
+/*
+ * The NCR SDMS bios follows Annex A of the SCSI-CAM draft, and
+ * therefore shares the scsicam_bios_param function.
+ */
+
+/*
+ * Function : int insn_to_offset (Scsi_Cmnd *cmd, u32 *insn)
+ *
+ * Purpose : convert instructions stored at NCR pointer into data
+ * pointer offset.
+ *
+ * Inputs : cmd - SCSI command; insn - pointer to instruction. Either current
+ * DSP, or saved data pointer.
+ *
+ * Returns : offset on success, -1 on failure.
+ */
+
+
+static int
+insn_to_offset (Scsi_Cmnd *cmd, u32 *insn) {
+ struct NCR53c7x0_hostdata *hostdata =
+ (struct NCR53c7x0_hostdata *) cmd->host->hostdata;
+ struct NCR53c7x0_cmd *ncmd =
+ (struct NCR53c7x0_cmd *) cmd->host_scribble;
+ int offset = 0, buffers;
+ struct scatterlist *segment;
+ char *ptr;
+ int found = 0;
+
+/*
+ * With the current code implementation, if the insn is inside dynamically
+ * generated code, the data pointer will be the instruction preceding
+ * the next transfer segment.
+ */
+
+ if (!check_address ((unsigned long) ncmd, sizeof (struct NCR53c7x0_cmd)) &&
+ ((insn >= ncmd->data_transfer_start &&
+ insn < ncmd->data_transfer_end) ||
+ (insn >= ncmd->residual &&
+ insn < (ncmd->residual +
+ sizeof(ncmd->residual))))) {
+ ptr = bus_to_virt(insn[3]);
+
+ if ((buffers = cmd->use_sg)) {
+ for (offset = 0,
+ segment = (struct scatterlist *) cmd->buffer;
+ buffers && !((found = ((ptr >= segment->address) &&
+ (ptr < (segment->address + segment->length)))));
+ --buffers, offset += segment->length, ++segment)
+#if 0
+ printk("scsi%d: comparing 0x%p to 0x%p\n",
+ cmd->host->host_no, saved, segment->address);
+#else
+ ;
+#endif
+ offset += ptr - segment->address;
+ } else {
+ found = 1;
+ offset = ptr - (char *) (cmd->request_buffer);
+ }
+ } else if ((insn >= hostdata->script +
+ hostdata->E_data_transfer / sizeof(u32)) &&
+ (insn <= hostdata->script +
+ hostdata->E_end_data_transfer / sizeof(u32))) {
+ found = 1;
+ offset = 0;
+ }
+ return found ? offset : -1;
+}
+
+
+
+/*
+ * Function : void print_progress (Scsi_Cmnd *cmd)
+ *
+ * Purpose : print the current location of the saved data pointer
+ *
+ * Inputs : cmd - command we are interested in
+ *
+ */
+
+static void
+print_progress (Scsi_Cmnd *cmd) {
+ NCR53c7x0_local_declare();
+ struct NCR53c7x0_cmd *ncmd =
+ (struct NCR53c7x0_cmd *) cmd->host_scribble;
+ int offset, i;
+ char *where;
+ u32 *ptr;
+ NCR53c7x0_local_setup (cmd->host);
+ for (i = 0; i < 2; ++i) {
+ if (check_address ((unsigned long) ncmd,
+ sizeof (struct NCR53c7x0_cmd)) == -1)
+ continue;
+ if (!i) {
+ where = "saved";
+ ptr = bus_to_virt(ncmd->saved_data_pointer);
+ } else {
+ where = "active";
+ ptr = bus_to_virt (NCR53c7x0_read32 (DSP_REG) -
+ NCR53c7x0_insn_size (NCR53c7x0_read8 (DCMD_REG)) *
+ sizeof(u32));
+ }
+ offset = insn_to_offset (cmd, ptr);
+
+ if (offset != -1)
+ printk ("scsi%d : %s data pointer at offset %d\n",
+ cmd->host->host_no, where, offset);
+ else {
+ int size;
+ printk ("scsi%d : can't determine %s data pointer offset\n",
+ cmd->host->host_no, where);
+ if (ncmd) {
+ size = print_insn (cmd->host,
+ bus_to_virt(ncmd->saved_data_pointer), "", 1);
+ print_insn (cmd->host,
+ bus_to_virt(ncmd->saved_data_pointer) + size * sizeof(u32),
+ "", 1);
+ }
+ }
+ }
+}
+
+
+static void
+print_dsa (struct Scsi_Host *host, u32 *dsa, const char *prefix) {
+ struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+ host->hostdata;
+ int i, len;
+ char *ptr;
+ Scsi_Cmnd *cmd;
+
+ if (check_address ((unsigned long) dsa, hostdata->dsa_end -
+ hostdata->dsa_start) == -1) {
+ printk("scsi%d : bad dsa virt 0x%p\n", host->host_no, dsa);
+ return;
+ }
+ printk("%sscsi%d : dsa at phys 0x%lx (virt 0x%p)\n"
+ " + %d : dsa_msgout length = %u, data = 0x%x (virt 0x%p)\n" ,
+ prefix ? prefix : "",
+ host->host_no, virt_to_bus (dsa), dsa, hostdata->dsa_msgout,
+ dsa[hostdata->dsa_msgout / sizeof(u32)],
+ dsa[hostdata->dsa_msgout / sizeof(u32) + 1],
+ bus_to_virt (dsa[hostdata->dsa_msgout / sizeof(u32) + 1]));
+
+ /*
+ * Only print messages if they're sane in length so we don't
+ * blow the kernel printk buffer on something which won't buy us
+ * anything.
+ */
+
+ if (dsa[hostdata->dsa_msgout / sizeof(u32)] <
+ sizeof (hostdata->free->select))
+ for (i = dsa[hostdata->dsa_msgout / sizeof(u32)],
+ ptr = bus_to_virt (dsa[hostdata->dsa_msgout / sizeof(u32) + 1]);
+ i > 0 && !check_address ((unsigned long) ptr, 1);
+ ptr += len, i -= len) {
+ printk(" ");
+ len = print_msg (ptr);
+ printk("\n");
+ if (!len)
+ break;
+ }
+
+ printk(" + %d : select_indirect = 0x%x\n",
+ hostdata->dsa_select, dsa[hostdata->dsa_select / sizeof(u32)]);
+ cmd = (Scsi_Cmnd *) bus_to_virt(dsa[hostdata->dsa_cmnd / sizeof(u32)]);
+ printk(" + %d : dsa_cmnd = 0x%x ", hostdata->dsa_cmnd,
+ (u32) virt_to_bus(cmd));
+ if (cmd) {
+ printk(" result = 0x%x, target = %d, lun = %d, cmd = ",
+ cmd->result, cmd->target, cmd->lun);
+ print_command(cmd->cmnd);
+ } else
+ printk("\n");
+ printk(" + %d : dsa_next = 0x%x\n", hostdata->dsa_next,
+ dsa[hostdata->dsa_next / sizeof(u32)]);
+ if (cmd) {
+ printk("scsi%d target %d : sxfer_sanity = 0x%x, scntl3_sanity = 0x%x\n"
+ " script : ",
+ host->host_no, cmd->target,
+ hostdata->sync[cmd->target].sxfer_sanity,
+ hostdata->sync[cmd->target].scntl3_sanity);
+ for (i = 0; i < (sizeof(hostdata->sync[cmd->target].script) / 4); ++i)
+ printk ("0x%x ", hostdata->sync[cmd->target].script[i]);
+ printk ("\n");
+ print_progress (cmd);
+ }
+}
+/*
+ * Function : void print_queues (Scsi_Host *host)
+ *
+ * Purpose : print the contents of the NCR issue and reconnect queues
+ *
+ * Inputs : host - SCSI host we are interested in
+ *
+ */
+
+static void
+print_queues (struct Scsi_Host *host) {
+ struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+ host->hostdata;
+ u32 *dsa, *next_dsa;
+ volatile u32 *ncrcurrent;
+ int left;
+ Scsi_Cmnd *cmd, *next_cmd;
+ unsigned long flags;
+
+ printk ("scsi%d : issue queue\n", host->host_no);
+
+ for (left = host->can_queue, cmd = (Scsi_Cmnd *) hostdata->issue_queue;
+ left >= 0 && cmd;
+ cmd = next_cmd) {
+ next_cmd = (Scsi_Cmnd *) cmd->SCp.ptr;
+ save_flags(flags);
+ cli();
+ if (cmd->host_scribble) {
+ if (check_address ((unsigned long) (cmd->host_scribble),
+ sizeof (cmd->host_scribble)) == -1)
+ printk ("scsi%d: scsi pid %ld bad pointer to NCR53c7x0_cmd\n",
+ host->host_no, cmd->pid);
+ /* print_dsa does sanity check on address, no need to check */
+ else
+ print_dsa (host, ((struct NCR53c7x0_cmd *) cmd->host_scribble)
+ -> dsa, "");
+ } else
+ printk ("scsi%d : scsi pid %ld for target %d lun %d has no NCR53c7x0_cmd\n",
+ host->host_no, cmd->pid, cmd->target, cmd->lun);
+ restore_flags(flags);
+ }
+
+ if (left <= 0) {
+ printk ("scsi%d : loop detected in issue queue\n",
+ host->host_no);
+ }
+
+ /*
+ * Traverse the NCR reconnect and start DSA structures, printing out
+ * each element until we hit the end or detect a loop. Currently,
+ * the reconnect structure is a linked list; and the start structure
+ * is an array. Eventually, the reconnect structure will become a
+ * list as well, since this simplifies the code.
+ */
+
+ printk ("scsi%d : schedule dsa array :\n", host->host_no);
+ for (left = host->can_queue, ncrcurrent = hostdata->schedule;
+ left > 0; ncrcurrent += 2, --left)
+ if (ncrcurrent[0] != hostdata->NOP_insn)
+/* FIXME : convert pointer to dsa_begin to pointer to dsa. */
+ print_dsa (host, bus_to_virt (ncrcurrent[1] -
+ (hostdata->E_dsa_code_begin -
+ hostdata->E_dsa_code_template)), "");
+ printk ("scsi%d : end schedule dsa array\n", host->host_no);
+
+ printk ("scsi%d : reconnect_dsa_head :\n", host->host_no);
+
+ for (left = host->can_queue,
+ dsa = bus_to_virt (hostdata->reconnect_dsa_head);
+ left >= 0 && dsa;
+ dsa = next_dsa) {
+ save_flags (flags);
+ cli();
+ if (check_address ((unsigned long) dsa, sizeof(dsa)) == -1) {
+ printk ("scsi%d: bad DSA pointer 0x%p", host->host_no,
+ dsa);
+ next_dsa = NULL;
+ }
+ else
+ {
+ next_dsa = bus_to_virt(dsa[hostdata->dsa_next / sizeof(u32)]);
+ print_dsa (host, dsa, "");
+ }
+ restore_flags(flags);
+ }
+ printk ("scsi%d : end reconnect_dsa_head\n", host->host_no);
+ if (left < 0)
+ printk("scsi%d: possible loop in ncr reconnect list\n",
+ host->host_no);
+}
+
+static void
+print_lots (struct Scsi_Host *host) {
+ NCR53c7x0_local_declare();
+ struct NCR53c7x0_hostdata *hostdata =
+ (struct NCR53c7x0_hostdata *) host->hostdata;
+ u32 *dsp_next, *dsp, *dsa, dbc_dcmd;
+ unsigned char dcmd, sbcl;
+ int i, size;
+ NCR53c7x0_local_setup(host);
+
+ if ((dsp_next = bus_to_virt(NCR53c7x0_read32 (DSP_REG)))) {
+ dbc_dcmd = NCR53c7x0_read32(DBC_REG);
+ dcmd = (dbc_dcmd & 0xff000000) >> 24;
+ dsp = dsp_next - NCR53c7x0_insn_size(dcmd);
+ dsa = bus_to_virt(NCR53c7x0_read32(DSA_REG));
+ sbcl = NCR53c7x0_read8 (SBCL_REG);
+
+ /*
+ * For the 53c710, the following will report value 0 for SCNTL3
+ * and STEST0 - we dont have these registers.
+ */
+ printk ("scsi%d : DCMD|DBC=0x%x, DNAD=0x%x (virt 0x%p)\n"
+ " DSA=0x%lx (virt 0x%p)\n"
+ " DSPS=0x%x, TEMP=0x%x (virt 0x%p), DMODE=0x%x\n"
+ " SXFER=0x%x, SCNTL3=0x%x\n"
+ " %s%s%sphase=%s, %d bytes in SCSI FIFO\n"
+ " STEST0=0x%x\n",
+ host->host_no, dbc_dcmd, NCR53c7x0_read32(DNAD_REG),
+ bus_to_virt(NCR53c7x0_read32(DNAD_REG)),
+ virt_to_bus(dsa), dsa,
+ NCR53c7x0_read32(DSPS_REG), NCR53c7x0_read32(TEMP_REG),
+ bus_to_virt (NCR53c7x0_read32(TEMP_REG)),
+ (int) NCR53c7x0_read8(hostdata->dmode),
+ (int) NCR53c7x0_read8(SXFER_REG),
+ ((hostdata->chip / 100) == 8) ?
+ (int) NCR53c7x0_read8(SCNTL3_REG_800) : 0,
+ (sbcl & SBCL_BSY) ? "BSY " : "",
+ (sbcl & SBCL_SEL) ? "SEL " : "",
+ (sbcl & SBCL_REQ) ? "REQ " : "",
+ sstat2_to_phase(NCR53c7x0_read8 (((hostdata->chip / 100) == 8) ?
+ SSTAT1_REG : SSTAT2_REG)),
+ (NCR53c7x0_read8 ((hostdata->chip / 100) == 8 ?
+ SSTAT1_REG : SSTAT2_REG) & SSTAT2_FF_MASK) >> SSTAT2_FF_SHIFT,
+ ((hostdata->chip / 100) == 8) ?
+ NCR53c7x0_read8 (STEST0_REG_800) : 0);
+ printk ("scsi%d : DSP 0x%lx (virt 0x%p) ->\n", host->host_no,
+ virt_to_bus(dsp), dsp);
+ for (i = 6; i > 0; --i, dsp += size)
+ size = print_insn (host, dsp, "", 1);
+ if (NCR53c7x0_read8 (SCNTL1_REG) & SCNTL1_CON) {
+ if ((hostdata->chip / 100) == 8)
+ printk ("scsi%d : connected (SDID=0x%x, SSID=0x%x)\n",
+ host->host_no, NCR53c7x0_read8 (SDID_REG_800),
+ NCR53c7x0_read8 (SSID_REG_800));
+ else
+ printk ("scsi%d : connected (SDID=0x%x)\n",
+ host->host_no, NCR53c7x0_read8 (SDID_REG_700));
+ print_dsa (host, dsa, "");
+ }
+
+#if 1
+ print_queues (host);
+#endif
+ }
+}
+
+/*
+ * Function : static int shutdown (struct Scsi_Host *host)
+ *
+ * Purpose : does a clean (we hope) shutdown of the NCR SCSI
+ * chip. Use prior to dumping core, unloading the NCR driver,
+ *
+ * Returns : 0 on success
+ */
+static int
+shutdown (struct Scsi_Host *host) {
+ NCR53c7x0_local_declare();
+ unsigned long flags;
+ struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+ host->hostdata;
+ NCR53c7x0_local_setup(host);
+ save_flags (flags);
+ cli();
+/* Get in a state where we can reset the SCSI bus */
+ ncr_halt (host);
+ ncr_scsi_reset (host);
+ hostdata->soft_reset(host);
+
+ disable (host);
+ restore_flags (flags);
+ return 0;
+}
+
+/*
+ * Function : void ncr_scsi_reset (struct Scsi_Host *host)
+ *
+ * Purpose : reset the SCSI bus.
+ */
+
+static void
+ncr_scsi_reset (struct Scsi_Host *host) {
+ NCR53c7x0_local_declare();
+ unsigned long flags;
+ NCR53c7x0_local_setup(host);
+ save_flags (flags);
+ cli();
+ NCR53c7x0_write8(SCNTL1_REG, SCNTL1_RST);
+ udelay(25); /* Minimum amount of time to assert RST */
+ NCR53c7x0_write8(SCNTL1_REG, 0);
+ restore_flags (flags);
+}
+
+/*
+ * Function : void hard_reset (struct Scsi_Host *host)
+ *
+ */
+
+static void
+hard_reset (struct Scsi_Host *host) {
+ struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+ host->hostdata;
+ unsigned long flags;
+ save_flags (flags);
+ cli();
+ ncr_scsi_reset(host);
+ NCR53c7x0_driver_init (host);
+ if (hostdata->soft_reset)
+ hostdata->soft_reset (host);
+ restore_flags(flags);
+}
+
+
+/*
+ * Function : Scsi_Cmnd *return_outstanding_commands (struct Scsi_Host *host,
+ * int free, int issue)
+ *
+ * Purpose : return a linked list (using the SCp.buffer field as next,
+ * so we don't perturb hostdata. We don't use a field of the
+ * NCR53c7x0_cmd structure since we may not have allocated one
+ * for the command causing the reset.) of Scsi_Cmnd structures that
+ * had propogated below the Linux issue queue level. If free is set,
+ * free the NCR53c7x0_cmd structures which are associated with
+ * the Scsi_Cmnd structures, and clean up any internal
+ * NCR lists that the commands were on. If issue is set,
+ * also return commands in the issue queue.
+ *
+ * Returns : linked list of commands
+ *
+ * NOTE : the caller should insure that the NCR chip is halted
+ * if the free flag is set.
+ */
+
+static Scsi_Cmnd *
+return_outstanding_commands (struct Scsi_Host *host, int free, int issue) {
+ struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+ host->hostdata;
+ struct NCR53c7x0_cmd *c;
+ int i;
+ u32 *ncrcurrent;
+ Scsi_Cmnd *list = NULL, *tmp;
+ for (c = (struct NCR53c7x0_cmd *) hostdata->running_list; c;
+ c = (struct NCR53c7x0_cmd *) c->next) {
+ if (c->cmd->SCp.buffer) {
+ printk ("scsi%d : loop detected in running list!\n", host->host_no);
+ break;
+ } else {
+ printk ("The sti() implicit in a printk() prevents hangs\n");
+ break;
+ }
+
+ c->cmd->SCp.buffer = (struct scatterlist *) list;
+ list = c->cmd;
+ if (free) {
+ c->next = hostdata->free;
+ hostdata->free = c;
+ }
+ }
+
+ if (free) {
+ for (i = 0, ncrcurrent = (u32 *) hostdata->schedule;
+ i < host->can_queue; ++i, ncrcurrent += 2) {
+ ncrcurrent[0] = hostdata->NOP_insn;
+ ncrcurrent[1] = 0xdeadbeef;
+ }
+ hostdata->ncrcurrent = NULL;
+ }
+
+ if (issue) {
+ for (tmp = (Scsi_Cmnd *) hostdata->issue_queue; tmp; tmp = tmp->next) {
+ if (tmp->SCp.buffer) {
+ printk ("scsi%d : loop detected in issue queue!\n",
+ host->host_no);
+ break;
+ }
+ tmp->SCp.buffer = (struct scatterlist *) list;
+ list = tmp;
+ }
+ if (free)
+ hostdata->issue_queue = NULL;
+
+ }
+ return list;
+}
+
+/*
+ * Function : static int disable (struct Scsi_Host *host)
+ *
+ * Purpose : disables the given NCR host, causing all commands
+ * to return a driver error. Call this so we can unload the
+ * module during development and try again. Eventually,
+ * we should be able to find clean workarounds for these
+ * problems.
+ *
+ * Inputs : host - hostadapter to twiddle
+ *
+ * Returns : 0 on success.
+ */
+
+static int
+disable (struct Scsi_Host *host) {
+ struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+ host->hostdata;
+ unsigned long flags;
+ Scsi_Cmnd *nuke_list, *tmp;
+ save_flags(flags);
+ cli();
+ if (hostdata->state != STATE_HALTED)
+ ncr_halt (host);
+ nuke_list = return_outstanding_commands (host, 1 /* free */, 1 /* issue */);
+ hard_reset (host);
+ hostdata->state = STATE_DISABLED;
+ restore_flags(flags);
+ printk ("scsi%d : nuking commands\n", host->host_no);
+ for (; nuke_list; nuke_list = tmp) {
+ tmp = (Scsi_Cmnd *) nuke_list->SCp.buffer;
+ nuke_list->result = DID_ERROR << 16;
+ nuke_list->scsi_done(nuke_list);
+ }
+ printk ("scsi%d : done. \n", host->host_no);
+ printk (KERN_ALERT "scsi%d : disabled. Unload and reload\n",
+ host->host_no);
+ return 0;
+}
+
+/*
+ * Function : static int ncr_halt (struct Scsi_Host *host)
+ *
+ * Purpose : halts the SCSI SCRIPTS(tm) processor on the NCR chip
+ *
+ * Inputs : host - SCSI chip to halt
+ *
+ * Returns : 0 on success
+ */
+
+static int
+ncr_halt (struct Scsi_Host *host) {
+ NCR53c7x0_local_declare();
+ unsigned long flags;
+ unsigned char istat, tmp;
+ struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+ host->hostdata;
+ int stage;
+ NCR53c7x0_local_setup(host);
+
+ save_flags(flags);
+ cli();
+ /* Stage 0 : eat all interrupts
+ Stage 1 : set ABORT
+ Stage 2 : eat all but abort interrupts
+ Stage 3 : eat all interrupts
+ */
+ for (stage = 0;;) {
+ if (stage == 1) {
+ NCR53c7x0_write8(hostdata->istat, ISTAT_ABRT);
+ ++stage;
+ }
+ istat = NCR53c7x0_read8 (hostdata->istat);
+ if (istat & ISTAT_SIP) {
+ tmp = NCR53c7x0_read8(SSTAT0_REG);
+ } else if (istat & ISTAT_DIP) {
+ tmp = NCR53c7x0_read8(DSTAT_REG);
+ if (stage == 2) {
+ if (tmp & DSTAT_ABRT) {
+ NCR53c7x0_write8(hostdata->istat, 0);
+ ++stage;
+ } else {
+ printk(KERN_ALERT "scsi%d : could not halt NCR chip\n",
+ host->host_no);
+ disable (host);
+ }
+ }
+ }
+ if (!(istat & (ISTAT_SIP|ISTAT_DIP)))
+ if (stage == 0)
+ ++stage;
+ else if (stage == 3)
+ break;
+ }
+ hostdata->state = STATE_HALTED;
+ restore_flags(flags);
+#if 0
+ print_lots (host);
+#endif
+ return 0;
+}
+
+/*
+ * Function: event_name (int event)
+ *
+ * Purpose: map event enum into user-readable strings.
+ */
+
+static const char *
+event_name (int event) {
+ switch (event) {
+ case EVENT_NONE: return "none";
+ case EVENT_ISSUE_QUEUE: return "to issue queue";
+ case EVENT_START_QUEUE: return "to start queue";
+ case EVENT_SELECT: return "selected";
+ case EVENT_DISCONNECT: return "disconnected";
+ case EVENT_RESELECT: return "reselected";
+ case EVENT_COMPLETE: return "completed";
+ case EVENT_IDLE: return "idle";
+ case EVENT_SELECT_FAILED: return "select failed";
+ case EVENT_BEFORE_SELECT: return "before select";
+ case EVENT_RESELECT_FAILED: return "reselect failed";
+ default: return "unknown";
+ }
+}
+
+/*
+ * Function : void dump_events (struct Scsi_Host *host, count)
+ *
+ * Purpose : print last count events which have occurred.
+ */
+static void
+dump_events (struct Scsi_Host *host, int count) {
+ struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+ host->hostdata;
+ struct NCR53c7x0_event event;
+ int i;
+ unsigned long flags;
+ if (hostdata->events) {
+ if (count > hostdata->event_size)
+ count = hostdata->event_size;
+ for (i = hostdata->event_index; count > 0;
+ i = (i ? i - 1 : hostdata->event_size -1), --count) {
+ save_flags(flags);
+/*
+ * By copying the event we're currently examining with interrupts
+ * disabled, we can do multiple printk(), etc. operations and
+ * still be guaranteed that they're happening on the same
+ * event structure.
+ */
+ cli();
+#if 0
+ event = hostdata->events[i];
+#else
+ memcpy ((void *) &event, (void *) &(hostdata->events[i]),
+ sizeof(event));
+#endif
+
+ restore_flags(flags);
+ printk ("scsi%d : %s event %d at %ld secs %ld usecs target %d lun %d\n",
+ host->host_no, event_name (event.event), count,
+ (long) event.time.tv_sec, (long) event.time.tv_usec,
+ event.target, event.lun);
+ if (event.dsa)
+ printk (" event for dsa 0x%lx (virt 0x%p)\n",
+ virt_to_bus(event.dsa), event.dsa);
+ if (event.pid != -1) {
+ printk (" event for pid %ld ", event.pid);
+ print_command (event.cmnd);
+ }
+ }
+ }
+}
+
+/*
+ * Function: check_address
+ *
+ * Purpose: Check to see if a possibly corrupt pointer will fault the
+ * kernel.
+ *
+ * Inputs: addr - address; size - size of area
+ *
+ * Returns: 0 if area is OK, -1 on error.
+ *
+ * NOTES: should be implemented in terms of vverify on kernels
+ * that have it.
+ */
+
+static int
+check_address (unsigned long addr, int size) {
+ return (MAP_NR(addr) < 1 || MAP_NR(addr + size) > MAP_NR(high_memory) ?
+ -1 : 0);
+}
+
+#ifdef MODULE
+int
+NCR53c7x0_release(struct Scsi_Host *host) {
+ struct NCR53c7x0_hostdata *hostdata =
+ (struct NCR53c7x0_hostdata *) host->hostdata;
+ struct NCR53c7x0_cmd *cmd, *tmp;
+ shutdown (host);
+ if (host->irq != IRQ_NONE)
+ {
+ int irq_count;
+ struct Scsi_Host *tmp;
+ for (irq_count = 0, tmp = first_host; tmp; tmp = tmp->next)
+ if (tmp->hostt == the_template && tmp->irq == host->irq)
+ ++irq_count;
+ if (irq_count == 1)
+ free_irq(host->irq, NULL);
+ }
+ if (host->dma_channel != DMA_NONE)
+ free_dma(host->dma_channel);
+ if (host->io_port)
+ release_region(host->io_port, host->n_io_port);
+
+ for (cmd = (struct NCR53c7x0_cmd *) hostdata->free; cmd; cmd = tmp,
+ --hostdata->num_cmds) {
+ tmp = (struct NCR53c7x0_cmd *) cmd->next;
+ /*
+ * If we're going to loop, try to stop it to get a more accurate
+ * count of the leaked commands.
+ */
+ cmd->next = NULL;
+ if (cmd->free)
+ cmd->free ((void *) cmd->real, cmd->size);
+ }
+ if (hostdata->num_cmds)
+ printk ("scsi%d : leaked %d NCR53c7x0_cmd structures\n",
+ host->host_no, hostdata->num_cmds);
+ if (hostdata->events)
+ vfree ((void *)hostdata->events);
+ return 1;
+}
+Scsi_Host_Template driver_template = NCR53c7xx;
+#include "scsi_module.c"
+#endif /* def MODULE */
diff --git a/drivers/scsi/53c7xx.h b/drivers/scsi/53c7xx.h
new file mode 100644
index 000000000..56271a104
--- /dev/null
+++ b/drivers/scsi/53c7xx.h
@@ -0,0 +1,1675 @@
+/*
+ * 53c710 driver. Modified from Drew Eckhardts driver
+ * for 53c810 by Richard Hirst [richard@sleepie.demon.co.uk]
+ *
+ * I have left the code for the 53c8xx family in here, because it didn't
+ * seem worth removing it. The possibility of IO_MAPPED chips rather
+ * than MEMORY_MAPPED remains, in case someone wants to add support for
+ * 53c710 chips on Intel PCs (some older machines have them on the
+ * motherboard).
+ *
+ * NOTE THERE MAY BE PROBLEMS WITH CASTS IN read8 AND Co.
+ */
+
+/*
+ * NCR 53c{7,8}0x0 driver, header file
+ *
+ * Sponsored by
+ * iX Multiuser Multitasking Magazine
+ * Hannover, Germany
+ * hm@ix.de
+ *
+ * Copyright 1993, 1994, 1995 Drew Eckhardt
+ * Visionary Computing
+ * (Unix and Linux consulting and custom programming)
+ * drew@PoohSticks.ORG
+ * +1 (303) 786-7975
+ *
+ * TolerANT and SCSI SCRIPTS are registered trademarks of NCR Corporation.
+ *
+ * PRE-ALPHA
+ *
+ * For more information, please consult
+ *
+ * NCR 53C700/53C700-66
+ * SCSI I/O Processor
+ * Data Manual
+ *
+ * NCR 53C810
+ * PCI-SCSI I/O Processor
+ * Data Manual
+ *
+ * NCR Microelectronics
+ * 1635 Aeroplaza Drive
+ * Colorado Springs, CO 80916
+ * +1 (719) 578-3400
+ *
+ * Toll free literature number
+ * +1 (800) 334-5454
+ *
+ */
+
+#ifndef NCR53c710_H
+#define NCR53c710_H
+#if !defined(LINUX_1_2) && !defined(LINUX_1_3)
+#include <linux/version.h>
+#if LINUX_VERSION_CODE > 65536 + 3 * 256
+#define LINUX_1_3
+#else
+#define LINUX_1_2
+#endif
+#endif
+
+/*
+ * Prevent name space pollution in hosts.c, and only provide the
+ * define we need to get the NCR53c7x0 driver into the host template
+ * array.
+ */
+
+#if defined(HOSTS_C) || defined(MODULE)
+#include <scsi/scsicam.h>
+
+extern int NCR53c7xx_abort(Scsi_Cmnd *);
+extern int NCR53c7xx_detect(Scsi_Host_Template *tpnt);
+extern int NCR53c7xx_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+extern int NCR53c7xx_reset(Scsi_Cmnd *, unsigned int);
+#ifdef MODULE
+extern int NCR53c7xx_release(struct Scsi_Host *);
+#else
+#define NCR53c7xx_release NULL
+#endif
+
+#ifdef LINUX_1_2
+#define NCR53c7xx {NULL, NULL, "NCR53c{7,8}xx (rel 17)", NCR53c7xx_detect,\
+ NULL, /* info */ NULL, /* command, deprecated */ NULL, \
+ NCR53c7xx_queue_command, NCR53c7xx_abort, NCR53c7xx_reset, \
+ NULL /* slave attach */, scsicam_bios_param, /* can queue */ 24, \
+ /* id */ 7, 127 /* old SG_ALL */, /* cmd per lun */ 3, \
+ /* present */ 0, /* unchecked isa dma */ 0, DISABLE_CLUSTERING}
+#else
+#define NCR53c7xx {NULL, NULL, NULL, NULL, \
+ "NCR53c{7,8}xx (rel 17)", NCR53c7xx_detect,\
+ NULL, /* info */ NULL, /* command, deprecated */ NULL, \
+ NCR53c7xx_queue_command, NCR53c7xx_abort, NCR53c7xx_reset, \
+ NULL /* slave attach */, scsicam_bios_param, /* can queue */ 24, \
+ /* id */ 7, 127 /* old SG_ALL */, /* cmd per lun */ 3, \
+ /* present */ 0, /* unchecked isa dma */ 0, DISABLE_CLUSTERING}
+#endif
+
+#endif /* defined(HOSTS_C) || defined(MODULE) */
+
+#ifndef HOSTS_C
+#ifdef LINUX_1_2
+/*
+ * Change virtual addresses to physical addresses and vv.
+ * These are trivial on the 1:1 Linux/i386 mapping (but if we ever
+ * make the kernel segment mapped at 0, we need to do translation
+ * on the i386 as well)
+ */
+extern inline unsigned long virt_to_phys(volatile void * address)
+{
+ return (unsigned long) address;
+}
+
+extern inline void * phys_to_virt(unsigned long address)
+{
+ return (void *) address;
+}
+
+/*
+ * IO bus memory addresses are also 1:1 with the physical address
+ */
+#define virt_to_bus virt_to_phys
+#define bus_to_virt phys_to_virt
+
+/*
+ * readX/writeX() are used to access memory mapped devices. On some
+ * architectures the memory mapped IO stuff needs to be accessed
+ * differently. On the x86 architecture, we just read/write the
+ * memory location directly.
+ */
+#define readb(addr) (*(volatile unsigned char *) (addr))
+#define readw(addr) (*(volatile unsigned short *) (addr))
+#define readl(addr) (*(volatile unsigned int *) (addr))
+
+#define writeb(b,addr) ((*(volatile unsigned char *) (addr)) = (b))
+#define writew(b,addr) ((*(volatile unsigned short *) (addr)) = (b))
+#define writel(b,addr) ((*(volatile unsigned int *) (addr)) = (b))
+
+#define mb()
+
+#endif /* def LINUX_1_2 */
+
+/* SCSI control 0 rw, default = 0xc0 */
+#define SCNTL0_REG 0x00
+#define SCNTL0_ARB1 0x80 /* 0 0 = simple arbitration */
+#define SCNTL0_ARB2 0x40 /* 1 1 = full arbitration */
+#define SCNTL0_STRT 0x20 /* Start Sequence */
+#define SCNTL0_WATN 0x10 /* Select with ATN */
+#define SCNTL0_EPC 0x08 /* Enable parity checking */
+/* Bit 2 is reserved on 800 series chips */
+#define SCNTL0_EPG_700 0x04 /* Enable parity generation */
+#define SCNTL0_AAP 0x02 /* ATN/ on parity error */
+#define SCNTL0_TRG 0x01 /* Target mode */
+
+/* SCSI control 1 rw, default = 0x00 */
+
+#define SCNTL1_REG 0x01
+#define SCNTL1_EXC 0x80 /* Extra Clock Cycle of Data setup */
+#define SCNTL1_ADB 0x40 /* contents of SODL on bus */
+#define SCNTL1_ESR_700 0x20 /* Enable SIOP response to selection
+ and reselection */
+#define SCNTL1_DHP_800 0x20 /* Disable halt on parity error or ATN
+ target mode only */
+#define SCNTL1_CON 0x10 /* Connected */
+#define SCNTL1_RST 0x08 /* SCSI RST/ */
+#define SCNTL1_AESP 0x04 /* Force bad parity */
+#define SCNTL1_SND_700 0x02 /* Start SCSI send */
+#define SCNTL1_IARB_800 0x02 /* Immediate Arbitration, start
+ arbitration immediately after
+ busfree is detected */
+#define SCNTL1_RCV_700 0x01 /* Start SCSI receive */
+#define SCNTL1_SST_800 0x01 /* Start SCSI transfer */
+
+/* SCSI control 2 rw, */
+
+#define SCNTL2_REG_800 0x02
+#define SCNTL2_800_SDU 0x80 /* SCSI disconnect unexpected */
+
+/* SCSI control 3 rw */
+
+#define SCNTL3_REG_800 0x03
+#define SCNTL3_800_SCF_SHIFT 4
+#define SCNTL3_800_SCF_MASK 0x70
+#define SCNTL3_800_SCF2 0x40 /* Synchronous divisor */
+#define SCNTL3_800_SCF1 0x20 /* 0x00 = SCLK/3 */
+#define SCNTL3_800_SCF0 0x10 /* 0x10 = SCLK/1 */
+ /* 0x20 = SCLK/1.5
+ 0x30 = SCLK/2
+ 0x40 = SCLK/3 */
+
+#define SCNTL3_800_CCF_SHIFT 0
+#define SCNTL3_800_CCF_MASK 0x07
+#define SCNTL3_800_CCF2 0x04 /* 0x00 50.01 to 66 */
+#define SCNTL3_800_CCF1 0x02 /* 0x01 16.67 to 25 */
+#define SCNTL3_800_CCF0 0x01 /* 0x02 25.01 - 37.5
+ 0x03 37.51 - 50
+ 0x04 50.01 - 66 */
+
+/*
+ * SCSI destination ID rw - the appropriate bit is set for the selected
+ * target ID. This is written by the SCSI SCRIPTS processor.
+ * default = 0x00
+ */
+#define SDID_REG_700 0x02
+#define SDID_REG_800 0x06
+
+#define GP_REG_800 0x07 /* General purpose IO */
+#define GP_800_IO1 0x02
+#define GP_800_IO2 0x01
+
+/* SCSI interrupt enable rw, default = 0x00 */
+#define SIEN_REG_700 0x03
+#define SIEN0_REG_800 0x40
+#define SIEN_MA 0x80 /* Phase mismatch (ini) or ATN (tgt) */
+#define SIEN_FC 0x40 /* Function complete */
+#define SIEN_700_STO 0x20 /* Selection or reselection timeout */
+#define SIEN_800_SEL 0x20 /* Selected */
+#define SIEN_700_SEL 0x10 /* Selected or reselected */
+#define SIEN_800_RESEL 0x10 /* Reselected */
+#define SIEN_SGE 0x08 /* SCSI gross error */
+#define SIEN_UDC 0x04 /* Unexpected disconnect */
+#define SIEN_RST 0x02 /* SCSI RST/ received */
+#define SIEN_PAR 0x01 /* Parity error */
+
+/*
+ * SCSI chip ID rw
+ * NCR53c700 :
+ * When arbitrating, the highest bit is used, when reselection or selection
+ * occurs, the chip responds to all IDs for which a bit is set.
+ * default = 0x00
+ * NCR53c810 :
+ * Uses bit mapping
+ */
+#define SCID_REG 0x04
+/* Bit 7 is reserved on 800 series chips */
+#define SCID_800_RRE 0x40 /* Enable response to reselection */
+#define SCID_800_SRE 0x20 /* Enable response to selection */
+/* Bits four and three are reserved on 800 series chips */
+#define SCID_800_ENC_MASK 0x07 /* Encoded SCSI ID */
+
+/* SCSI transfer rw, default = 0x00 */
+#define SXFER_REG 0x05
+#define SXFER_DHP 0x80 /* Disable halt on parity */
+
+#define SXFER_TP2 0x40 /* Transfer period msb */
+#define SXFER_TP1 0x20
+#define SXFER_TP0 0x10 /* lsb */
+#define SXFER_TP_MASK 0x70
+/* FIXME : SXFER_TP_SHIFT == 5 is right for '8xx chips */
+#define SXFER_TP_SHIFT 5
+#define SXFER_TP_4 0x00 /* Divisors */
+#define SXFER_TP_5 0x10<<1
+#define SXFER_TP_6 0x20<<1
+#define SXFER_TP_7 0x30<<1
+#define SXFER_TP_8 0x40<<1
+#define SXFER_TP_9 0x50<<1
+#define SXFER_TP_10 0x60<<1
+#define SXFER_TP_11 0x70<<1
+
+#define SXFER_MO3 0x08 /* Max offset msb */
+#define SXFER_MO2 0x04
+#define SXFER_MO1 0x02
+#define SXFER_MO0 0x01 /* lsb */
+#define SXFER_MO_MASK 0x0f
+#define SXFER_MO_SHIFT 0
+
+/*
+ * SCSI output data latch rw
+ * The contents of this register are driven onto the SCSI bus when
+ * the Assert Data Bus bit of the SCNTL1 register is set and
+ * the CD, IO, and MSG bits of the SOCL register match the SCSI phase
+ */
+#define SODL_REG_700 0x06
+#define SODL_REG_800 0x54
+
+
+/*
+ * SCSI output control latch rw, default = 0
+ * Note that when the chip is being manually programmed as an initiator,
+ * the MSG, CD, and IO bits must be set correctly for the phase the target
+ * is driving the bus in. Otherwise no data transfer will occur due to
+ * phase mismatch.
+ */
+
+#define SOCL_REG 0x07
+#define SOCL_REQ 0x80 /* REQ */
+#define SOCL_ACK 0x40 /* ACK */
+#define SOCL_BSY 0x20 /* BSY */
+#define SOCL_SEL 0x10 /* SEL */
+#define SOCL_ATN 0x08 /* ATN */
+#define SOCL_MSG 0x04 /* MSG */
+#define SOCL_CD 0x02 /* C/D */
+#define SOCL_IO 0x01 /* I/O */
+
+/*
+ * SCSI first byte received latch ro
+ * This register contains the first byte received during a block MOVE
+ * SCSI SCRIPTS instruction, including
+ *
+ * Initiator mode Target mode
+ * Message in Command
+ * Status Message out
+ * Data in Data out
+ *
+ * It also contains the selecting or reselecting device's ID and our
+ * ID.
+ *
+ * Note that this is the register the various IF conditionals can
+ * operate on.
+ */
+#define SFBR_REG 0x08
+
+/*
+ * SCSI input data latch ro
+ * In initiator mode, data is latched into this register on the rising
+ * edge of REQ/. In target mode, data is latched on the rising edge of
+ * ACK/
+ */
+#define SIDL_REG_700 0x09
+#define SIDL_REG_800 0x50
+
+/*
+ * SCSI bus data lines ro
+ * This register reflects the instantaneous status of the SCSI data
+ * lines. Note that SCNTL0 must be set to disable parity checking,
+ * otherwise reading this register will latch new parity.
+ */
+#define SBDL_REG_700 0x0a
+#define SBDL_REG_800 0x58
+
+#define SSID_REG_800 0x0a
+#define SSID_800_VAL 0x80 /* Exactly two bits asserted at sel */
+#define SSID_800_ENCID_MASK 0x07 /* Device which performed operation */
+
+
+/*
+ * SCSI bus control lines rw,
+ * instantaneous readout of control lines
+ */
+#define SBCL_REG 0x0b
+#define SBCL_REQ 0x80 /* REQ ro */
+#define SBCL_ACK 0x40 /* ACK ro */
+#define SBCL_BSY 0x20 /* BSY ro */
+#define SBCL_SEL 0x10 /* SEL ro */
+#define SBCL_ATN 0x08 /* ATN ro */
+#define SBCL_MSG 0x04 /* MSG ro */
+#define SBCL_CD 0x02 /* C/D ro */
+#define SBCL_IO 0x01 /* I/O ro */
+#define SBCL_PHASE_CMDOUT SBCL_CD
+#define SBCL_PHASE_DATAIN SBCL_IO
+#define SBCL_PHASE_DATAOUT 0
+#define SBCL_PHASE_MSGIN (SBCL_CD|SBCL_IO|SBCL_MSG)
+#define SBCL_PHASE_MSGOUT (SBCL_CD|SBCL_MSG)
+#define SBCL_PHASE_STATIN (SBCL_CD|SBCL_IO)
+#define SBCL_PHASE_MASK (SBCL_CD|SBCL_IO|SBCL_MSG)
+/*
+ * Synchronous SCSI Clock Control bits
+ * 0 - set by DCNTL
+ * 1 - SCLK / 1.0
+ * 2 - SCLK / 1.5
+ * 3 - SCLK / 2.0
+ */
+#define SBCL_SSCF1 0x02 /* wo, -66 only */
+#define SBCL_SSCF0 0x01 /* wo, -66 only */
+#define SBCL_SSCF_MASK 0x03
+
+/*
+ * XXX note : when reading the DSTAT and STAT registers to clear interrupts,
+ * insure that 10 clocks elapse between the two
+ */
+/* DMA status ro */
+#define DSTAT_REG 0x0c
+#define DSTAT_DFE 0x80 /* DMA FIFO empty */
+#define DSTAT_800_MDPE 0x40 /* Master Data Parity Error */
+#define DSTAT_800_BF 0x20 /* Bus Fault */
+#define DSTAT_ABRT 0x10 /* Aborted - set on error */
+#define DSTAT_SSI 0x08 /* SCRIPTS single step interrupt */
+#define DSTAT_SIR 0x04 /* SCRIPTS interrupt received -
+ set when INT instruction is
+ executed */
+#define DSTAT_WTD 0x02 /* Watchdog timeout detected */
+#define DSTAT_OPC 0x01 /* Illegal instruction */
+#define DSTAT_800_IID 0x01 /* Same thing, different name */
+
+
+/* NCR53c800 moves this stuff into SIST0 */
+#define SSTAT0_REG 0x0d /* SCSI status 0 ro */
+#define SIST0_REG_800 0x42
+#define SSTAT0_MA 0x80 /* ini : phase mismatch,
+ * tgt : ATN/ asserted
+ */
+#define SSTAT0_CMP 0x40 /* function complete */
+#define SSTAT0_700_STO 0x20 /* Selection or reselection timeout */
+#define SIST0_800_SEL 0x20 /* Selected */
+#define SSTAT0_700_SEL 0x10 /* Selected or reselected */
+#define SIST0_800_RSL 0x10 /* Reselected */
+#define SSTAT0_SGE 0x08 /* SCSI gross error */
+#define SSTAT0_UDC 0x04 /* Unexpected disconnect */
+#define SSTAT0_RST 0x02 /* SCSI RST/ received */
+#define SSTAT0_PAR 0x01 /* Parity error */
+
+/* And uses SSTAT0 for what was SSTAT1 */
+
+#define SSTAT1_REG 0x0e /* SCSI status 1 ro */
+#define SSTAT1_ILF 0x80 /* SIDL full */
+#define SSTAT1_ORF 0x40 /* SODR full */
+#define SSTAT1_OLF 0x20 /* SODL full */
+#define SSTAT1_AIP 0x10 /* Arbitration in progress */
+#define SSTAT1_LOA 0x08 /* Lost arbitration */
+#define SSTAT1_WOA 0x04 /* Won arbitration */
+#define SSTAT1_RST 0x02 /* Instant readout of RST/ */
+#define SSTAT1_SDP 0x01 /* Instant readout of SDP/ */
+
+#define SSTAT2_REG 0x0f /* SCSI status 2 ro */
+#define SSTAT2_FF3 0x80 /* number of bytes in synchronous */
+#define SSTAT2_FF2 0x40 /* data FIFO */
+#define SSTAT2_FF1 0x20
+#define SSTAT2_FF0 0x10
+#define SSTAT2_FF_MASK 0xf0
+#define SSTAT2_FF_SHIFT 4
+
+/*
+ * Latched signals, latched on the leading edge of REQ/ for initiators,
+ * ACK/ for targets.
+ */
+#define SSTAT2_SDP 0x08 /* SDP */
+#define SSTAT2_MSG 0x04 /* MSG */
+#define SSTAT2_CD 0x02 /* C/D */
+#define SSTAT2_IO 0x01 /* I/O */
+#define SSTAT2_PHASE_CMDOUT SSTAT2_CD
+#define SSTAT2_PHASE_DATAIN SSTAT2_IO
+#define SSTAT2_PHASE_DATAOUT 0
+#define SSTAT2_PHASE_MSGIN (SSTAT2_CD|SSTAT2_IO|SSTAT2_MSG)
+#define SSTAT2_PHASE_MSGOUT (SSTAT2_CD|SSTAT2_MSG)
+#define SSTAT2_PHASE_STATIN (SSTAT2_CD|SSTAT2_IO)
+#define SSTAT2_PHASE_MASK (SSTAT2_CD|SSTAT2_IO|SSTAT2_MSG)
+
+
+/* NCR53c700-66 only */
+#define SCRATCHA_REG_00 0x10 /* through 0x13 Scratch A rw */
+/* NCR53c710 and higher */
+#define DSA_REG 0x10 /* DATA structure address */
+
+#define CTEST0_REG_700 0x14 /* Chip test 0 ro */
+#define CTEST0_REG_800 0x18 /* Chip test 0 rw, general purpose */
+/* 0x80 - 0x04 are reserved */
+#define CTEST0_700_RTRG 0x02 /* Real target mode */
+#define CTEST0_700_DDIR 0x01 /* Data direction, 1 =
+ * SCSI bus to host, 0 =
+ * host to SCSI.
+ */
+
+#define CTEST1_REG_700 0x15 /* Chip test 1 ro */
+#define CTEST1_REG_800 0x19 /* Chip test 1 ro */
+#define CTEST1_FMT3 0x80 /* Identify which byte lanes are empty */
+#define CTEST1_FMT2 0x40 /* in the DMA FIFO */
+#define CTEST1_FMT1 0x20
+#define CTEST1_FMT0 0x10
+
+#define CTEST1_FFL3 0x08 /* Identify which bytes lanes are full */
+#define CTEST1_FFL2 0x04 /* in the DMA FIFO */
+#define CTEST1_FFL1 0x02
+#define CTEST1_FFL0 0x01
+
+#define CTEST2_REG_700 0x16 /* Chip test 2 ro */
+#define CTEST2_REG_800 0x1a /* Chip test 2 ro */
+
+#define CTEST2_800_DDIR 0x80 /* 1 = SCSI->host */
+#define CTEST2_800_SIGP 0x40 /* A copy of SIGP in ISTAT.
+ Reading this register clears */
+#define CTEST2_800_CIO 0x20 /* Configured as IO */.
+#define CTEST2_800_CM 0x10 /* Configured as memory */
+
+/* 0x80 - 0x40 are reserved on 700 series chips */
+#define CTEST2_700_SOFF 0x20 /* SCSI Offset Compare,
+ * As an initiator, this bit is
+ * one when the synchronous offset
+ * is zero, as a target this bit
+ * is one when the synchronous
+ * offset is at the maximum
+ * defined in SXFER
+ */
+#define CTEST2_700_SFP 0x10 /* SCSI FIFO parity bit,
+ * reading CTEST3 unloads a byte
+ * from the FIFO and sets this
+ */
+#define CTEST2_700_DFP 0x08 /* DMA FIFO parity bit,
+ * reading CTEST6 unloads a byte
+ * from the FIFO and sets this
+ */
+#define CTEST2_TEOP 0x04 /* SCSI true end of process,
+ * indicates a totally finished
+ * transfer
+ */
+#define CTEST2_DREQ 0x02 /* Data request signal */
+/* 0x01 is reserved on 700 series chips */
+#define CTEST2_800_DACK 0x01
+
+/*
+ * Chip test 3 ro
+ * Unloads the bottom byte of the eight deep SCSI synchronous FIFO,
+ * check SSTAT2 FIFO full bits to determine size. Note that a GROSS
+ * error results if a read is attempted on this register. Also note
+ * that 16 and 32 bit reads of this register will cause corruption.
+ */
+#define CTEST3_REG_700 0x17
+/* Chip test 3 rw */
+#define CTEST3_REG_800 0x1b
+#define CTEST3_800_V3 0x80 /* Chip revision */
+#define CTEST3_800_V2 0x40
+#define CTEST3_800_V1 0x20
+#define CTEST3_800_V0 0x10
+#define CTEST3_800_FLF 0x08 /* Flush DMA FIFO */
+#define CTEST3_800_CLF 0x04 /* Clear DMA FIFO */
+#define CTEST3_800_FM 0x02 /* Fetch mode pin */
+/* bit 0 is reserved on 800 series chips */
+
+#define CTEST4_REG_700 0x18 /* Chip test 4 rw */
+#define CTEST4_REG_800 0x21 /* Chip test 4 rw */
+/* 0x80 is reserved on 700 series chips */
+#define CTEST4_800_BDIS 0x80 /* Burst mode disable */
+#define CTEST4_ZMOD 0x40 /* High impedance mode */
+#define CTEST4_SZM 0x20 /* SCSI bus high impedance */
+#define CTEST4_700_SLBE 0x10 /* SCSI loopback enabled */
+#define CTEST4_800_SRTM 0x10 /* Shadow Register Test Mode */
+#define CTEST4_700_SFWR 0x08 /* SCSI FIFO write enable,
+ * redirects writes from SODL
+ * to the SCSI FIFO.
+ */
+#define CTEST4_800_MPEE 0x08 /* Enable parity checking
+ during master cycles on PCI
+ bus */
+
+/*
+ * These bits send the contents of the CTEST6 register to the appropriate
+ * byte lane of the 32 bit DMA FIFO. Normal operation is zero, otherwise
+ * the high bit means the low two bits select the byte lane.
+ */
+#define CTEST4_FBL2 0x04
+#define CTEST4_FBL1 0x02
+#define CTEST4_FBL0 0x01
+#define CTEST4_FBL_MASK 0x07
+#define CTEST4_FBL_0 0x04 /* Select DMA FIFO byte lane 0 */
+#define CTEST4_FBL_1 0x05 /* Select DMA FIFO byte lane 1 */
+#define CTEST4_FBL_2 0x06 /* Select DMA FIFO byte lane 2 */
+#define CTEST4_FBL_3 0x07 /* Select DMA FIFO byte lane 3 */
+#define CTEST4_800_SAVE (CTEST4_800_BDIS)
+
+
+#define CTEST5_REG_700 0x19 /* Chip test 5 rw */
+#define CTEST5_REG_800 0x22 /* Chip test 5 rw */
+/*
+ * Clock Address Incrementor. When set, it increments the
+ * DNAD register to the next bus size boundary. It automatically
+ * resets itself when the operation is complete.
+ */
+#define CTEST5_ADCK 0x80
+/*
+ * Clock Byte Counter. When set, it decrements the DBC register to
+ * the next bus size boundary.
+ */
+#define CTEST5_BBCK 0x40
+/*
+ * Reset SCSI Offset. Setting this bit to 1 clears the current offset
+ * pointer in the SCSI synchronous offset counter (SSTAT). This bit
+ * is set to 1 if a SCSI Gross Error Condition occurs. The offset should
+ * be cleared when a synchronous transfer fails. When written, it is
+ * automatically cleared after the SCSI synchronous offset counter is
+ * reset.
+ */
+/* Bit 5 is reserved on 800 series chips */
+#define CTEST5_700_ROFF 0x20
+/*
+ * Master Control for Set or Reset pulses. When 1, causes the low
+ * four bits of register to set when set, 0 causes the low bits to
+ * clear when set.
+ */
+#define CTEST5_MASR 0x10
+#define CTEST5_DDIR 0x08 /* DMA direction */
+/*
+ * Bits 2-0 are reserved on 800 series chips
+ */
+#define CTEST5_700_EOP 0x04 /* End of process */
+#define CTEST5_700_DREQ 0x02 /* Data request */
+#define CTEST5_700_DACK 0x01 /* Data acknowledge */
+
+/*
+ * Chip test 6 rw - writing to this register writes to the byte
+ * lane in the DMA FIFO as determined by the FBL bits in the CTEST4
+ * register.
+ */
+#define CTEST6_REG_700 0x1a
+#define CTEST6_REG_800 0x23
+
+#define CTEST7_REG 0x1b /* Chip test 7 rw */
+/* 0x80 - 0x40 are reserved on NCR53c700 and NCR53c700-66 chips */
+#define CTEST7_10_CDIS 0x80 /* Cache burst disable */
+#define CTEST7_10_SC1 0x40 /* Snoop control bits */
+#define CTEST7_10_SC0 0x20
+#define CTEST7_10_SC_MASK 0x60
+/* 0x20 is reserved on the NCR53c700 */
+#define CTEST7_0060_FM 0x20 /* Fetch mode */
+#define CTEST7_STD 0x10 /* Selection timeout disable */
+#define CTEST7_DFP 0x08 /* DMA FIFO parity bit for CTEST6 */
+#define CTEST7_EVP 0x04 /* 1 = host bus even parity, 0 = odd */
+#define CTEST7_10_TT1 0x02 /* Transfer type */
+#define CTEST7_00_DC 0x02 /* Set to drive DC low during instruction
+ fetch */
+#define CTEST7_DIFF 0x01 /* Differential mode */
+
+#define CTEST7_SAVE ( CTEST7_EVP | CTEST7_DIFF )
+
+
+#define TEMP_REG 0x1c /* through 0x1f Temporary stack rw */
+
+#define DFIFO_REG 0x20 /* DMA FIFO rw */
+/*
+ * 0x80 is reserved on the NCR53c710, the CLF and FLF bits have been
+ * moved into the CTEST8 register.
+ */
+#define DFIFO_00_FLF 0x80 /* Flush DMA FIFO to memory */
+#define DFIFO_00_CLF 0x40 /* Clear DMA and SCSI FIFOs */
+#define DFIFO_BO6 0x40
+#define DFIFO_BO5 0x20
+#define DFIFO_BO4 0x10
+#define DFIFO_BO3 0x08
+#define DFIFO_BO2 0x04
+#define DFIFO_BO1 0x02
+#define DFIFO_BO0 0x01
+#define DFIFO_10_BO_MASK 0x7f /* 7 bit counter */
+#define DFIFO_00_BO_MASK 0x3f /* 6 bit counter */
+
+/*
+ * Interrupt status rw
+ * Note that this is the only register which can be read while SCSI
+ * SCRIPTS are being executed.
+ */
+#define ISTAT_REG_700 0x21
+#define ISTAT_REG_800 0x14
+#define ISTAT_ABRT 0x80 /* Software abort, write
+ *1 to abort, wait for interrupt. */
+/* 0x40 and 0x20 are reserved on NCR53c700 and NCR53c700-66 chips */
+#define ISTAT_10_SRST 0x40 /* software reset */
+#define ISTAT_10_SIGP 0x20 /* signal script */
+/* 0x10 is reserved on NCR53c700 series chips */
+#define ISTAT_800_SEM 0x10 /* semaphore */
+#define ISTAT_CON 0x08 /* 1 when connected */
+#define ISTAT_800_INTF 0x04 /* Interrupt on the fly */
+#define ISTAT_700_PRE 0x04 /* Pointer register empty.
+ * Set to 1 when DSPS and DSP
+ * registers are empty in pipeline
+ * mode, always set otherwise.
+ */
+#define ISTAT_SIP 0x02 /* SCSI interrupt pending from
+ * SCSI portion of SIOP see
+ * SSTAT0
+ */
+#define ISTAT_DIP 0x01 /* DMA interrupt pending
+ * see DSTAT
+ */
+
+/* NCR53c700-66 and NCR53c710 only */
+#define CTEST8_REG 0x22 /* Chip test 8 rw */
+#define CTEST8_0066_EAS 0x80 /* Enable alternate SCSI clock,
+ * ie read from SCLK/ rather than CLK/
+ */
+#define CTEST8_0066_EFM 0x40 /* Enable fetch and master outputs */
+#define CTEST8_0066_GRP 0x20 /* Generate Receive Parity for
+ * pass through. This insures that
+ * bad parity won't reach the host
+ * bus.
+ */
+#define CTEST8_0066_TE 0x10 /* TolerANT enable. Enable
+ * active negation, should only
+ * be used for slow SCSI
+ * non-differential.
+ */
+#define CTEST8_0066_HSC 0x08 /* Halt SCSI clock */
+#define CTEST8_0066_SRA 0x04 /* Shorten REQ/ACK filtering,
+ * must be set for fast SCSI-II
+ * speeds.
+ */
+#define CTEST8_0066_DAS 0x02 /* Disable automatic target/initiator
+ * switching.
+ */
+#define CTEST8_0066_LDE 0x01 /* Last disconnect enable.
+ * The status of pending
+ * disconnect is maintained by
+ * the core, eliminating
+ * the possibility of missing a
+ * selection or reselection
+ * while waiting to fetch a
+ * WAIT DISCONNECT opcode.
+ */
+
+#define CTEST8_10_V3 0x80 /* Chip revision */
+#define CTEST8_10_V2 0x40
+#define CTEST8_10_V1 0x20
+#define CTEST8_10_V0 0x10
+#define CTEST8_10_V_MASK 0xf0
+#define CTEST8_10_FLF 0x08 /* Flush FIFOs */
+#define CTEST8_10_CLF 0x04 /* Clear FIFOs */
+#define CTEST8_10_FM 0x02 /* Fetch pin mode */
+#define CTEST8_10_SM 0x01 /* Snoop pin mode */
+
+
+/*
+ * The CTEST9 register may be used to differentiate between a
+ * NCR53c700 and a NCR53c710.
+ *
+ * Write 0xff to this register.
+ * Read it.
+ * If the contents are 0xff, it is a NCR53c700
+ * If the contents are 0x00, it is a NCR53c700-66 first revision
+ * If the contents are some other value, it is some other NCR53c700-66
+ */
+#define CTEST9_REG_00 0x23 /* Chip test 9 ro */
+#define LCRC_REG_10 0x23
+
+/*
+ * 0x24 through 0x27 are the DMA byte counter register. Instructions
+ * write their high 8 bits into the DCMD register, the low 24 bits into
+ * the DBC register.
+ *
+ * Function is dependent on the command type being executed.
+ */
+
+
+#define DBC_REG 0x24
+/*
+ * For Block Move Instructions, DBC is a 24 bit quantity representing
+ * the number of bytes to transfer.
+ * For Transfer Control Instructions, DBC is bit fielded as follows :
+ */
+/* Bits 20 - 23 should be clear */
+#define DBC_TCI_TRUE (1 << 19) /* Jump when true */
+#define DBC_TCI_COMPARE_DATA (1 << 18) /* Compare data */
+#define DBC_TCI_COMPARE_PHASE (1 << 17) /* Compare phase with DCMD field */
+#define DBC_TCI_WAIT_FOR_VALID (1 << 16) /* Wait for REQ */
+/* Bits 8 - 15 are reserved on some implementations ? */
+#define DBC_TCI_MASK_MASK 0xff00 /* Mask for data compare */
+#define DBC_TCI_MASK_SHIFT 8
+#define DBC_TCI_DATA_MASK 0xff /* Data to be compared */
+#define DBC_TCI_DATA_SHIFT 0
+
+#define DBC_RWRI_IMMEDIATE_MASK 0xff00 /* Immediate data */
+#define DBC_RWRI_IMMEDIATE_SHIFT 8 /* Amount to shift */
+#define DBC_RWRI_ADDRESS_MASK 0x3f0000 /* Register address */
+#define DBC_RWRI_ADDRESS_SHIFT 16
+
+
+/*
+ * DMA command r/w
+ */
+#define DCMD_REG 0x27
+#define DCMD_TYPE_MASK 0xc0 /* Masks off type */
+#define DCMD_TYPE_BMI 0x00 /* Indicates a Block Move instruction */
+#define DCMD_BMI_IO 0x01 /* I/O, CD, and MSG bits selecting */
+#define DCMD_BMI_CD 0x02 /* the phase for the block MOVE */
+#define DCMD_BMI_MSG 0x04 /* instruction */
+
+#define DCMD_BMI_OP_MASK 0x18 /* mask for opcode */
+#define DCMD_BMI_OP_MOVE_T 0x00 /* MOVE */
+#define DCMD_BMI_OP_MOVE_I 0x08 /* MOVE Initiator */
+
+#define DCMD_BMI_INDIRECT 0x20 /* Indirect addressing */
+
+#define DCMD_TYPE_TCI 0x80 /* Indicates a Transfer Control
+ instruction */
+#define DCMD_TCI_IO 0x01 /* I/O, CD, and MSG bits selecting */
+#define DCMD_TCI_CD 0x02 /* the phase for the block MOVE */
+#define DCMD_TCI_MSG 0x04 /* instruction */
+#define DCMD_TCI_OP_MASK 0x38 /* mask for opcode */
+#define DCMD_TCI_OP_JUMP 0x00 /* JUMP */
+#define DCMD_TCI_OP_CALL 0x08 /* CALL */
+#define DCMD_TCI_OP_RETURN 0x10 /* RETURN */
+#define DCMD_TCI_OP_INT 0x18 /* INT */
+
+#define DCMD_TYPE_RWRI 0x40 /* Indicates I/O or register Read/Write
+ instruction */
+#define DCMD_RWRI_OPC_MASK 0x38 /* Opcode mask */
+#define DCMD_RWRI_OPC_WRITE 0x28 /* Write SFBR to register */
+#define DCMD_RWRI_OPC_READ 0x30 /* Read register to SFBR */
+#define DCMD_RWRI_OPC_MODIFY 0x38 /* Modify in place */
+
+#define DCMD_RWRI_OP_MASK 0x07
+#define DCMD_RWRI_OP_MOVE 0x00
+#define DCMD_RWRI_OP_SHL 0x01
+#define DCMD_RWRI_OP_OR 0x02
+#define DCMD_RWRI_OP_XOR 0x03
+#define DCMD_RWRI_OP_AND 0x04
+#define DCMD_RWRI_OP_SHR 0x05
+#define DCMD_RWRI_OP_ADD 0x06
+#define DCMD_RWRI_OP_ADDC 0x07
+
+#define DCMD_TYPE_MMI 0xc0 /* Indicates a Memory Move instruction
+ (three words) */
+
+
+#define DNAD_REG 0x28 /* through 0x2b DMA next address for
+ data */
+#define DSP_REG 0x2c /* through 0x2f DMA SCRIPTS pointer rw */
+#define DSPS_REG 0x30 /* through 0x33 DMA SCRIPTS pointer
+ save rw */
+#define DMODE_REG_00 0x34 /* DMA mode rw */
+#define DMODE_00_BL1 0x80 /* Burst length bits */
+#define DMODE_00_BL0 0x40
+#define DMODE_BL_MASK 0xc0
+/* Burst lengths (800) */
+#define DMODE_BL_2 0x00 /* 2 transfer */
+#define DMODE_BL_4 0x40 /* 4 transfers */
+#define DMODE_BL_8 0x80 /* 8 transfers */
+#define DMODE_BL_16 0xc0 /* 16 transfers */
+
+#define DMODE_10_BL_1 0x00 /* 1 transfer */
+#define DMODE_10_BL_2 0x40 /* 2 transfers */
+#define DMODE_10_BL_4 0x80 /* 4 transfers */
+#define DMODE_10_BL_8 0xc0 /* 8 transfers */
+#define DMODE_10_FC2 0x20 /* Driven to FC2 pin */
+#define DMODE_10_FC1 0x10 /* Driven to FC1 pin */
+#define DMODE_710_PD 0x08 /* Program/data on FC0 pin */
+#define DMODE_710_UO 0x02 /* User prog. output */
+
+#define DMODE_700_BW16 0x20 /* Host buswidth = 16 */
+#define DMODE_700_286 0x10 /* 286 mode */
+#define DMODE_700_IOM 0x08 /* Transfer to IO port */
+#define DMODE_700_FAM 0x04 /* Fixed address mode */
+#define DMODE_700_PIPE 0x02 /* Pipeline mode disables
+ * automatic fetch / exec
+ */
+#define DMODE_MAN 0x01 /* Manual start mode,
+ * requires a 1 to be written
+ * to the start DMA bit in the DCNTL
+ * register to run scripts
+ */
+
+#define DMODE_700_SAVE ( DMODE_00_BL_MASK | DMODE_00_BW16 | DMODE_00_286 )
+
+/* NCR53c800 series only */
+#define SCRATCHA_REG_800 0x34 /* through 0x37 Scratch A rw */
+/* NCR53c710 only */
+#define SCRATCHB_REG_10 0x34 /* through 0x37 scratch B rw */
+
+#define DMODE_REG_10 0x38 /* DMA mode rw, NCR53c710 and newer */
+#define DMODE_800_SIOM 0x20 /* Source IO = 1 */
+#define DMODE_800_DIOM 0x10 /* Destination IO = 1 */
+#define DMODE_800_ERL 0x08 /* Enable Read Line */
+
+/* 35-38 are reserved on 700 and 700-66 series chips */
+#define DIEN_REG 0x39 /* DMA interrupt enable rw */
+/* 0x80, 0x40, and 0x20 are reserved on 700-series chips */
+#define DIEN_800_MDPE 0x40 /* Master data parity error */
+#define DIEN_800_BF 0x20 /* BUS fault */
+#define DIEN_700_BF 0x20 /* BUS fault */
+#define DIEN_ABRT 0x10 /* Enable aborted interrupt */
+#define DIEN_SSI 0x08 /* Enable single step interrupt */
+#define DIEN_SIR 0x04 /* Enable SCRIPTS INT command
+ * interrupt
+ */
+/* 0x02 is reserved on 800 series chips */
+#define DIEN_700_WTD 0x02 /* Enable watchdog timeout interrupt */
+#define DIEN_700_OPC 0x01 /* Enable illegal instruction
+ * interrupt
+ */
+#define DIEN_800_IID 0x01 /* Same meaning, different name */
+
+/*
+ * DMA watchdog timer rw
+ * set in 16 CLK input periods.
+ */
+#define DWT_REG 0x3a
+
+/* DMA control rw */
+#define DCNTL_REG 0x3b
+#define DCNTL_700_CF1 0x80 /* Clock divisor bits */
+#define DCNTL_700_CF0 0x40
+#define DCNTL_700_CF_MASK 0xc0
+/* Clock divisors Divisor SCLK range (MHZ) */
+#define DCNTL_700_CF_2 0x00 /* 2.0 37.51-50.00 */
+#define DCNTL_700_CF_1_5 0x40 /* 1.5 25.01-37.50 */
+#define DCNTL_700_CF_1 0x80 /* 1.0 16.67-25.00 */
+#define DCNTL_700_CF_3 0xc0 /* 3.0 50.01-66.67 (53c700-66) */
+
+#define DCNTL_700_S16 0x20 /* Load scripts 16 bits at a time */
+#define DCNTL_SSM 0x10 /* Single step mode */
+#define DCNTL_700_LLM 0x08 /* Low level mode, can only be set
+ * after selection */
+#define DCNTL_800_IRQM 0x08 /* Totem pole IRQ pin */
+#define DCNTL_STD 0x04 /* Start DMA / SCRIPTS */
+/* 0x02 is reserved */
+#define DCNTL_00_RST 0x01 /* Software reset, resets everything
+ * but 286 mode bit in DMODE. On the
+ * NCR53c710, this bit moved to CTEST8
+ */
+#define DCNTL_10_COM 0x01 /* 700 software compatibility mode */
+#define DCNTL_10_EA 0x20 /* Enable Ack - needed for MVME166 */
+
+#define DCNTL_700_SAVE ( DCNTL_CF_MASK | DCNTL_S16)
+
+
+/* NCR53c700-66 only */
+#define SCRATCHB_REG_00 0x3c /* through 0x3f scratch b rw */
+#define SCRATCHB_REG_800 0x5c /* through 0x5f scratch b rw */
+/* NCR53c710 only */
+#define ADDER_REG_10 0x3c /* Adder, NCR53c710 only */
+
+#define SIEN1_REG_800 0x41
+#define SIEN1_800_STO 0x04 /* selection/reselection timeout */
+#define SIEN1_800_GEN 0x02 /* general purpose timer */
+#define SIEN1_800_HTH 0x01 /* handshake to handshake */
+
+#define SIST1_REG_800 0x43
+#define SIST1_800_STO 0x04 /* selection/reselection timeout */
+#define SIST1_800_GEN 0x02 /* general purpose timer */
+#define SIST1_800_HTH 0x01 /* handshake to handshake */
+
+#define SLPAR_REG_800 0x44 /* Parity */
+
+#define MACNTL_REG_800 0x46 /* Memory access control */
+#define MACNTL_800_TYP3 0x80
+#define MACNTL_800_TYP2 0x40
+#define MACNTL_800_TYP1 0x20
+#define MACNTL_800_TYP0 0x10
+#define MACNTL_800_DWR 0x08
+#define MACNTL_800_DRD 0x04
+#define MACNTL_800_PSCPT 0x02
+#define MACNTL_800_SCPTS 0x01
+
+#define GPCNTL_REG_800 0x47 /* General Purpose Pin Control */
+
+/* Timeouts are expressed such that 0=off, 1=100us, doubling after that */
+#define STIME0_REG_800 0x48 /* SCSI Timer Register 0 */
+#define STIME0_800_HTH_MASK 0xf0 /* Handshake to Handshake timeout */
+#define STIME0_800_HTH_SHIFT 4
+#define STIME0_800_SEL_MASK 0x0f /* Selection timeout */
+#define STIME0_800_SEL_SHIFT 0
+
+#define STIME1_REG_800 0x49
+#define STIME1_800_GEN_MASK 0x0f /* General purpose timer */
+
+#define RESPID_REG_800 0x4a /* Response ID, bit fielded. 8
+ bits on narrow chips, 16 on WIDE */
+
+#define STEST0_REG_800 0x4c
+#define STEST0_800_SLT 0x08 /* Selection response logic test */
+#define STEST0_800_ART 0x04 /* Arbitration priority encoder test */
+#define STEST0_800_SOZ 0x02 /* Synchronous offset zero */
+#define STEST0_800_SOM 0x01 /* Synchronous offset maximum */
+
+#define STEST1_REG_800 0x4d
+#define STEST1_800_SCLK 0x80 /* Disable SCSI clock */
+
+#define STEST2_REG_800 0x4e
+#define STEST2_800_SCE 0x80 /* Enable SOCL/SODL */
+#define STEST2_800_ROF 0x40 /* Reset SCSI sync offset */
+#define STEST2_800_SLB 0x10 /* Enable SCSI loopback mode */
+#define STEST2_800_SZM 0x08 /* SCSI high impedance mode */
+#define STEST2_800_EXT 0x02 /* Extend REQ/ACK filter 30 to 60ns */
+#define STEST2_800_LOW 0x01 /* SCSI low level mode */
+
+#define STEST3_REG_800 0x4f
+#define STEST3_800_TE 0x80 /* Enable active negation */
+#define STEST3_800_STR 0x40 /* SCSI FIFO test read */
+#define STEST3_800_HSC 0x20 /* Halt SCSI clock */
+#define STEST3_800_DSI 0x10 /* Disable single initiator response */
+#define STEST3_800_TTM 0x04 /* Time test mode */
+#define STEST3_800_CSF 0x02 /* Clear SCSI FIFO */
+#define STEST3_800_STW 0x01 /* SCSI FIFO test write */
+
+#define OPTION_PARITY 0x1 /* Enable parity checking */
+#define OPTION_TAGGED_QUEUE 0x2 /* Enable SCSI-II tagged queuing */
+#define OPTION_700 0x8 /* Always run NCR53c700 scripts */
+#define OPTION_INTFLY 0x10 /* Use INTFLY interrupts */
+#define OPTION_DEBUG_INTR 0x20 /* Debug interrupts */
+#define OPTION_DEBUG_INIT_ONLY 0x40 /* Run initialization code and
+ simple test code, return
+ DID_NO_CONNECT if any SCSI
+ commands are attempted. */
+#define OPTION_DEBUG_READ_ONLY 0x80 /* Return DID_ERROR if any
+ SCSI write is attempted */
+#define OPTION_DEBUG_TRACE 0x100 /* Animated trace mode, print
+ each address and instruction
+ executed to debug buffer. */
+#define OPTION_DEBUG_SINGLE 0x200 /* stop after executing one
+ instruction */
+#define OPTION_SYNCHRONOUS 0x400 /* Enable sync SCSI. */
+#define OPTION_MEMORY_MAPPED 0x800 /* NCR registers have valid
+ memory mapping */
+#define OPTION_IO_MAPPED 0x1000 /* NCR registers have valid
+ I/O mapping */
+#define OPTION_DEBUG_PROBE_ONLY 0x2000 /* Probe only, don't even init */
+#define OPTION_DEBUG_TESTS_ONLY 0x4000 /* Probe, init, run selected tests */
+#define OPTION_DEBUG_TEST0 0x08000 /* Run test 0 */
+#define OPTION_DEBUG_TEST1 0x10000 /* Run test 1 */
+#define OPTION_DEBUG_TEST2 0x20000 /* Run test 2 */
+#define OPTION_DEBUG_DUMP 0x40000 /* Dump commands */
+#define OPTION_DEBUG_TARGET_LIMIT 0x80000 /* Only talk to target+luns specified */
+#define OPTION_DEBUG_NCOMMANDS_LIMIT 0x100000 /* Limit the number of commands */
+#define OPTION_DEBUG_SCRIPT 0x200000 /* Print when checkpoints are passed */
+#define OPTION_DEBUG_FIXUP 0x400000 /* print fixup values */
+#define OPTION_DEBUG_DSA 0x800000
+#define OPTION_DEBUG_CORRUPTION 0x1000000 /* Detect script corruption */
+#define OPTION_DEBUG_SDTR 0x2000000 /* Debug SDTR problem */
+#define OPTION_DEBUG_MISMATCH 0x4000000 /* Debug phase mismatches */
+#define OPTION_DISCONNECT 0x8000000 /* Allow disconnect */
+#define OPTION_DEBUG_DISCONNECT 0x10000000
+#define OPTION_ALWAYS_SYNCHRONOUS 0x20000000 /* Negotiate sync. transfers
+ on power up */
+#define OPTION_DEBUG_QUEUES 0x80000000
+#define OPTION_DEBUG_ALLOCATION 0x100000000LL
+#define OPTION_DEBUG_SYNCHRONOUS 0x200000000LL /* Sanity check SXFER and
+ SCNTL3 registers */
+#define OPTION_NO_ASYNC 0x400000000LL /* Don't automagically send
+ SDTR for async transfers when
+ we haven't been told to do
+ a synchronous transfer. */
+#define OPTION_NO_PRINT_RACE 0x800000000LL /* Don't print message when
+ the reselect/WAIT DISCONNECT
+ race condition hits */
+#if !defined(PERM_OPTIONS)
+#define PERM_OPTIONS 0
+#endif
+
+/*
+ * Some data which is accessed by the NCR chip must be 4-byte aligned.
+ * For some hosts the default is less than that (eg. 68K uses 2-byte).
+ * Alignment has only been forced where it is important; also if one
+ * 32 bit structure field is aligned then it is assumed that following
+ * 32 bit fields are also aligned. Take care when adding fields
+ * which are other than 32 bit.
+ */
+
+struct NCR53c7x0_synchronous {
+ u32 select_indirect /* Value used for indirect selection */
+ __attribute__ ((aligned (4)));
+ u32 sscf_710; /* Used to set SSCF bits for 710 */
+ u32 script[8]; /* Size ?? Script used when target is
+ reselected */
+ unsigned char synchronous_want[5]; /* Per target desired SDTR */
+/*
+ * Set_synchronous programs these, select_indirect and current settings after
+ * int_debug_should show a match.
+ */
+ unsigned char sxfer_sanity, scntl3_sanity;
+};
+
+#define CMD_FLAG_SDTR 1 /* Initiating synchronous
+ transfer negotiation */
+#define CMD_FLAG_WDTR 2 /* Initiating wide transfer
+ negotiation */
+#define CMD_FLAG_DID_SDTR 4 /* did SDTR */
+#define CMD_FLAG_DID_WDTR 8 /* did WDTR */
+
+struct NCR53c7x0_table_indirect {
+ u32 count;
+ void *address;
+};
+
+enum ncr_event {
+ EVENT_NONE = 0,
+/*
+ * Order is IMPORTANT, since these must correspond to the event interrupts
+ * in 53c7,8xx.scr
+ */
+
+ EVENT_ISSUE_QUEUE = 0x5000000, /* 0 Command was added to issue queue */
+ EVENT_START_QUEUE, /* 1 Command moved to start queue */
+ EVENT_SELECT, /* 2 Command completed selection */
+ EVENT_DISCONNECT, /* 3 Command disconnected */
+ EVENT_RESELECT, /* 4 Command reselected */
+ EVENT_COMPLETE, /* 5 Command completed */
+ EVENT_IDLE, /* 6 */
+ EVENT_SELECT_FAILED, /* 7 */
+ EVENT_BEFORE_SELECT, /* 8 */
+ EVENT_RESELECT_FAILED /* 9 */
+};
+
+struct NCR53c7x0_event {
+ enum ncr_event event; /* What type of event */
+ unsigned char target;
+ unsigned char lun;
+ struct timeval time;
+ u32 *dsa; /* What's in the DSA register now (virt) */
+/*
+ * A few things from that SCSI pid so we know what happened after
+ * the Scsi_Cmnd structure in question may have disappeared.
+ */
+ unsigned long pid; /* The SCSI PID which caused this
+ event */
+ unsigned char cmnd[12];
+};
+
+/*
+ * Things in the NCR53c7x0_cmd structure are split into two parts :
+ *
+ * 1. A fixed portion, for things which are not accessed directly by static NCR
+ * code (ie, are referenced only by the Linux side of the driver,
+ * or only by dynamically generated code).
+ *
+ * 2. The DSA portion, for things which are accessed directly by static NCR
+ * code.
+ *
+ * This is a little ugly, but it
+ * 1. Avoids conflicts between the NCR code's picture of the structure, and
+ * Linux code's idea of what it looks like.
+ *
+ * 2. Minimizes the pain in the Linux side of the code needed
+ * to calculate real dsa locations for things, etc.
+ *
+ */
+
+struct NCR53c7x0_cmd {
+ void *real; /* Real, unaligned address for
+ free function */
+ void (* free)(void *, int); /* Command to deallocate; NULL
+ for structures allocated with
+ scsi_register, etc. */
+ Scsi_Cmnd *cmd; /* Associated Scsi_Cmnd
+ structure, Scsi_Cmnd points
+ at NCR53c7x0_cmd using
+ host_scribble structure */
+
+ int size; /* scsi_malloc'd size of this
+ structure */
+
+ int flags; /* CMD_* flags */
+
+/*
+ * SDTR and WIDE messages are an either/or affair
+ * in this message, since we will go into message out and send
+ * _the whole mess_ without dropping out of message out to
+ * let the target go into message in after sending the first
+ * message.
+ */
+
+ unsigned char select[11]; /* Select message, includes
+ IDENTIFY
+ (optional) QUEUE TAG
+ (optional) SDTR or WDTR
+ */
+
+
+ volatile struct NCR53c7x0_cmd *next; /* Linux maintained lists (free,
+ running, eventually finished */
+
+
+ u32 *data_transfer_start; /* Start of data transfer routines */
+ u32 *data_transfer_end; /* Address after end of data transfer o
+ routines */
+/*
+ * The following three fields were moved from the DSA proper to here
+ * since only dynamically generated NCR code refers to them, meaning
+ * we don't need dsa_* absolutes, and it is simpler to let the
+ * host code refer to them directly.
+ */
+
+/*
+ * HARD CODED : residual and saved_residual need to agree with the sizes
+ * used in NCR53c7,8xx.scr.
+ *
+ * FIXME: we want to consider the case where we have odd-length
+ * scatter/gather buffers and a WIDE transfer, in which case
+ * we'll need to use the CHAIN MOVE instruction. Ick.
+ */
+ u32 residual[6] __attribute__ ((aligned (4)));
+ /* Residual data transfer which
+ allows pointer code to work
+ right.
+
+ [0-1] : Conditional call to
+ appropriate other transfer
+ routine.
+ [2-3] : Residual block transfer
+ instruction.
+ [4-5] : Jump to instruction
+ after splice.
+ */
+ u32 saved_residual[6]; /* Copy of old residual, so we
+ can get another partial
+ transfer and still recover
+ */
+
+ u32 saved_data_pointer; /* Saved data pointer */
+
+ u32 dsa_next_addr; /* _Address_ of dsa_next field
+ in this dsa for RISCy
+ style constant. */
+
+ u32 dsa_addr; /* Address of dsa; RISCy style
+ constant */
+
+ u32 dsa[0]; /* Variable length (depending
+ on host type, number of scatter /
+ gather buffers, etc). */
+};
+
+struct NCR53c7x0_break {
+ u32 *address, old_instruction[2];
+ struct NCR53c7x0_break *next;
+ unsigned char old_size; /* Size of old instruction */
+};
+
+/* Indicates that the NCR is not executing code */
+#define STATE_HALTED 0
+/*
+ * Indicates that the NCR is executing the wait for select / reselect
+ * script. Only used when running NCR53c700 compatible scripts, only
+ * state during which an ABORT is _not_ considered an error condition.
+ */
+#define STATE_WAITING 1
+/* Indicates that the NCR is executing other code. */
+#define STATE_RUNNING 2
+/*
+ * Indicates that the NCR was being aborted.
+ */
+#define STATE_ABORTING 3
+/* Indicates that the NCR was successfully aborted. */
+#define STATE_ABORTED 4
+/* Indicates that the NCR has been disabled due to a fatal error */
+#define STATE_DISABLED 5
+
+/*
+ * Where knowledge of SCSI SCRIPT(tm) specified values are needed
+ * in an interrupt handler, an interrupt handler exists for each
+ * different SCSI script so we don't have name space problems.
+ *
+ * Return values of these handlers are as follows :
+ */
+#define SPECIFIC_INT_NOTHING 0 /* don't even restart */
+#define SPECIFIC_INT_RESTART 1 /* restart at the next instruction */
+#define SPECIFIC_INT_ABORT 2 /* recoverable error, abort cmd */
+#define SPECIFIC_INT_PANIC 3 /* unrecoverable error, panic */
+#define SPECIFIC_INT_DONE 4 /* normal command completion */
+#define SPECIFIC_INT_BREAK 5 /* break point encountered */
+
+struct NCR53c7x0_hostdata {
+ int size; /* Size of entire Scsi_Host
+ structure */
+ int board; /* set to board type, useful if
+ we have host specific things,
+ ie, a general purpose I/O
+ bit is being used to enable
+ termination, etc. */
+
+ int chip; /* set to chip type; 700-66 is
+ 700-66, rest are last three
+ digits of part number */
+
+ char valid_ids[8]; /* Valid SCSI ID's for adapter */
+ /*
+ * PCI bus, device, function, only for NCR53c8x0 chips.
+ * pci_valid indicates that the PCI configuration information
+ * is valid, and we can twiddle MAX_LAT, etc. as recommended
+ * for maximum performance in the NCR documentation.
+ */
+ unsigned char pci_bus, pci_device_fn;
+ unsigned pci_valid:1;
+
+ u32 *dsp; /* dsp to restart with after
+ all stacked interrupts are
+ handled. */
+
+ unsigned dsp_changed:1; /* Has dsp changed within this
+ set of stacked interrupts ? */
+
+ unsigned char dstat; /* Most recent value of dstat */
+ unsigned dstat_valid:1;
+
+ unsigned expecting_iid:1; /* Expect IID interrupt */
+ unsigned expecting_sto:1; /* Expect STO interrupt */
+
+ /*
+ * The code stays cleaner if we use variables with function
+ * pointers and offsets that are unique for the different
+ * scripts rather than having a slew of switch(hostdata->chip)
+ * statements.
+ *
+ * It also means that the #defines from the SCSI SCRIPTS(tm)
+ * don't have to be visible outside of the script-specific
+ * instructions, preventing name space pollution.
+ */
+
+ void (* init_fixup)(struct Scsi_Host *host);
+ void (* init_save_regs)(struct Scsi_Host *host);
+ void (* dsa_fixup)(struct NCR53c7x0_cmd *cmd);
+ void (* soft_reset)(struct Scsi_Host *host);
+ int (* run_tests)(struct Scsi_Host *host);
+
+ /*
+ * Called when DSTAT_SIR is set, indicating an interrupt generated
+ * by the INT instruction, where values are unique for each SCSI
+ * script. Should return one of the SPEC_* values.
+ */
+
+ int (* dstat_sir_intr)(struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd);
+
+ int dsa_len; /* Size of DSA structure */
+
+ /*
+ * Location of DSA fields for the SCSI SCRIPT corresponding to this
+ * chip.
+ */
+
+ s32 dsa_start;
+ s32 dsa_end;
+ s32 dsa_next;
+ s32 dsa_prev;
+ s32 dsa_cmnd;
+ s32 dsa_select;
+ s32 dsa_msgout;
+ s32 dsa_cmdout;
+ s32 dsa_dataout;
+ s32 dsa_datain;
+ s32 dsa_msgin;
+ s32 dsa_msgout_other;
+ s32 dsa_write_sync;
+ s32 dsa_write_resume;
+ s32 dsa_check_reselect;
+ s32 dsa_status;
+ s32 dsa_saved_pointer;
+ s32 dsa_jump_dest;
+
+ /*
+ * Important entry points that generic fixup code needs
+ * to know about, fixed up.
+ */
+
+ s32 E_accept_message;
+ s32 E_command_complete;
+ s32 E_data_transfer;
+ s32 E_dsa_code_template;
+ s32 E_dsa_code_template_end;
+ s32 E_end_data_transfer;
+ s32 E_msg_in;
+ s32 E_initiator_abort;
+ s32 E_other_transfer;
+ s32 E_other_in;
+ s32 E_other_out;
+ s32 E_target_abort;
+ s32 E_debug_break;
+ s32 E_reject_message;
+ s32 E_respond_message;
+ s32 E_select;
+ s32 E_select_msgout;
+ s32 E_test_0;
+ s32 E_test_1;
+ s32 E_test_2;
+ s32 E_test_3;
+ s32 E_dsa_zero;
+ s32 E_cmdout_cmdout;
+ s32 E_wait_reselect;
+ s32 E_dsa_code_begin;
+
+ long long options; /* Bitfielded set of options enabled */
+ volatile u32 test_completed; /* Test completed */
+ int test_running; /* Test currently running */
+ s32 test_source
+ __attribute__ ((aligned (4)));
+ volatile s32 test_dest;
+
+ volatile int state; /* state of driver, only used for
+ OPTION_700 */
+
+ unsigned char dmode; /*
+ * set to the address of the DMODE
+ * register for this chip.
+ */
+ unsigned char istat; /*
+ * set to the address of the ISTAT
+ * register for this chip.
+ */
+
+ int scsi_clock; /*
+ * SCSI clock in HZ. 0 may be used
+ * for unknown, although this will
+ * disable synchronous negotiation.
+ */
+
+ volatile int intrs; /* Number of interrupts */
+ volatile int resets; /* Number of SCSI resets */
+ unsigned char saved_dmode;
+ unsigned char saved_ctest4;
+ unsigned char saved_ctest7;
+ unsigned char saved_dcntl;
+ unsigned char saved_scntl3;
+
+ unsigned char this_id_mask;
+
+ /* Debugger information */
+ struct NCR53c7x0_break *breakpoints, /* Linked list of all break points */
+ *breakpoint_current; /* Current breakpoint being stepped
+ through, NULL if we are running
+ normally. */
+#ifdef NCR_DEBUG
+ int debug_size; /* Size of debug buffer */
+ volatile int debug_count; /* Current data count */
+ volatile char *debug_buf; /* Output ring buffer */
+ volatile char *debug_write; /* Current write pointer */
+ volatile char *debug_read; /* Current read pointer */
+#endif /* def NCR_DEBUG */
+
+ /* XXX - primitive debugging junk, remove when working ? */
+ int debug_print_limit; /* Number of commands to print
+ out exhaustive debugging
+ information for if
+ OPTION_DEBUG_DUMP is set */
+
+ unsigned char debug_lun_limit[16]; /* If OPTION_DEBUG_TARGET_LIMIT
+ set, puke if commands are sent
+ to other target/lun combinations */
+
+ int debug_count_limit; /* Number of commands to execute
+ before puking to limit debugging
+ output */
+
+
+ volatile unsigned idle:1; /* set to 1 if idle */
+
+ /*
+ * Table of synchronous+wide transfer parameters set on a per-target
+ * basis.
+ */
+
+ volatile struct NCR53c7x0_synchronous sync[16]
+ __attribute__ ((aligned (4)));
+
+ volatile Scsi_Cmnd *issue_queue
+ __attribute__ ((aligned (4)));
+ /* waiting to be issued by
+ Linux driver */
+ volatile struct NCR53c7x0_cmd *running_list;
+ /* commands running, maintained
+ by Linux driver */
+
+ volatile struct NCR53c7x0_cmd *ncrcurrent; /* currently connected
+ nexus, ONLY valid for
+ NCR53c700/NCR53c700-66
+ */
+
+ volatile struct NCR53c7x0_cmd *spare; /* pointer to spare,
+ allocated at probe time,
+ which we can use for
+ initialization */
+ volatile struct NCR53c7x0_cmd *free;
+ int max_cmd_size; /* Maximum size of NCR53c7x0_cmd
+ based on number of
+ scatter/gather segments, etc.
+ */
+ volatile int num_cmds; /* Number of commands
+ allocated */
+ volatile int extra_allocate;
+ volatile unsigned char cmd_allocated[16]; /* Have we allocated commands
+ for this target yet? If not,
+ do so ASAP */
+ volatile unsigned char busy[16][8]; /* number of commands
+ executing on each target
+ */
+ /*
+ * Eventually, I'll switch to a coroutine for calling
+ * cmd->done(cmd), etc. so that we can overlap interrupt
+ * processing with this code for maximum performance.
+ */
+
+ volatile struct NCR53c7x0_cmd *finished_queue;
+
+ /* Shared variables between SCRIPT and host driver */
+ volatile u32 *schedule
+ __attribute__ ((aligned (4))); /* Array of JUMPs to dsa_begin
+ routines of various DSAs.
+ When not in use, replace
+ with jump to next slot */
+
+
+ volatile unsigned char msg_buf[16]; /* buffer for messages
+ other than the command
+ complete message */
+
+ /* Per-target default synchronous and WIDE messages */
+ volatile unsigned char synchronous_want[16][5];
+ volatile unsigned char wide_want[16][4];
+
+ /* Bit fielded set of targets we want to speak synchronously with */
+ volatile u16 initiate_sdtr;
+ /* Bit fielded set of targets we want to speak wide with */
+ volatile u16 initiate_wdtr;
+ /* Bit fielded list of targets we've talked to. */
+ volatile u16 talked_to;
+
+ /* Array of bit-fielded lun lists that we need to request_sense */
+ volatile unsigned char request_sense[16];
+
+ u32 addr_reconnect_dsa_head
+ __attribute__ ((aligned (4))); /* RISCy style constant,
+ address of following */
+ volatile u32 reconnect_dsa_head;
+ /* Data identifying nexus we are trying to match during reselection */
+ volatile unsigned char reselected_identify; /* IDENTIFY message */
+ volatile unsigned char reselected_tag; /* second byte of queue tag
+ message or 0 */
+
+ /* These were static variables before we moved them */
+
+ s32 NCR53c7xx_zero
+ __attribute__ ((aligned (4)));
+ s32 NCR53c7xx_sink;
+ u32 NOP_insn;
+ char NCR53c7xx_msg_reject;
+ char NCR53c7xx_msg_abort;
+ char NCR53c7xx_msg_nop;
+
+ /*
+ * Following item introduced by RGH to support NCRc710, which is
+ * VERY brain-dead when it come to memory moves
+ */
+
+ /* DSA save area used only by the NCR chip */
+ volatile unsigned long saved2_dsa
+ __attribute__ ((aligned (4)));
+
+ volatile unsigned long emulated_intfly
+ __attribute__ ((aligned (4)));
+
+ volatile int event_size, event_index;
+ volatile struct NCR53c7x0_event *events;
+
+ /* If we need to generate code to kill off the currently connected
+ command, this is where we do it. Should have a BMI instruction
+ to source or sink the current data, followed by a JUMP
+ to abort_connected */
+
+ u32 *abort_script;
+
+ int script_count; /* Size of script in words */
+ u32 script[0]; /* Relocated SCSI script */
+
+};
+
+#define IRQ_NONE 255
+#define DMA_NONE 255
+#define IRQ_AUTO 254
+#define DMA_AUTO 254
+
+#define BOARD_GENERIC 0
+
+#define NCR53c7x0_insn_size(insn) \
+ (((insn) & DCMD_TYPE_MASK) == DCMD_TYPE_MMI ? 3 : 2)
+
+
+#define NCR53c7x0_local_declare() \
+ volatile unsigned char *NCR53c7x0_address_memory; \
+ unsigned int NCR53c7x0_address_io; \
+ int NCR53c7x0_memory_mapped
+
+#define NCR53c7x0_local_setup(host) \
+ NCR53c7x0_address_memory = (void *) (host)->base; \
+ NCR53c7x0_address_io = (unsigned int) (host)->io_port; \
+ NCR53c7x0_memory_mapped = ((struct NCR53c7x0_hostdata *) \
+ host->hostdata)-> options & OPTION_MEMORY_MAPPED
+
+#ifdef BIG_ENDIAN
+/* These could be more efficient, given that we are always memory mapped,
+ * but they don't give the same problems as the write macros, so leave
+ * them. */
+#define NCR53c7x0_read8(address) \
+ (NCR53c7x0_memory_mapped ? \
+ (unsigned int)readb((u32)NCR53c7x0_address_memory + ((u32)(address)^3)) : \
+ inb(NCR53c7x0_address_io + (address)))
+
+#define NCR53c7x0_read16(address) \
+ (NCR53c7x0_memory_mapped ? \
+ (unsigned int)readw((u32)NCR53c7x0_address_memory + ((u32)(address)^2)) : \
+ inw(NCR53c7x0_address_io + (address)))
+#else
+#define NCR53c7x0_read8(address) \
+ (NCR53c7x0_memory_mapped ? \
+ (unsigned int)readb((u32)NCR53c7x0_address_memory + (u32)(address)) : \
+ inb(NCR53c7x0_address_io + (address)))
+
+#define NCR53c7x0_read16(address) \
+ (NCR53c7x0_memory_mapped ? \
+ (unsigned int)readw((u32)NCR53c7x0_address_memory + (u32)(address)) : \
+ inw(NCR53c7x0_address_io + (address)))
+#endif
+#define NCR53c7x0_read32(address) \
+ (NCR53c7x0_memory_mapped ? \
+ (unsigned int) readl((u32)NCR53c7x0_address_memory + (u32)(address)) : \
+ inl(NCR53c7x0_address_io + (address)))
+
+#ifdef BIG_ENDIAN
+/* If we are big-endian, then we are not Intel, so probably don't have
+ * an i/o map as well as a memory map. So, lets assume memory mapped.
+ * Also, I am having terrible problems trying to persuade the compiler
+ * not to lay down code which does a read after write for these macros.
+ * If you remove 'volatile' from writeb() and friends it is ok....
+ */
+
+#define NCR53c7x0_write8(address,value) \
+ *(volatile unsigned char *) \
+ ((u32)NCR53c7x0_address_memory + ((u32)(address)^3)) = (value)
+
+#define NCR53c7x0_write16(address,value) \
+ *(volatile unsigned short *) \
+ ((u32)NCR53c7x0_address_memory + ((u32)(address)^2)) = (value)
+
+#define NCR53c7x0_write32(address,value) \
+ *(volatile unsigned long *) \
+ ((u32)NCR53c7x0_address_memory + ((u32)(address))) = (value)
+
+#else
+
+#define NCR53c7x0_write8(address,value) \
+ (NCR53c7x0_memory_mapped ? \
+ ({writeb((value), (u32)NCR53c7x0_address_memory + (u32)(address)); mb();}) : \
+ outb((value), NCR53c7x0_address_io + (address)))
+
+#define NCR53c7x0_write16(address,value) \
+ (NCR53c7x0_memory_mapped ? \
+ ({writew((value), (u32)NCR53c7x0_address_memory + (u32)(address)); mb();}) : \
+ outw((value), NCR53c7x0_address_io + (address)))
+
+#define NCR53c7x0_write32(address,value) \
+ (NCR53c7x0_memory_mapped ? \
+ ({writel((value), (u32)NCR53c7x0_address_memory + (u32)(address)); mb();}) : \
+ outl((value), NCR53c7x0_address_io + (address)))
+
+#endif
+
+/* Patch arbitrary 32 bit words in the script */
+#define patch_abs_32(script, offset, symbol, value) \
+ for (i = 0; i < (sizeof (A_##symbol##_used) / sizeof \
+ (u32)); ++i) { \
+ (script)[A_##symbol##_used[i] - (offset)] += (value); \
+ if (hostdata->options & OPTION_DEBUG_FIXUP) \
+ printk("scsi%d : %s reference %d at 0x%x in %s is now 0x%x\n",\
+ host->host_no, #symbol, i, A_##symbol##_used[i] - \
+ (int)(offset), #script, (script)[A_##symbol##_used[i] - \
+ (offset)]); \
+ }
+
+/* Patch read/write instruction immediate field */
+#define patch_abs_rwri_data(script, offset, symbol, value) \
+ for (i = 0; i < (sizeof (A_##symbol##_used) / sizeof \
+ (u32)); ++i) \
+ (script)[A_##symbol##_used[i] - (offset)] = \
+ ((script)[A_##symbol##_used[i] - (offset)] & \
+ ~DBC_RWRI_IMMEDIATE_MASK) | \
+ (((value) << DBC_RWRI_IMMEDIATE_SHIFT) & \
+ DBC_RWRI_IMMEDIATE_MASK)
+
+/* Patch transfer control instruction data field */
+#define patch_abs_tci_data(script, offset, symbol, value) \
+ for (i = 0; i < (sizeof (A_##symbol##_used) / sizeof \
+ (u32)); ++i) \
+ (script)[A_##symbol##_used[i] - (offset)] = \
+ ((script)[A_##symbol##_used[i] - (offset)] & \
+ ~DBC_TCI_DATA_MASK) | \
+ (((value) << DBC_TCI_DATA_SHIFT) & \
+ DBC_TCI_DATA_MASK)
+
+/* Patch field in dsa structure (assignment should be +=?) */
+#define patch_dsa_32(dsa, symbol, word, value) \
+ { \
+ (dsa)[(hostdata->##symbol - hostdata->dsa_start) / sizeof(u32) \
+ + (word)] = (value); \
+ if (hostdata->options & OPTION_DEBUG_DSA) \
+ printk("scsi : dsa %s symbol %s(%d) word %d now 0x%x\n", \
+ #dsa, #symbol, hostdata->##symbol, \
+ (word), (u32) (value)); \
+ }
+
+/* Paranoid people could use panic() here. */
+#define FATAL(host) shutdown((host));
+
+#endif /* NCR53c710_C */
+#endif /* NCR53c710_H */
diff --git a/drivers/scsi/53c7xx.scr b/drivers/scsi/53c7xx.scr
new file mode 100644
index 000000000..2fc9db2dd
--- /dev/null
+++ b/drivers/scsi/53c7xx.scr
@@ -0,0 +1,1591 @@
+#undef DEBUG
+#undef EVENTS
+#undef NO_SELECTION_TIMEOUT
+#define BIG_ENDIAN
+
+; 53c710 driver. Modified from Drew Eckhardts driver
+; for 53c810 by Richard Hirst [richard@sleepie.demon.co.uk]
+;
+; I have left the script for the 53c8xx family in here, as it is likely
+; to be useful to see what I changed when bug hunting.
+
+; NCR 53c810 driver, main script
+; Sponsored by
+; iX Multiuser Multitasking Magazine
+; hm@ix.de
+;
+; Copyright 1993, 1994, 1995 Drew Eckhardt
+; Visionary Computing
+; (Unix and Linux consulting and custom programming)
+; drew@PoohSticks.ORG
+; +1 (303) 786-7975
+;
+; TolerANT and SCSI SCRIPTS are registered trademarks of NCR Corporation.
+;
+; PRE-ALPHA
+;
+; For more information, please consult
+;
+; NCR 53C810
+; PCI-SCSI I/O Processor
+; Data Manual
+;
+; NCR 53C710
+; SCSI I/O Processor
+; Programmers Guide
+;
+; NCR Microelectronics
+; 1635 Aeroplaza Drive
+; Colorado Springs, CO 80916
+; 1+ (719) 578-3400
+;
+; Toll free literature number
+; +1 (800) 334-5454
+;
+; IMPORTANT : This code is self modifying due to the limitations of
+; the NCR53c7,8xx series chips. Persons debugging this code with
+; the remote debugger should take this into account, and NOT set
+; breakpoints in modified instructions.
+;
+; Design:
+; The NCR53c7,8xx family of SCSI chips are busmasters with an onboard
+; microcontroller using a simple instruction set.
+;
+; So, to minimize the effects of interrupt latency, and to maximize
+; throughput, this driver offloads the practical maximum amount
+; of processing to the SCSI chip while still maintaining a common
+; structure.
+;
+; Where tradeoffs were needed between efficiency on the older
+; chips and the newer NCR53c800 series, the NCR53c800 series
+; was chosen.
+;
+; While the NCR53c700 and NCR53c700-66 lacked the facilities to fully
+; automate SCSI transfers without host processor intervention, this
+; isn't the case with the NCR53c710 and newer chips which allow
+;
+; - reads and writes to the internal registers from within the SCSI
+; scripts, allowing the SCSI SCRIPTS(tm) code to save processor
+; state so that multiple threads of execution are possible, and also
+; provide an ALU for loop control, etc.
+;
+; - table indirect addressing for some instructions. This allows
+; pointers to be located relative to the DSA ((Data Structure
+; Address) register.
+;
+; These features make it possible to implement a mailbox style interface,
+; where the same piece of code is run to handle I/O for multiple threads
+; at once minimizing our need to relocate code. Since the NCR53c700/
+; NCR53c800 series have a unique combination of features, making a
+; a standard ingoing/outgoing mailbox system, costly, I've modified it.
+;
+; - Mailboxes are a mixture of code and data. This lets us greatly
+; simplify the NCR53c810 code and do things that would otherwise
+; not be possible.
+;
+; The saved data pointer is now implemented as follows :
+;
+; Control flow has been architected such that if control reaches
+; munge_save_data_pointer, on a restore pointers message or
+; reconnection, a jump to the address formerly in the TEMP register
+; will allow the SCSI command to resume execution.
+;
+
+;
+; Note : the DSA structures must be aligned on 32 bit boundaries,
+; since the source and destination of MOVE MEMORY instructions
+; must share the same alignment and this is the alignment of the
+; NCR registers.
+;
+
+; For some systems (MVME166, for example) dmode is always the same, so don't
+; waste time writing it
+
+#if 1
+#define DMODE_MEMORY_TO_NCR
+#define DMODE_MEMORY_TO_MEMORY
+#define DMODE_NCR_TO_MEMORY
+#else
+#define DMODE_MEMORY_TO_NCR MOVE dmode_memory_to_ncr TO DMODE
+#define DMODE_MEMORY_TO_MEMORY MOVE dmode_memory_to_memory TO DMODE
+#define DMODE_NCR_TO_MEMORY MOVE dmode_ncr_to_memory TO DMODE
+#endif
+
+ABSOLUTE dsa_temp_lun = 0 ; Patch to lun for current dsa
+ABSOLUTE dsa_temp_next = 0 ; Patch to dsa next for current dsa
+ABSOLUTE dsa_temp_addr_next = 0 ; Patch to address of dsa next address
+ ; for current dsa
+ABSOLUTE dsa_temp_sync = 0 ; Patch to address of per-target
+ ; sync routine
+ABSOLUTE dsa_sscf_710 = 0 ; Patch to address of per-target
+ ; sscf value (53c710)
+ABSOLUTE dsa_temp_target = 0 ; Patch to id for current dsa
+ABSOLUTE dsa_temp_addr_saved_pointer = 0; Patch to address of per-command
+ ; saved data pointer
+ABSOLUTE dsa_temp_addr_residual = 0 ; Patch to address of per-command
+ ; current residual code
+ABSOLUTE dsa_temp_addr_saved_residual = 0; Patch to address of per-command
+ ; saved residual code
+ABSOLUTE dsa_temp_addr_new_value = 0 ; Address of value for JUMP operand
+ABSOLUTE dsa_temp_addr_array_value = 0 ; Address to copy to
+ABSOLUTE dsa_temp_addr_dsa_value = 0 ; Address of this DSA value
+
+;
+; Once a device has initiated reselection, we need to compare it
+; against the singly linked list of commands which have disconnected
+; and are pending reselection. These commands are maintained in
+; an unordered singly linked list of DSA structures, through the
+; DSA pointers at their 'centers' headed by the reconnect_dsa_head
+; pointer.
+;
+; To avoid complications in removing commands from the list,
+; I minimize the amount of expensive (at eight operations per
+; addition @ 500-600ns each) pointer operations which must
+; be done in the NCR driver by precomputing them on the
+; host processor during dsa structure generation.
+;
+; The fixed-up per DSA code knows how to recognize the nexus
+; associated with the corresponding SCSI command, and modifies
+; the source and destination pointers for the MOVE MEMORY
+; instruction which is executed when reselected_ok is called
+; to remove the command from the list. Similarly, DSA is
+; loaded with the address of the next DSA structure and
+; reselected_check_next is called if a failure occurs.
+;
+; Perhaps more concisely, the net effect of the mess is
+;
+; for (dsa = reconnect_dsa_head, dest = &reconnect_dsa_head,
+; src = NULL; dsa; dest = &dsa->next, dsa = dsa->next) {
+; src = &dsa->next;
+; if (target_id == dsa->id && target_lun == dsa->lun) {
+; *dest = *src;
+; break;
+; }
+; }
+;
+; if (!dsa)
+; error (int_err_unexpected_reselect);
+; else
+; longjmp (dsa->jump_resume, 0);
+;
+;
+
+#if (CHIP != 700) && (CHIP != 70066)
+; Define DSA structure used for mailboxes
+ENTRY dsa_code_template
+dsa_code_template:
+ENTRY dsa_code_begin
+dsa_code_begin:
+; RGH: Don't care about TEMP and DSA here
+ DMODE_MEMORY_TO_NCR
+ MOVE MEMORY 4, dsa_temp_addr_dsa_value, addr_scratch
+ DMODE_MEMORY_TO_MEMORY
+#if (CHIP == 710)
+ MOVE MEMORY 4, addr_scratch, saved_dsa
+ ; We are about to go and select the device, so must set SSCF bits
+ MOVE MEMORY 4, dsa_sscf_710, addr_scratch
+#ifdef BIG_ENDIAN
+ MOVE SCRATCH3 TO SFBR
+#else
+ MOVE SCRATCH0 TO SFBR
+#endif
+ MOVE SFBR TO SBCL
+ MOVE MEMORY 4, saved_dsa, addr_dsa
+#else
+ CALL scratch_to_dsa
+#endif
+ CALL select
+; Handle the phase mismatch which may have resulted from the
+; MOVE FROM dsa_msgout if we returned here. The CLEAR ATN
+; may or may not be necessary, and we should update script_asm.pl
+; to handle multiple pieces.
+ CLEAR ATN
+ CLEAR ACK
+
+; Replace second operand with address of JUMP instruction dest operand
+; in schedule table for this DSA. Becomes dsa_jump_dest in 53c7,8xx.c.
+ENTRY dsa_code_fix_jump
+dsa_code_fix_jump:
+ MOVE MEMORY 4, NOP_insn, 0
+ JUMP select_done
+
+; wrong_dsa loads the DSA register with the value of the dsa_next
+; field.
+;
+wrong_dsa:
+#if (CHIP == 710)
+; NOTE DSA is corrupt when we arrive here!
+#endif
+; Patch the MOVE MEMORY INSTRUCTION such that
+; the destination address is the address of the OLD
+; next pointer.
+;
+ MOVE MEMORY 4, dsa_temp_addr_next, reselected_ok_patch + 8
+ DMODE_MEMORY_TO_NCR
+;
+; Move the _contents_ of the next pointer into the DSA register as
+; the next I_T_L or I_T_L_Q tupple to check against the established
+; nexus.
+;
+ MOVE MEMORY 4, dsa_temp_next, addr_scratch
+ DMODE_MEMORY_TO_MEMORY
+#if (CHIP == 710)
+ MOVE MEMORY 4, addr_scratch, saved_dsa
+ MOVE MEMORY 4, saved_dsa, addr_dsa
+#else
+ CALL scratch_to_dsa
+#endif
+ JUMP reselected_check_next
+
+ABSOLUTE dsa_save_data_pointer = 0
+ENTRY dsa_code_save_data_pointer
+dsa_code_save_data_pointer:
+#if (CHIP == 710)
+ ; When we get here, TEMP has been saved in jump_temp+4, DSA is corrupt
+ ; We MUST return with DSA correct
+ MOVE MEMORY 4, jump_temp+4, dsa_temp_addr_saved_pointer
+; HARD CODED : 24 bytes needs to agree with 53c7,8xx.h
+ MOVE MEMORY 24, dsa_temp_addr_residual, dsa_temp_addr_saved_residual
+ CLEAR ACK
+#ifdef DEBUG
+ INT int_debug_saved
+#endif
+ MOVE MEMORY 4, saved_dsa, addr_dsa
+ JUMP jump_temp
+#else
+ DMODE_NCR_TO_MEMORY
+ MOVE MEMORY 4, addr_temp, dsa_temp_addr_saved_pointer
+ DMODE_MEMORY_TO_MEMORY
+; HARD CODED : 24 bytes needs to agree with 53c7,8xx.h
+ MOVE MEMORY 24, dsa_temp_addr_residual, dsa_temp_addr_saved_residual
+ CLEAR ACK
+#ifdef DEBUG
+ INT int_debug_saved
+#endif
+ RETURN
+#endif
+ABSOLUTE dsa_restore_pointers = 0
+ENTRY dsa_code_restore_pointers
+dsa_code_restore_pointers:
+#if (CHIP == 710)
+ ; TEMP and DSA are corrupt when we get here, but who cares!
+ MOVE MEMORY 4, dsa_temp_addr_saved_pointer, jump_temp + 4
+; HARD CODED : 24 bytes needs to agree with 53c7,8xx.h
+ MOVE MEMORY 24, dsa_temp_addr_saved_residual, dsa_temp_addr_residual
+ CLEAR ACK
+ ; Restore DSA, note we don't care about TEMP
+ MOVE MEMORY 4, saved_dsa, addr_dsa
+#ifdef DEBUG
+ INT int_debug_restored
+#endif
+ JUMP jump_temp
+#else
+ DMODE_MEMORY_TO_NCR
+ MOVE MEMORY 4, dsa_temp_addr_saved_pointer, addr_temp
+ DMODE_MEMORY_TO_MEMORY
+; HARD CODED : 24 bytes needs to agree with 53c7,8xx.h
+ MOVE MEMORY 24, dsa_temp_addr_saved_residual, dsa_temp_addr_residual
+ CLEAR ACK
+#ifdef DEBUG
+ INT int_debug_restored
+#endif
+ RETURN
+#endif
+
+ABSOLUTE dsa_check_reselect = 0
+; dsa_check_reselect determines whether or not the current target and
+; lun match the current DSA
+ENTRY dsa_code_check_reselect
+dsa_code_check_reselect:
+#if (CHIP == 710)
+ /* Arrives here with DSA correct */
+ /* Assumes we are always ID 7 */
+ MOVE LCRC TO SFBR ; LCRC has our ID and his ID bits set
+ JUMP REL (wrong_dsa), IF NOT dsa_temp_target, AND MASK 0x80
+#else
+ MOVE SSID TO SFBR ; SSID contains 3 bit target ID
+; FIXME : we need to accommodate bit fielded and binary here for '7xx/'8xx chips
+ JUMP REL (wrong_dsa), IF NOT dsa_temp_target, AND MASK 0xf8
+#endif
+;
+; Hack - move to scratch first, since SFBR is not writeable
+; via the CPU and hence a MOVE MEMORY instruction.
+;
+ DMODE_MEMORY_TO_NCR
+ MOVE MEMORY 1, reselected_identify, addr_scratch
+ DMODE_MEMORY_TO_MEMORY
+#ifdef BIG_ENDIAN
+ ; BIG ENDIAN ON MVME166
+ MOVE SCRATCH3 TO SFBR
+#else
+ MOVE SCRATCH0 TO SFBR
+#endif
+; FIXME : we need to accommodate bit fielded and binary here for '7xx/'8xx chips
+; Are you sure about that? richard@sleepie.demon.co.uk
+ JUMP REL (wrong_dsa), IF NOT dsa_temp_lun, AND MASK 0xf8
+; Patch the MOVE MEMORY INSTRUCTION such that
+; the source address is the address of this dsa's
+; next pointer.
+ MOVE MEMORY 4, dsa_temp_addr_next, reselected_ok_patch + 4
+ CALL reselected_ok
+#if (CHIP == 710)
+; Restore DSA following memory moves in reselected_ok
+; dsa_temp_sync doesn't really care about DSA, but it has an
+; optional debug INT so a valid DSA is a good idea.
+ MOVE MEMORY 4, saved_dsa, addr_dsa
+#endif
+ CALL dsa_temp_sync
+; Release ACK on the IDENTIFY message _after_ we've set the synchronous
+; transfer parameters!
+ CLEAR ACK
+; Implicitly restore pointers on reselection, so a RETURN
+; will transfer control back to the right spot.
+ CALL REL (dsa_code_restore_pointers)
+ RETURN
+ENTRY dsa_zero
+dsa_zero:
+ENTRY dsa_code_template_end
+dsa_code_template_end:
+
+; Perform sanity check for dsa_fields_start == dsa_code_template_end -
+; dsa_zero, puke.
+
+ABSOLUTE dsa_fields_start = 0 ; Sanity marker
+ ; pad 48 bytes (fix this RSN)
+ABSOLUTE dsa_next = 48 ; len 4 Next DSA
+ ; del 4 Previous DSA address
+ABSOLUTE dsa_cmnd = 56 ; len 4 Scsi_Cmnd * for this thread.
+ABSOLUTE dsa_select = 60 ; len 4 Device ID, Period, Offset for
+ ; table indirect select
+ABSOLUTE dsa_msgout = 64 ; len 8 table indirect move parameter for
+ ; select message
+ABSOLUTE dsa_cmdout = 72 ; len 8 table indirect move parameter for
+ ; command
+ABSOLUTE dsa_dataout = 80 ; len 4 code pointer for dataout
+ABSOLUTE dsa_datain = 84 ; len 4 code pointer for datain
+ABSOLUTE dsa_msgin = 88 ; len 8 table indirect move for msgin
+ABSOLUTE dsa_status = 96 ; len 8 table indirect move for status byte
+ABSOLUTE dsa_msgout_other = 104 ; len 8 table indirect for normal message out
+ ; (Synchronous transfer negotiation, etc).
+ABSOLUTE dsa_end = 112
+
+ABSOLUTE schedule = 0 ; Array of JUMP dsa_begin or JUMP (next),
+ ; terminated by a call to JUMP wait_reselect
+
+; Linked lists of DSA structures
+ABSOLUTE reconnect_dsa_head = 0 ; Link list of DSAs which can reconnect
+ABSOLUTE addr_reconnect_dsa_head = 0 ; Address of variable containing
+ ; address of reconnect_dsa_head
+
+; These select the source and destination of a MOVE MEMORY instruction
+ABSOLUTE dmode_memory_to_memory = 0x0
+ABSOLUTE dmode_memory_to_ncr = 0x0
+ABSOLUTE dmode_ncr_to_memory = 0x0
+
+ABSOLUTE addr_scratch = 0x0
+ABSOLUTE addr_temp = 0x0
+#if (CHIP == 710)
+ABSOLUTE saved_dsa = 0x0
+ABSOLUTE emulfly = 0x0
+ABSOLUTE addr_dsa = 0x0
+#endif
+#endif /* CHIP != 700 && CHIP != 70066 */
+
+; Interrupts -
+; MSB indicates type
+; 0 handle error condition
+; 1 handle message
+; 2 handle normal condition
+; 3 debugging interrupt
+; 4 testing interrupt
+; Next byte indicates specific error
+
+; XXX not yet implemented, I'm not sure if I want to -
+; Next byte indicates the routine the error occurred in
+; The LSB indicates the specific place the error occurred
+
+ABSOLUTE int_err_unexpected_phase = 0x00000000 ; Unexpected phase encountered
+ABSOLUTE int_err_selected = 0x00010000 ; SELECTED (nee RESELECTED)
+ABSOLUTE int_err_unexpected_reselect = 0x00020000
+ABSOLUTE int_err_check_condition = 0x00030000
+ABSOLUTE int_err_no_phase = 0x00040000
+ABSOLUTE int_msg_wdtr = 0x01000000 ; WDTR message received
+ABSOLUTE int_msg_sdtr = 0x01010000 ; SDTR received
+ABSOLUTE int_msg_1 = 0x01020000 ; single byte special message
+ ; received
+
+ABSOLUTE int_norm_select_complete = 0x02000000 ; Select complete, reprogram
+ ; registers.
+ABSOLUTE int_norm_reselect_complete = 0x02010000 ; Nexus established
+ABSOLUTE int_norm_command_complete = 0x02020000 ; Command complete
+ABSOLUTE int_norm_disconnected = 0x02030000 ; Disconnected
+ABSOLUTE int_norm_aborted =0x02040000 ; Aborted *dsa
+ABSOLUTE int_norm_reset = 0x02050000 ; Generated BUS reset.
+ABSOLUTE int_norm_emulateintfly = 0x02060000 ; 53C710 Emulated intfly
+ABSOLUTE int_debug_break = 0x03000000 ; Break point
+#ifdef DEBUG
+ABSOLUTE int_debug_scheduled = 0x03010000 ; new I/O scheduled
+ABSOLUTE int_debug_idle = 0x03020000 ; scheduler is idle
+ABSOLUTE int_debug_dsa_loaded = 0x03030000 ; dsa reloaded
+ABSOLUTE int_debug_reselected = 0x03040000 ; NCR reselected
+ABSOLUTE int_debug_head = 0x03050000 ; issue head overwritten
+ABSOLUTE int_debug_disconnected = 0x03060000 ; disconnected
+ABSOLUTE int_debug_disconnect_msg = 0x03070000 ; got message to disconnect
+ABSOLUTE int_debug_dsa_schedule = 0x03080000 ; in dsa_schedule
+ABSOLUTE int_debug_reselect_check = 0x03090000 ; Check for reselection of DSA
+ABSOLUTE int_debug_reselected_ok = 0x030a0000 ; Reselection accepted
+#endif
+ABSOLUTE int_debug_panic = 0x030b0000 ; Panic driver
+#ifdef DEBUG
+ABSOLUTE int_debug_saved = 0x030c0000 ; save/restore pointers
+ABSOLUTE int_debug_restored = 0x030d0000
+ABSOLUTE int_debug_sync = 0x030e0000 ; Sanity check synchronous
+ ; parameters.
+ABSOLUTE int_debug_datain = 0x030f0000 ; going into data in phase
+ ; now.
+ABSOLUTE int_debug_check_dsa = 0x03100000 ; Sanity check DSA against
+ ; SDID.
+#endif
+
+ABSOLUTE int_test_1 = 0x04000000 ; Test 1 complete
+ABSOLUTE int_test_2 = 0x04010000 ; Test 2 complete
+ABSOLUTE int_test_3 = 0x04020000 ; Test 3 complete
+
+
+; These should start with 0x05000000, with low bits incrementing for
+; each one.
+
+#ifdef EVENTS
+ABSOLUTE int_EVENT_SELECT = 0
+ABSOLUTE int_EVENT_DISCONNECT = 0
+ABSOLUTE int_EVENT_RESELECT = 0
+ABSOLUTE int_EVENT_COMPLETE = 0
+ABSOLUTE int_EVENT_IDLE = 0
+ABSOLUTE int_EVENT_SELECT_FAILED = 0
+ABSOLUTE int_EVENT_BEFORE_SELECT = 0
+ABSOLUTE int_EVENT_RESELECT_FAILED = 0
+#endif
+
+ABSOLUTE NCR53c7xx_msg_abort = 0 ; Pointer to abort message
+ABSOLUTE NCR53c7xx_msg_reject = 0 ; Pointer to reject message
+ABSOLUTE NCR53c7xx_zero = 0 ; long with zero in it, use for source
+ABSOLUTE NCR53c7xx_sink = 0 ; long to dump worthless data in
+ABSOLUTE NOP_insn = 0 ; NOP instruction
+
+; Pointer to message, potentially multi-byte
+ABSOLUTE msg_buf = 0
+
+; Pointer to holding area for reselection information
+ABSOLUTE reselected_identify = 0
+ABSOLUTE reselected_tag = 0
+
+; Request sense command pointer, it's a 6 byte command, should
+; be constant for all commands since we always want 16 bytes of
+; sense and we don't need to change any fields as we did under
+; SCSI-I when we actually cared about the LUN field.
+;EXTERNAL NCR53c7xx_sense ; Request sense command
+
+#if (CHIP != 700) && (CHIP != 70066)
+; dsa_schedule
+; PURPOSE : after a DISCONNECT message has been received, and pointers
+; saved, insert the current DSA structure at the head of the
+; disconnected queue and fall through to the scheduler.
+;
+; CALLS : OK
+;
+; INPUTS : dsa - current DSA structure, reconnect_dsa_head - list
+; of disconnected commands
+;
+; MODIFIES : SCRATCH, reconnect_dsa_head
+;
+; EXITS : always passes control to schedule
+
+ENTRY dsa_schedule
+dsa_schedule:
+#ifdef DEBUG
+ INT int_debug_dsa_schedule
+#endif
+
+;
+; Calculate the address of the next pointer within the DSA
+; structure of the command that is currently disconnecting
+;
+#if (CHIP == 710)
+ ; Read what should be the current DSA from memory - actual DSA
+ ; register is probably corrupt
+ MOVE MEMORY 4, saved_dsa, addr_scratch
+#else
+ CALL dsa_to_scratch
+#endif
+ MOVE SCRATCH0 + dsa_next TO SCRATCH0
+ MOVE SCRATCH1 + 0 TO SCRATCH1 WITH CARRY
+ MOVE SCRATCH2 + 0 TO SCRATCH2 WITH CARRY
+ MOVE SCRATCH3 + 0 TO SCRATCH3 WITH CARRY
+
+; Point the next field of this DSA structure at the current disconnected
+; list
+ DMODE_NCR_TO_MEMORY
+ MOVE MEMORY 4, addr_scratch, dsa_schedule_insert + 8
+ DMODE_MEMORY_TO_MEMORY
+dsa_schedule_insert:
+ MOVE MEMORY 4, reconnect_dsa_head, 0
+
+; And update the head pointer.
+#if (CHIP == 710)
+ ; Read what should be the current DSA from memory - actual DSA
+ ; register is probably corrupt
+ MOVE MEMORY 4, saved_dsa, addr_scratch
+#else
+ CALL dsa_to_scratch
+#endif
+ DMODE_NCR_TO_MEMORY
+ MOVE MEMORY 4, addr_scratch, reconnect_dsa_head
+ DMODE_MEMORY_TO_MEMORY
+/* Temporarily, see what happens. */
+#ifndef ORIGINAL
+#if (CHIP != 710)
+ MOVE SCNTL2 & 0x7f TO SCNTL2
+#endif
+ CLEAR ACK
+#endif
+#if (CHIP == 710)
+ ; Time to correct DSA following memory move
+ MOVE MEMORY 4, saved_dsa, addr_dsa
+#endif
+ WAIT DISCONNECT
+#ifdef EVENTS
+ INT int_EVENT_DISCONNECT;
+#endif
+#ifdef DEBUG
+ INT int_debug_disconnected
+#endif
+ JUMP schedule
+#endif
+
+;
+; select
+;
+; PURPOSE : establish a nexus for the SCSI command referenced by DSA.
+; On success, the current DSA structure is removed from the issue
+; queue. Usually, this is entered as a fall-through from schedule,
+; although the contingent allegiance handling code will write
+; the select entry address to the DSP to restart a command as a
+; REQUEST SENSE. A message is sent (usually IDENTIFY, although
+; additional SDTR or WDTR messages may be sent). COMMAND OUT
+; is handled.
+;
+; INPUTS : DSA - SCSI command, issue_dsa_head
+;
+; CALLS : NOT OK
+;
+; MODIFIES : SCRATCH, issue_dsa_head
+;
+; EXITS : on reselection or selection, go to select_failed
+; otherwise, RETURN so control is passed back to
+; dsa_begin.
+;
+
+ENTRY select
+select:
+
+#ifdef EVENTS
+ INT int_EVENT_BEFORE_SELECT
+#endif
+
+#ifdef DEBUG
+ INT int_debug_scheduled
+#endif
+ CLEAR TARGET
+
+; XXX
+;
+; In effect, SELECTION operations are backgrounded, with execution
+; continuing until code which waits for REQ or a fatal interrupt is
+; encountered.
+;
+; So, for more performance, we could overlap the code which removes
+; the command from the NCRs issue queue with the selection, but
+; at this point I don't want to deal with the error recovery.
+;
+
+#if (CHIP != 700) && (CHIP != 70066)
+#if (CHIP == 710)
+ ; Enable selection timer
+#ifdef NO_SELECTION_TIMEOUT
+ MOVE CTEST7 & 0xff TO CTEST7
+#else
+ MOVE CTEST7 & 0xef TO CTEST7
+#endif
+#endif
+ SELECT ATN FROM dsa_select, select_failed
+ JUMP select_msgout, WHEN MSG_OUT
+ENTRY select_msgout
+select_msgout:
+#if (CHIP == 710)
+ ; Disable selection timer
+ MOVE CTEST7 | 0x10 TO CTEST7
+#endif
+ MOVE FROM dsa_msgout, WHEN MSG_OUT
+#else
+ENTRY select_msgout
+ SELECT ATN 0, select_failed
+select_msgout:
+ MOVE 0, 0, WHEN MSGOUT
+#endif
+
+#ifdef EVENTS
+ INT int_EVENT_SELECT
+#endif
+ RETURN
+
+;
+; select_done
+;
+; PURPOSE: continue on to normal data transfer; called as the exit
+; point from dsa_begin.
+;
+; INPUTS: dsa
+;
+; CALLS: OK
+;
+;
+
+select_done:
+#if (CHIP == 710)
+; NOTE DSA is corrupt when we arrive here!
+ MOVE MEMORY 4, saved_dsa, addr_dsa
+#endif
+
+#ifdef DEBUG
+ENTRY select_check_dsa
+select_check_dsa:
+ INT int_debug_check_dsa
+#endif
+
+; After a successful selection, we should get either a CMD phase or
+; some transfer request negotiation message.
+
+ JUMP cmdout, WHEN CMD
+ INT int_err_unexpected_phase, WHEN NOT MSG_IN
+
+select_msg_in:
+ CALL msg_in, WHEN MSG_IN
+ JUMP select_msg_in, WHEN MSG_IN
+
+cmdout:
+ INT int_err_unexpected_phase, WHEN NOT CMD
+#if (CHIP == 700)
+ INT int_norm_selected
+#endif
+ENTRY cmdout_cmdout
+cmdout_cmdout:
+#if (CHIP != 700) && (CHIP != 70066)
+ MOVE FROM dsa_cmdout, WHEN CMD
+#else
+ MOVE 0, 0, WHEN CMD
+#endif /* (CHIP != 700) && (CHIP != 70066) */
+
+;
+; data_transfer
+; other_out
+; other_in
+; other_transfer
+;
+; PURPOSE : handle the main data transfer for a SCSI command in
+; several parts. In the first part, data_transfer, DATA_IN
+; and DATA_OUT phases are allowed, with the user provided
+; code (usually dynamically generated based on the scatter/gather
+; list associated with a SCSI command) called to handle these
+; phases.
+;
+; After control has passed to one of the user provided
+; DATA_IN or DATA_OUT routines, back calls are made to
+; other_transfer_in or other_transfer_out to handle non-DATA IN
+; and DATA OUT phases respectively, with the state of the active
+; data pointer being preserved in TEMP.
+;
+; On completion, the user code passes control to other_transfer
+; which causes DATA_IN and DATA_OUT to result in unexpected_phase
+; interrupts so that data overruns may be trapped.
+;
+; INPUTS : DSA - SCSI command
+;
+; CALLS : OK in data_transfer_start, not ok in other_out and other_in, ok in
+; other_transfer
+;
+; MODIFIES : SCRATCH
+;
+; EXITS : if STATUS IN is detected, signifying command completion,
+; the NCR jumps to command_complete. If MSG IN occurs, a
+; CALL is made to msg_in. Otherwise, other_transfer runs in
+; an infinite loop.
+;
+
+ENTRY data_transfer
+data_transfer:
+ JUMP cmdout_cmdout, WHEN CMD
+ CALL msg_in, WHEN MSG_IN
+ INT int_err_unexpected_phase, WHEN MSG_OUT
+ JUMP do_dataout, WHEN DATA_OUT
+ JUMP do_datain, WHEN DATA_IN
+ JUMP command_complete, WHEN STATUS
+ JUMP data_transfer
+ENTRY end_data_transfer
+end_data_transfer:
+
+;
+; FIXME: On NCR53c700 and NCR53c700-66 chips, do_dataout/do_datain
+; should be fixed up whenever the nexus changes so it can point to the
+; correct routine for that command.
+;
+
+#if (CHIP != 700) && (CHIP != 70066)
+; Nasty jump to dsa->dataout
+do_dataout:
+#if (CHIP == 710)
+ MOVE MEMORY 4, saved_dsa, addr_scratch
+#else
+ CALL dsa_to_scratch
+#endif
+ MOVE SCRATCH0 + dsa_dataout TO SCRATCH0
+ MOVE SCRATCH1 + 0 TO SCRATCH1 WITH CARRY
+ MOVE SCRATCH2 + 0 TO SCRATCH2 WITH CARRY
+ MOVE SCRATCH3 + 0 TO SCRATCH3 WITH CARRY
+ DMODE_NCR_TO_MEMORY
+ MOVE MEMORY 4, addr_scratch, dataout_to_jump + 4
+ DMODE_MEMORY_TO_MEMORY
+dataout_to_jump:
+ MOVE MEMORY 4, 0, dataout_jump + 4
+#if (CHIP == 710)
+ ; Time to correct DSA following memory move
+ MOVE MEMORY 4, saved_dsa, addr_dsa
+#endif
+dataout_jump:
+ JUMP 0
+
+; Nasty jump to dsa->dsain
+do_datain:
+#if (CHIP == 710)
+ MOVE MEMORY 4, saved_dsa, addr_scratch
+#else
+ CALL dsa_to_scratch
+#endif
+ MOVE SCRATCH0 + dsa_datain TO SCRATCH0
+ MOVE SCRATCH1 + 0 TO SCRATCH1 WITH CARRY
+ MOVE SCRATCH2 + 0 TO SCRATCH2 WITH CARRY
+ MOVE SCRATCH3 + 0 TO SCRATCH3 WITH CARRY
+ DMODE_NCR_TO_MEMORY
+ MOVE MEMORY 4, addr_scratch, datain_to_jump + 4
+ DMODE_MEMORY_TO_MEMORY
+ENTRY datain_to_jump
+datain_to_jump:
+ MOVE MEMORY 4, 0, datain_jump + 4
+#if (CHIP == 710)
+ ; Time to correct DSA following memory move
+ MOVE MEMORY 4, saved_dsa, addr_dsa
+#endif
+#ifdef DEBUG
+ INT int_debug_datain
+#endif
+datain_jump:
+ JUMP 0
+#endif /* (CHIP != 700) && (CHIP != 70066) */
+
+
+; Note that other_out and other_in loop until a non-data phase
+; is discovered, so we only execute return statements when we
+; can go on to the next data phase block move statement.
+
+ENTRY other_out
+other_out:
+#if 0
+ INT 0x03ffdead
+#endif
+ INT int_err_unexpected_phase, WHEN CMD
+ JUMP msg_in_restart, WHEN MSG_IN
+ INT int_err_unexpected_phase, WHEN MSG_OUT
+ INT int_err_unexpected_phase, WHEN DATA_IN
+ JUMP command_complete, WHEN STATUS
+ JUMP other_out, WHEN NOT DATA_OUT
+#if (CHIP == 710)
+; TEMP should be OK, as we got here from a call in the user dataout code.
+#endif
+ RETURN
+
+ENTRY other_in
+other_in:
+#if 0
+ INT 0x03ffdead
+#endif
+ INT int_err_unexpected_phase, WHEN CMD
+ JUMP msg_in_restart, WHEN MSG_IN
+ INT int_err_unexpected_phase, WHEN MSG_OUT
+ INT int_err_unexpected_phase, WHEN DATA_OUT
+ JUMP command_complete, WHEN STATUS
+ JUMP other_in, WHEN NOT DATA_IN
+#if (CHIP == 710)
+; TEMP should be OK, as we got here from a call in the user datain code.
+#endif
+ RETURN
+
+
+ENTRY other_transfer
+other_transfer:
+ INT int_err_unexpected_phase, WHEN CMD
+ CALL msg_in, WHEN MSG_IN
+ INT int_err_unexpected_phase, WHEN MSG_OUT
+ INT int_err_unexpected_phase, WHEN DATA_OUT
+ INT int_err_unexpected_phase, WHEN DATA_IN
+ JUMP command_complete, WHEN STATUS
+ JUMP other_transfer
+
+;
+; msg_in_restart
+; msg_in
+; munge_msg
+;
+; PURPOSE : process messages from a target. msg_in is called when the
+; caller hasn't read the first byte of the message. munge_message
+; is called when the caller has read the first byte of the message,
+; and left it in SFBR. msg_in_restart is called when the caller
+; hasn't read the first byte of the message, and wishes RETURN
+; to transfer control back to the address of the conditional
+; CALL instruction rather than to the instruction after it.
+;
+; Various int_* interrupts are generated when the host system
+; needs to intervene, as is the case with SDTR, WDTR, and
+; INITIATE RECOVERY messages.
+;
+; When the host system handles one of these interrupts,
+; it can respond by reentering at reject_message,
+; which rejects the message and returns control to
+; the caller of msg_in or munge_msg, accept_message
+; which clears ACK and returns control, or reply_message
+; which sends the message pointed to by the DSA
+; msgout_other table indirect field.
+;
+; DISCONNECT messages are handled by moving the command
+; to the reconnect_dsa_queue.
+#if (CHIP == 710)
+; NOTE: DSA should be valid when we get here - we cannot save both it
+; and TEMP in this routine.
+#endif
+;
+; INPUTS : DSA - SCSI COMMAND, SFBR - first byte of message (munge_msg
+; only)
+;
+; CALLS : NO. The TEMP register isn't backed up to allow nested calls.
+;
+; MODIFIES : SCRATCH, DSA on DISCONNECT
+;
+; EXITS : On receipt of SAVE DATA POINTER, RESTORE POINTERS,
+; and normal return from message handlers running under
+; Linux, control is returned to the caller. Receipt
+; of DISCONNECT messages pass control to dsa_schedule.
+;
+ENTRY msg_in_restart
+msg_in_restart:
+; XXX - hackish
+;
+; Since it's easier to debug changes to the statically
+; compiled code, rather than the dynamically generated
+; stuff, such as
+;
+; MOVE x, y, WHEN data_phase
+; CALL other_z, WHEN NOT data_phase
+; MOVE x, y, WHEN data_phase
+;
+; I'd like to have certain routines (notably the message handler)
+; restart on the conditional call rather than the next instruction.
+;
+; So, subtract 8 from the return address
+
+ MOVE TEMP0 + 0xf8 TO TEMP0
+ MOVE TEMP1 + 0xff TO TEMP1 WITH CARRY
+ MOVE TEMP2 + 0xff TO TEMP2 WITH CARRY
+ MOVE TEMP3 + 0xff TO TEMP3 WITH CARRY
+
+ENTRY msg_in
+msg_in:
+ MOVE 1, msg_buf, WHEN MSG_IN
+
+munge_msg:
+ JUMP munge_extended, IF 0x01 ; EXTENDED MESSAGE
+ JUMP munge_2, IF 0x20, AND MASK 0xdf ; two byte message
+;
+; XXX - I've seen a handful of broken SCSI devices which fail to issue
+; a SAVE POINTERS message before disconnecting in the middle of
+; a transfer, assuming that the DATA POINTER will be implicitly
+; restored.
+;
+; Historically, I've often done an implicit save when the DISCONNECT
+; message is processed. We may want to consider having the option of
+; doing that here.
+;
+ JUMP munge_save_data_pointer, IF 0x02 ; SAVE DATA POINTER
+ JUMP munge_restore_pointers, IF 0x03 ; RESTORE POINTERS
+ JUMP munge_disconnect, IF 0x04 ; DISCONNECT
+ INT int_msg_1, IF 0x07 ; MESSAGE REJECT
+ INT int_msg_1, IF 0x0f ; INITIATE RECOVERY
+#ifdef EVENTS
+ INT int_EVENT_SELECT_FAILED
+#endif
+ JUMP reject_message
+
+munge_2:
+ JUMP reject_message
+;
+; The SCSI standard allows targets to recover from transient
+; error conditions by backing up the data pointer with a
+; RESTORE POINTERS message.
+;
+; So, we must save and restore the _residual_ code as well as
+; the current instruction pointer. Because of this messiness,
+; it is simpler to put dynamic code in the dsa for this and to
+; just do a simple jump down there.
+;
+
+munge_save_data_pointer:
+#if (CHIP == 710)
+ ; We have something in TEMP here, so first we must save that
+ MOVE TEMP0 TO SFBR
+ MOVE SFBR TO SCRATCH0
+ MOVE TEMP1 TO SFBR
+ MOVE SFBR TO SCRATCH1
+ MOVE TEMP2 TO SFBR
+ MOVE SFBR TO SCRATCH2
+ MOVE TEMP3 TO SFBR
+ MOVE SFBR TO SCRATCH3
+ MOVE MEMORY 4, addr_scratch, jump_temp + 4
+ ; Now restore DSA
+ MOVE MEMORY 4, saved_dsa, addr_dsa
+#endif
+ MOVE DSA0 + dsa_save_data_pointer TO SFBR
+ MOVE SFBR TO SCRATCH0
+ MOVE DSA1 + 0xff TO SFBR WITH CARRY
+ MOVE SFBR TO SCRATCH1
+ MOVE DSA2 + 0xff TO SFBR WITH CARRY
+ MOVE SFBR TO SCRATCH2
+ MOVE DSA3 + 0xff TO SFBR WITH CARRY
+ MOVE SFBR TO SCRATCH3
+
+ DMODE_NCR_TO_MEMORY
+ MOVE MEMORY 4, addr_scratch, jump_dsa_save + 4
+ DMODE_MEMORY_TO_MEMORY
+jump_dsa_save:
+ JUMP 0
+
+munge_restore_pointers:
+#if (CHIP == 710)
+ ; The code at dsa_restore_pointers will RETURN, but we don't care
+ ; about TEMP here, as it will overwrite it anyway.
+#endif
+ MOVE DSA0 + dsa_restore_pointers TO SFBR
+ MOVE SFBR TO SCRATCH0
+ MOVE DSA1 + 0xff TO SFBR WITH CARRY
+ MOVE SFBR TO SCRATCH1
+ MOVE DSA2 + 0xff TO SFBR WITH CARRY
+ MOVE SFBR TO SCRATCH2
+ MOVE DSA3 + 0xff TO SFBR WITH CARRY
+ MOVE SFBR TO SCRATCH3
+
+ DMODE_NCR_TO_MEMORY
+ MOVE MEMORY 4, addr_scratch, jump_dsa_restore + 4
+ DMODE_MEMORY_TO_MEMORY
+jump_dsa_restore:
+ JUMP 0
+
+
+munge_disconnect:
+#ifdef DEBUG
+ INT int_debug_disconnect_msg
+#endif
+
+/*
+ * Before, we overlapped processing with waiting for disconnect, but
+ * debugging was beginning to appear messy. Temporarily move things
+ * to just before the WAIT DISCONNECT.
+ */
+
+#ifdef ORIGINAL
+#if (CHIP == 710)
+; Following clears Unexpected Disconnect bit. What do we do?
+#else
+ MOVE SCNTL2 & 0x7f TO SCNTL2
+#endif
+ CLEAR ACK
+#endif
+
+#if (CHIP != 700) && (CHIP != 70066)
+ JUMP dsa_schedule
+#else
+ WAIT DISCONNECT
+ INT int_norm_disconnected
+#endif
+
+munge_extended:
+ CLEAR ACK
+ INT int_err_unexpected_phase, WHEN NOT MSG_IN
+ MOVE 1, msg_buf + 1, WHEN MSG_IN
+ JUMP munge_extended_2, IF 0x02
+ JUMP munge_extended_3, IF 0x03
+ JUMP reject_message
+
+munge_extended_2:
+ CLEAR ACK
+ MOVE 1, msg_buf + 2, WHEN MSG_IN
+ JUMP reject_message, IF NOT 0x02 ; Must be WDTR
+ CLEAR ACK
+ MOVE 1, msg_buf + 3, WHEN MSG_IN
+ INT int_msg_wdtr
+
+munge_extended_3:
+ CLEAR ACK
+ MOVE 1, msg_buf + 2, WHEN MSG_IN
+ JUMP reject_message, IF NOT 0x01 ; Must be SDTR
+ CLEAR ACK
+ MOVE 2, msg_buf + 3, WHEN MSG_IN
+ INT int_msg_sdtr
+
+ENTRY reject_message
+reject_message:
+ SET ATN
+ CLEAR ACK
+ MOVE 1, NCR53c7xx_msg_reject, WHEN MSG_OUT
+ RETURN
+
+ENTRY accept_message
+accept_message:
+ CLEAR ATN
+ CLEAR ACK
+ RETURN
+
+ENTRY respond_message
+respond_message:
+ SET ATN
+ CLEAR ACK
+ MOVE FROM dsa_msgout_other, WHEN MSG_OUT
+ RETURN
+
+;
+; command_complete
+;
+; PURPOSE : handle command termination when STATUS IN is detected by reading
+; a status byte followed by a command termination message.
+;
+; Normal termination results in an INTFLY instruction, and
+; the host system can pick out which command terminated by
+; examining the MESSAGE and STATUS buffers of all currently
+; executing commands;
+;
+; Abnormal (CHECK_CONDITION) termination results in an
+; int_err_check_condition interrupt so that a REQUEST SENSE
+; command can be issued out-of-order so that no other command
+; clears the contingent allegiance condition.
+;
+;
+; INPUTS : DSA - command
+;
+; CALLS : OK
+;
+; EXITS : On successful termination, control is passed to schedule.
+; On abnormal termination, the user will usually modify the
+; DSA fields and corresponding buffers and return control
+; to select.
+;
+
+ENTRY command_complete
+command_complete:
+ MOVE FROM dsa_status, WHEN STATUS
+#if (CHIP != 700) && (CHIP != 70066)
+ MOVE SFBR TO SCRATCH0 ; Save status
+#endif /* (CHIP != 700) && (CHIP != 70066) */
+ENTRY command_complete_msgin
+command_complete_msgin:
+ MOVE FROM dsa_msgin, WHEN MSG_IN
+; Indicate that we should be expecting a disconnect
+#if (CHIP != 710)
+ MOVE SCNTL2 & 0x7f TO SCNTL2
+#else
+ ; Above code cleared the Unexpected Disconnect bit, what do we do?
+#endif
+ CLEAR ACK
+#if (CHIP != 700) && (CHIP != 70066)
+ WAIT DISCONNECT
+
+;
+; The SCSI specification states that when a UNIT ATTENTION condition
+; is pending, as indicated by a CHECK CONDITION status message,
+; the target shall revert to asynchronous transfers. Since
+; synchronous transfers parameters are maintained on a per INITIATOR/TARGET
+; basis, and returning control to our scheduler could work on a command
+; running on another lun on that target using the old parameters, we must
+; interrupt the host processor to get them changed, or change them ourselves.
+;
+; Once SCSI-II tagged queueing is implemented, things will be even more
+; hairy, since contingent allegiance conditions exist on a per-target/lun
+; basis, and issuing a new command with a different tag would clear it.
+; In these cases, we must interrupt the host processor to get a request
+; added to the HEAD of the queue with the request sense command, or we
+; must automatically issue the request sense command.
+
+#if 0
+ MOVE SCRATCH0 TO SFBR
+ JUMP command_failed, IF 0x02
+#endif
+#if (CHIP == 710)
+#if defined(MVME166_INTFLY)
+; For MVME166 (ie CHIP=710) we will force an INTFLY by triggering a software
+; interupt (SW7). We can use SCRATCH, as we are about to jump to
+; schedule, which corrupts it anyway. Will probably remove this later,
+; but want to check performance effects first.
+
+#define INTFLY_ADDR 0xfff40070
+
+ MOVE 0 TO SCRATCH0
+ MOVE 0x80 TO SCRATCH1
+ MOVE 0 TO SCRATCH2
+ MOVE 0 TO SCRATCH3
+ MOVE MEMORY 4, addr_scratch, INTFLY_ADDR
+#else
+ INT int_norm_emulateintfly
+#endif
+#else
+ INTFLY
+#endif
+#endif /* (CHIP != 700) && (CHIP != 70066) */
+#if (CHIP == 710)
+ ; Time to correct DSA following memory move
+ MOVE MEMORY 4, saved_dsa, addr_dsa
+#endif
+#ifdef EVENTS
+ INT int_EVENT_COMPLETE
+#endif
+#if (CHIP != 700) && (CHIP != 70066)
+ JUMP schedule
+command_failed:
+ INT int_err_check_condition
+#else
+ INT int_norm_command_complete
+#endif
+
+;
+; wait_reselect
+;
+; PURPOSE : This is essentially the idle routine, where control lands
+; when there are no new processes to schedule. wait_reselect
+; waits for reselection, selection, and new commands.
+;
+; When a successful reselection occurs, with the aid
+; of fixed up code in each DSA, wait_reselect walks the
+; reconnect_dsa_queue, asking each dsa if the target ID
+; and LUN match its.
+;
+; If a match is found, a call is made back to reselected_ok,
+; which through the miracles of self modifying code, extracts
+; the found DSA from the reconnect_dsa_queue and then
+; returns control to the DSAs thread of execution.
+;
+; INPUTS : NONE
+;
+; CALLS : OK
+;
+; MODIFIES : DSA,
+;
+; EXITS : On successful reselection, control is returned to the
+; DSA which called reselected_ok. If the WAIT RESELECT
+; was interrupted by a new commands arrival signaled by
+; SIG_P, control is passed to schedule. If the NCR is
+; selected, the host system is interrupted with an
+; int_err_selected which is usually responded to by
+; setting DSP to the target_abort address.
+
+ENTRY wait_reselect
+wait_reselect:
+#ifdef EVENTS
+ int int_EVENT_IDLE
+#endif
+#ifdef DEBUG
+ int int_debug_idle
+#endif
+ WAIT RESELECT wait_reselect_failed
+
+reselected:
+#ifdef EVENTS
+ int int_EVENT_RESELECT
+#endif
+ CLEAR TARGET
+ DMODE_MEMORY_TO_MEMORY
+ ; Read all data needed to reestablish the nexus -
+ MOVE 1, reselected_identify, WHEN MSG_IN
+ ; We used to CLEAR ACK here.
+#if (CHIP != 700) && (CHIP != 70066)
+#ifdef DEBUG
+ int int_debug_reselected
+#endif
+
+ ; Point DSA at the current head of the disconnected queue.
+ DMODE_MEMORY_TO_NCR
+ MOVE MEMORY 4, reconnect_dsa_head, addr_scratch
+ DMODE_MEMORY_TO_MEMORY
+#if (CHIP == 710)
+ MOVE MEMORY 4, addr_scratch, saved_dsa
+#else
+ CALL scratch_to_dsa
+#endif
+
+ ; Fix the update-next pointer so that the reconnect_dsa_head
+ ; pointer is the one that will be updated if this DSA is a hit
+ ; and we remove it from the queue.
+
+ MOVE MEMORY 4, addr_reconnect_dsa_head, reselected_ok_patch + 8
+#if (CHIP == 710)
+ ; Time to correct DSA following memory move
+ MOVE MEMORY 4, saved_dsa, addr_dsa
+#endif
+
+ENTRY reselected_check_next
+reselected_check_next:
+#ifdef DEBUG
+ INT int_debug_reselect_check
+#endif
+ ; Check for a NULL pointer.
+ MOVE DSA0 TO SFBR
+ JUMP reselected_not_end, IF NOT 0
+ MOVE DSA1 TO SFBR
+ JUMP reselected_not_end, IF NOT 0
+ MOVE DSA2 TO SFBR
+ JUMP reselected_not_end, IF NOT 0
+ MOVE DSA3 TO SFBR
+ JUMP reselected_not_end, IF NOT 0
+ INT int_err_unexpected_reselect
+
+reselected_not_end:
+ ;
+ ; XXX the ALU is only eight bits wide, and the assembler
+ ; wont do the dirt work for us. As long as dsa_check_reselect
+ ; is negative, we need to sign extend with 1 bits to the full
+ ; 32 bit width of the address.
+ ;
+ ; A potential work around would be to have a known alignment
+ ; of the DSA structure such that the base address plus
+ ; dsa_check_reselect doesn't require carrying from bytes
+ ; higher than the LSB.
+ ;
+
+ MOVE DSA0 TO SFBR
+ MOVE SFBR + dsa_check_reselect TO SCRATCH0
+ MOVE DSA1 TO SFBR
+ MOVE SFBR + 0xff TO SCRATCH1 WITH CARRY
+ MOVE DSA2 TO SFBR
+ MOVE SFBR + 0xff TO SCRATCH2 WITH CARRY
+ MOVE DSA3 TO SFBR
+ MOVE SFBR + 0xff TO SCRATCH3 WITH CARRY
+
+ DMODE_NCR_TO_MEMORY
+ MOVE MEMORY 4, addr_scratch, reselected_check + 4
+ DMODE_MEMORY_TO_MEMORY
+#if (CHIP == 710)
+ ; Time to correct DSA following memory move
+ MOVE MEMORY 4, saved_dsa, addr_dsa
+#endif
+reselected_check:
+ JUMP 0
+
+
+;
+;
+#if (CHIP == 710)
+; We have problems here - the memory move corrupts TEMP and DSA. This
+; routine is called from DSA code, and patched from many places. Scratch
+; is probably free when it is called.
+; We have to:
+; copy temp to scratch, one byte at a time
+; write scratch to patch a jump in place of the return
+; do the move memory
+; jump to the patched in return address
+; DSA is corrupt when we get here, and can be left corrupt
+
+ENTRY reselected_ok
+reselected_ok:
+ MOVE TEMP0 TO SFBR
+ MOVE SFBR TO SCRATCH0
+ MOVE TEMP1 TO SFBR
+ MOVE SFBR TO SCRATCH1
+ MOVE TEMP2 TO SFBR
+ MOVE SFBR TO SCRATCH2
+ MOVE TEMP3 TO SFBR
+ MOVE SFBR TO SCRATCH3
+ MOVE MEMORY 4, addr_scratch, reselected_ok_jump + 4
+reselected_ok_patch:
+ MOVE MEMORY 4, 0, 0
+reselected_ok_jump:
+ JUMP 0
+#else
+ENTRY reselected_ok
+reselected_ok:
+reselected_ok_patch:
+ MOVE MEMORY 4, 0, 0 ; Patched : first word
+ ; is address of
+ ; successful dsa_next
+ ; Second word is last
+ ; unsuccessful dsa_next,
+ ; starting with
+ ; dsa_reconnect_head
+ ; We used to CLEAR ACK here.
+#ifdef DEBUG
+ INT int_debug_reselected_ok
+#endif
+#ifdef DEBUG
+ INT int_debug_check_dsa
+#endif
+ RETURN ; Return control to where
+#endif
+#else
+ INT int_norm_reselected
+#endif /* (CHIP != 700) && (CHIP != 70066) */
+
+selected:
+ INT int_err_selected;
+
+;
+; A select or reselect failure can be caused by one of two conditions :
+; 1. SIG_P was set. This will be the case if the user has written
+; a new value to a previously NULL head of the issue queue.
+;
+; 2. The NCR53c810 was selected or reselected by another device.
+;
+; 3. The bus was already busy since we were selected or reselected
+; before starting the command.
+
+wait_reselect_failed:
+#ifdef EVENTS
+ INT int_EVENT_RESELECT_FAILED
+#endif
+; Check selected bit.
+#if (CHIP == 710)
+ ; Must work out how to tell if we are selected....
+#else
+ MOVE SIST0 & 0x20 TO SFBR
+ JUMP selected, IF 0x20
+#endif
+; Reading CTEST2 clears the SIG_P bit in the ISTAT register.
+ MOVE CTEST2 & 0x40 TO SFBR
+ JUMP schedule, IF 0x40
+; Check connected bit.
+; FIXME: this needs to change if we support target mode
+ MOVE ISTAT & 0x08 TO SFBR
+ JUMP reselected, IF 0x08
+; FIXME : Something bogus happened, and we shouldn't fail silently.
+#if 0
+ JUMP schedule
+#else
+ INT int_debug_panic
+#endif
+
+
+select_failed:
+#if (CHIP == 710)
+ ; Disable selection timer
+ MOVE CTEST7 | 0x10 TO CTEST7
+#endif
+#ifdef EVENTS
+ int int_EVENT_SELECT_FAILED
+#endif
+; Otherwise, mask the selected and reselected bits off SIST0
+#if (CHIP ==710)
+ ; Let's assume we don't get selected for now
+ MOVE SSTAT0 & 0x10 TO SFBR
+#else
+ MOVE SIST0 & 0x30 TO SFBR
+ JUMP selected, IF 0x20
+#endif
+ JUMP reselected, IF 0x10
+; If SIGP is set, the user just gave us another command, and
+; we should restart or return to the scheduler.
+; Reading CTEST2 clears the SIG_P bit in the ISTAT register.
+ MOVE CTEST2 & 0x40 TO SFBR
+ JUMP select, IF 0x40
+; Check connected bit.
+; FIXME: this needs to change if we support target mode
+; FIXME: is this really necessary?
+ MOVE ISTAT & 0x08 TO SFBR
+ JUMP reselected, IF 0x08
+; FIXME : Something bogus happened, and we shouldn't fail silently.
+#if 0
+ JUMP schedule
+#else
+ INT int_debug_panic
+#endif
+
+;
+; test_1
+; test_2
+;
+; PURPOSE : run some verification tests on the NCR. test_1
+; copies test_src to test_dest and interrupts the host
+; processor, testing for cache coherency and interrupt
+; problems in the processes.
+;
+; test_2 runs a command with offsets relative to the
+; DSA on entry, and is useful for miscellaneous experimentation.
+;
+
+; Verify that interrupts are working correctly and that we don't
+; have a cache invalidation problem.
+
+ABSOLUTE test_src = 0, test_dest = 0
+ENTRY test_1
+test_1:
+ MOVE MEMORY 4, test_src, test_dest
+ INT int_test_1
+
+;
+; Run arbitrary commands, with test code establishing a DSA
+;
+
+ENTRY test_2
+test_2:
+ CLEAR TARGET
+#if (CHIP == 710)
+ ; Enable selection timer
+#ifdef NO_SELECTION_TIMEOUT
+ MOVE CTEST7 & 0xff TO CTEST7
+#else
+ MOVE CTEST7 & 0xef TO CTEST7
+#endif
+#endif
+ SELECT ATN FROM 0, test_2_fail
+ JUMP test_2_msgout, WHEN MSG_OUT
+ENTRY test_2_msgout
+test_2_msgout:
+#if (CHIP == 710)
+ ; Disable selection timer
+ MOVE CTEST7 | 0x10 TO CTEST7
+#endif
+ MOVE FROM 8, WHEN MSG_OUT
+ MOVE FROM 16, WHEN CMD
+ MOVE FROM 24, WHEN DATA_IN
+ MOVE FROM 32, WHEN STATUS
+ MOVE FROM 40, WHEN MSG_IN
+#if (CHIP != 710)
+ MOVE SCNTL2 & 0x7f TO SCNTL2
+#endif
+ CLEAR ACK
+ WAIT DISCONNECT
+test_2_fail:
+#if (CHIP == 710)
+ ; Disable selection timer
+ MOVE CTEST7 | 0x10 TO CTEST7
+#endif
+ INT int_test_2
+
+ENTRY debug_break
+debug_break:
+ INT int_debug_break
+
+;
+; initiator_abort
+; target_abort
+;
+; PURPOSE : Abort the currently established nexus from with initiator
+; or target mode.
+;
+;
+
+ENTRY target_abort
+target_abort:
+ SET TARGET
+ DISCONNECT
+ CLEAR TARGET
+ JUMP schedule
+
+ENTRY initiator_abort
+initiator_abort:
+ SET ATN
+;
+; The SCSI-I specification says that targets may go into MSG out at
+; their leisure upon receipt of the ATN single. On all versions of the
+; specification, we can't change phases until REQ transitions true->false,
+; so we need to sink/source one byte of data to allow the transition.
+;
+; For the sake of safety, we'll only source one byte of data in all
+; cases, but to accommodate the SCSI-I dain bramage, we'll sink an
+; arbitrary number of bytes.
+ JUMP spew_cmd, WHEN CMD
+ JUMP eat_msgin, WHEN MSG_IN
+ JUMP eat_datain, WHEN DATA_IN
+ JUMP eat_status, WHEN STATUS
+ JUMP spew_dataout, WHEN DATA_OUT
+ JUMP sated
+spew_cmd:
+ MOVE 1, NCR53c7xx_zero, WHEN CMD
+ JUMP sated
+eat_msgin:
+ MOVE 1, NCR53c7xx_sink, WHEN MSG_IN
+ JUMP eat_msgin, WHEN MSG_IN
+ JUMP sated
+eat_status:
+ MOVE 1, NCR53c7xx_sink, WHEN STATUS
+ JUMP eat_status, WHEN STATUS
+ JUMP sated
+eat_datain:
+ MOVE 1, NCR53c7xx_sink, WHEN DATA_IN
+ JUMP eat_datain, WHEN DATA_IN
+ JUMP sated
+spew_dataout:
+ MOVE 1, NCR53c7xx_zero, WHEN DATA_OUT
+sated:
+#if (CHIP != 710)
+ MOVE SCNTL2 & 0x7f TO SCNTL2
+#endif
+ MOVE 1, NCR53c7xx_msg_abort, WHEN MSG_OUT
+ WAIT DISCONNECT
+ INT int_norm_aborted
+
+#if (CHIP != 710)
+;
+; dsa_to_scratch
+; scratch_to_dsa
+;
+; PURPOSE :
+; The NCR chips cannot do a move memory instruction with the DSA register
+; as the source or destination. So, we provide a couple of subroutines
+; that let us switch between the DSA register and scratch register.
+;
+; Memory moves to/from the DSPS register also don't work, but we
+; don't use them.
+;
+;
+
+
+dsa_to_scratch:
+ MOVE DSA0 TO SFBR
+ MOVE SFBR TO SCRATCH0
+ MOVE DSA1 TO SFBR
+ MOVE SFBR TO SCRATCH1
+ MOVE DSA2 TO SFBR
+ MOVE SFBR TO SCRATCH2
+ MOVE DSA3 TO SFBR
+ MOVE SFBR TO SCRATCH3
+ RETURN
+
+scratch_to_dsa:
+ MOVE SCRATCH0 TO SFBR
+ MOVE SFBR TO DSA0
+ MOVE SCRATCH1 TO SFBR
+ MOVE SFBR TO DSA1
+ MOVE SCRATCH2 TO SFBR
+ MOVE SFBR TO DSA2
+ MOVE SCRATCH3 TO SFBR
+ MOVE SFBR TO DSA3
+ RETURN
+#endif
+
+#if (CHIP == 710)
+; Little patched jump, used to overcome problems with TEMP getting
+; corrupted on memory moves.
+
+jump_temp:
+ JUMP 0
+#endif
diff --git a/drivers/scsi/ChangeLog.ncr53c8xx b/drivers/scsi/ChangeLog.ncr53c8xx
index ccf31d453..edc8f395c 100644
--- a/drivers/scsi/ChangeLog.ncr53c8xx
+++ b/drivers/scsi/ChangeLog.ncr53c8xx
@@ -1,3 +1,75 @@
+Sun May 11 22:30 1997 Gerard Roudier (groudier@club-internet.fr)
+ * revision 2.1b
+ - Cosmetic changes.
+ - Some heavy testings under pre-linux-2.1.37-6
+
+Sun May 4 22:30 1997 Gerard Roudier (groudier@club-internet.fr)
+ * revision 2.1a
+ - PFEN wrongly used for PREFETCH feature bit testing.
+ Changed to _F_PFEN.
+ - 2 SCR_COPY that need NO FLUSH bit to be removed had been missed
+ in tp->getscr[] script (loads SXFER and SCNTL3 on reselection).
+
+Sat May 3 22:30 1997 Gerard Roudier (groudier@club-internet.fr)
+ * revision 2.1
+ - Use the NO FLUSH option for MOVE MEMORY (COPY) each time it is
+ possible. More than 100 COPY with NO FLUSH and 6 with FLUSH for
+ my configuration (max queued command / device = 8).
+ This option bit is removed from the script instance for chips
+ that donnot support prefetching.
+ - Rewrite the ncr_exception() routine more simple (I think) and
+ remove useless code.
+ - Change the data_in and data_out script management.
+ Use the bottom part of these scripts instead of the beginning.
+ That avoids to zero the scatter/gather array when a command is
+ queued (1k) and to deal with some weird IID on MOVE 0 bytes when
+ a target wants to transfer more bytes than expected.
+ - Misc. improvements in the init code.
+ - Remove IOMAPPED/MMIO automatic switching option.
+ Was useless and reported not reliable.
+ - Fix a double read of DSTAT and remove DFE testing in the
+ Phase mismatch service routine.
+ - Etc...
+
+Fri Apr 26 20:00 1997 Gerard Roudier (groudier@club-internet.fr)
+ * revision 2.0a
+ - Add support if the Diamond FirePort 40 (SYM53C875J chip)
+
+Mon Apr 22 22:00 1997 Gerard Roudier (groudier@club-internet.fr)
+ * revision 2.0
+ - incorporate __initdata and __initfunc directives in order to
+ allow 'init' to free unused memory after driver initialisations.
+ Patch sent by Roberto Fichera.
+ - rewrite the init code of the driver. Now a feature descriptor
+ is used for each real chip types. The code is a lot more clean,
+ since the driver uses device and revision ids only in the
+ detection procedure.
+ - add 'pcifix' boot command line. This command allows to fix up PCI
+ config space for new chips which support features based on the
+ cache line size and 'write and invalidate'.
+ - incorporate in the driver, the code used for error recovery
+ testing. This code is normally not compiled; have to define
+ SCSI_NCR_DEBUG_ERROR_RECOVERY in order to compile it.
+ - take into account actual SCSI bus mode for 53C895 LVD/SE controller.
+ In single ended mode only fast20 is supported.
+ (Just to not be late since such controllers are not yet available)
+
+
+Sat Apr 20 21:00 1997 Gerard Roudier (groudier@club-internet.fr)
+ * revision 1.18f
+ - fix an old bug included in the initial port (version 0.0).
+ The driver allocated 10 bytes of static data and uses 12 bytes.
+ No danger, since data are generally aligned on 4 bytes boundary
+ and so byte 10 and 11 are free (I hope ...)
+
+Wed Apr 16 12:00 1997 Gerard Roudier (groudier@club-internet.fr)
+ * revision 1.18e
+ - reset all when an unexpected data cycle is detected while
+ disconnecting.
+ - make changes to abort() ans reset() functions according to
+ Leonard's documentation.
+ - small fix in some message for hard errors.
+
Sat Apr 5 13:00 1997 Gerard Roudier (groudier@club-internet.fr)
* revision 1.18d
- Probe NCR pci device ids in reverse order if asked by user from
diff --git a/drivers/scsi/Config.in b/drivers/scsi/Config.in
index 580c3d161..ce08d4873 100644
--- a/drivers/scsi/Config.in
+++ b/drivers/scsi/Config.in
@@ -87,6 +87,9 @@ if [ "$CONFIG_PCI" = "y" ]; then
dep_tristate 'Qlogic ISP SCSI support' CONFIG_SCSI_QLOGIC_ISP $CONFIG_SCSI
fi
dep_tristate 'Seagate ST-02 and Future Domain TMC-8xx SCSI support' CONFIG_SCSI_SEAGATE $CONFIG_SCSI
+if [ "$CONFIG_PCI" = "y" -a "$CONFIG_SCSI_AM53C974" != "y" ]; then
+ dep_tristate 'Tekram DC-390(T) (AMD PCscsi) SCSI support' CONFIG_SCSI_DC390T $CONFIG_SCSI
+fi
dep_tristate 'Trantor T128/T128F/T228 SCSI support' CONFIG_SCSI_T128 $CONFIG_SCSI
dep_tristate 'UltraStor 14F/34F support' CONFIG_SCSI_U14_34F $CONFIG_SCSI
if [ "$CONFIG_SCSI_U14_34F" != "n" ]; then
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index f06ef1204..02c066202 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -95,6 +95,30 @@ else
endif
endif
+ifeq ($(CONFIG_A4000T_SCSI),y)
+L_OBJS += amiga7xx.o 53c7xx.o
+else
+ ifeq ($(CONFIG_A4000T_SCSI),m)
+ M_OBJS += amiga7xx.o 53c7xx.o
+ endif
+endif
+
+ifeq ($(CONFIG_A4091_SCSI),y)
+L_OBJS += amiga7xx.o 53c7xx.o
+else
+ ifeq ($(CONFIG_A4091_SCSI),m)
+ M_OBJS += amiga7xx.o 53c7xx.o
+ endif
+endif
+
+ifeq ($(CONFIG_WARPENGINE_SCSI),y)
+L_OBJS += amiga7xx.o 53c7xx.o
+else
+ ifeq ($(CONFIG_WARPENGINE_SCSI),m)
+ M_OBJS += amiga7xx.o 53c7xx.o
+ endif
+endif
+
ifeq ($(CONFIG_A3000_SCSI),y)
L_OBJS += a3000.o wd33c93.o
else
@@ -193,6 +217,14 @@ else
endif
endif
+ifeq ($(CONFIG_SCSI_DC390T),y)
+L_OBJS += tmscsim.o
+else
+ ifeq ($(CONFIG_SCSI_DC390T),m)
+ M_OBJS += tmscsim.o
+ endif
+endif
+
ifeq ($(CONFIG_SCSI_AM53C974),y)
L_OBJS += AM53C974.o
else
@@ -418,6 +450,16 @@ seagate.o: seagate.c
mv scriptu.h 53c8xx_u.h
rm fake.c
+53c7xx.o : 53c7xx_d.h 53c7xx.c
+ $(CC) $(CFLAGS) -c 53c7xx.c
+
+53c7xx_d.h 53c7xx_u.h : 53c7xx.scr script_asm.pl
+ ln -sf 53c7xx.scr fake.c
+ $(CPP) -traditional -DCHIP=710 fake.c | grep -v '^#' | perl -s script_asm.pl -ncr7x0_family
+ mv script.h 53c7xx_d.h
+ mv scriptu.h 53c7xx_u.h
+ rm fake.c
+
ncr53c8xx.o : ncr53c8xx.c
$(CC) $(CFLAGS) -c ncr53c8xx.c
diff --git a/drivers/scsi/README.ncr53c8xx b/drivers/scsi/README.ncr53c8xx
index 53b690f7c..d93492a83 100644
--- a/drivers/scsi/README.ncr53c8xx
+++ b/drivers/scsi/README.ncr53c8xx
@@ -1,10 +1,10 @@
-The linux NCR53C8XX driver README file
+The Linux NCR53C8XX driver README file
Written by Gerard Roudier <groudier@club-internet.fr>
21 Rue Carnot
95170 DEUIL LA BARRE - FRANCE
-6 April 1997
+9 May 1997
===============================================================================
1. Introduction
@@ -22,6 +22,7 @@ Written by Gerard Roudier <groudier@club-internet.fr>
8.5 Set debug mode
8.6 Clear profile counters
8.7 Set flag (no_sync)
+ 8.8 Debug error recovery
9. Configuration parameters
10. Boot setup commands
10.1 Syntax
@@ -203,7 +204,6 @@ General information:
IO port address 0x6000, IRQ number 10
Using memory mapped IO at virtual address 0x282c000
Synchronous transfer period 25, max commands per lun 4
-
Profiling information:
num_trans = 18014
num_kbytes = 671314
@@ -390,6 +390,57 @@ Available commands:
- setflag all
will allow disconnection for all devices on the SCSI bus.
+
+8.8 Debug error recovery
+
+ debug_error_recovery <error to trigger>
+
+ Available error type to trigger:
+ sge: SCSI gross error
+ abort: abort command from the middle-level driver
+ reset: reset command from the middle-level driver
+ parity: scsi parity detected in DATA IN phase
+ none: restore driver normal behaviour
+
+ The code corresponding to this feature is normally not compiled.
+ Its purpose is driver testing only. In order to compile the code
+ that allows to trigger error recovery you must define at compile time
+ SCSI_NCR_DEBUG_ERROR_RECOVERY.
+ If you have compiled the driver with this option, nothing will happen
+ as long as you donnot use the control command 'debug_error_recovery'
+ with sge, abort, reset or parity as argument.
+ If you select an error type, it will be triggered by the driver every
+ 30 seconds.
+
+8.9 PCI configuration fix-up
+
+ pcifix <option bits>
+
+ Available option bits:
+ 0x1: Set PCI cache-line size register if not set.
+ 0x2: Set write and invalidate bit in PCI command register.
+
+ Use 'pcifix:3' in order to allow the driver to fix both PCI features.
+
+ These options only apply to new SYMBIOS chips 810A, 825A, 860 and 875
+ and are only supported for Pentium and 486 class processors.
+ Recent SYMBIOS 53C8XX scsi processors are able to use PCI read multiple
+ and PCI write and invalidate commands. These features require the
+ cache line size register to be properly set in the PCI configuration
+ space of the chips. On the other hand, chips will use PCI write and
+ invalidate commands only if the corresponding bit is set to 1 in the
+ PCI command register.
+
+ Not all PCI bioses set the PCI cache line register and the PCI write and
+ invalidate bit in the PCI configuration space of 53C8XX chips.
+ Optimized PCI accesses may be broken for some PCI/memory controllers or
+ make problems with some PCI boards.
+
+ This fix-up works flawlessly on my system.
+ (MB Triton HX / 53C875 / 53C810A)
+ I use these options at my own risks as you will do if you decide to
+ use them too.
+
9. Configuration parameters
If the firmware of all your devices is perfect enough, all the
@@ -736,9 +787,9 @@ Driver and common files:
You must untar the distribution with the following command:
- tar zxvf ncrBsd2Linux-1.18d-src.tar.gz
+ tar zxvf ncrBsd2Linux-2.1b-src.tar.gz
-The sub-directory ncr53c8xx-1.18d will be created. Change to this directory.
+The sub-directory ncr53c8xx-2.1b will be created. Change to this directory.
12.2 Installation procedure
diff --git a/drivers/scsi/a2091.c b/drivers/scsi/a2091.c
index a8638cc97..0290331ce 100644
--- a/drivers/scsi/a2091.c
+++ b/drivers/scsi/a2091.c
@@ -3,6 +3,7 @@
#include <linux/blk.h>
#include <linux/sched.h>
#include <linux/version.h>
+#include <linux/init.h>
#include <asm/setup.h>
#include <asm/page.h>
@@ -190,7 +191,7 @@ static void dma_stop (struct Scsi_Host *instance, Scsi_Cmnd *SCpnt,
static int num_a2091 = 0;
-int a2091_detect(Scsi_Host_Template *tpnt)
+__initfunc(int a2091_detect(Scsi_Host_Template *tpnt))
{
static unsigned char called = 0;
struct Scsi_Host *instance;
@@ -243,13 +244,11 @@ Scsi_Host_Template driver_template = A2091_SCSI;
int a2091_release(struct Scsi_Host *instance)
{
#ifdef MODULE
-DMA(instance)->CNTR = 0;
-zorro_unconfig_board(instance->unique_id, 0);
-if (--num_a2091 == 0)
- free_irq(IRQ_AMIGA_PORTS, a2091_intr);
-wd33c93_release();
+ DMA(instance)->CNTR = 0;
+ zorro_unconfig_board(instance->unique_id, 0);
+ if (--num_a2091 == 0)
+ free_irq(IRQ_AMIGA_PORTS, a2091_intr);
+ wd33c93_release();
#endif
-return 1;
+ return 1;
}
-
-
diff --git a/drivers/scsi/a3000.c b/drivers/scsi/a3000.c
index 93aa6efa7..fdc7fd41d 100644
--- a/drivers/scsi/a3000.c
+++ b/drivers/scsi/a3000.c
@@ -3,6 +3,7 @@
#include <linux/blk.h>
#include <linux/sched.h>
#include <linux/version.h>
+#include <linux/init.h>
#include <asm/setup.h>
#include <asm/page.h>
@@ -166,7 +167,7 @@ static void dma_stop (struct Scsi_Host *instance, Scsi_Cmnd *SCpnt,
}
}
-int a3000_detect(Scsi_Host_Template *tpnt)
+__initfunc(int a3000_detect(Scsi_Host_Template *tpnt))
{
static unsigned char called = 0;
diff --git a/drivers/scsi/amiga7xx.c b/drivers/scsi/amiga7xx.c
new file mode 100644
index 000000000..2e4b1aa3e
--- /dev/null
+++ b/drivers/scsi/amiga7xx.c
@@ -0,0 +1,107 @@
+/*
+ * Detection routine for the NCR53c710 based Amiga SCSI Controllers for Linux.
+ * Amiga MacroSystemUS WarpEngine SCSI controller.
+ * Amiga Technologies A4000T SCSI controller.
+ * Amiga Technologies/DKB A4091 SCSI controller.
+ *
+ * Written 1997 by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ * plus modifications of the 53c7xx.c driver to support the Amiga.
+ */
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/blk.h>
+#include <linux/sched.h>
+#include <linux/version.h>
+#include <linux/config.h>
+#include <linux/zorro.h>
+
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/amigaints.h>
+#include <asm/amigahw.h>
+#include <asm/irq.h>
+
+#include "scsi.h"
+#include "hosts.h"
+#include "53c7xx.h"
+#include "amiga7xx.h"
+
+#include<linux/stat.h>
+
+struct proc_dir_entry proc_scsi_amiga7xx = {
+ PROC_SCSI_AMIGA7XX, 8, "Amiga7xx",
+ S_IFDIR | S_IRUGO | S_IXUGO, 2
+};
+
+int amiga7xx_detect(Scsi_Host_Template *tpnt)
+{
+ static unsigned char called = 0;
+ int key;
+ int num = 0;
+ unsigned long address;
+ long long options;
+ struct ConfigDev *cd;
+
+ if (called || !MACH_IS_AMIGA)
+ return 0;
+
+ tpnt->proc_dir = &proc_scsi_amiga7xx;
+
+#ifdef CONFIG_WARPENGINE_SCSI
+ if ((key = zorro_find(MANUF_MACROSYSTEMS, PROD_WARP_ENGINE, 0, 0)))
+ {
+ cd = zorro_get_board(key);
+ address = (unsigned long)kernel_map((unsigned long)cd->cd_BoardAddr,
+ cd->cd_BoardSize, KERNELMAP_NOCACHE_SER, NULL);
+
+ options = OPTION_MEMORY_MAPPED|OPTION_DEBUG_TEST1|OPTION_INTFLY|OPTION_SYNCHRONOUS|OPTION_ALWAYS_SYNCHRONOUS|OPTION_DISCONNECT;
+
+ clock = 50000000; /* 50MHz SCSI Clock */
+
+ ncr53c7xx_init(tpnt, 0, 710, (u32)(unsigned char *)(address + 0x40000),
+ 0, IRQ_AMIGA_PORTS & ~IRQ_MACHSPEC, DMA_NONE,
+ options, clock);
+
+ zorro_config_board(key, 0);
+ num++;
+ }
+#endif
+
+#ifdef CONFIG_A4000T_SCSI
+ if (AMIGAHW_PRESENT(A4000_SCSI))
+ {
+ options = OPTION_MEMORY_MAPPED|OPTION_DEBUG_TEST1|OPTION_INTFLY|OPTION_SYNCHRONOUS|OPTION_ALWAYS_SYNCHRONOUS|OPTION_DISCONNECT;
+
+ clock = 50000000; /* 50MHz SCSI Clock */
+
+ ncr53c7xx_init(tpnt, 0, 710, (u32)(unsigned char *)ZTWO_VADDR(0xDD0040),
+ 0, IRQ_AMIGA_PORTS, DMA_NONE,
+ options, clock);
+ num++;
+ }
+#endif
+
+#ifdef CONFIG_A4091_SCSI
+ while ( (key = zorro_find(MANUF_COMMODORE, PROD_A4091, 0, 0)) ||
+ (key = zorro_find(MANUF_COMMODORE2, PROD_A4091_2, 0, 0)) )
+ {
+ cd = zorro_get_board(key);
+ address = (unsigned long)kernel_map((unsigned long)cd->cd_BoardAddr,
+ cd->cd_BoardSize, KERNELMAP_NOCACHE_SER, NULL);
+
+ options = OPTION_MEMORY_MAPPED|OPTION_DEBUG_TEST1|OPTION_INTFLY|OPTION_SYNCHRONOUS|OPTION_ALWAYS_SYNCHRONOUS|OPTION_DISCONNECT;
+
+ clock = 50000000; /* 50MHz SCSI Clock */
+
+ ncr53c7xx_init(tpnt, 0, 710, (u32)(unsigned char *)(address+0x800000),
+ 0, IRQ_AMIGA_PORTS & ~IRQ_MACHSPEC, DMA_NONE,
+ options, clock);
+
+ zorro_config_board(key, 0);
+ num++;
+ }
+#endif
+
+ called = 1;
+ return num;
+}
diff --git a/drivers/scsi/amiga7xx.h b/drivers/scsi/amiga7xx.h
new file mode 100644
index 000000000..ca85dca7b
--- /dev/null
+++ b/drivers/scsi/amiga7xx.h
@@ -0,0 +1,52 @@
+#ifndef AMIGA7XX_H
+
+#include <linux/types.h>
+
+int amiga7xx_detect(Scsi_Host_Template *);
+const char *NCR53c7x0_info(void);
+int NCR53c7xx_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+int NCR53c7xx_abort(Scsi_Cmnd *);
+int NCR53c7x0_release (Scsi_Host_Template *);
+int NCR53c7xx_reset(Scsi_Cmnd *, unsigned int);
+void NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs);
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifndef CMD_PER_LUN
+#define CMD_PER_LUN 3
+#endif
+
+#ifndef CAN_QUEUE
+#define CAN_QUEUE 24
+#endif
+
+#if defined(HOSTS_C) || defined(MODULE)
+#include <scsi/scsicam.h>
+
+extern struct proc_dir_entry proc_scsi_amiga7xx;
+
+#define AMIGA7XX_SCSI {/* next */ NULL, \
+ /* usage_count */ NULL, \
+ /* proc_dir_entry */ NULL, \
+ /* proc_info */ NULL, \
+ /* name */ "Amiga NCR53c710 SCSI", \
+ /* detect */ amiga7xx_detect, \
+ /* release */ NULL, \
+ /* info */ NULL, \
+ /* command */ NULL, \
+ /* queuecommand */ NCR53c7xx_queue_command, \
+ /* abort */ NCR53c7xx_abort, \
+ /* reset */ NCR53c7xx_reset, \
+ /* slave_attach */ NULL, \
+ /* bios_param */ scsicam_bios_param, \
+ /* can_queue */ 24, \
+ /* this_id */ 7, \
+ /* sg_tablesize */ 127, \
+ /* cmd_per_lun */ 3, \
+ /* present */ 0, \
+ /* unchecked_isa_dma */ 0, \
+ /* use_clustering */ DISABLE_CLUSTERING }
+#endif
+#endif /* AMIGA7XX_H */
diff --git a/drivers/scsi/atari_NCR5380.c b/drivers/scsi/atari_NCR5380.c
index 497b47f67..c77e5cd71 100644
--- a/drivers/scsi/atari_NCR5380.c
+++ b/drivers/scsi/atari_NCR5380.c
@@ -323,7 +323,7 @@ typedef struct {
static TAG_ALLOC TagAlloc[8][8]; /* 8 targets and 8 LUNs */
-static void init_tags( void )
+__initfunc(static void init_tags( void ))
{
int target, lun;
TAG_ALLOC *ta;
@@ -665,7 +665,7 @@ static __inline__ void queue_main(void)
}
-static void NCR5380_all_init (void)
+static inline void NCR5380_all_init (void)
{
static int done = 0;
if (!done) {
@@ -684,7 +684,7 @@ static void NCR5380_all_init (void)
* Inputs : instance, pointer to this instance. Unused.
*/
-static void NCR5380_print_options (struct Scsi_Host *instance)
+__initfunc(static void NCR5380_print_options (struct Scsi_Host *instance))
{
printk(" generic options"
#ifdef AUTOSENSE
@@ -848,7 +848,7 @@ lprint_Scsi_Cmnd (Scsi_Cmnd *cmd, char *pos, char *buffer, int length)
*
*/
-static void NCR5380_init (struct Scsi_Host *instance, int flags)
+__initfunc(static void NCR5380_init (struct Scsi_Host *instance, int flags))
{
int i;
SETUP_HOSTDATA(instance);
diff --git a/drivers/scsi/atari_scsi.c b/drivers/scsi/atari_scsi.c
index d0de9dcdb..15dfb01f1 100644
--- a/drivers/scsi/atari_scsi.c
+++ b/drivers/scsi/atari_scsi.c
@@ -89,6 +89,7 @@
#include <linux/blk.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
+#include <linux/init.h>
#include <asm/setup.h>
#include <asm/atarihw.h>
@@ -765,7 +766,7 @@ int atari_scsi_release (struct Scsi_Host *sh)
}
#endif
-void atari_scsi_setup( char *str, int *ints )
+__initfunc(void atari_scsi_setup( char *str, int *ints ))
{
/* Format of atascsi parameter is:
* atascsi=<can_queue>,<cmd_per_lun>,<sg_tablesize>,<hostid>,<use_tags>
@@ -869,7 +870,7 @@ int atari_scsi_reset( Scsi_Cmnd *cmd, unsigned int reset_flags)
}
-static void atari_scsi_reset_boot( void )
+__initfunc(static void atari_scsi_reset_boot( void ))
{
unsigned long end;
@@ -1025,6 +1026,10 @@ static unsigned long atari_dma_xfer_len( unsigned long wanted_len,
{
unsigned long possible_len, limit;
+ if (is_hades)
+ /* Hades has no SCSI DMA at all :-( Always force use of PIO */
+ return( 0 );
+
if (IS_A_TT())
/* TT SCSI DMA can transfer arbitrary #bytes */
return( wanted_len );
diff --git a/drivers/scsi/dc390.h b/drivers/scsi/dc390.h
new file mode 100644
index 000000000..bfe20c96b
--- /dev/null
+++ b/drivers/scsi/dc390.h
@@ -0,0 +1,147 @@
+/***********************************************************************
+ * FILE NAME : DC390.H *
+ * BY : C.L. Huang *
+ * Description: Device Driver for Tekram DC-390(T) PCI SCSI *
+ * Bus Master Host Adapter *
+ ***********************************************************************/
+
+/* Kernel version autodetection */
+
+#include <linux/version.h>
+/* Convert Linux Version, Patch-level, Sub-level to LINUX_VERSION_CODE. */
+#define ASC_LINUX_VERSION(V, P, S) (((V) * 65536) + ((P) * 256) + (S))
+
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,50)
+#define VERSION_ELF_1_2_13
+#elseif LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,95)
+#define VERSION_1_3_85
+#else
+#define VERSION_2_0_0
+#endif
+
+/*
+ * AMD 53C974 driver, header file
+ */
+
+#ifndef DC390_H
+#define DC390_H
+
+#if defined(HOSTS_C) || defined(MODULE)
+
+#ifdef VERSION_2_0_0
+#include <scsi/scsicam.h>
+#else
+#include <linux/scsicam.h>
+#endif
+
+extern int DC390_detect(Scsi_Host_Template *psht);
+extern int DC390_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *));
+extern int DC390_abort(Scsi_Cmnd *cmd);
+
+#ifdef VERSION_2_0_0
+extern int DC390_reset(Scsi_Cmnd *cmd, unsigned int resetFlags);
+#else
+extern int DC390_reset(Scsi_Cmnd *cmd);
+#endif
+
+#ifdef VERSION_ELF_1_2_13
+extern int DC390_bios_param(Disk *disk, int devno, int geom[]);
+#else
+extern int DC390_bios_param(Disk *disk, kdev_t devno, int geom[]);
+#endif
+
+#ifdef MODULE
+static int DC390_release(struct Scsi_Host *);
+#else
+#define DC390_release NULL
+#endif
+
+#ifndef VERSION_ELF_1_2_13
+extern struct proc_dir_entry proc_scsi_tmscsim;
+extern int tmscsim_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout);
+#endif
+
+#ifdef VERSION_2_0_0
+
+#define DC390_T { \
+ NULL, /* *next */ \
+ NULL, /* *usage_count */ \
+ &proc_scsi_tmscsim, /* *proc_dir */ \
+ tmscsim_proc_info, /* (*proc_info)() */ \
+ "Tekram DC390(T) V1.10 Dec-05-1996", /* *name */ \
+ DC390_detect, \
+ DC390_release, /* (*release)() */ \
+ NULL, /* *(*info)() */ \
+ NULL, /* (*command)() */ \
+ DC390_queue_command, \
+ DC390_abort, \
+ DC390_reset, \
+ NULL, /* slave attach */\
+ DC390_bios_param, \
+ 10,/* can queue(-1) */ \
+ 7, /* id(-1) */ \
+ SG_ALL, \
+ 2, /* cmd per lun(2) */ \
+ 0, /* present */ \
+ 0, /* unchecked isa dma */ \
+ DISABLE_CLUSTERING \
+ }
+#endif
+
+
+#ifdef VERSION_1_3_85
+
+#define DC390_T { \
+ NULL, /* *next */ \
+ NULL, /* *usage_count */ \
+ &proc_scsi_tmscsim, /* *proc_dir */ \
+ tmscsim_proc_info, /* (*proc_info)() */ \
+ "Tekram DC390(T) V1.10 Dec-05-1996", /* *name */ \
+ DC390_detect, \
+ DC390_release, /* (*release)() */ \
+ NULL, /* *(*info)() */ \
+ NULL, /* (*command)() */ \
+ DC390_queue_command, \
+ DC390_abort, \
+ DC390_reset, \
+ NULL, /* slave attach */\
+ DC390_bios_param, \
+ 10,/* can queue(-1) */ \
+ 7, /* id(-1) */ \
+ SG_ALL, \
+ 2, /* cmd per lun(2) */ \
+ 0, /* present */ \
+ 0, /* unchecked isa dma */ \
+ DISABLE_CLUSTERING \
+ }
+#endif
+
+
+#ifdef VERSION_ELF_1_2_13
+
+#define DC390_T { \
+ NULL, \
+ NULL, \
+ "Tekram DC390(T) V1.10 Dec-05-1996",\
+ DC390_detect, \
+ DC390_release, \
+ NULL, /* info */ \
+ NULL, /* command, deprecated */ \
+ DC390_queue_command, \
+ DC390_abort, \
+ DC390_reset, \
+ NULL, /* slave attach */\
+ DC390_bios_param, \
+ 10,/* can queue(-1) */ \
+ 7, /* id(-1) */ \
+ 16,/* old (SG_ALL) */ \
+ 2, /* cmd per lun(2) */ \
+ 0, /* present */ \
+ 0, /* unchecked isa dma */ \
+ DISABLE_CLUSTERING \
+ }
+#endif
+
+#endif /* defined(HOSTS_C) || defined(MODULE) */
+
+#endif /* DC390_H */
diff --git a/drivers/scsi/eata.c b/drivers/scsi/eata.c
index fb82d349a..cfff8bfa3 100644
--- a/drivers/scsi/eata.c
+++ b/drivers/scsi/eata.c
@@ -1,6 +1,13 @@
/*
* eata.c - Low-level driver for EATA/DMA SCSI host adapters.
*
+ * 17 May 1997 rev. 3.10 for linux 2.0.30 and 2.1.38
+ * Use of serial_number_at_timeout in abort and reset processing.
+ * Use of the __initfunc and __initdata macro in setup code.
+ * Minor cleanups in the list_statistics code.
+ * Increased controller busy timeout in order to better support
+ * slow SCSI devices.
+ *
* 24 Feb 1997 rev. 3.00 for linux 2.0.29 and 2.1.26
* When loading as a module, parameter passing is now supported
* both in 2.0 and in 2.1 style.
@@ -202,8 +209,7 @@
* lc:n disables linked commands;
* tc:y enables tagged commands;
* tc:n disables tagged commands;
- * tm:0 use head/simple/ordered queue tag sequences for reads and ordered
- * queue tags for writes;
+ * tm:0 use head/simple/ordered queue tag sequences;
* tm:1 use only simple queue tags;
* tm:2 use only head of queue tags;
* tm:3 use only ordered queue tags;
@@ -232,10 +238,12 @@
* between increasing or decreasing by minimizing the seek distance between
* the sector of the commands just completed and the sector of the first
* command in the list to be sorted.
- * Trivial math assures that if there are (Q-1) outstanding request for
- * random seeks over S sectors, the unsorted average seek distance is S/2,
- * while the sorted average seek distance is S/(Q-1). The seek distance is
- * hence divided by a factor (Q-1)/2.
+ * Trivial math assures that the unsorted average seek distance when doing
+ * random seeks over S sectors is S/3.
+ * When (Q-1) requests are uniformly distributed over S sectors, the average
+ * distance between two adjacent requests is S/((Q-1) + 1), so the sorted
+ * average seek distance for (Q-1) random requests over S sectors is S/Q.
+ * The elevator sorting hence divides the seek distance by a factor Q/3.
* The above pure geometric remarks are valid in all cases and the
* driver effectively reduces the seek distance by the predicted factor
* when there are Q concurrent read i/o operations on the device, but this
@@ -286,10 +294,18 @@ MODULE_AUTHOR("Dario Ballabio");
#include <asm/dma.h>
#include <asm/irq.h>
#include "eata.h"
-#include<linux/stat.h>
-#include<linux/config.h>
-#include<linux/bios32.h>
-#include<linux/pci.h>
+#include <linux/stat.h>
+#include <linux/config.h>
+#include <linux/bios32.h>
+#include <linux/pci.h>
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,36)
+#include <linux/init.h>
+#else
+#define __initfunc(A) A
+#define __initdata
+#define __init
+#endif
struct proc_dir_entry proc_scsi_eata2x = {
PROC_SCSI_EATA2X, 6, "eata2x",
@@ -517,7 +533,7 @@ static struct Scsi_Host *sh[MAX_BOARDS + 1];
static const char *driver_name = "EATA";
static unsigned int irqlist[MAX_IRQ], calls[MAX_IRQ];
-static unsigned int io_port[] = {
+static unsigned int io_port[] __initdata = {
/* Space for MAX_INT_PARAM ports usable while loading as a module */
SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP,
@@ -638,8 +654,7 @@ static void select_queue_depths(struct Scsi_Host *host, Scsi_Device *devlist) {
return;
}
-static inline int wait_on_busy(unsigned int iobase) {
- unsigned int loop = MAXLOOP;
+static inline int wait_on_busy(unsigned int iobase, unsigned int loop) {
while (inb(iobase + REG_AUX_STATUS) & ABSY_ASSERTED)
if (--loop == 0) return TRUE;
@@ -649,7 +664,7 @@ static inline int wait_on_busy(unsigned int iobase) {
static inline int do_dma(unsigned int iobase, unsigned int addr, unchar cmd) {
- if (wait_on_busy(iobase)) return TRUE;
+ if (wait_on_busy(iobase, (addr ? MAXLOOP * 100 : MAXLOOP))) return TRUE;
if ((addr = V2DEV(addr))) {
outb((char) (addr >> 24), iobase + REG_LOW);
@@ -678,8 +693,8 @@ static inline int read_pio(unsigned int iobase, ushort *start, ushort *end) {
return FALSE;
}
-static inline int port_detect(unsigned int port_base, unsigned int j,
- Scsi_Host_Template *tpnt) {
+__initfunc (static inline int port_detect \
+ (unsigned int port_base, unsigned int j, Scsi_Host_Template *tpnt)) {
unsigned char irq, dma_channel, subversion, i;
unsigned char protocol_rev;
struct eata_info info;
@@ -882,7 +897,7 @@ static inline int port_detect(unsigned int port_base, unsigned int j,
sh[j]->max_lun = info.max_lun + 1;
}
- if (dma_channel == NO_DMA) sprintf(dma_name, "%s", "NO DMA");
+ if (dma_channel == NO_DMA) sprintf(dma_name, "%s", "BMST");
else sprintf(dma_name, "DMA %u", dma_channel);
for (i = 0; i < sh[j]->can_queue; i++)
@@ -941,7 +956,7 @@ static inline int port_detect(unsigned int port_base, unsigned int j,
return TRUE;
}
-void eata2x_setup(char *str, int *ints) {
+__initfunc (void eata2x_setup(char *str, int *ints)) {
int i, argc = ints[0];
char *cur = str, *pc;
@@ -974,7 +989,7 @@ void eata2x_setup(char *str, int *ints) {
return;
}
-static void add_pci_ports(void) {
+__initfunc (static void add_pci_ports(void)) {
#if defined(CONFIG_PCI)
@@ -1009,7 +1024,7 @@ static void add_pci_ports(void) {
return;
}
-int eata2x_detect(Scsi_Host_Template *tpnt) {
+__initfunc (int eata2x_detect(Scsi_Host_Template *tpnt)) {
unsigned long flags;
unsigned int j = 0, k;
@@ -1166,6 +1181,9 @@ int eata2x_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
cpp->reqsen = TRUE;
cpp->dispri = TRUE;
+#if 0
+ if (SCpnt->device->type == TYPE_TAPE) cpp->hbaci = TRUE;
+#endif
cpp->one = TRUE;
cpp->channel = SCpnt->channel;
cpp->target = SCpnt->target;
@@ -1182,14 +1200,12 @@ int eata2x_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
else if (tag_mode == TAG_SIMPLE) cpp->mess[0] = SIMPLE_QUEUE_TAG;
else if (tag_mode == TAG_HEAD) cpp->mess[0] = HEAD_OF_QUEUE_TAG;
else if (tag_mode == TAG_ORDERED) cpp->mess[0] = ORDERED_QUEUE_TAG;
- else if ((SCpnt->device->current_tag % SCpnt->device->queue_depth) == 0)
+ else if (SCpnt->device->current_tag == 0)
cpp->mess[0] = ORDERED_QUEUE_TAG;
- else if ((SCpnt->device->current_tag % SCpnt->device->queue_depth) == 1)
+ else if (SCpnt->device->current_tag == 1)
cpp->mess[0] = HEAD_OF_QUEUE_TAG;
- else if (cpp->din)
- cpp->mess[0] = SIMPLE_QUEUE_TAG;
else
- cpp->mess[0] = ORDERED_QUEUE_TAG;
+ cpp->mess[0] = SIMPLE_QUEUE_TAG;
cpp->mess[1] = SCpnt->device->current_tag++;
}
@@ -1208,7 +1224,7 @@ int eata2x_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
if (linked_comm && SCpnt->device->queue_depth > 2
&& TLDEV(SCpnt->device->type)) {
HD(j)->cp_stat[i] = READY;
- flush_dev(SCpnt->device, 0, j, FALSE);
+ flush_dev(SCpnt->device, SCpnt->request.sector, j, FALSE);
restore_flags(flags);
return 0;
}
@@ -1238,7 +1254,8 @@ int eata2x_abort(Scsi_Cmnd *SCarg) {
cli();
j = ((struct hostdata *) SCarg->host->hostdata)->board_number;
- if (SCarg->host_scribble == NULL) {
+ if (SCarg->host_scribble == NULL
+ || SCarg->serial_number != SCarg->serial_number_at_timeout) {
printk("%s: abort, target %d.%d:%d, pid %ld inactive.\n",
BN(j), SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid);
restore_flags(flags);
@@ -1252,7 +1269,7 @@ int eata2x_abort(Scsi_Cmnd *SCarg) {
if (i >= sh[j]->can_queue)
panic("%s: abort, invalid SCarg->host_scribble.\n", BN(j));
- if (wait_on_busy(sh[j]->io_port)) {
+ if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
printk("%s: abort, timeout error.\n", BN(j));
restore_flags(flags);
return SCSI_ABORT_ERROR;
@@ -1321,13 +1338,19 @@ int eata2x_reset(Scsi_Cmnd *SCarg, unsigned int reset_flags) {
if (SCarg->host_scribble == NULL)
printk("%s: reset, pid %ld inactive.\n", BN(j), SCarg->pid);
+ if (SCarg->serial_number != SCarg->serial_number_at_timeout) {
+ printk("%s: reset, pid %ld, reset not running.\n", BN(j), SCarg->pid);
+ restore_flags(flags);
+ return SCSI_RESET_NOT_RUNNING;
+ }
+
if (HD(j)->in_reset) {
printk("%s: reset, exit, already in reset.\n", BN(j));
restore_flags(flags);
return SCSI_RESET_ERROR;
}
- if (wait_on_busy(sh[j]->io_port)) {
+ if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
printk("%s: reset, exit, timeout error.\n", BN(j));
restore_flags(flags);
return SCSI_RESET_ERROR;
@@ -1480,7 +1503,7 @@ static inline void reorder(unsigned int j, unsigned long cursec,
unsigned int rev = FALSE, s = TRUE, r = TRUE;
unsigned int input_only = TRUE, overlap = FALSE;
unsigned long sl[n_ready], pl[n_ready], ll[n_ready];
- unsigned long maxsec = 0, minsec = ULONG_MAX, seek = 0;
+ unsigned long maxsec = 0, minsec = ULONG_MAX, seek = 0, iseek = 0;
static unsigned int flushcount = 0, batchcount = 0, sortcount = 0;
static unsigned int readycount = 0, ovlcount = 0, inputcount = 0;
@@ -1491,8 +1514,8 @@ static inline void reorder(unsigned int j, unsigned long cursec,
printk("fc %d bc %d ic %d oc %d rc %d rs %d sc %d re %d"\
" av %ldK as %ldK.\n", flushcount, batchcount, inputcount,
ovlcount, readycount, readysorted, sortcount, revcount,
- seeknosort / (readycount - batchcount + 1),
- seeksorted / (readycount - batchcount + 1));
+ seeknosort / (readycount + 1),
+ seeksorted / (readycount + 1));
if (n_ready <= 1) return;
@@ -1520,6 +1543,10 @@ static inline void reorder(unsigned int j, unsigned long cursec,
}
+ if (link_statistics) {
+ if (cursec > sl[0]) seek += cursec - sl[0]; else seek += sl[0] - cursec;
+ }
+
if (cursec > ((maxsec + minsec) / 2)) rev = TRUE;
if (!((rev && r) || (!rev && s))) sort(sl, il, n_ready, rev);
@@ -1537,10 +1564,11 @@ static inline void reorder(unsigned int j, unsigned long cursec,
if (overlap) sort(pl, il, n_ready, FALSE);
if (link_statistics) {
+ if (cursec > sl[0]) iseek = cursec - sl[0]; else iseek = sl[0] - cursec;
batchcount++; readycount += n_ready, seeknosort += seek / 1024;
if (input_only) inputcount++;
if (overlap) { ovlcount++; seeksorted += seek / 1024; }
- else seeksorted += (maxsec - minsec) / 1024;
+ else seeksorted += (iseek + maxsec - minsec) / 1024;
if (rev && !r) { revcount++; readysorted += n_ready; }
if (!rev && !s) { sortcount++; readysorted += n_ready; }
}
diff --git a/drivers/scsi/eata.h b/drivers/scsi/eata.h
index 82791396a..cba391414 100644
--- a/drivers/scsi/eata.h
+++ b/drivers/scsi/eata.h
@@ -12,7 +12,7 @@ int eata2x_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
int eata2x_abort(Scsi_Cmnd *);
int eata2x_reset(Scsi_Cmnd *, unsigned int);
-#define EATA_VERSION "3.00.09"
+#define EATA_VERSION "3.10.00"
#define EATA { \
diff --git a/drivers/scsi/gvp11.c b/drivers/scsi/gvp11.c
index 76da3403f..165a68e60 100644
--- a/drivers/scsi/gvp11.c
+++ b/drivers/scsi/gvp11.c
@@ -3,6 +3,7 @@
#include <linux/blk.h>
#include <linux/sched.h>
#include <linux/version.h>
+#include <linux/init.h>
#include <asm/setup.h>
#include <asm/page.h>
@@ -198,7 +199,7 @@ static void dma_stop (struct Scsi_Host *instance, Scsi_Cmnd *SCpnt,
static int num_gvp11 = 0;
-int gvp11_detect(Scsi_Host_Template *tpnt)
+__initfunc(int gvp11_detect(Scsi_Host_Template *tpnt))
{
static unsigned char called = 0;
struct Scsi_Host *instance;
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
index 41e5dab80..9bf8c5ec3 100644
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -42,6 +42,10 @@
#include "hosts.h"
+#if defined(CONFIG_A4000T_SCSI) || defined(CONFIG_WARPENGINE_SCSI) || defined(CONFIG_A4091_SCSI)
+#include "amiga7xx.h"
+#endif
+
#ifdef CONFIG_A3000_SCSI
#include "a3000.h"
#endif
@@ -158,6 +162,10 @@
#include "NCR53c406a.h"
#endif
+#ifdef CONFIG_SCSI_DC390T
+#include "dc390.h"
+#endif
+
#ifdef CONFIG_SCSI_AM53C974
#include "AM53C974.h"
#endif
@@ -221,6 +229,9 @@ Scsi_Host_Template * scsi_hosts = NULL;
static Scsi_Host_Template builtin_scsi_hosts[] =
{
#ifdef CONFIG_AMIGA
+#if defined(CONFIG_WARPENGINE_SCSI) || defined(CONFIG_A4000T_SCSI) || defined(CONFIG_A4091_SCSI)
+ AMIGA7XX_SCSI,
+#endif
#ifdef CONFIG_A3000_SCSI
A3000_SCSI,
#endif
@@ -314,6 +325,9 @@ static Scsi_Host_Template builtin_scsi_hosts[] =
#ifdef CONFIG_SCSI_EATA
EATA,
#endif
+#ifdef CONFIG_SCSI_DC390T
+ DC390_T,
+#endif
#ifdef CONFIG_SCSI_AM53C974
AM53C974,
#endif
diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c
index 7cbb86070..efd6568f1 100644
--- a/drivers/scsi/ide-scsi.c
+++ b/drivers/scsi/ide-scsi.c
@@ -242,7 +242,7 @@ static void idescsi_pc_intr (ide_drive_t *drive)
printk (KERN_INFO "ide-scsi: Reached idescsi_pc_intr interrupt handler\n");
#endif /* IDESCSI_DEBUG_LOG */
- if (clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
+ if (test_and_clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
#if IDESCSI_DEBUG_LOG
printk ("ide-scsi: %s: DMA complete\n", drive->name);
#endif /* IDESCSI_DEBUG_LOG */
diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c
index a029cef95..e62795b11 100644
--- a/drivers/scsi/ncr53c8xx.c
+++ b/drivers/scsi/ncr53c8xx.c
@@ -40,7 +40,7 @@
*/
/*
-** 16 April 1997, version 1.18e
+** 9 May 1997, version 2.1b
**
** Supported SCSI-II features:
** Synchronous negotiation
@@ -56,7 +56,7 @@
** 53C820 (Wide, NCR BIOS in flash bios required)
** 53C825 (Wide, ~53C820 with on board rom BIOS)
** 53C860 (Narrow fast 20, BIOS required)
-** 53C875 (Wide fast 40 with on board rom BIOS)
+** 53C875 (Wide fast 20 with on board rom BIOS)
** 53C895 (Ultra2 80 MB/s with on board rom BIOS)
**
** Other features:
@@ -65,7 +65,6 @@
** Shared IRQ (since linux-1.3.72)
*/
-#define SCSI_NCR_DEBUG
#define SCSI_NCR_DEBUG_FLAGS (0)
#define NCR_DATE "pl24 96/12/14"
@@ -103,6 +102,11 @@
#include <linux/time.h>
#include <linux/timer.h>
#include <linux/stat.h>
+#ifdef __mips__
+#include <asm/bootinfo.h>
+#include <asm/pgtable.h>
+#include <asm/sni.h>
+#endif /* __mips__ */
#include <linux/version.h>
#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0)
@@ -111,6 +115,17 @@
#include "../block/blk.h"
#endif
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,35)
+#include <linux/init.h>
+#else
+#ifndef __initdata
+#define __initdata
+#endif
+#ifndef __initfunc
+#define __initfunc(__arginit) __arginit
+#endif
+#endif
+
#include "scsi.h"
#include "hosts.h"
#include "constants.h"
@@ -133,15 +148,6 @@ typedef u32 u_int32;
*/
/*
-** Proc info and user command support
-*/
-
-#ifdef SCSI_NCR_PROC_INFO_SUPPORT
-#define SCSI_NCR_PROFILE
-#define SCSI_NCR_USER_COMMAND
-#endif
-
-/*
** SCSI address of this device.
** The boot routines should have set it.
** If not, use this.
@@ -212,8 +218,6 @@ typedef u32 u_int32;
#if defined(SCSI_NCR_IOMAPPED)
#define NCR_IOMAPPED
-#else
-#define NCR_MEMORYMAPPED
#endif
/*
@@ -264,6 +268,8 @@ typedef int vm_size_t;
** In the original Bsd driver, vtophys() is called to translate
** data addresses to IO bus addresses. In order to minimize
** change, I decide to define vtophys() as virt_to_bus().
+*
+* FIXME: Bus addresses are _not_ physical addresses.
*/
#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0)
@@ -292,6 +298,7 @@ static inline vm_offset_t remap_pci_mem(u_long base, u_long size)
return (vm_offset_t) (page_remapped ? (page_remapped + page_offs) : 0UL);
}
+
static inline void unmap_pci_mem(vm_offset_t vaddr, u_long size)
{
if (vaddr)
@@ -422,6 +429,8 @@ static int guess_xfer_direction(int opcode);
** Head of list of NCR boards
**
** Host is retrieved by its irq level.
+** If interrupts are shared, the internal host control block
+** address (struct ncb) is used as device id.
*/
static struct Scsi_Host *first_host = NULL;
@@ -470,6 +479,7 @@ struct ncr_driver_setup {
unsigned ultra_scsi : 2;
unsigned force_sync_nego: 1;
unsigned reverse_probe: 1;
+ unsigned pci_fix_up: 2;
u_char verbose;
u_char default_tags;
u_short default_sync;
@@ -482,8 +492,13 @@ struct ncr_driver_setup {
u_char irqm;
};
-static struct ncr_driver_setup driver_setup = SCSI_NCR_DRIVER_SETUP;
-static struct ncr_driver_setup driver_safe_setup= SCSI_NCR_DRIVER_SAFE_SETUP;
+static struct ncr_driver_setup
+ driver_setup = SCSI_NCR_DRIVER_SETUP;
+
+#ifdef SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT
+static struct ncr_driver_setup
+ driver_safe_setup __initdata = SCSI_NCR_DRIVER_SAFE_SETUP;
+#endif
/*
** Other Linux definitions
@@ -503,7 +518,8 @@ static void ncr53c8xx_intr(int irq, struct pt_regs * regs);
static void ncr53c8xx_timeout(unsigned long np);
-#define bootverbose (driver_setup.verbose)
+//#define bootverbose (driver_setup.verbose)
+#define bootverbose 2
/*==========================================================
**
@@ -531,7 +547,7 @@ static void ncr53c8xx_timeout(unsigned long np);
** Can be changed at runtime too.
*/
-#ifdef SCSI_NCR_DEBUG
+#ifdef SCSI_NCR_DEBUG_INFO_SUPPORT
#define DEBUG_FLAGS ncr_debug
#else
#define DEBUG_FLAGS SCSI_NCR_DEBUG_FLAGS
@@ -572,54 +588,54 @@ static void ncr53c8xx_timeout(unsigned long np);
** IO mapped input / ouput
*/
-#define IOM_INB(r) inb (np->port + offsetof(struct ncr_reg, r))
-#define IOM_INB_OFF(o) inb (np->port + (o))
-#define IOM_INW(r) inw (np->port + offsetof(struct ncr_reg, r))
-#define IOM_INL(r) inl (np->port + offsetof(struct ncr_reg, r))
-#define IOM_INL_OFF(o) inl (np->port + (o))
+#define IOM_INB(r) inb (np->port + offsetof(struct ncr_reg, r))
+#define IOM_INB_OFF(o) inb (np->port + (o))
+#define IOM_INW(r) inw (np->port + offsetof(struct ncr_reg, r))
+#define IOM_INL(r) inl (np->port + offsetof(struct ncr_reg, r))
+#define IOM_INL_OFF(o) inl (np->port + (o))
-#define IOM_OUTB(r, val) outb ((val), np->port+offsetof(struct ncr_reg,r))
-#define IOM_OUTW(r, val) outw ((val), np->port+offsetof(struct ncr_reg,r))
-#define IOM_OUTL(r, val) outl ((val), np->port+offsetof(struct ncr_reg,r))
-#define IOM_OUTL_OFF(o, val) outl ((val), np->port + (o))
+#define IOM_OUTB(r, val) outb ((val), np->port+offsetof(struct ncr_reg,r))
+#define IOM_OUTW(r, val) outw ((val), np->port+offsetof(struct ncr_reg,r))
+#define IOM_OUTL(r, val) outl ((val), np->port+offsetof(struct ncr_reg,r))
+#define IOM_OUTL_OFF(o, val) outl ((val), np->port + (o))
/*
** MEMORY mapped IO input / output
*/
-#define MMIO_INB(r) readb(&np->reg->r)
-#define MMIO_INB_OFF(o) readb((char *)np->reg + (o))
-#define MMIO_INW(r) readw(&np->reg->r)
-#define MMIO_INL(r) readl(&np->reg->r)
-#define MMIO_INL_OFF(o) readl((char *)np->reg + (o))
+#define MMIO_INB(r) (*(volatile u8 *)(&np->reg->r))
+#define MMIO_INB_OFF(o) (*(volatile u8 *)((char *)np->reg + (o)))
+#define MMIO_INW(r) (*(volatile u16 *)(&np->reg->r))
+#define MMIO_INL(r) (*(volatile u32 *)(&np->reg->r))
+#define MMIO_INL_OFF(o) (*(volatile u32 *)((char *)np->reg + (o)))
-#define MMIO_OUTB(r, val) writeb((val), &np->reg->r)
-#define MMIO_OUTW(r, val) writew((val), &np->reg->r)
-#define MMIO_OUTL(r, val) writel((val), &np->reg->r)
-#define MMIO_OUTL_OFF(o, val) writel((val), (char *)np->reg + (o))
+#define MMIO_OUTB(r, val) (*(volatile u8 *) &np->reg->r = (val))
+#define MMIO_OUTW(r, val) (*(volatile u16 *) &np->reg->r = (val))
+#define MMIO_OUTL(r, val) (*(volatile u32 *) &np->reg->r = (val))
+#define MMIO_OUTL_OFF(o, val) (*(volatile u32 *) ((char *)np->reg + (o)) = (val))
/*
-** IO mapped only input / output
+** IO mapped input / output
*/
#if defined(NCR_IOMAPPED)
-#define INB(r) IOM_INB(r)
-#define INB_OFF(o) IOM_INB_OFF(o)
-#define INW(r) IOM_INW(r)
-#define INL(r) IOM_INL(r)
-#define INL_OFF(o) IOM_INL_OFF(o)
+#define INB(r) IOM_INB(r)
+#define INB_OFF(o) IOM_INB_OFF(o)
+#define INW(r) IOM_INW(r)
+#define INL(r) IOM_INL(r)
+#define INL_OFF(o) IOM_INL_OFF(o)
-#define OUTB(r, val) IOM_OUTB(r, val)
-#define OUTW(r, val) IOM_OUTW(r, val)
-#define OUTL(r, val) IOM_OUTL(r, val)
-#define OUTL_OFF(o, val) IOM_OUTL_OFF(o, val)
+#define OUTB(r, val) IOM_OUTB(r, val)
+#define OUTW(r, val) IOM_OUTW(r, val)
+#define OUTL(r, val) IOM_OUTL(r, val)
+#define OUTL_OFF(o, val) IOM_OUTL_OFF(o, val)
/*
** MEMORY mapped only input / output
*/
-#elif defined(NCR_MEMORYMAPPED)
+#else
#define INB(r) MMIO_INB(r)
#define INB_OFF(o) MMIO_INB_OFF(o)
@@ -632,23 +648,6 @@ static void ncr53c8xx_timeout(unsigned long np);
#define OUTL(r, val) MMIO_OUTL(r, val)
#define OUTL_OFF(o, val) MMIO_OUTL_OFF(o, val)
-/*
-** IO mapped or MEMORY mapped
-*/
-
-#else
-
-#define INB(r) (np->reg ? MMIO_INB(r) : IOM_INB(r))
-#define INB_OFF(o) (np->reg ? MMIO_INB_OFF(o) : IOM_INB_OFF(o))
-#define INW(r) (np->reg ? MMIO_INW(r) : IOM_INW(r))
-#define INL(r) (np->reg ? MMIO_INL(r) : IOM_INL(r))
-#define INL_OFF(o) (np->reg ? MMIO_INL_OFF(o) : IOM_INL_OFF(o))
-
-#define OUTB(r, val) (np->reg ? MMIO_OUTB(r, val) : IOM_OUTB(r, val))
-#define OUTW(r, val) (np->reg ? MMIO_OUTW(r, val) : IOM_OUTW(r, val))
-#define OUTL(r, val) (np->reg ? MMIO_OUTL(r, val) : IOM_OUTL(r, val))
-#define OUTL_OFF(o, val) (np->reg ? MMIO_OUTL_OFF(o, val) : IOM_OUTL_OFF(o, val))
-
#endif
/*
@@ -657,6 +656,10 @@ static void ncr53c8xx_timeout(unsigned long np);
#define OUTONB(r, m) OUTB(r, INB(r) | (m))
#define OUTOFFB(r, m) OUTB(r, INB(r) & ~(m))
+#define OUTONW(r, m) OUTW(r, INW(r) | (m))
+#define OUTOFFW(r, m) OUTW(r, INW(r) & ~(m))
+#define OUTONL(r, m) OUTL(r, INL(r) | (m))
+#define OUTOFFL(r, m) OUTL(r, INL(r) & ~(m))
/*==========================================================
**
@@ -700,7 +703,8 @@ static void ncr53c8xx_timeout(unsigned long np);
#define SIR_IGN_RESIDUE (11)
#define SIR_MISSING_SAVE (12)
#define SIR_DATA_IO_IS_OUT (13)
-#define SIR_MAX (13)
+#define SIR_DATA_IO_IS_IN (14)
+#define SIR_MAX (14)
/*==========================================================
**
@@ -798,6 +802,10 @@ struct usrcmd {
#define UC_SETFLAG 15
#define UC_CLEARPROF 16
+#ifdef SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
+#define UC_DEBUG_ERROR_RECOVERY 17
+#endif
+
#define UF_TRACE (0x01)
#define UF_NODISC (0x02)
@@ -813,7 +821,6 @@ struct tstamp {
u_long end;
u_long select;
u_long command;
- u_long data;
u_long status;
u_long disconnect;
u_long reselect;
@@ -1340,13 +1347,20 @@ struct ncb {
**-----------------------------------------------
*/
int unit; /* Unit number */
- int chip; /* Chip number */
+ char chip_name[8]; /* Chip name */
+ char inst_name[16]; /* Instance name */
+ u_int features; /* Chip features map */
struct timer_list timer; /* Timer link header */
int ncr_cache; /* Cache test variable */
Scsi_Cmnd *waiting_list; /* Waiting list header for commands */
/* that we can't put into the squeue */
u_long settle_time; /* Reset in progess */
u_char release_stage; /* Synchronisation stage on release */
+#ifdef SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
+ u_char debug_error_recovery;
+ u_char stalling;
+ u_char assert_atn;
+#endif
/*-----------------------------------------------
** Added field to support differences
@@ -1359,9 +1373,6 @@ struct ncb {
*/
u_short device_id;
u_char revision_id;
-#define ChipDevice ((np)->device_id)
-#define ChipVersion ((np)->revision_id & 0xf0)
-
u_char sv_scntl3;
u_char sv_dmode;
u_char sv_dcntl;
@@ -1370,6 +1381,7 @@ struct ncb {
u_char sv_ctest5;
u_char sv_gpcntl;
u_char sv_stest2;
+ u_char sv_stest4;
u_char rv_dmode;
u_char rv_dcntl;
@@ -1377,6 +1389,9 @@ struct ncb {
u_char rv_ctest4;
u_char rv_ctest5;
u_char rv_stest2;
+
+ u_char maxburst;
+ u_char scsi_mode;
u_char multiplier;
/*-----------------------------------------------
@@ -1616,8 +1631,8 @@ struct script {
ncrcmd resel_tmp [ 5];
ncrcmd resel_lun [ 18];
ncrcmd resel_tag [ 24];
- ncrcmd data_io [ 2]; /* MUST be just before data_in */
- ncrcmd data_in [MAX_SCATTER * 4 + 7];
+ ncrcmd data_io [ 6];
+ ncrcmd data_in [MAX_SCATTER * 4 + 4];
};
/*
@@ -1642,7 +1657,7 @@ struct scripth {
ncrcmd getcc2 [ 14];
#endif
ncrcmd getcc3 [ 10];
- ncrcmd data_out [MAX_SCATTER * 4 + 7];
+ ncrcmd data_out [MAX_SCATTER * 4 + 4];
ncrcmd aborttag [ 4];
ncrcmd abort [ 22];
ncrcmd snooptest [ 9];
@@ -1664,10 +1679,10 @@ static void ncr_exception (ncb_p np);
static void ncr_free_ccb (ncb_p np, ccb_p cp, u_long t, u_long l);
static void ncr_getclock (ncb_p np, int mult);
static void ncr_selectclock (ncb_p np, u_char scntl3);
-static void ncr_save_bios_setting (ncb_p np);
static ccb_p ncr_get_ccb (ncb_p np, u_long t,u_long l);
static void ncr_init (ncb_p np, char * msg, u_long code);
-static int ncr_intr (ncb_p np);
+static int ncr_int_sbmc (ncb_p np);
+static int ncr_int_par (ncb_p np);
static void ncr_int_ma (ncb_p np);
static void ncr_int_sir (ncb_p np);
static void ncr_int_sto (ncb_p np);
@@ -1675,7 +1690,7 @@ static u_long ncr_lookup (char* id);
static void ncr_negotiate (struct ncb* np, struct tcb* tp);
static void ncr_opennings (ncb_p np, lcb_p lp, Scsi_Cmnd * xp);
-#ifdef SCSI_NCR_PROFILE
+#ifdef SCSI_NCR_PROFILE_SUPPORT
static void ncb_profile (ncb_p np, ccb_p cp);
#endif
@@ -1694,12 +1709,12 @@ static void ncr_timeout (ncb_p np);
static void ncr_wakeup (ncb_p np, u_long code);
static void ncr_start_reset (ncb_p np, int settle_delay);
-#ifdef SCSI_NCR_USER_COMMAND
+#ifdef SCSI_NCR_USER_COMMAND_SUPPORT
static void ncr_usercmd (ncb_p np);
#endif
-static int ncr_attach (Scsi_Host_Template *tpnt, int unit, u_short device_id,
- u_char revision_id, int chip, u_int base, u_int io_port,
+static int ncr_attach (Scsi_Host_Template *tpnt, int unit,
+ ncr_chip *chip, u_int base, u_int io_port,
int irq, int bus, u_char device_fn);
static void insert_into_waiting_list(ncb_p np, Scsi_Cmnd *cmd);
@@ -1720,24 +1735,13 @@ static void process_waiting_list(ncb_p np, int sts);
**==========================================================
*/
-#ifdef SCSI_NCR_DEBUG
+#ifdef SCSI_NCR_DEBUG_INFO_SUPPORT
static int ncr_debug = SCSI_NCR_DEBUG_FLAGS;
#endif
-/*==========================================================
-**
-**
-** Global static data: auto configure
-**
-**
-**==========================================================
-*/
-
-static char *ncr_name (ncb_p np)
+static inline char *ncr_name (ncb_p np)
{
- static char name[16];
- sprintf(name, "ncr53c%d-%d", np->chip, np->unit);
- return (name);
+ return np->inst_name;
}
@@ -1783,10 +1787,10 @@ static char *ncr_name (ncb_p np)
* Kernel variables referenced in the scripts.
* THESE MUST ALL BE ALIGNED TO A 4-BYTE BOUNDARY.
*/
-static void *script_kvars[] =
+static void *script_kvars[] __initdata =
{ (void *)&jiffies };
-static struct script script0 = {
+static struct script script0 __initdata = {
/*--------------------------< START >-----------------------*/ {
/*
** Claim to be still alive ...
@@ -1881,7 +1885,7 @@ static struct script script0 = {
** patch the launch field.
** should look like an idle process.
*/
- SCR_COPY (4),
+ SCR_COPY_F (4),
RADDR (dsa),
PADDR (skip2),
SCR_COPY (8),
@@ -1987,7 +1991,7 @@ static struct script script0 = {
** We patch the address part of a
** COPY command with the DSA-register.
*/
- SCR_COPY (4),
+ SCR_COPY_F (4),
RADDR (dsa),
PADDR (loadpos),
/*
@@ -2376,7 +2380,7 @@ static struct script script0 = {
/*
** and copy back the header to the ccb.
*/
- SCR_COPY (4),
+ SCR_COPY_F (4),
RADDR (dsa),
PADDR (cleanup0),
SCR_COPY (sizeof (struct head)),
@@ -2482,7 +2486,7 @@ static struct script script0 = {
**
** CAUTION: only little endian architectures supported! XXX
*/
- SCR_COPY (1),
+ SCR_COPY_F (1),
NADDR (header.savep),
PADDR (disconnect0),
}/*-------------------------< DISCONNECT0 >--------------*/,{
@@ -2491,7 +2495,7 @@ static struct script script0 = {
/*
** neither this
*/
- SCR_COPY (1),
+ SCR_COPY_F (1),
NADDR (header.goalp),
PADDR (disconnect1),
}/*-------------------------< DISCONNECT1 >--------------*/,{
@@ -2587,7 +2591,7 @@ static struct script script0 = {
** This NOP will be patched with LED OFF
** SCR_REG_REG (gpreg, SCR_OR, 0x01)
*/
- SCR_JUMP ^ IFFALSE (0),
+ SCR_NO_OP,
0,
/*
** make the DSA invalid.
@@ -2609,7 +2613,7 @@ static struct script script0 = {
** This NOP will be patched with LED ON
** SCR_REG_REG (gpreg, SCR_AND, 0xfe)
*/
- SCR_JUMP ^ IFFALSE (0),
+ SCR_NO_OP,
0,
/*
** ... zu nichts zu gebrauchen ?
@@ -2635,7 +2639,7 @@ static struct script script0 = {
** This NOP will be patched with LED ON
** SCR_REG_REG (gpreg, SCR_AND, 0xfe)
*/
- SCR_JUMP ^ IFFALSE (0),
+ SCR_NO_OP,
0,
/*
** If it's not connected :(
@@ -2758,10 +2762,14 @@ static struct script script0 = {
** to low-level scsi drivers, we must trust the target
** for actual data direction when we cannot guess it.
** The programmed interrupt patches savep, lastp, goalp,
-** etc.., and restarts the scsi script at data_out.
+** etc.., and restarts the scsi script at data_out/in.
*/
SCR_INT ^ IFTRUE (WHEN (SCR_DATA_OUT)),
SIR_DATA_IO_IS_OUT,
+ SCR_INT ^ IFTRUE (WHEN (SCR_DATA_IN)),
+ SIR_DATA_IO_IS_IN,
+ SCR_JUMP,
+ PADDR (no_data),
}/*-------------------------< DATA_IN >--------------------*/,{
/*
@@ -2769,15 +2777,7 @@ static struct script script0 = {
** #define MAX_SCATTER parameter,
** it is filled in at runtime.
**
-** SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_IN)),
-** PADDR (no_data),
-** SCR_COPY (sizeof (u_long)),
-** KVAR(SCRIPT_KVAR_JIFFIES),
-** NADDR (header.stamp.data),
-** SCR_MOVE_TBL ^ SCR_DATA_IN,
-** offsetof (struct dsb, data[ 0]),
-**
-** ##===========< i=1; i<MAX_SCATTER >=========
+** ##===========< i=0; i<MAX_SCATTER >=========
** || SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_IN)),
** || PADDR (checkatn),
** || SCR_MOVE_TBL ^ SCR_DATA_IN,
@@ -2793,7 +2793,7 @@ static struct script script0 = {
}/*--------------------------------------------------------*/
};
-static struct scripth scripth0 = {
+static struct scripth scripth0 __initdata = {
/*-------------------------< TRYLOOP >---------------------*/{
/*
** Load an entry of the start queue into dsa
@@ -3109,7 +3109,7 @@ static struct scripth scripth0 = {
** We patch the address part of a COPY command
** with the address of the dsa register ...
*/
- SCR_COPY (4),
+ SCR_COPY_F (4),
RADDR (dsa),
PADDRH (getcc1),
/*
@@ -3247,15 +3247,7 @@ static struct scripth scripth0 = {
** #define MAX_SCATTER parameter,
** it is filled in at runtime.
**
-** SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_OUT)),
-** PADDR (no_data),
-** SCR_COPY (sizeof (u_long)),
-** KVAR(SCRIPT_KVAR_JIFFIES),
-** NADDR (header.stamp.data),
-** SCR_MOVE_TBL ^ SCR_DATA_OUT,
-** offsetof (struct dsb, data[ 0]),
-**
-** ##===========< i=1; i<MAX_SCATTER >=========
+** ##===========< i=0; i<MAX_SCATTER >=========
** || SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_OUT)),
** || PADDR (dispatch),
** || SCR_MOVE_TBL ^ SCR_DATA_OUT,
@@ -3269,7 +3261,7 @@ static struct scripth scripth0 = {
**
**---------------------------------------------------------
*/
-0 /* was (u_long)&ident ? */
+0
}/*-------------------------< ABORTTAG >-------------------*/,{
/*
** Abort a bad reselection.
@@ -3343,7 +3335,9 @@ static struct scripth scripth0 = {
**==========================================================
*/
+__initfunc(
void ncr_script_fill (struct script * scr, struct scripth * scrh)
+)
{
int i;
ncrcmd *p;
@@ -3363,15 +3357,7 @@ void ncr_script_fill (struct script * scr, struct scripth * scrh)
p = scr->data_in;
- *p++ =SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_IN));
- *p++ =PADDR (no_data);
- *p++ =SCR_COPY (sizeof (u_long));
- *p++ =KVAR(SCRIPT_KVAR_JIFFIES);
- *p++ =NADDR (header.stamp.data);
- *p++ =SCR_MOVE_TBL ^ SCR_DATA_IN;
- *p++ =offsetof (struct dsb, data[ 0]);
-
- for (i=1; i<MAX_SCATTER; i++) {
+ for (i=0; i<MAX_SCATTER; i++) {
*p++ =SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_IN));
*p++ =PADDR (checkatn);
*p++ =SCR_MOVE_TBL ^ SCR_DATA_IN;
@@ -3387,15 +3373,7 @@ void ncr_script_fill (struct script * scr, struct scripth * scrh)
p = scrh->data_out;
- *p++ =SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_OUT));
- *p++ =PADDR (no_data);
- *p++ =SCR_COPY (sizeof (u_long));
- *p++ =KVAR(SCRIPT_KVAR_JIFFIES);
- *p++ =NADDR (header.stamp.data);
- *p++ =SCR_MOVE_TBL ^ SCR_DATA_OUT;
- *p++ =offsetof (struct dsb, data[ 0]);
-
- for (i=1; i<MAX_SCATTER; i++) {
+ for (i=0; i<MAX_SCATTER; i++) {
*p++ =SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_OUT));
*p++ =PADDR (dispatch);
*p++ =SCR_MOVE_TBL ^ SCR_DATA_OUT;
@@ -3419,11 +3397,14 @@ void ncr_script_fill (struct script * scr, struct scripth * scrh)
**==========================================================
*/
+__initfunc(
static void ncr_script_copy_and_bind (ncb_p np, ncrcmd *src, ncrcmd *dst, int len)
+)
{
ncrcmd opcode, new, old, tmp1, tmp2;
ncrcmd *start, *end;
int relocs;
+ int opchanged = 0;
start = src;
end = src + len/4;
@@ -3470,6 +3451,14 @@ static void ncr_script_copy_and_bind (ncb_p np, ncrcmd *src, ncrcmd *dst, int le
ncr_name(np), (int) (src-start-1));
DELAY (1000000);
}
+ /*
+ ** If PREFETCH feature not enabled, remove
+ ** the NO FLUSH bit if present.
+ */
+ if ((opcode & SCR_NO_FLUSH) && !(np->features & _F_PFEN)) {
+ dst[-1] = (opcode & ~SCR_NO_FLUSH);
+ ++opchanged;
+ }
break;
case 0x0:
@@ -3546,6 +3535,9 @@ static void ncr_script_copy_and_bind (ncb_p np, ncrcmd *src, ncrcmd *dst, int le
*dst++ = *src++;
};
+ if (bootverbose > 1 && opchanged)
+ printf("%s: NO FLUSH bit removed from %d script instructions\n",
+ ncr_name(np), opchanged);
}
/*==========================================================
@@ -3595,6 +3587,218 @@ static void PRINT_ADDR(Scsi_Cmnd *cmd)
if (np) PRINT_LUN(np, cmd->target, cmd->lun);
}
+/*===============================================================
+**
+** Prepare io register values used by ncr_init() according
+** to selected and supported features.
+**
+** NCR chips allow burst lengths of 2, 4, 8, 16, 32, 64, 128
+** transfers. 32,64,128 are only supported by 875 and 895 chips.
+** We use log base 2 (burst length) as internal code, with
+** value 0 meaning "burst disabled".
+**
+**===============================================================
+*/
+
+/*
+ * Burst length from burst code.
+ */
+#define burst_length(bc) (!(bc))? 0 : 1 << (bc)
+
+/*
+ * Burst code from io register bits.
+ */
+#define burst_code(dmode, ctest4, ctest5) \
+ (ctest4) & 0x80? 0 : (((dmode) & 0xc0) >> 6) + ((ctest5) & 0x04) + 1
+
+/*
+ * Set initial io register bits from burst code.
+ */
+static inline void ncr_init_burst(ncb_p np, u_char bc)
+{
+ np->rv_ctest4 &= ~0x80;
+ np->rv_dmode &= ~(0x3 << 6);
+ np->rv_ctest5 &= ~0x4;
+
+ if (!bc) {
+ np->rv_ctest4 |= 0x80;
+ }
+ else {
+ --bc;
+ np->rv_dmode |= ((bc & 0x3) << 6);
+ np->rv_ctest5 |= (bc & 0x4);
+ }
+}
+
+__initfunc(
+static int ncr_prepare_setting(ncb_p np)
+)
+{
+ u_char burst_max;
+
+ /*
+ ** Save assumed BIOS setting
+ */
+
+ np->sv_scntl3 = INB(nc_scntl3) & 0x07;
+ np->sv_dmode = INB(nc_dmode) & 0xce;
+ np->sv_dcntl = INB(nc_dcntl) & 0xa8;
+ np->sv_ctest3 = INB(nc_ctest3) & 0x01;
+ np->sv_ctest4 = INB(nc_ctest4) & 0x80;
+ np->sv_ctest5 = INB(nc_ctest5) & 0x24;
+ np->sv_gpcntl = INB(nc_gpcntl);
+ np->sv_stest2 = INB(nc_stest2) & 0x20;
+ np->sv_stest4 = INB(nc_stest4);
+
+ /*
+ ** Get the frequency of the chip's clock.
+ ** Find the right value for scntl3.
+ */
+
+ if (np->features & _F_QUAD)
+ np->multiplier = 4;
+ else if (np->features & _F_DBLR)
+ np->multiplier = 2;
+ else
+ np->multiplier = 1;
+
+ np->clock_khz = (np->features & _F_CLK80)? 80000 : 40000;
+ np->clock_khz *= np->multiplier;
+
+ if (np->clock_khz != 40000)
+ ncr_getclock(np, np->multiplier);
+
+ if (np->clock_khz <= 25000) np->rv_scntl3 = 0x01;
+ else if (np->clock_khz <= 37500) np->rv_scntl3 = 0x02;
+ else if (np->clock_khz <= 50000) np->rv_scntl3 = 0x03;
+ else if (np->clock_khz <= 75000) np->rv_scntl3 = 0x04;
+ else if (np->clock_khz <= 100000) np->rv_scntl3 = 0x05;
+ else if (np->clock_khz <= 150000) np->rv_scntl3 = 0x06;
+ else np->rv_scntl3 = 0x07;
+
+ /*
+ ** Get on-board RAM bus address when supported
+ */
+ if (np->features & _F_RAM) {
+ OUTONB(nc_ctest2, 0x8);
+ np->paddr2 = INL(nc_scr0);
+ OUTOFFB(nc_ctest2, 0x8);
+ }
+
+ /*
+ ** Prepare initial value of other IO registers
+ */
+#if defined SCSI_NCR_TRUST_BIOS_SETTING
+ np->rv_dmode = np->sv_dmode;
+ np->rv_dcntl = np->sv_dcntl;
+ np->rv_ctest3 = np->sv_ctest3;
+ np->rv_ctest4 = np->sv_ctest4;
+ np->rv_ctest5 = np->sv_ctest5;
+ burst_max = burst_code(np->sv_dmode, np->sv_ctest4, np->sv_ctest5);
+#else
+ np->rv_dmode = 0;
+ np->rv_dcntl = 0;
+ np->rv_ctest3 = 0;
+ np->rv_ctest4 = 0;
+ np->rv_ctest5 = 0;
+ np->rv_stest2 = 0;
+
+ /*
+ ** Select burst length (dwords)
+ */
+ burst_max = driver_setup.burst_max;
+ if (burst_max == 255)
+ burst_max = burst_code(np->sv_dmode, np->sv_ctest4, np->sv_ctest5);
+ if (burst_max > 7)
+ burst_max = 7;
+ if (burst_max > np->maxburst)
+ burst_max = np->maxburst;
+
+ /*
+ ** Select all supported special features
+ */
+ if (np->features & _F_ERL)
+ np->rv_dmode |= ERL; /* Enable Read Line */
+ if (np->features & _F_BOF)
+ np->rv_dmode |= BOF; /* Burst Opcode Fetch */
+ if (np->features & _F_ERMP)
+ np->rv_dmode |= ERMP; /* Enable Read Multiple */
+ if (np->features & _F_PFEN)
+ np->rv_dcntl |= PFEN; /* Prefetch Enable */
+ if (np->features & _F_CLSE)
+ np->rv_dcntl |= CLSE; /* Cache Line Size Enable */
+ if (np->features & _F_WRIE)
+ np->rv_ctest3 |= WRIE; /* Write and Invalidate */
+ if (np->features & _F_DFS)
+ np->rv_ctest5 |= DFS; /* Dma Fifo Size */
+
+ /*
+ ** Select some other
+ */
+ if (driver_setup.master_parity)
+ np->rv_ctest4 |= MPEE; /* Master parity checking */
+
+#endif /* SCSI_NCR_TRUST_BIOS_SETTING */
+
+ /*
+ * Prepare initial io register bits for burst length
+ */
+ ncr_init_burst(np, burst_max);
+
+ /*
+ ** Set differential mode.
+ */
+ switch(driver_setup.diff_support) {
+ case 3:
+ if (INB(nc_gpreg) & 0x08)
+ break;
+ case 2:
+ np->rv_stest2 |= 0x20;
+ break;
+ case 1:
+ np->rv_stest2 |= (np->sv_stest2 & 0x20);
+ break;
+ default:
+ break;
+ }
+
+ /*
+ ** Set irq mode.
+ */
+ switch(driver_setup.irqm) {
+ case 2:
+ np->rv_dcntl |= IRQM;
+ break;
+ case 1:
+ np->rv_stest2 |= (np->sv_dcntl & IRQM);
+ break;
+ default:
+ break;
+ }
+
+ /*
+ ** Announce all that stuff to user.
+ */
+ if (bootverbose > 1) {
+ printf ("%s: initial value of SCNTL3 = %02x, final = %02x\n",
+ ncr_name(np), np->sv_scntl3, np->rv_scntl3);
+ printf ("%s: initial value of dmode/dcntl/ctest3/4/5 = (hex) %02x/%02x/%02x/%02x/%02x\n",
+ ncr_name(np), np->sv_dmode, np->sv_dcntl, np->sv_ctest3, np->sv_ctest4, np->sv_ctest5);
+ printf ("%s: final value of dmode/dcntl/ctest3/4/5 = (hex) %02x/%02x/%02x/%02x/%02x\n",
+ ncr_name(np), np->rv_dmode, np->rv_dcntl, np->rv_ctest3, np->rv_ctest4, np->rv_ctest5);
+ if (np->rv_stest2 & 0x20)
+ printf ("%s: DIFF mode set\n", ncr_name(np));
+ }
+
+ if (bootverbose && np->paddr2)
+ printf ("%s: on-board RAM at 0x%lx\n", ncr_name(np), np->paddr2);
+
+ if (bootverbose && np->ns_sync < 25)
+ printf ("%s: Ultra%s SCSI support enabled\n", ncr_name(np),
+ np->ns_sync < 12 ? "-2": "");
+
+ return 0;
+}
/*
** Host attach and initialisations.
@@ -3602,25 +3806,23 @@ static void PRINT_ADDR(Scsi_Cmnd *cmd)
** Allocate host data and ncb structure.
** Request IO region and remap MMIO region.
** Do chip initialization.
-** Try with mmio.
-** If mmio not possible (misconfigured cache),
-** retry with io mapped.
** If all is OK, install interrupt handling and
** start the timer daemon.
*/
-static int ncr_attach (Scsi_Host_Template *tpnt, int unit, ushort device_id,
- u_char revision_id, int chip, u_int base, u_int io_port,
+__initfunc(
+static int ncr_attach (Scsi_Host_Template *tpnt, int unit,
+ ncr_chip *chip, u_int base, u_int io_port,
int irq, int bus, u_char device_fn)
-
+)
{
struct host_data *host_data;
ncb_p np;
struct Scsi_Host *instance = 0;
u_long flags = 0;
-printf("ncr53c8xx: unit=%d chip=%d rev=0x%x base=0x%x, io_port=0x%x, irq=%d\n",
- unit, chip, revision_id, base, io_port, irq);
+printf("ncr53c8xx: unit=%d chip=%s rev=0x%x base=0x%x, io_port=0x%x, irq=%d\n",
+ unit, chip->name, chip->revision_id, base, io_port, irq);
/*
** Allocate host_data structure
@@ -3645,10 +3847,21 @@ printf("ncr53c8xx: unit=%d chip=%d rev=0x%x base=0x%x, io_port=0x%x, irq=%d\n",
np->ccb = (ccb_p) (((u_long) &host_data->_ccb_data) & CCB_ALIGN_MASK);
bzero (np->ccb, sizeof (*np->ccb));
- np->unit = unit;
- np->chip = chip;
- np->device_id = device_id;
- np->revision_id = revision_id;
+ /*
+ ** Store input informations in the host data structure.
+ */
+ strncpy(np->chip_name, chip->name, sizeof(np->chip_name) - 1);
+ np->unit = unit;
+ sprintf(np->inst_name, "ncr53c%s-%d", np->chip_name, np->unit);
+ np->device_id = chip->device_id;
+ np->revision_id = chip->revision_id;
+ np->features = chip->features;
+ np->maxwide = (np->features & _F_WIDE)? 1 : 0;
+ np->ns_sync = 25;
+ np->clock_khz = 40000;
+ np->clock_divn = chip->nr_divisor;
+ np->maxoffs = chip->offset_max;
+ np->maxburst = chip->burst_max;
np->script0 =
(struct script *) (((u_long) &host_data->script_data) & SCR_ALIGN_MASK);
@@ -3673,9 +3886,7 @@ printf("ncr53c8xx: unit=%d chip=%d rev=0x%x base=0x%x, io_port=0x%x, irq=%d\n",
np->vaddr = remap_pci_mem((u_long) base, (u_long) 128);
if (!np->vaddr) {
printf("%s: can't map memory mapped IO region\n", ncr_name(np));
-#ifdef NCR_MEMORYMAPPED
goto attach_error;
-#endif
}
else
if (bootverbose > 1)
@@ -3699,97 +3910,16 @@ printf("ncr53c8xx: unit=%d chip=%d rev=0x%x base=0x%x, io_port=0x%x, irq=%d\n",
np->port = io_port;
/*
- ** Save initial value of some io registers.
- */
-
- ncr_save_bios_setting(np);
-
- /*
** Do chip dependent initialization.
*/
-
- np->maxwide = 0;
- np->rv_scntl3 = 0x13; /* default: 40MHz clock */
- np->ns_sync = 25;
- np->clock_khz = 40000;
- np->clock_divn = 4;
- np->maxoffs = 8;
- np->multiplier = 1;
-
- /*
- ** Get the frequency of the chip's clock.
- ** Find the right value for scntl3.
- */
-
- switch (device_id) {
- case PCI_DEVICE_ID_NCR_53C825:
- np->maxwide = 1;
- break;
- case PCI_DEVICE_ID_NCR_53C860:
- if (driver_setup.ultra_scsi) {
- np->rv_scntl3 = 0x15;
- np->clock_khz = 80000;
- np->ns_sync = 12;
- }
- else
- np->rv_scntl3 = 0x35; /* always assume 80MHz clock for 860 */
- np->clock_divn = 5;
- break;
- case PCI_DEVICE_ID_NCR_53C875:
- case PCI_DEVICE_ID_NCR_53C885:
- np->maxwide = 1;
- if (driver_setup.special_features)
- np->maxoffs = 16;
- np->clock_divn = 5;
- if (device_id == PCI_DEVICE_ID_NCR_53C875)
- ncr_getclock(np, revision_id >= 2 ? 2 : 1);
- else
- ncr_getclock(np, 2);
- break;
- case PCI_DEVICE_ID_NCR_53C895:
- case PCI_DEVICE_ID_NCR_53C896:
- np->maxwide = 1;
- if (driver_setup.special_features)
- np->maxoffs = 31;
- np->clock_divn = 7;
- ncr_getclock(np, 4);
- break;
- }
-
- /*
- ** Get on-board RAM bus address when supported
- */
- switch (device_id) {
- case PCI_DEVICE_ID_NCR_53C825:
- if (revision_id < 0x10)
- break;
- case PCI_DEVICE_ID_NCR_53C875:
- case PCI_DEVICE_ID_NCR_53C885:
- case PCI_DEVICE_ID_NCR_53C895:
- case PCI_DEVICE_ID_NCR_53C896:
- if (driver_setup.special_features) {
- OUTONB(nc_ctest2, 0x8);
- np->paddr2 = INL(nc_scr0);
- OUTOFFB(nc_ctest2, 0x8);
- }
- break;
- }
-
- if (bootverbose && np->paddr2)
- printf ("%s: on-board RAM at 0x%lx\n", ncr_name(np), np->paddr2);
-
- if (bootverbose && np->ns_sync < 25)
- printf ("%s: Ultra%s SCSI support enabled\n", ncr_name(np),
- np->ns_sync < 12 ? "-2": "");
+ (void)ncr_prepare_setting(np);
#ifndef NCR_IOMAPPED
if (np->paddr2 && sizeof(struct script) <= 4096) {
np->vaddr2 = remap_pci_mem((u_long) np->paddr2, (u_long) 4096);
if (!np->vaddr2) {
printf("%s: can't map memory mapped IO region\n", ncr_name(np));
-#ifdef NCR_MEMORYMAPPED
goto attach_error;
-#endif
}
else
if (bootverbose > 1)
@@ -3831,16 +3961,23 @@ printf("ncr53c8xx: unit=%d chip=%d rev=0x%x base=0x%x, io_port=0x%x, irq=%d\n",
np->ccb->p_ccb = vtophys (np->ccb);
/*
+ ** Patch the script for LED support.
+ */
+
+ if (driver_setup.led_pin & (~np->sv_gpcntl) & 0x01) {
+ np->features |= _F_LED0;
+ np->script0->reselect[0] = SCR_REG_REG(gpreg, SCR_OR, 0x01);
+ np->script0->reselect1[0] = SCR_REG_REG(gpreg, SCR_AND, 0xfe);
+ np->script0->reselect2[0] = SCR_REG_REG(gpreg, SCR_AND, 0xfe);
+ }
+
+ /*
** init data structure
*/
np->jump_tcb.l_cmd = SCR_JUMP;
np->jump_tcb.l_paddr = NCB_SCRIPTH_PHYS (np, abort);
-#if !defined(NCR_IOMAPPED) && !defined(NCR_MEMORYMAPPED)
-retry_chip_init:
-#endif
-
/*
** Get SCSI addr of host adapter (set by bios?).
*/
@@ -3864,14 +4001,6 @@ retry_chip_init:
*/
if (ncr_snooptest (np)) {
-#if !defined(NCR_IOMAPPED) && !defined(NCR_MEMORYMAPPED)
- if (np->reg) {
-printf("%s: cache misconfigured, retrying with IO mapped at 0x%lx\n",
- ncr_name(np), (u_long) np->port);
- np->reg = 0;
- goto retry_chip_init;
- }
-#endif
printf ("CACHE INCORRECTLY CONFIGURED.\n");
goto attach_error;
};
@@ -3962,18 +4091,25 @@ printf("%s: cache misconfigured, retrying with IO mapped at 0x%lx\n",
attach_error:
if (!instance) return -1;
+ printf("%s: detaching...\n", ncr_name(np));
#ifndef NCR_IOMAPPED
if (np->vaddr) {
+#ifdef DEBUG_NCR53C8XX
printf("%s: releasing memory mapped IO region %lx[%d]\n", ncr_name(np), (u_long) np->vaddr, 128);
+#endif
unmap_pci_mem((vm_offset_t) np->vaddr, (u_long) 128);
}
if (np->vaddr2) {
+#ifdef DEBUG_NCR53C8XX
printf("%s: releasing memory mapped IO region %lx[%d]\n", ncr_name(np), (u_long) np->vaddr2, 4096);
+#endif
unmap_pci_mem((vm_offset_t) np->vaddr2, (u_long) 4096);
}
#endif
if (np->port) {
+#ifdef DEBUG_NCR53C8XX
printf("%s: releasing IO region %x[%d]\n", ncr_name(np), np->port, 128);
+#endif
release_region(np->port, 128);
}
scsi_unregister(instance);
@@ -3984,47 +4120,6 @@ attach_error:
/*==========================================================
**
**
-** Process pending device interrupts.
-**
-**
-**==========================================================
-*/
-int ncr_intr(np)
- ncb_p np;
-{
- int n = 0;
- u_long flags;
-
- save_flags(flags); cli();
-
- if (DEBUG_FLAGS & DEBUG_TINY) printf ("[");
-
-#ifdef SCSI_NCR_PARANOIA
- if (INB(nc_istat) & (INTF|SIP|DIP)) {
- /*
- ** Repeat until no outstanding ints
- */
- do {
-#endif
- ncr_exception (np);
-#ifdef SCSI_NCR_PARANOIA
- } while (INB(nc_istat) & (INTF|SIP|DIP));
-
- n=1;
- np->ticks = 5 * HZ;
- };
-#endif
-
- if (DEBUG_FLAGS & DEBUG_TINY) printf ("]\n");
-
- restore_flags(flags);
-
- return (n);
-}
-
-/*==========================================================
-**
-**
** Start execution of a SCSI command.
** This is called from the generic SCSI driver.
**
@@ -4107,7 +4202,7 @@ int ncr_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *))
**
**----------------------------------------------------
*/
-#ifdef SCSI_NCR_PROFILE
+#ifdef SCSI_NCR_PROFILE_SUPPORT
bzero (&cp->phys.header.stamp, sizeof (struct tstamp));
cp->phys.header.stamp.start = jiffies;
#endif
@@ -4337,25 +4432,30 @@ int ncr_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *))
*/
cp->segments = segments;
+ if (!cp->data_len)
+ xfer_direction = XferNone;
switch (xfer_direction) {
+ u_long endp;
default:
case XferBoth:
- cp->phys.header.savep = NCB_SCRIPT_PHYS (np, data_io);
- cp->phys.header.goalp = cp->phys.header.savep +8 +20 +segments*16;
- break;
+ cp->phys.header.savep = NCB_SCRIPT_PHYS (np, data_io);
+ cp->phys.header.goalp = cp->phys.header.savep;
+ break;
case XferIn:
- cp->phys.header.savep = NCB_SCRIPT_PHYS (np, data_in);
- cp->phys.header.goalp = cp->phys.header.savep +20 +segments*16;
- break;
+ endp = NCB_SCRIPT_PHYS (np, data_in) + MAX_SCATTER*16;
+ cp->phys.header.goalp = endp + 8;
+ cp->phys.header.savep = endp - segments*16;
+ break;
case XferOut:
- cp->phys.header.savep = NCB_SCRIPTH_PHYS (np, data_out);
- cp->phys.header.goalp = cp->phys.header.savep +20 +segments*16;
- break;
+ endp = NCB_SCRIPTH_PHYS (np, data_out) + MAX_SCATTER*16;
+ cp->phys.header.goalp = endp + 8;
+ cp->phys.header.savep = endp - segments*16;
+ break;
case XferNone:
- cp->phys.header.savep = NCB_SCRIPT_PHYS (np, no_data);
- cp->phys.header.goalp = cp->phys.header.savep;
- break;
+ cp->phys.header.savep = NCB_SCRIPT_PHYS (np, no_data);
+ cp->phys.header.goalp = cp->phys.header.savep;
+ break;
}
cp->phys.header.lastp = cp->phys.header.savep;
@@ -4463,6 +4563,9 @@ int ncr_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *))
** Script processor may be waiting for reselect.
** Wake it up.
*/
+#ifdef SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
+ if (!np->stalling)
+#endif
OUTB (nc_istat, SIGP);
/*
@@ -4530,6 +4633,11 @@ int ncr_reset_bus (Scsi_Cmnd *cmd, int sync_reset)
u_long flags;
int found;
+#ifdef SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
+ if (np->stalling)
+ np->stalling = 0;
+#endif
+
save_flags(flags); cli();
/*
* Return immediately if reset is in progress.
@@ -4607,6 +4715,11 @@ static int ncr_abort_command (Scsi_Cmnd *cmd)
int found;
int retv;
+#ifdef SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
+ if (np->stalling == 2)
+ np->stalling = 0;
+#endif
+
save_flags(flags); cli();
/*
* First, look for the scsi command in the waiting list
@@ -4663,6 +4776,9 @@ static int ncr_abort_command (Scsi_Cmnd *cmd)
** processor will sleep on SEL_WAIT_RESEL.
** Let's wake it up, since it may have to work.
*/
+#ifdef SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
+ if (!np->stalling)
+#endif
OUTB (nc_istat, SIGP);
restore_flags(flags);
@@ -4697,7 +4813,7 @@ static int ncr_detach(ncb_p np, int irq)
** Set release_stage to 1 and wait that ncr_timeout() set it to 2.
*/
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
printf("%s: stopping the timer\n", ncr_name(np));
#endif
np->release_stage = 1;
@@ -4710,7 +4826,7 @@ static int ncr_detach(ncb_p np, int irq)
** Disable chip interrupts
*/
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
printf("%s: disabling chip interrupts\n", ncr_name(np));
#endif
OUTW (nc_sien , 0);
@@ -4720,7 +4836,7 @@ static int ncr_detach(ncb_p np, int irq)
** Free irq
*/
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
printf("%s: freeing irq %d\n", ncr_name(np), irq);
#endif
#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,70)
@@ -4758,17 +4874,17 @@ static int ncr_detach(ncb_p np, int irq)
*/
#ifndef NCR_IOMAPPED
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
printf("%s: releasing memory mapped IO region %lx[%d]\n", ncr_name(np), (u_long) np->vaddr, 128);
#endif
unmap_pci_mem((vm_offset_t) np->vaddr, (u_long) 128);
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
printf("%s: releasing memory mapped IO region %lx[%d]\n", ncr_name(np), (u_long) np->vaddr2, 4096);
#endif
unmap_pci_mem((vm_offset_t) np->vaddr2, (u_long) 4096);
#endif
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
printf("%s: releasing IO region %x[%d]\n", ncr_name(np), np->port, 128);
#endif
release_region(np->port, 128);
@@ -4783,7 +4899,7 @@ static int ncr_detach(ncb_p np, int irq)
printf("%s: shall free an active ccb (host_status=%d)\n",
ncr_name(np), cp->host_status);
}
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
printf("%s: freeing ccb (%lx)\n", ncr_name(np), (u_long) cp);
#endif
m_free(cp, sizeof(*cp));
@@ -4798,7 +4914,7 @@ static int ncr_detach(ncb_p np, int irq)
for (lun = 0 ; lun < MAX_LUN ; lun++) {
lp = tp->lp[lun];
if (lp) {
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
printf("%s: freeing lp (%lx)\n", ncr_name(np), (u_long) lp);
#endif
m_free(lp, sizeof(*lp));
@@ -4851,7 +4967,7 @@ void ncr_complete (ncb_p np, ccb_p cp)
** timestamp
** Optional, spare some CPU time
*/
-#ifdef SCSI_NCR_PROFILE
+#ifdef SCSI_NCR_PROFILE_SUPPORT
ncb_profile (np, cp);
#endif
@@ -5158,46 +5274,6 @@ void ncr_wakeup (ncb_p np, u_long code)
};
}
-/*===============================================================
-**
-** NCR chips allow burst lengths of 2, 4, 8, 16, 32, 64, 128
-** transfers. 32,64,128 are only supported by 875 and 895 chips.
-** We use log base 2 (burst length) as internal code, with
-** value 0 meaning "burst disabled".
-**
-**===============================================================
-*/
-
-/*
- * Burst length from burst code.
- */
-#define burst_length(bc) (!(bc))? 0 : 1 << (bc)
-
-/*
- * Burst code from io register bits.
- */
-#define burst_code(dmode, ctest4, ctest5) \
- (ctest4) & 0x80? 0 : (((dmode) & 0xc0) >> 6) + ((ctest5) & 0x04) + 1
-
-/*
- * Set initial io register bits from burst code.
- */
-static void ncr_init_burst(ncb_p np, u_char bc)
-{
- np->rv_ctest4 &= ~0x80;
- np->rv_dmode &= ~(0x3 << 6);
- np->rv_ctest5 &= ~0x4;
-
- if (!bc) {
- np->rv_ctest4 |= 0x80;
- }
- else {
- --bc;
- np->rv_dmode |= ((bc & 0x3) << 6);
- np->rv_ctest5 |= (bc & 0x4);
- }
-}
-
/*==========================================================
**
**
@@ -5212,7 +5288,6 @@ void ncr_init (ncb_p np, char * msg, u_long code)
int i;
u_long usrsync;
u_char usrwide;
- u_char burst_max;
/*
** Reset chip.
@@ -5236,7 +5311,6 @@ void ncr_init (ncb_p np, char * msg, u_long code)
/*
** Start at first entry.
*/
-
np->squeueput = 0;
np->script0->startpos[0] = NCB_SCRIPTH_PHYS (np, tryloop);
np->script0->start0 [0] = SCR_INT ^ IFFALSE (0);
@@ -5249,161 +5323,30 @@ void ncr_init (ncb_p np, char * msg, u_long code)
/*
** Init chip.
*/
-#if defined SCSI_NCR_TRUST_BIOS_SETTING
- np->rv_dmode = np->sv_dmode;
- np->rv_dcntl = np->sv_dcntl;
- np->rv_ctest3 = np->sv_ctest3;
- np->rv_ctest4 = np->sv_ctest4;
- np->rv_ctest5 = np->sv_ctest5;
- burst_max = burst_code(np->sv_dmode, np->sv_ctest4, np->sv_ctest5);
-#else
- np->rv_dmode = 0;
- np->rv_dcntl = 0;
- np->rv_ctest3 = 0;
- np->rv_ctest4 = 0;
- burst_max = driver_setup.burst_max;
- if (burst_max == 255)
- burst_max = burst_code(np->sv_dmode, np->sv_ctest4, np->sv_ctest5);
- if (burst_max > 7)
- burst_max = 7;
-
-/** NCR53C810 **/
- if (ChipDevice == PCI_DEVICE_ID_NCR_53C810 && ChipVersion == 0) {
- burst_max = burst_max < 4 ? burst_max : 4;
- if (driver_setup.special_features)
- np->rv_dmode = ERL; /* read line */
- }
- else
-/** NCR53C815 **/
- if (ChipDevice == PCI_DEVICE_ID_NCR_53C815) {
- burst_max = burst_max < 4 ? burst_max : 4;
- if (driver_setup.special_features)
- np->rv_dmode = BOF | ERL; /* burst opcode fetch, read line */
- }
- else
-/** NCR53C825 **/
- if (ChipDevice == PCI_DEVICE_ID_NCR_53C825 && ChipVersion == 0) {
- burst_max = burst_max < 4 ? burst_max : 4;
- if (driver_setup.special_features)
- np->rv_dmode = BOF | ERL; /* burst opcode fetch, read line */
- }
- else
-/** NCR53C810A or NCR53C860 **/
- if ((ChipDevice == PCI_DEVICE_ID_NCR_53C810 && ChipVersion >= 0x10) ||
- ChipDevice == PCI_DEVICE_ID_NCR_53C860) {
- burst_max = burst_max < 4 ? burst_max : 4;
- if (driver_setup.special_features) {
- np->rv_dmode = BOF | ERMP | ERL;
- /* burst op-code fetch, read multiple */
- /* read line */
- np->rv_dcntl = PFEN | CLSE;
- /* prefetch, cache line size */
- np->rv_ctest3 = WRIE; /* write and invalidate */
- }
- }
- else
-/** NCR53C825A or NCR53C875 or NCR53C885 or NCR53C895 or NCR53C896 **/
- if ((ChipDevice == PCI_DEVICE_ID_NCR_53C825 && ChipVersion >= 0x10) ||
- ChipDevice == PCI_DEVICE_ID_NCR_53C875 ||
- ChipDevice == PCI_DEVICE_ID_NCR_53C885 ||
- ChipDevice == PCI_DEVICE_ID_NCR_53C895 ||
- ChipDevice == PCI_DEVICE_ID_NCR_53C896) {
- if (!driver_setup.special_features)
- burst_max = burst_max < 4 ? burst_max : 4;
- else {
- burst_max = burst_max < 7 ? burst_max : 7;
- np->rv_dmode = BOF | ERMP | ERL;
- /* burst op-code fetch, read multiple */
- /* read line, burst 128 (ctest5&4) */
- np->rv_dcntl = PFEN | CLSE;
- /* prefetch, cache line size */
- np->rv_ctest3 = WRIE; /* write and invalidate */
- np->rv_ctest5 = DFS; /* large dma fifo (0x20) */
- }
- }
-/** OTHERS **/
- else {
- burst_max = burst_max < 4 ? burst_max : 4;
- }
-#endif /* SCSI_NCR_TRUST_BIOS_SETTING */
- /*
- * Prepare initial io register bits for burst length
- */
- ncr_init_burst(np, burst_max);
-
- /*
- ** Set differential mode.
- */
- switch(driver_setup.diff_support) {
- case 3:
- if (INB(nc_gpreg) & 0x08)
- break;
- case 2:
- np->rv_stest2 |= 0x20;
- break;
- case 1:
- np->rv_stest2 |= (np->sv_stest2 & 0x20);
- break;
- default:
- break;
- }
-
- /*
- ** Set irq mode.
- */
- switch(driver_setup.irqm) {
- case 2:
- np->rv_dcntl |= IRQM;
- break;
- case 1:
- np->rv_stest2 |= (np->sv_dcntl & IRQM);
- break;
- default:
- break;
- }
-
- if (bootverbose > 1) {
- printf ("%s: initial value of dmode/dcntl/ctest3/4/5 = (hex) %02x/%02x/%02x/%02x/%02x\n",
- ncr_name(np), np->sv_dmode, np->sv_dcntl, np->sv_ctest3, np->sv_ctest4, np->sv_ctest5);
- }
- if (bootverbose > 1) {
- printf ("%s: final value of dmode/dcntl/ctest3/4/5 = (hex) %02x/%02x/%02x/%02x/%02x\n",
- ncr_name(np), np->rv_dmode, np->rv_dcntl, np->rv_ctest3, np->rv_ctest4, np->rv_ctest5);
- if (np->rv_stest2 & 0x20)
- printf ("%s: setting up differential mode\n", ncr_name(np));
- }
-
- OUTB (nc_istat, 0x00 ); /* Remove Reset, abort ... */
+ OUTB (nc_istat, 0x00 ); /* Remove Reset, abort */
if (driver_setup.scsi_parity)
- OUTB (nc_scntl0, 0xca ); /* full arb., ena parity, par->ATN */
+ OUTB (nc_scntl0, 0xca); /* full arb., ena parity, par->ATN */
else
- OUTB (nc_scntl0, 0xc0 ); /* full arb., (no parity) */
+ OUTB (nc_scntl0, 0xc0); /* full arb., (no parity) */
- OUTB (nc_scntl1, 0x00 ); /* odd parity, and remove CRST!! */
+ OUTB (nc_scntl1, 0x00); /* odd parity, and remove CRST!! */
- ncr_selectclock(np, np->rv_scntl3);
+ ncr_selectclock(np, np->rv_scntl3); /* Select SCSI clock */
- OUTB (nc_scid , RRE|np->myaddr);/* host adapter SCSI address */
- OUTW (nc_respid, 1ul<<np->myaddr);/* id to respond to */
- OUTB (nc_istat , SIGP ); /* Signal Process */
- OUTB (nc_dmode , np->rv_dmode); /* Burst length = 2 .. 16 transfers */
+ OUTB (nc_scid , RRE|np->myaddr); /* Adapter SCSI address */
+ OUTW (nc_respid, 1ul<<np->myaddr); /* Id to respond to */
+ OUTB (nc_istat , SIGP ); /* Signal Process */
+ OUTB (nc_dmode , np->rv_dmode); /* Burst length, dma mode */
+ OUTB (nc_ctest5, np->rv_ctest5); /* Large fifo + large burst */
- if (driver_setup.special_features && np->rv_ctest5)
- OUTB (nc_ctest5, np->rv_ctest5); /* large fifo + large burst */
+ OUTB (nc_dcntl , NOCOM|np->rv_dcntl); /* Protect SFBR */
+ OUTB (nc_ctest3, np->rv_ctest3); /* Write and invalidate */
+ OUTB (nc_ctest4, np->rv_ctest4); /* Master parity checking */
- OUTB (nc_dcntl , NOCOM|np->rv_dcntl);/* no single step mode, protect SFBR*/
- OUTB (nc_ctest3, np->rv_ctest3); /* write and invalidate */
-
- if (driver_setup.master_parity)
- OUTB (nc_ctest4, MPEE|np->rv_ctest4); /* enable master parity checking */
- else
- OUTB (nc_ctest4, 0x00|np->rv_ctest4); /* disable master parity checking */
-
- OUTB (nc_stest2, EXT|np->rv_stest2); /* Extended Sreq/Sack filtering */
- OUTB (nc_stest3, TE ); /* TolerANT enable */
- OUTB (nc_stime0, 0x0d ); /* HTH = disable STO = 0.4 sec. */
- /* 0.25 sec recommended for scsi 1 */
+ OUTB (nc_stest2, EXT|np->rv_stest2); /* Extended Sreq/Sack filtering */
+ OUTB (nc_stest3, TE); /* TolerANT enable */
+ OUTB (nc_stime0, 0x0d ); /* HTH disabled STO 0.4 sec. */
/*
** Reinitialize usrsync.
@@ -5436,31 +5379,11 @@ void ncr_init (ncb_p np, char * msg, u_long code)
np->disc = 0;
/*
- ** Fill in target structure.
+ ** Enable GPIO0 pin for writing if LED support.
*/
- for (i=0;i<MAX_TARGET;i++) {
- tcb_p tp = &np->target[i];
-
- tp->sval = 0;
- tp->wval = np->rv_scntl3;
-
- tp->usrsync = usrsync;
- tp->usrwide = usrwide;
-
- ncr_negotiate (np, tp);
- }
-
- /*
- ** Enable GPIO0 pin for writing.
- ** Patch the script for LED support.
- */
-
- if (driver_setup.led_pin & (~np->sv_gpcntl) & 0x01) {
+ if (np->features & _F_LED0) {
OUTOFFB (nc_gpcntl, 0x01);
- np->script0->reselect[0] = SCR_REG_REG(gpreg, SCR_OR, 0x01);
- np->script0->reselect1[0] = SCR_REG_REG(gpreg, SCR_AND, 0xfe);
- np->script0->reselect2[0] = SCR_REG_REG(gpreg, SCR_AND, 0xfe);
}
/*
@@ -5480,6 +5403,31 @@ void ncr_init (ncb_p np, char * msg, u_long code)
OUTB (nc_dien , MDPE|BF|ABRT|SSI|SIR|IID);
/*
+ ** For 895/6 enable SBMC interrupt and save current SCSI bus mode.
+ */
+ if (np->features & _F_ULTRA2) {
+ OUTONW (nc_sien, SBMC);
+ np->scsi_mode = INB (nc_stest4) & SMODE;
+ }
+
+ /*
+ ** Fill in target structure.
+ ** Prepare sync negotiation according to actual SCSI bus mode.
+ */
+
+ for (i=0;i<MAX_TARGET;i++) {
+ tcb_p tp = &np->target[i];
+
+ tp->sval = 0;
+ tp->wval = np->rv_scntl3;
+
+ tp->usrsync = usrsync;
+ tp->usrwide = usrwide;
+
+ ncr_negotiate (np, tp);
+ }
+
+ /*
** Start script processor.
*/
@@ -5502,14 +5450,12 @@ static void ncr_negotiate (struct ncb* np, struct tcb* tp)
u_long minsync = tp->usrsync;
- if (driver_setup.ultra_scsi >= 2) {
- if (minsync < 10) minsync=10;
- }
- else if (driver_setup.ultra_scsi == 1) {
- if (minsync < 12) minsync=12;
- }
- else {
- if (minsync < 25) minsync=25;
+ /*
+ ** SCSI bus mode limit
+ */
+
+ if (np->scsi_mode && np->scsi_mode == SMODE_SE) {
+ if (minsync < 12) minsync = 12;
}
/*
@@ -5628,7 +5574,7 @@ static int ncr_getsync(ncb_p np, u_char fac, u_char *fakp, u_char *scntl3p)
*fakp = fak - 4;
*scntl3p = ((idiv+1) << 4) + (fac < 25 ? ULTRA : 0);
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
printf("fac=%d idiv=%d per=%d fak=%x ", fac, idiv, per, *fakp);
#endif
@@ -5867,7 +5813,7 @@ static void ncr_settags (tcb_p tp, lcb_p lp)
**----------------------------------------------------
*/
-#ifdef SCSI_NCR_USER_COMMAND
+#ifdef SCSI_NCR_USER_COMMAND_SUPPORT
static void ncr_usercmd (ncb_p np)
{
@@ -5897,7 +5843,7 @@ static void ncr_usercmd (ncb_p np)
break;
case UC_SETDEBUG:
-#ifdef SCSI_NCR_DEBUG
+#ifdef SCSI_NCR_DEBUG_INFO_SUPPORT
ncr_debug = np->user.data;
#endif
break;
@@ -5929,12 +5875,106 @@ static void ncr_usercmd (ncb_p np)
case UC_CLEARPROF:
bzero(&np->profile, sizeof(np->profile));
break;
+#ifdef UC_DEBUG_ERROR_RECOVERY
+ case UC_DEBUG_ERROR_RECOVERY:
+ np->debug_error_recovery = np->user.data;
+ break;
+#endif
}
np->user.cmd=0;
}
#endif
+/*=====================================================================
+**
+** Embedded error recovery debugging code.
+**
+**=====================================================================
+**
+** This code is conditionned by SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT.
+** It only can be enabled after boot-up with a control command.
+**
+** Every 30 seconds the timer handler of the driver decides to
+** change the behaviour of the driver in order to trigger errors.
+**
+** If last command was "debug_error_recovery sge", the driver
+** sets sync offset of all targets that use sync transfers to 2,
+** and so hopes a SCSI gross error at the next read operation.
+**
+** If last command was "debug_error_recovery abort", the driver
+** does not signal new scsi commands to the script processor, until
+** it is asked to abort or reset a command by the mid-level driver.
+**
+** If last command was "debug_error_recovery reset", the driver
+** does not signal new scsi commands to the script processor, until
+** it is asked to reset a command by the mid-level driver.
+**
+** If last command was "debug_error_recovery parity", the driver
+** will assert ATN on the next DATA IN phase mismatch, and so will
+** behave as if a parity error had been detected.
+**
+** The command "debug_error_recovery none" makes the driver behave
+** normaly.
+**
+**=====================================================================
+*/
+
+#ifdef SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
+static void ncr_trigger_errors (ncb_p np)
+{
+ /*
+ ** If np->debug_error_recovery is not zero, we want to
+ ** simulate common errors in order to test error recovery.
+ */
+ do {
+ static u_long last = 0l;
+
+ if (!np->debug_error_recovery)
+ break;
+ if (!last)
+ last = jiffies;
+ else if (jiffies < last + 30*HZ)
+ break;
+ last = jiffies;
+ /*
+ * This one triggers SCSI gross errors.
+ */
+ if (np->debug_error_recovery == 1) {
+ int i;
+ printf("%s: testing error recovery from SCSI gross error...\n", ncr_name(np));
+ for (i = 0 ; i < MAX_TARGET ; i++) {
+ if (np->target[i].sval & 0x1f) {
+ np->target[i].sval &= ~0x1f;
+ np->target[i].sval += 2;
+ }
+ }
+ }
+ /*
+ * This one triggers abort from the mid-level driver.
+ */
+ else if (np->debug_error_recovery == 2) {
+ printf("%s: testing error recovery from mid-level driver abort()...\n", ncr_name(np));
+ np->stalling = 2;
+ }
+ /*
+ * This one triggers reset from the mid-level driver.
+ */
+ else if (np->debug_error_recovery == 3) {
+ printf("%s: testing error recovery from mid-level driver reset()...\n", ncr_name(np));
+ np->stalling = 3;
+ }
+ /*
+ * This one set ATN on phase mismatch in DATA IN phase and so
+ * will behave as on scsi parity error detected.
+ */
+ else if (np->debug_error_recovery == 4) {
+ printf("%s: testing data in parity error...\n", ncr_name(np));
+ np->assert_atn = 1;
+ }
+ } while (0);
+}
+#endif
/*==========================================================
**
@@ -5977,6 +6017,10 @@ static void ncr_timeout (ncb_p np)
add_timer(&np->timer);
+#ifdef SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
+ ncr_trigger_errors (np);
+#endif
+
/*
** If we are resetting the ncr, wait for settle_time before
** clearing it. Then command processing will be resumed.
@@ -6084,6 +6128,9 @@ static void ncr_timeout (ncb_p np)
*/
ncr_complete (np, cp);
+#ifdef SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
+ if (!np->stalling)
+#endif
OUTB (nc_istat, SIGP);
}
restore_flags(flags);
@@ -6138,6 +6185,7 @@ static void ncr_log_hard_error(ncb_p np, u_short sist, u_char dstat)
{
u_int32 dsp;
int script_ofs;
+ int script_size;
char *script_name;
u_char *script_base;
int i;
@@ -6146,11 +6194,13 @@ static void ncr_log_hard_error(ncb_p np, u_short sist, u_char dstat)
if (dsp > np->p_script && dsp <= np->p_script + sizeof(struct script)) {
script_ofs = dsp - np->p_script;
+ script_size = sizeof(struct script);
script_base = (u_char *) np->script;
script_name = "script";
}
else {
script_ofs = dsp - np->p_scripth;
+ script_size = sizeof(struct scripth);
script_base = (u_char *) np->scripth;
script_name = "scripth";
}
@@ -6162,7 +6212,7 @@ static void ncr_log_hard_error(ncb_p np, u_short sist, u_char dstat)
(unsigned)INL (nc_dbc));
if (((script_ofs & 3) == 0) &&
- (unsigned)script_ofs < sizeof(struct script)) {
+ (unsigned)script_ofs < script_size) {
printf ("%s: script cmd = %08x\n", ncr_name(np),
(int) *(ncrcmd *)(script_base + script_ofs));
}
@@ -6173,13 +6223,36 @@ static void ncr_log_hard_error(ncb_p np, u_short sist, u_char dstat)
printf (".\n");
}
-/*==========================================================
-**
+/*============================================================
**
** ncr chip exception handler.
**
+**============================================================
**
-**==========================================================
+** In normal cases, interrupt conditions occur one at a
+** time. The ncr is able to stack in some extra registers
+** other interrupts that will occurs after the first one.
+** But severall interrupts may occur at the same time.
+**
+** We probably should only try to deal with the normal
+** case, but it seems that multiple interrupts occur in
+** some cases that are not abnormal at all.
+**
+** The most frequent interrupt condition is Phase Mismatch.
+** We should want to service this interrupt quickly.
+** A SCSI parity error may be delivered at the same time.
+** The SIR interrupt is not very frequent in this driver,
+** since the INTFLY is likely used for command completion
+** signaling.
+** The Selection Timeout interrupt may be triggered with
+** IID and/or UDC.
+** The SBMC interrupt (SCSI Bus Mode Change) may probably
+** occur at any time.
+**
+** This handler try to deal as cleverly as possible with all
+** the above.
+**
+**============================================================
*/
void ncr_exception (ncb_p np)
@@ -6193,14 +6266,23 @@ void ncr_exception (ncb_p np)
*/
while ((istat = INB (nc_istat)) & INTF) {
if (DEBUG_FLAGS & DEBUG_TINY) printf ("F ");
+#ifdef SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
+ if (np->stalling)
+ OUTB (nc_istat, INTF);
+ else
+#endif
OUTB (nc_istat, (istat & SIGP) | INTF);
np->profile.num_fly++;
ncr_wakeup (np, 0);
};
- if (!(istat & (SIP|DIP))) {
+ if (!(istat & (SIP|DIP)))
return;
- }
+
+ np->profile.num_int++;
+
+ if (istat & CABRT)
+ OUTB (nc_istat, CABRT);
/*
** Steinbach's Guideline for Systems Programming:
@@ -6209,7 +6291,6 @@ void ncr_exception (ncb_p np)
sist = (istat & SIP) ? INW (nc_sist) : 0;
dstat = (istat & DIP) ? INB (nc_dstat) : 0;
- np->profile.num_int++;
if (DEBUG_FLAGS & DEBUG_TINY)
printf ("<%d|%x:%x|%x:%x>",
@@ -6217,234 +6298,121 @@ void ncr_exception (ncb_p np)
dstat,sist,
(unsigned)INL(nc_dsp),
(unsigned)INL(nc_dbc));
- if ((dstat==DFE) && (sist==PAR)) return;
-/*==========================================================
-**
-** First the normal cases.
-**
-**==========================================================
-*/
- /*-------------------------------------------
- ** SCSI reset
- **-------------------------------------------
- */
-
- if (sist & RST) {
- ncr_init (np, bootverbose ? "scsi reset" : NULL, HS_RESET);
- return;
- };
-
- /*-------------------------------------------
- ** selection timeout
+ /*========================================================
+ ** First, interrupts we want to service cleanly.
**
- ** IID excluded from dstat mask!
- ** (chip bug)
- **-------------------------------------------
- */
-
- if ((sist & STO) &&
- !(sist & (GEN|HTH|MA|SGE|UDC|RST|PAR)) &&
- !(dstat & (MDPE|BF|ABRT|SIR))) {
- ncr_int_sto (np);
- return;
- };
-
- /*-------------------------------------------
- ** Phase mismatch.
- **-------------------------------------------
- */
-
- if ((sist & MA) &&
- !(sist & (STO|GEN|HTH|SGE|UDC|RST|PAR)) &&
- !(dstat & (MDPE|BF|ABRT|SIR|IID))) {
- ncr_int_ma (np);
+ ** Phase mismatch is the most frequent interrupt, and
+ ** so we have to service it as quickly and as cleanly
+ ** as possible.
+ ** Programmed interrupts are rarely used in this driver,
+ ** but we must handle them cleanly anyway.
+ ** We try to deal with PAR and SBMC combined with
+ ** some other interrupt(s).
+ **=========================================================
+ */
+
+ if (!(sist & (STO|GEN|HTH|SGE|UDC|RST)) &&
+ !(dstat & (MDPE|BF|ABRT|IID))) {
+ if ((sist & SBMC) && ncr_int_sbmc (np))
+ return;
+ if ((sist & PAR) && ncr_int_par (np))
+ return;
+ if (sist & MA) {
+ ncr_int_ma (np);
+ return;
+ }
+ if (dstat & SIR) {
+ ncr_int_sir (np);
+ return;
+ }
+ if (!(sist & (SBMC|PAR)) && !(dstat & SSI))
+ printf("%s: unknown interrupt(s) ignored sist=%x dstat=%x\n",
+ ncr_name(np), sist, dstat);
+ OUTONB (nc_dcntl, (STD|NOCOM));
return;
};
- /*----------------------------------------
- ** move command with length 0
- **----------------------------------------
+ /*========================================================
+ ** Now, interrupts that need some fixing up.
+ ** Order and multiple interrupts is so less important.
+ **
+ ** If SRST has been asserted, we just reset the chip.
+ **
+ ** Selection is intirely handled by the chip. If the
+ ** chip says STO, we trust it. Seems some other
+ ** interrupts may occur at the same time (UDC, IID), so
+ ** we ignore them. In any case we do enough fix-up
+ ** in the service routine.
+ ** We just exclude some fatal dma errors.
+ **=========================================================
*/
- if ((dstat & IID) &&
- !(sist & (STO|GEN|HTH|MA|SGE|UDC|RST|PAR)) &&
- !(dstat & (MDPE|BF|ABRT|SIR)) &&
- ((INL(nc_dbc) & 0xf8000000) == SCR_MOVE_TBL)) {
- /*
- ** Target wants more data than available.
- ** The "no_data" script will do it.
- */
- OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, no_data));
+ if (sist & RST) {
+ ncr_init (np, bootverbose ? "scsi reset" : NULL, HS_RESET);
return;
};
- /*-------------------------------------------
- ** Programmed interrupt
- **-------------------------------------------
- */
-
- if ((dstat & SIR) &&
- !(sist & (STO|GEN|HTH|MA|SGE|UDC|RST|PAR)) &&
- !(dstat & (MDPE|BF|ABRT|IID)) &&
- (INB(nc_dsps) <= SIR_MAX)) {
- ncr_int_sir (np);
+ if ((sist & STO) &&
+ !(dstat & (MDPE|BF|ABRT))) {
+ ncr_int_sto (np);
return;
};
- /*========================================
- ** do the register dump
- **========================================
+ /*=========================================================
+ ** Now, interrupts we are not able to recover cleanly.
+ ** (At least for the moment).
+ **
+ ** Do the register dump.
+ ** Log message for real hard errors.
+ ** Clear all fifos.
+ ** For MDPE, BF, ABORT, IID, SGE and HTH we reset the
+ ** BUS and the chip.
+ ** We are more soft for UDC.
+ **=========================================================
*/
if (jiffies - np->regtime > 10*HZ) {
- int i;
np->regtime = jiffies;
- for (i=0; i<sizeof(np->regdump); i++)
+ for (i = 0; i<sizeof(np->regdump); i++)
((char*)&np->regdump)[i] = INB_OFF(i);
np->regdump.nc_dstat = dstat;
np->regdump.nc_sist = sist;
};
- /*=========================================
- ** log message for real hard errors
- **=========================================
- */
ncr_log_hard_error(np, sist, dstat);
- /*----------------------------------------
- ** clean up the dma fifo
- **----------------------------------------
- */
-
- if ( (INB(nc_sstat0) & (ILF|ORF|OLF) ) ||
- (INB(nc_sstat1) & (FF3210) ) ||
- (INB(nc_sstat2) & (ILF1|ORF1|OLF1)) || /* wide .. */
- !(dstat & DFE)) {
- printf ("%s: have to clear fifos.\n", ncr_name (np));
- OUTB (nc_stest3, TE|CSF); /* clear scsi fifo */
- OUTONB (nc_ctest3, CLF); /* clear dma fifo */
- }
-
- /*----------------------------------------
- ** handshake timeout
- **----------------------------------------
- */
-
- if (sist & HTH) {
- printf ("%s: handshake timeout\n", ncr_name(np));
- OUTB (nc_scntl1, CRST);
- DELAY (1000);
- OUTB (nc_scntl1, 0x00);
- OUTB (nc_scr0, HS_FAIL);
- OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, cleanup));
- return;
- }
-
- /*----------------------------------------
- ** unexpected disconnect
- **----------------------------------------
- */
+ printf ("%s: have to clear fifos.\n", ncr_name (np));
+ OUTB (nc_stest3, TE|CSF);
+ OUTONB (nc_ctest3, CLF);
- if ((sist & UDC) &&
- !(sist & (STO|GEN|HTH|MA|SGE|RST|PAR)) &&
- !(dstat & (MDPE|BF|ABRT|SIR|IID))) {
- OUTB (nc_scr0, HS_UNEXPECTED);
- OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, cleanup));
+ if ((sist & (SGE)) ||
+ (dstat & (MDPE|BF|ABORT|IID))) {
+ ncr_start_reset(np, 2);
return;
};
- /*----------------------------------------
- ** cannot disconnect
- **----------------------------------------
- */
-
- if ((dstat & IID) &&
- !(sist & (STO|GEN|HTH|MA|SGE|UDC|RST|PAR)) &&
- !(dstat & (MDPE|BF|ABRT|SIR)) &&
- ((INL(nc_dbc) & 0xf8000000) == SCR_WAIT_DISC)) {
- /*
- ** Unexpected data cycle while waiting for disconnect.
- ** LDSC and CON bits may help in order to understand
- ** what really happened. Print some info message and let
- ** the reset function reset the BUS and the NCR.
- */
- printf("%s:%d: data cycle while waiting for disconnect, LDSC=%d CON=%d\n",
- ncr_name (np), (int)(INB(nc_ctest0)&0x0f),
- (0!=(INB(nc_sstat2)&LDSC)), (0!=(INB(nc_scntl1)&ISCON)));
- };
-
- /*----------------------------------------
- ** single step
- **----------------------------------------
- */
-
- if ((dstat & SSI) &&
- !(sist & (STO|GEN|HTH|MA|SGE|UDC|RST|PAR)) &&
- !(dstat & (MDPE|BF|ABRT|SIR|IID))) {
- OUTONB (nc_dcntl, (STD|NOCOM));
+ if (sist & HTH) {
+ printf ("%s: handshake timeout\n", ncr_name(np));
+ ncr_start_reset(np, 2);
return;
};
-/*
-** @RECOVER@ HTH, SGE, ABRT.
-**
-** We should try to recover from these interrupts.
-** They may occur if there are problems with synch transfers, or
-** if targets are switched on or off while the driver is running.
-*/
-
- if (sist & SGE) {
- OUTONB (nc_ctest3, CLF); /* clear scsi offsets */
- }
-
- /*
- ** Freeze controller to be able to read the messages.
- */
-
- if (DEBUG_FLAGS & DEBUG_FREEZE) {
- unsigned char val;
- for (i=0; i<0x60; i++) {
- switch (i%16) {
-
- case 0:
- printf ("%s: reg[%d0]: ",
- ncr_name(np),i/16);
- break;
- case 4:
- case 8:
- case 12:
- printf (" ");
- break;
- };
- val = INB_OFF(i);
- printf (" %x%x", val/16, val%16);
- if (i%16==15) printf (".\n");
- }
-
- del_timer(&np->timer);
-
- printf ("%s: halted!\n", ncr_name(np));
- /*
- ** don't restart controller ...
- */
- OUTB (nc_istat, SRST);
+ if (sist & UDC) {
+ printf ("%s: unexpected disconnect\n", ncr_name(np));
+ if (INB (nc_scr1) != 0xff) {
+ OUTB (nc_scr1, HS_UNEXPECTED);
+ OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, cleanup));
+ };
+ ncr_start_reset(np, 2);
return;
};
-#ifdef NCR_FREEZE
- /*
- ** Freeze system to be able to read the messages.
- */
- printf ("ncr: fatal error: system halted - press reset to reboot ...");
- cli();
- for (;;);
-#endif
-
- /*
- ** sorry, have to kill ALL jobs ...
+ /*=========================================================
+ ** We just miss the cause of the interrupt. :(
+ ** Print a message. The timeout will do the real work.
+ **=========================================================
*/
-
- ncr_start_reset(np, 2);
+ printf ("%s: unknown interrupt\n", ncr_name(np));
}
/*==========================================================
@@ -6503,6 +6471,70 @@ void ncr_int_sto (ncb_p np)
/*==========================================================
**
+** ncr chip exception handler for SCSI bus mode change
+**
+**==========================================================
+**
+** I'm not quite sure of what is to be done in such a
+** situation.
+** For now,
+** Reset the bus if some devices use too fast sync transfers.
+** Otherwise, just try to renegotiate sync with targets.
+**
+**----------------------------------------------------------
+*/
+
+static int ncr_int_sbmc (ncb_p np)
+{
+ u_char scsi_mode = INB (nc_stest4) & SMODE;
+ int i;
+ int oversync;
+
+ printf("%s: SCSI bus mode change from %x to %x\n", ncr_name(np),
+ np->scsi_mode, scsi_mode);
+
+ if (scsi_mode == np->scsi_mode)
+ return 0;
+
+ np->scsi_mode = scsi_mode;
+ oversync = 0;
+ for (i = 0; i < MAX_TARGET; i++) {
+ tcb_p tp = &np->target[i];
+
+ if (np->ns_sync < 12 && tp->maxoffs && tp->usrsync < 12) {
+ if (scsi_mode != SMODE_SE)
+ ncr_negotiate(np, tp);
+ else
+ ++oversync;
+ }
+ }
+
+ if (oversync)
+ ncr_start_reset(np, 2);
+
+ return oversync;
+}
+
+/*==========================================================
+**
+** ncr chip exception handler for SCSI parity error.
+**
+**==========================================================
+**
+** SCSI parity errors are handled by the SCSI script.
+** So, we just print some message.
+**
+**----------------------------------------------------------
+*/
+
+static int ncr_int_par (ncb_p np)
+{
+ printf("%s: SCSI parity error detected\n", ncr_name(np));
+ return 0;
+}
+
+/*==========================================================
+**
**
** ncr chip exception handler for phase errors.
**
@@ -6538,22 +6570,18 @@ static void ncr_int_ma (ncb_p np)
/*
** Take into account dma fifo and various buffers and latches,
- ** only if the interrupted phase in an OUTPUT phase.
+ ** only if the interrupted phase was DATA OUT.
*/
- if ((cmd & 1) == 0) {
+ if ((cmd & 7) == 0) {
u_char ctest5, ss0, ss2;
u_short delta;
- if (!(INB(nc_dstat) & DFE)) {
- ctest5 = (np->rv_ctest5 & DFS) ? INB (nc_ctest5) : 0;
- if (ctest5 & DFS)
- delta=(((ctest5 << 8) | (INB (nc_dfifo) & 0xff)) - rest) & 0x3ff;
- else
- delta=(INB (nc_dfifo) - rest) & 0x7f;
- } else {
- delta = 0;
- }
+ ctest5 = (np->rv_ctest5 & DFS) ? INB (nc_ctest5) : 0;
+ if (ctest5 & DFS)
+ delta=(((ctest5 << 8) | (INB (nc_dfifo) & 0xff)) - rest) & 0x3ff;
+ else
+ delta=(INB (nc_dfifo) - rest) & 0x7f;
/*
** The data in the dma fifo has not been transfered to
@@ -6582,9 +6610,10 @@ static void ncr_int_ma (ncb_p np)
} else {
if (DEBUG_FLAGS & (DEBUG_TINY|DEBUG_PHASE))
printf ("P%x%x RL=%d ", cmd&7, sbcl&7, rest);
- if (!(INB(nc_dstat) & DFE))
- printf("INPUT phase mismatch with DMA fifo not empty, P%x%x RL=%d\n",
- cmd&7, sbcl&7, rest);
+ if ((cmd & 7) != 1) {
+ OUTONB (nc_ctest3, CLF );
+ OUTB (nc_stest3, TE|CSF);
+ }
}
/*
@@ -6660,7 +6689,7 @@ static void ncr_int_ma (ncb_p np)
};
/*
- ** if old phase not dataphase, leave here.
+ ** check cmd against assumed interrupted script command.
*/
if (cmd != (vdsp[0] >> 24)) {
@@ -6670,6 +6699,18 @@ static void ncr_int_ma (ncb_p np)
return;
}
+
+#ifdef SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
+ if ((cmd & 7) == 1 && np->assert_atn) {
+ np->assert_atn = 0;
+ OUTONB(nc_socl, CATN);
+ }
+#endif
+
+ /*
+ ** if old phase not dataphase, leave here.
+ */
+
if (cmd & 0x06) {
PRINT_ADDR(cp->cmd);
printf ("phase change %x-%x %d@%08x resid=%d.\n",
@@ -6712,7 +6753,10 @@ static void ncr_int_ma (ncb_p np)
*/
np->profile.num_break++;
OUTL (nc_temp, vtophys (newcmd));
- OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, dispatch));
+ if ((cmd & 7) == 0)
+ OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, dispatch));
+ else
+ OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, checkatn));
}
/*==========================================================
@@ -6778,15 +6822,24 @@ void ncr_int_sir (ncb_p np)
}
switch (num) {
+ u_long endp;
case SIR_DATA_IO_IS_OUT:
+ case SIR_DATA_IO_IS_IN:
/*
-** We did not guess the direction of transfer. We assumed DATA IN,
-** but the the target drove DATA OUT.
-** We have to patch the script context with DATA OUT context and
-** restart processing at data out script address.
-*/
- cp->phys.header.savep = NCB_SCRIPTH_PHYS (np, data_out);
- cp->phys.header.goalp = cp->phys.header.savep +20 +cp->segments*16;
+** We did not guess the direction of transfer. We have to wait for
+** actual data direction driven by the target before setting
+** pointers. We must patch the global header too.
+*/
+ if (num == SIR_DATA_IO_IS_OUT) {
+ endp = NCB_SCRIPTH_PHYS (np, data_out) + MAX_SCATTER*16;
+ cp->phys.header.goalp = endp + 8;
+ cp->phys.header.savep = endp - cp->segments*16;
+ } else {
+ endp = NCB_SCRIPT_PHYS (np, data_in) + MAX_SCATTER*16;
+ cp->phys.header.goalp = endp + 8;
+ cp->phys.header.savep = endp - cp->segments*16;
+ }
+
cp->phys.header.lastp = cp->phys.header.savep;
np->header.savep = cp->phys.header.savep;
np->header.goalp = cp->phys.header.goalp;
@@ -7276,6 +7329,7 @@ void ncr_int_sir (ncb_p np)
(unsigned) np->header.goalp);
break;
+#if 0 /* This stuff does not work */
/*--------------------------------------------------------------------
**
** Processing of a "S_QUEUE_FULL" status.
@@ -7353,6 +7407,7 @@ void ncr_int_sir (ncb_p np)
printf ("%s: queue empty.\n", ncr_name (np));
np->script->start1[0] = SCR_INT ^ IFFALSE (0);
break;
+#endif /* This stuff does not work */
};
out:
@@ -7362,7 +7417,7 @@ out:
/*==========================================================
**
**
-** Acquire a control block
+** Aquire a control block
**
**
**==========================================================
@@ -7496,10 +7551,10 @@ static void ncr_alloc_ccb (ncb_p np, u_long target, u_long lun)
tp->jump_tcb.l_cmd = (SCR_JUMP^IFFALSE (DATA (0x80 + target)));
tp->jump_tcb.l_paddr = np->jump_tcb.l_paddr;
- tp->getscr[0] = SCR_COPY (1);
+ tp->getscr[0] = (np->features & _F_PFEN)? SCR_COPY(1) : SCR_COPY_F(1);
tp->getscr[1] = vtophys (&tp->sval);
tp->getscr[2] = np->paddr + offsetof (struct ncr_reg, nc_sxfer);
- tp->getscr[3] = SCR_COPY (1);
+ tp->getscr[3] = (np->features & _F_PFEN)? SCR_COPY(1) : SCR_COPY_F(1);
tp->getscr[4] = vtophys (&tp->wval);
tp->getscr[5] = np->paddr + offsetof (struct ncr_reg, nc_scntl3);
@@ -7712,12 +7767,15 @@ static int ncr_scatter(ccb_p cp, Scsi_Cmnd *cmd)
int segment = 0;
int use_sg = (int) cmd->use_sg;
+#if 0
bzero (cp->phys.data, sizeof (cp->phys.data));
+#endif
data = cp->phys.data;
cp->data_len = 0;
if (!use_sg) {
if (cmd->request_bufflen) {
+ data = &data[MAX_SCATTER - 1];
data[0].addr = vtophys(cmd->request_buffer);
data[0].size = cmd->request_bufflen;
cp->data_len = data[0].size;
@@ -7727,6 +7785,7 @@ static int ncr_scatter(ccb_p cp, Scsi_Cmnd *cmd)
else if (use_sg <= MAX_SCATTER) {
struct scatterlist *scatter = (struct scatterlist *)cmd->buffer;
+ data = &data[MAX_SCATTER - use_sg];
while (segment < use_sg) {
data[segment].addr = vtophys(scatter[segment].address);
data[segment].size = scatter[segment].length;
@@ -7753,7 +7812,9 @@ static int ncr_scatter(ccb_p cp, Scsi_Cmnd *cmd)
*/
#ifndef NCR_IOMAPPED
+__initfunc(
static int ncr_regtest (struct ncb* np)
+)
{
register volatile u_long data;
/*
@@ -7777,7 +7838,9 @@ static int ncr_regtest (struct ncb* np)
}
#endif
+__initfunc(
static int ncr_snooptest (struct ncb* np)
+)
{
u_long ncr_rd, ncr_wr, ncr_bk, host_rd, host_wr, pc, err=0;
int i;
@@ -7801,6 +7864,7 @@ static int ncr_snooptest (struct ncb* np)
/*
** Start script (exchange values)
*/
+flush_cache_all();
OUTL (nc_dsp, pc);
/*
** Wait 'til done (with timeout)
@@ -7871,7 +7935,7 @@ static int ncr_snooptest (struct ncb* np)
**==========================================================
*/
-#ifdef SCSI_NCR_PROFILE
+#ifdef SCSI_NCR_PROFILE_SUPPORT
/*
** Compute the difference in jiffies ticks.
@@ -7883,7 +7947,7 @@ static int ncr_snooptest (struct ncb* np)
#define PROFILE cp->phys.header.stamp
static void ncb_profile (ncb_p np, ccb_p cp)
{
- int co, da, st, en, di, se, post,work,disc;
+ int co, st, en, di, se, post,work,disc;
u_long diff;
PROFILE.end = jiffies;
@@ -7891,9 +7955,6 @@ static void ncb_profile (ncb_p np, ccb_p cp)
st = ncr_delta (PROFILE.start,PROFILE.status);
if (st<0) return; /* status not reached */
- da = ncr_delta (PROFILE.start,PROFILE.data);
- if (da<0) return; /* No data transfer phase */
-
co = ncr_delta (PROFILE.start,PROFILE.command);
if (co<0) return; /* command not executed */
@@ -7930,7 +7991,7 @@ static void ncb_profile (ncb_p np, ccb_p cp)
}
#undef PROFILE
-#endif /* SCSI_NCR_PROFILE */
+#endif /* SCSI_NCR_PROFILE_SUPPORT */
/*==========================================================
**
@@ -7991,7 +8052,7 @@ static u_long ncr_lookup(char * id)
/*==========================================================
**
** Determine the ncr's clock frequency.
-** This is important for the negotiation
+** This is essential for the negotiation
** of the synchronous transfer rate.
**
**==========================================================
@@ -7999,20 +8060,53 @@ static u_long ncr_lookup(char * id)
** Note: we have to return the correct value.
** THERE IS NO SAVE DEFAULT VALUE.
**
-** We assume that all NCR based boards are delivered
-** with a 40Mhz clock. Because we have to divide
-** by an integer value greater than 3, only clock
-** frequencies of 40Mhz (/4) or 50MHz (/5) permit
-** the FAST-SCSI rate of 10MHz.
+** Most NCR/SYMBIOS boards are delivered with a 40 Mhz clock.
+** 53C860 and 53C875 rev. 1 support fast20 transfers but
+** do not have a clock doubler and so are provided with a
+** 80 MHz clock. All other fast20 boards incorporate a doubler
+** and so should be delivered with a 40 MHz clock.
+** The future fast40 chips (895/895) use a 40 Mhz base clock
+** and provide a clock quadrupler (160 Mhz). The code below
+** tries to deal as cleverly as possible with all this stuff.
**
**----------------------------------------------------------
*/
/*
+ * Select NCR SCSI clock frequency
+ */
+static void ncr_selectclock(ncb_p np, u_char scntl3)
+{
+ if (np->multiplier < 2) {
+ OUTB(nc_scntl3, scntl3);
+ return;
+ }
+
+ if (bootverbose >= 2)
+ printf ("%s: enabling clock multiplier\n", ncr_name(np));
+
+ OUTB(nc_stest1, DBLEN); /* Enable clock multiplier */
+ if (np->multiplier > 2) { /* Poll bit 5 of stest4 for quadrupler */
+ int i = 20;
+ while (!(INB(nc_stest4) & LCKFRQ) && --i > 0)
+ DELAY(20);
+ if (!i)
+ printf("%s: the chip cannot lock the frequency\n", ncr_name(np));
+ } else /* Wait 20 micro-seconds for doubler */
+ DELAY(20);
+ OUTB(nc_stest3, HSC); /* Halt the scsi clock */
+ OUTB(nc_scntl3, scntl3);
+ OUTB(nc_stest1, (DBLEN|DBLSEL));/* Select clock multiplier */
+ OUTB(nc_stest3, 0x00); /* Restart scsi clock */
+}
+
+
+/*
* calculate NCR SCSI clock frequency (in KHz)
*/
-static unsigned
-ncrgetfreq (ncb_p np, int gen)
+__initfunc(
+static unsigned ncrgetfreq (ncb_p np, int gen)
+)
{
unsigned ms = 0;
@@ -8058,38 +8152,11 @@ ncrgetfreq (ncb_p np, int gen)
}
/*
- * Select NCR SCSI clock frequency
- */
-static void ncr_selectclock(ncb_p np, u_char scntl3)
-{
- if (np->multiplier < 2) {
- OUTB(nc_scntl3, scntl3);
- return;
- }
-
- if (bootverbose >= 2)
- printf ("%s: enabling clock multiplier\n", ncr_name(np));
-
- OUTB(nc_stest1, DBLEN); /* Enable clock multiplier */
- if (np->multiplier > 2) { /* Poll bit 5 of stest4 for quadrupler */
- int i = 20;
- while (!(INB(nc_stest4) & 0x20) && --i > 0)
- DELAY(20);
- if (!i)
- printf("%s: the chip cannot lock the frequency\n", ncr_name(np));
- } else /* Wait 20 micro-seconds for doubler */
- DELAY(20);
- OUTB(nc_stest3, 0x20); /* Halt the scsi clock */
- OUTB(nc_scntl3, scntl3);
- OUTB(nc_stest1, (DBLEN|DBLSEL));/* Select clock multiplier */
- OUTB(nc_stest3, 0x00); /* Restart scsi clock */
-}
-
-
-/*
* Get/probe NCR SCSI clock frequency
*/
+__initfunc(
static void ncr_getclock (ncb_p np, int mult)
+)
{
unsigned char scntl3 = INB(nc_scntl3);
unsigned char stest1 = INB(nc_stest1);
@@ -8151,58 +8218,14 @@ static void ncr_getclock (ncb_p np, int mult)
np->ns_sync = 25;
if (f1 >= 160000) {
- if (driver_setup.ultra_scsi) np->ns_sync = 10;
- np->rv_scntl3 = 7;
+ if (np->features & _F_ULTRA2) np->ns_sync = 10;
+ else if (np->features & _F_ULTRA) np->ns_sync = 12;
}
else if (f1 >= 80000) {
- if (driver_setup.ultra_scsi) np->ns_sync = 12;
- np->rv_scntl3 = 5;
- }
- else {
- np->rv_scntl3 = 3;
- }
-
- if (bootverbose > 1) {
- printf ("%s: initial value of SCNTL3 = %02x, final = %02x\n",
- ncr_name(np), scntl3, np->rv_scntl3);
+ if (np->features & _F_ULTRA) np->ns_sync = 12;
}
}
-/*
-** Save some features set by bios
-**
-** DMODE 0xce
-** 0x02 burst op-code fetch
-** 0x04 enable read multiple
-** 0x08 enable read line
-** 0xc0 burst length 16/8/2
-** DCNTL 0xa8
-** 0x08 totem pole irq
-** 0x20 enable pre-fetch
-** 0x80 enable cache line size
-** CTEST3 0x01
-** 0x01 set write and invalidate
-** CTEST4 0x80
-** 0x80 burst disabled
-** CTEST5 0x24
-** 0x20 large dma fifo (875 and 895 only)
-** 0x04 burst len 32/64/128 (875 and 895 only)
-** GPCNTL general purpose control register
-** STEST2 0x20 differential mode
-*/
-
-static void ncr_save_bios_setting(ncb_p np)
-{
- np->sv_scntl3 = INB(nc_scntl3) & 0x07;
- np->sv_dmode = INB(nc_dmode) & 0xce;
- np->sv_dcntl = INB(nc_dcntl) & 0xa8;
- np->sv_ctest3 = INB(nc_ctest3) & 0x01;
- np->sv_ctest4 = INB(nc_ctest4) & 0x80;
- np->sv_ctest5 = INB(nc_ctest5) & 0x24;
- np->sv_gpcntl = INB(nc_gpcntl);
- np->sv_stest2 = INB(nc_stest2) & 0x20;
-}
-
/*===================== LINUX ENTRY POINTS SECTION ==========================*/
#ifndef uchar
@@ -8224,8 +8247,11 @@ static void ncr_save_bios_setting(ncb_p np)
** ---------------------------------------------------------------------
*/
+__initfunc(
void ncr53c8xx_setup(char *str, int *ints)
+)
{
+#ifdef SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT
char *cur = str;
char *pv;
int val;
@@ -8295,6 +8321,8 @@ void ncr53c8xx_setup(char *str, int *ints)
driver_setup.diff_support= val;
else if (!strncmp(cur, "irqm:", 5))
driver_setup.irqm = val;
+ else if (!strncmp(cur, "pcifix:", 7))
+ driver_setup.pci_fix_up = val;
else if (!strncmp(cur, "safe:", 5) && val)
memcpy(&driver_setup, &driver_safe_setup, sizeof(driver_setup));
@@ -8302,34 +8330,11 @@ void ncr53c8xx_setup(char *str, int *ints)
if ((cur = strchr(cur, ',')) != NULL)
++cur;
}
+#endif /* SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT */
}
-static int ncr53c8xx_pci_init(Scsi_Host_Template *tpnt, int unit, int board, int chip,
- uchar bus, uchar device_fn, int options);
-
-/*
-** NCR53C8XX devices description table
-*/
-
-static struct {
- ushort pci_device_id;
- int chip;
- int max_revision;
- int min_revision;
-} pci_chip_ids[] = {
- {PCI_DEVICE_ID_NCR_53C810, 810, -1, -1},
-/* {PCI_DEVICE_ID_NCR_53C810AP, 810, -1, -1}, */
- {PCI_DEVICE_ID_NCR_53C815, 815, -1, -1},
- {PCI_DEVICE_ID_NCR_53C820, 820, -1, -1},
- {PCI_DEVICE_ID_NCR_53C825, 825, -1, -1},
- {PCI_DEVICE_ID_NCR_53C860, 860, -1, -1},
- {PCI_DEVICE_ID_NCR_53C875, 875, -1, -1},
- {PCI_DEVICE_ID_NCR_53C885, 885, -1, -1},
- {PCI_DEVICE_ID_NCR_53C895, 895, -1, -1},
- {PCI_DEVICE_ID_NCR_53C896, 896, -1, -1}
-};
-
-#define NPCI_CHIP_IDS (sizeof (pci_chip_ids) / sizeof(pci_chip_ids[0]))
+static int ncr53c8xx_pci_init(Scsi_Host_Template *tpnt, int unit,
+ uchar bus, uchar device_fn);
/*
** Linux entry point for NCR53C8XX devices detection routine.
@@ -8343,16 +8348,12 @@ static struct {
** Returns the number of boards successfully attached.
*/
-int ncr53c8xx_detect(Scsi_Host_Template *tpnt)
+__initfunc(
+static void ncr_print_driver_setup(void)
+)
{
- int i, j;
- int count = 0; /* Number of boards detected */
- uchar pci_bus, pci_device_fn;
- short pci_index; /* Device index to PCI BIOS calls */
-
#define YesNo(y) y ? 'y' : 'n'
- if (bootverbose >= 2) {
- printk("ncr53c8xx: setup=disc:%c,specf:%c,ultra:%c,tags:%d,sync:%d,burst:%d,wide:%c,diff:%d\n",
+ printk("ncr53c8xx: setup=disc:%c,specf:%c,ultra:%c,tags:%d,sync:%d,burst:%d,wide:%c,diff:%d\n",
YesNo(driver_setup.disconnection),
YesNo(driver_setup.special_features),
YesNo(driver_setup.ultra_scsi),
@@ -8361,7 +8362,7 @@ int ncr53c8xx_detect(Scsi_Host_Template *tpnt)
driver_setup.burst_max,
YesNo(driver_setup.max_wide),
driver_setup.diff_support);
- printk("ncr53c8xx: setup=mpar:%c,spar:%c,fsn=%c,verb:%d,debug:0x%x,led:%c,settle:%d,irqm:%d\n",
+ printk("ncr53c8xx: setup=mpar:%c,spar:%c,fsn=%c,verb:%d,debug:0x%x,led:%c,settle:%d,irqm:%d\n",
YesNo(driver_setup.master_parity),
YesNo(driver_setup.scsi_parity),
YesNo(driver_setup.force_sync_nego),
@@ -8370,10 +8371,30 @@ int ncr53c8xx_detect(Scsi_Host_Template *tpnt)
YesNo(driver_setup.led_pin),
driver_setup.settle_delay,
driver_setup.irqm);
- }
#undef YesNo
+}
-#ifdef SCSI_NCR_DEBUG
+/*
+** NCR53C8XX devices description table and chip ids list.
+*/
+
+static ncr_chip ncr_chip_table[] __initdata = SCSI_NCR_CHIP_TABLE;
+static ushort ncr_chip_ids[] __initdata = SCSI_NCR_CHIP_IDS;
+
+__initfunc(
+int ncr53c8xx_detect(Scsi_Host_Template *tpnt)
+)
+{
+ int i, j;
+ int chips;
+ int count = 0;
+ uchar bus, device_fn;
+ short index;
+
+ if (bootverbose >= 2)
+ ncr_print_driver_setup();
+
+#ifdef SCSI_NCR_DEBUG_INFO_SUPPORT
ncr_debug = driver_setup.debug;
#endif
@@ -8384,21 +8405,21 @@ int ncr53c8xx_detect(Scsi_Host_Template *tpnt)
# endif
#endif
- if (pcibios_present()) {
- for (j = 0; j < NPCI_CHIP_IDS; ++j) {
- i = driver_setup.reverse_probe ? NPCI_CHIP_IDS-1 - j : j;
- for (pci_index = 0;
- !pcibios_find_device(PCI_VENDOR_ID_NCR,
- pci_chip_ids[i].pci_device_id, pci_index, &pci_bus,
- &pci_device_fn);
- ++pci_index)
- if (!ncr53c8xx_pci_init(tpnt, count, 0, pci_chip_ids[i].chip,
- pci_bus, pci_device_fn, /* no options */ 0))
- ++count;
- }
- }
+ if (!pcibios_present())
+ return 0;
- return count;
+ chips = sizeof(ncr_chip_ids) / sizeof(ncr_chip_ids[0]);
+ for (j = 0; j < chips ; ++j) {
+ i = driver_setup.reverse_probe ? chips-1 - j : j;
+ for (index = 0; ; index++) {
+ if (pcibios_find_device(PCI_VENDOR_ID_NCR, ncr_chip_ids[i],
+ index, &bus, &device_fn))
+ break;
+ if (!ncr53c8xx_pci_init(tpnt, count, bus, device_fn))
+ ++count;
+ }
+ }
+ return count;
}
@@ -8440,6 +8461,17 @@ static int ncr53c8xx_pci_init(Scsi_Host_Template *tpnt, int unit, int board, int
pcibios_strerror(error));
return -1;
}
+#ifdef CONFIG_SNI_RM200_PCI
+ /*
+ * The onboard NCR bypasses the normal PCI interrupt system.
+ */
+ if (mips_machgroup == MACH_GROUP_SNI_RM
+ && mips_machtype == MACH_SNI_RM200_PCI
+ && bus == 0 && device_fn == PCI_DEVFN(0, 1))
+ irq = PCIMT_IRQ_SCSI;
+printk("ncr53c8xx_pci_init() #1: bus == %d, device_fn == %d\n", bus, device_fn);
+#endif
+
if (vendor_id != PCI_VENDOR_ID_NCR) {
printk("ncr53c8xx: not initializing, 0x%04x is not NCR vendor ID\n", (int) vendor_id);
@@ -8527,7 +8559,7 @@ static void ncr53c8xx_select_queue_depths(struct Scsi_Host *host, struct scsi_de
device->queue_depth = 1;
#endif
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
printk("ncr53c8xx_select_queue_depth: id=%d, lun=%d, queue_depth=%d\n",
device->id, device->lun, device->queue_depth);
#endif
@@ -8543,19 +8575,19 @@ printk("ncr53c8xx_select_queue_depth: id=%d, lun=%d, queue_depth=%d\n",
int ncr53c8xx_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *))
{
int sts;
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
printk("ncr53c8xx_queue_command\n");
#endif
if ((sts = ncr_queue_command(cmd, done)) != DID_OK) {
cmd->result = ScsiResult(sts, 0);
done(cmd);
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
printk("ncr53c8xx : command not queued - result=%d\n", sts);
#endif
return sts;
}
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
printk("ncr53c8xx : command successfully queued\n");
#endif
return sts;
@@ -8573,8 +8605,14 @@ static void ncr53c8xx_intr(int irq, struct pt_regs * regs)
{
struct Scsi_Host *host;
struct host_data *host_data;
+#if 0
+ u_long flags;
-#ifdef DEBUG
+ save_flags(flags); cli();
+#endif
+
+printk("Yow, an NCR interrupt!\n");
+#ifdef DEBUG_NCR53C8XX
printk("ncr53c8xx : interrupt received\n");
#endif
@@ -8583,12 +8621,20 @@ printk("ncr53c8xx : interrupt received\n");
host_data = (struct host_data *) host->hostdata;
#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,70)
# ifdef SCSI_NCR_SHARE_IRQ
- if (dev_id == host_data->ncb)
+ if (dev_id == host_data->ncb) {
+#else
+ if (1) {
# endif
#endif
- ncr_intr(host_data->ncb);
+ if (DEBUG_FLAGS & DEBUG_TINY) printf ("[");
+ ncr_exception(host_data->ncb);
+ if (DEBUG_FLAGS & DEBUG_TINY) printf ("]\n");
+ }
}
}
+#if 0
+ restore_flags(flags);
+#endif
}
/*
@@ -8696,7 +8742,7 @@ int ncr53c8xx_abort(Scsi_Cmnd *cmd)
int ncr53c8xx_release(struct Scsi_Host *host)
{
struct host_data *host_data;
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
printk("ncr53c8xx : release\n");
#endif
@@ -8847,6 +8893,8 @@ static int guess_xfer_direction(int opcode)
**=========================================================================
*/
+#ifdef SCSI_NCR_USER_COMMAND_SUPPORT
+
#define is_digit(c) ((c) >= '0' && (c) <= '9')
#define digit_to_bin(c) ((c) - '0')
#define is_space(c) ((c) == ' ' || (c) == '\t')
@@ -8928,6 +8976,10 @@ static int ncr_user_command(ncb_p np, char *buffer, int length)
uc->cmd = UC_SETFLAG;
else if ((arg_len = is_keyword(ptr, len, "clearprof")) != 0)
uc->cmd = UC_CLEARPROF;
+#ifdef UC_DEBUG_ERROR_RECOVERY
+ else if ((arg_len = is_keyword(ptr, len, "debug_error_recovery")) != 0)
+ uc->cmd = UC_DEBUG_ERROR_RECOVERY;
+#endif
else
arg_len = 0;
@@ -9028,13 +9080,30 @@ printf("ncr_user_command: data=%ld\n", uc->data);
ptr += arg_len; len -= arg_len;
}
break;
+#ifdef UC_DEBUG_ERROR_RECOVERY
+ case UC_DEBUG_ERROR_RECOVERY:
+ SKIP_SPACES(1);
+ if ((arg_len = is_keyword(ptr, len, "sge")))
+ uc->data = 1;
+ else if ((arg_len = is_keyword(ptr, len, "abort")))
+ uc->data = 2;
+ else if ((arg_len = is_keyword(ptr, len, "reset")))
+ uc->data = 3;
+ else if ((arg_len = is_keyword(ptr, len, "parity")))
+ uc->data = 4;
+ else if ((arg_len = is_keyword(ptr, len, "none")))
+ uc->data = 0;
+ else
+ return -EINVAL;
+ ptr += arg_len; len -= arg_len;
+ break;
+#endif
default:
break;
}
if (len)
return -EINVAL;
-#ifdef SCSI_NCR_USER_COMMAND
else {
long flags;
@@ -9042,10 +9111,13 @@ printf("ncr_user_command: data=%ld\n", uc->data);
ncr_usercmd (np);
restore_flags(flags);
}
-#endif
return length;
}
+#endif /* SCSI_NCR_USER_COMMAND_SUPPORT */
+
+#ifdef SCSI_NCR_USER_INFO_SUPPORT
+
struct info_str
{
char *buffer;
@@ -9104,7 +9176,7 @@ static int ncr_host_info(ncb_p np, char *ptr, off_t offset, int len)
info.pos = 0;
copy_info(&info, "General information:\n");
- copy_info(&info, " Chip NCR53C%03d, ", np->chip);
+ copy_info(&info, " Chip NCR53C%s, ", np->chip_name);
copy_info(&info, "device id 0x%x, ", np->device_id);
copy_info(&info, "revision id 0x%x\n", np->revision_id);
@@ -9124,7 +9196,7 @@ static int ncr_host_info(ncb_p np, char *ptr, off_t offset, int len)
copy_info(&info, "verbosity level %d\n", driver_setup.verbose);
}
-#ifdef SCSI_NCR_PROFILE
+#ifdef SCSI_NCR_PROFILE_SUPPORT
copy_info(&info, "Profiling information:\n");
copy_info(&info, " %-12s = %lu\n", "num_trans",np->profile.num_trans);
copy_info(&info, " %-12s = %lu\n", "num_kbytes",np->profile.num_kbytes);
@@ -9141,6 +9213,8 @@ static int ncr_host_info(ncb_p np, char *ptr, off_t offset, int len)
return info.pos > info.offset? info.pos - info.offset : 0;
}
+#endif /* SCSI_NCR_USER_INFO_SUPPORT */
+
/*
** Entry point of the scsi proc fs of the driver.
** - func = 0 means read (returns profile data)
@@ -9171,20 +9245,26 @@ printf("ncr53c8xx_proc_info: hostno=%d, func=%d\n", hostno, func);
return -EINVAL;
if (func) {
+#ifdef SCSI_NCR_USER_COMMAND_SUPPORT
retv = ncr_user_command(ncb, buffer, length);
-#ifdef DEBUG_PROC_INFO
-printf("ncr_user_command: retv=%d\n", retv);
+#else
+ retv = -EINVAL;
#endif
}
else {
if (start)
*start = buffer;
+#ifdef SCSI_NCR_USER_INFO_SUPPORT
retv = ncr_host_info(ncb, buffer, offset, length);
+#else
+ retv = -EINVAL;
+#endif
}
return retv;
}
+
/*=========================================================================
** End of proc file system stuff
**=========================================================================
diff --git a/drivers/scsi/ncr53c8xx.h b/drivers/scsi/ncr53c8xx.h
index 3c0c7fb03..412c66a37 100644
--- a/drivers/scsi/ncr53c8xx.h
+++ b/drivers/scsi/ncr53c8xx.h
@@ -45,36 +45,7 @@
/*
** Name and revision of the driver
*/
-#define SCSI_NCR_DRIVER_NAME "ncr53c8xx - revision 1.18f"
-
-/*
-** If SCSI_NCR_SETUP_SPECIAL_FEATURES is defined,
-** the driver enables or not the following features according to chip id
-** revision id:
-** DMODE 0xce
-** 0x02 burst op-code fetch
-** 0x04 enable read multiple
-** 0x08 enable read line
-** 0xc0 burst length 16/8/2
-** DCNTL 0xa0
-** 0x20 enable pre-fetch
-** 0x80 enable cache line size
-** CTEST3 0x01
-** 0x01 set write and invalidate
-** CTEST4 0x80
-** 0x80 burst disabled
-** CTEST5 0x24 (825a and 875 only)
-** 0x04 burst 128
-** 0x80 large dma fifo
-**
-** If SCSI_NCR_TRUST_BIOS_SETTING is defined, the driver will use the
-** initial value of corresponding bit fields, assuming they have been
-** set by the SDMS BIOS.
-** When Linux is booted from another O/S, these assertion is false and
-** the driver will not be able to guess it.
-*/
-
-/*********** LINUX SPECIFIC SECTION ******************/
+#define SCSI_NCR_DRIVER_NAME "ncr53c8xx - revision 2.1b"
/*
** Check supported Linux versions
@@ -97,28 +68,6 @@
#define LINUX_VERSION_CODE LinuxVersionCode(1,2,13)
#endif
-#if !defined(VERSION)
-#define VERSION ((LINUX_VERSION_CODE >> 16) & 0xff)
-#define PATCHLEVEL ((LINUX_VERSION_CODE >> 8) & 0xff)
-#define SUBLEVEL ((LINUX_VERSION_CODE >> 0) & 0xff)
-#endif
-
-#if VERSION == 0 || VERSION > 3
-# error Only Linux version 1 and probable 2 or 3 supported.
-#endif
-
-#if VERSION == 1 && PATCHLEVEL == 2
-# if SUBLEVEL != 13
-# error Only sublevel 13 of Linux 1.2 is supported.
-# endif
-#endif
-
-#if VERSION == 1 && PATCHLEVEL == 3
-# if SUBLEVEL < 45
-# error Only sublevels >=45 of Linux 1.3 are supported.
-# endif
-#endif
-
/*
** Normal IO or memory mapped IO.
**
@@ -139,6 +88,20 @@
# define SCSI_NCR_SHARE_IRQ
#endif
+/*
+** If you want a driver as small as possible, donnot define the
+** following options.
+*/
+
+#define SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT
+#define SCSI_NCR_DEBUG_INFO_SUPPORT
+#ifdef SCSI_NCR_PROC_INFO_SUPPORT
+# define SCSI_NCR_PROFILE_SUPPORT
+# define SCSI_NCR_USER_COMMAND_SUPPORT
+# define SCSI_NCR_USER_INFO_SUPPORT
+/* # define SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT */
+#endif
+
/* ---------------------------------------------------------------------
** Take into account kernel configured parameters.
** Most of these options can be overridden at startup by a command line.
@@ -208,14 +171,6 @@
#endif
/*
- * Default sync to 0 will force asynchronous at startup
- */
-#ifdef CONFIG_SCSI_FORCE_ASYNCHRONOUS
-#undef SCSI_NCR_SETUP_DEFAULT_SYNC
-#define SCSI_NCR_SETUP_DEFAULT_SYNC (255)
-#endif
-
-/*
* Disallow disconnections at boot-up
*/
#ifdef CONFIG_SCSI_NCR53C8XX_NO_DISCONNECT
@@ -291,57 +246,6 @@
#endif
/*
-** Initial setup.
-** Can be overriden at startup by a command line.
-*/
-#define SCSI_NCR_DRIVER_SETUP \
-{ \
- SCSI_NCR_SETUP_MASTER_PARITY, \
- SCSI_NCR_SETUP_SCSI_PARITY, \
- SCSI_NCR_SETUP_DISCONNECTION, \
- SCSI_NCR_SETUP_SPECIAL_FEATURES, \
- SCSI_NCR_SETUP_ULTRA_SCSI, \
- SCSI_NCR_SETUP_FORCE_SYNC_NEGO, \
- 0, \
- 1, \
- SCSI_NCR_SETUP_DEFAULT_TAGS, \
- SCSI_NCR_SETUP_DEFAULT_SYNC, \
- 0x00, \
- 7, \
- SCSI_NCR_SETUP_LED_PIN, \
- 1, \
- SCSI_NCR_SETUP_SETTLE_TIME, \
- SCSI_NCR_SETUP_DIFF_SUPPORT, \
- 0 \
-}
-
-/*
-** Boot fail safe setup.
-** Override initial setup from boot command line:
-** ncr53c8xx=safe:y
-*/
-#define SCSI_NCR_DRIVER_SAFE_SETUP \
-{ \
- 0, \
- 1, \
- 0, \
- 0, \
- 0, \
- 0, \
- 0, \
- 2, \
- 0, \
- 255, \
- 0x00, \
- 255, \
- 0, \
- 0, \
- 10, \
- 1, \
- 1 \
-}
-
-/*
** Define Scsi_Host_Template parameters
**
** Used by hosts.c and ncr53c8xx.c with module configuration.
@@ -399,6 +303,198 @@ int ncr53c8xx_release(struct Scsi_Host *);
#ifndef HOSTS_C
/*
+** NCR53C8XX Device Ids
+*/
+
+#ifndef PCI_DEVICE_ID_NCR_53C810
+#define PCI_DEVICE_ID_NCR_53C810 1
+#endif
+
+#ifndef PCI_DEVICE_ID_NCR_53C810AP
+#define PCI_DEVICE_ID_NCR_53C810AP 5
+#endif
+
+#ifndef PCI_DEVICE_ID_NCR_53C815
+#define PCI_DEVICE_ID_NCR_53C815 4
+#endif
+
+#ifndef PCI_DEVICE_ID_NCR_53C820
+#define PCI_DEVICE_ID_NCR_53C820 2
+#endif
+
+#ifndef PCI_DEVICE_ID_NCR_53C825
+#define PCI_DEVICE_ID_NCR_53C825 3
+#endif
+
+#ifndef PCI_DEVICE_ID_NCR_53C860
+#define PCI_DEVICE_ID_NCR_53C860 6
+#endif
+
+#ifndef PCI_DEVICE_ID_NCR_53C875
+#define PCI_DEVICE_ID_NCR_53C875 0xf
+#endif
+
+#ifndef PCI_DEVICE_ID_NCR_53C875J
+#define PCI_DEVICE_ID_NCR_53C875J 0x8f
+#endif
+
+#ifndef PCI_DEVICE_ID_NCR_53C885
+#define PCI_DEVICE_ID_NCR_53C885 0xd
+#endif
+
+#ifndef PCI_DEVICE_ID_NCR_53C895
+#define PCI_DEVICE_ID_NCR_53C895 0xc
+#endif
+
+#ifndef PCI_DEVICE_ID_NCR_53C896
+#define PCI_DEVICE_ID_NCR_53C896 0xb
+#endif
+
+/*
+** NCR53C8XX devices features table.
+*/
+typedef struct {
+ unsigned short device_id;
+ unsigned short revision_id;
+ char *name;
+ unsigned char burst_max;
+ unsigned char offset_max;
+ unsigned char nr_divisor;
+ unsigned int features;
+#define _F_LED0 (1<<0)
+#define _F_WIDE (1<<1)
+#define _F_ULTRA (1<<2)
+#define _F_ULTRA2 (1<<3)
+#define _F_DBLR (1<<4)
+#define _F_QUAD (1<<5)
+#define _F_ERL (1<<6)
+#define _F_CLSE (1<<7)
+#define _F_WRIE (1<<8)
+#define _F_ERMP (1<<9)
+#define _F_BOF (1<<10)
+#define _F_DFS (1<<11)
+#define _F_PFEN (1<<12)
+#define _F_LDSTR (1<<13)
+#define _F_RAM (1<<14)
+#define _F_CLK80 (1<<15)
+#define _F_CACHE_SET (_F_ERL|_F_CLSE|_F_WRIE|_F_ERMP)
+#define _F_SCSI_SET (_F_WIDE|_F_ULTRA|_F_ULTRA2|_F_DBLR|_F_QUAD|F_CLK80)
+#define _F_SPECIAL_SET (_F_CACHE_SET|_F_BOF|_F_DFS|_F_LDSTR|_F_PFEN|_F_RAM)
+} ncr_chip;
+
+#define SCSI_NCR_CHIP_TABLE \
+{ \
+ {PCI_DEVICE_ID_NCR_53C810, 0x0f, "810", 4, 8, 4, \
+ _F_ERL} \
+ , \
+ {PCI_DEVICE_ID_NCR_53C810, 0xff, "810a", 4, 8, 4, \
+ _F_CACHE_SET|_F_LDSTR|_F_PFEN|_F_BOF} \
+ , \
+ {PCI_DEVICE_ID_NCR_53C815, 0xff, "815", 4, 8, 4, \
+ _F_ERL|_F_BOF} \
+ , \
+ {PCI_DEVICE_ID_NCR_53C820, 0xff, "820", 4, 8, 4, \
+ _F_WIDE|_F_ERL} \
+ , \
+ {PCI_DEVICE_ID_NCR_53C825, 0x0f, "825", 4, 8, 4, \
+ _F_WIDE|_F_ERL|_F_BOF} \
+ , \
+ {PCI_DEVICE_ID_NCR_53C825, 0xff, "825a", 7, 8, 4, \
+ _F_WIDE|_F_CACHE_SET|_F_BOF|_F_DFS|_F_LDSTR|_F_PFEN|_F_RAM} \
+ , \
+ {PCI_DEVICE_ID_NCR_53C860, 0xff, "860", 4, 8, 5, \
+ _F_WIDE|_F_ULTRA|_F_CLK80|_F_CACHE_SET|_F_BOF|_F_LDSTR|_F_PFEN|_F_RAM} \
+ , \
+ {PCI_DEVICE_ID_NCR_53C875, 0x01, "875", 7, 16, 5, \
+ _F_WIDE|_F_ULTRA|_F_CLK80|_F_CACHE_SET|_F_BOF|_F_DFS|_F_LDSTR|_F_PFEN|_F_RAM} \
+ , \
+ {PCI_DEVICE_ID_NCR_53C875, 0xff, "875", 7, 16, 5, \
+ _F_WIDE|_F_ULTRA|_F_DBLR|_F_CACHE_SET|_F_BOF|_F_DFS|_F_LDSTR|_F_PFEN|_F_RAM} \
+ , \
+ {PCI_DEVICE_ID_NCR_53C875J, 0xff, "875J", 7, 16, 5, \
+ _F_WIDE|_F_ULTRA|_F_DBLR|_F_CACHE_SET|_F_BOF|_F_DFS|_F_LDSTR|_F_PFEN|_F_RAM} \
+ , \
+ {PCI_DEVICE_ID_NCR_53C885, 0xff, "885", 7, 16, 5, \
+ _F_WIDE|_F_ULTRA|_F_DBLR|_F_CACHE_SET|_F_BOF|_F_DFS|_F_LDSTR|_F_PFEN|_F_RAM} \
+ , \
+ {PCI_DEVICE_ID_NCR_53C895, 0xff, "895", 7, 31, 7, \
+ _F_WIDE|_F_ULTRA|_F_ULTRA2|_F_QUAD|_F_CACHE_SET|_F_BOF|_F_DFS|_F_LDSTR|_F_PFEN|_F_RAM} \
+ , \
+ {PCI_DEVICE_ID_NCR_53C896, 0xff, "896", 7, 31, 7, \
+ _F_WIDE|_F_ULTRA|_F_ULTRA2|_F_QUAD|_F_CACHE_SET|_F_BOF|_F_DFS|_F_LDSTR|_F_PFEN|_F_RAM} \
+}
+
+/*
+ * List of supported NCR chip ids
+ */
+#define SCSI_NCR_CHIP_IDS \
+{ \
+ PCI_DEVICE_ID_NCR_53C810, \
+ PCI_DEVICE_ID_NCR_53C815, \
+ PCI_DEVICE_ID_NCR_53C820, \
+ PCI_DEVICE_ID_NCR_53C825, \
+ PCI_DEVICE_ID_NCR_53C860, \
+ PCI_DEVICE_ID_NCR_53C875, \
+ PCI_DEVICE_ID_NCR_53C875J, \
+ PCI_DEVICE_ID_NCR_53C885, \
+ PCI_DEVICE_ID_NCR_53C895, \
+ PCI_DEVICE_ID_NCR_53C896 \
+}
+
+/*
+** Initial setup.
+** Can be overriden at startup by a command line.
+*/
+#define SCSI_NCR_DRIVER_SETUP \
+{ \
+ SCSI_NCR_SETUP_MASTER_PARITY, \
+ SCSI_NCR_SETUP_SCSI_PARITY, \
+ SCSI_NCR_SETUP_DISCONNECTION, \
+ SCSI_NCR_SETUP_SPECIAL_FEATURES, \
+ SCSI_NCR_SETUP_ULTRA_SCSI, \
+ SCSI_NCR_SETUP_FORCE_SYNC_NEGO, \
+ 0, \
+ 0, \
+ 1, \
+ SCSI_NCR_SETUP_DEFAULT_TAGS, \
+ SCSI_NCR_SETUP_DEFAULT_SYNC, \
+ 0x00, \
+ 7, \
+ SCSI_NCR_SETUP_LED_PIN, \
+ 1, \
+ SCSI_NCR_SETUP_SETTLE_TIME, \
+ SCSI_NCR_SETUP_DIFF_SUPPORT, \
+ 0 \
+}
+
+/*
+** Boot fail safe setup.
+** Override initial setup from boot command line:
+** ncr53c8xx=safe:y
+*/
+#define SCSI_NCR_DRIVER_SAFE_SETUP \
+{ \
+ 0, \
+ 1, \
+ 0, \
+ 0, \
+ 0, \
+ 0, \
+ 0, \
+ 0, \
+ 2, \
+ 0, \
+ 255, \
+ 0x00, \
+ 255, \
+ 0, \
+ 0, \
+ 10, \
+ 1, \
+ 1 \
+}
+
+/*
** Define the table of target capabilities by host and target
**
** If you have problems with a scsi device, note the host unit and the
@@ -486,50 +582,6 @@ int ncr53c8xx_release(struct Scsi_Host *);
#endif
#endif
-/*
-** NCR53C8XX Device Ids
-*/
-
-#ifndef PCI_DEVICE_ID_NCR_53C810
-#define PCI_DEVICE_ID_NCR_53C810 1
-#endif
-
-#ifndef PCI_DEVICE_ID_NCR_53C810AP
-#define PCI_DEVICE_ID_NCR_53C810AP 5
-#endif
-
-#ifndef PCI_DEVICE_ID_NCR_53C815
-#define PCI_DEVICE_ID_NCR_53C815 4
-#endif
-
-#ifndef PCI_DEVICE_ID_NCR_53C820
-#define PCI_DEVICE_ID_NCR_53C820 2
-#endif
-
-#ifndef PCI_DEVICE_ID_NCR_53C825
-#define PCI_DEVICE_ID_NCR_53C825 3
-#endif
-
-#ifndef PCI_DEVICE_ID_NCR_53C860
-#define PCI_DEVICE_ID_NCR_53C860 6
-#endif
-
-#ifndef PCI_DEVICE_ID_NCR_53C875
-#define PCI_DEVICE_ID_NCR_53C875 0xf
-#endif
-
-#ifndef PCI_DEVICE_ID_NCR_53C885
-#define PCI_DEVICE_ID_NCR_53C885 0xd
-#endif
-
-#ifndef PCI_DEVICE_ID_NCR_53C895
-#define PCI_DEVICE_ID_NCR_53C895 0xc
-#endif
-
-#ifndef PCI_DEVICE_ID_NCR_53C896
-#define PCI_DEVICE_ID_NCR_53C896 0xb
-#endif
-
/**************** ORIGINAL CONTENT of ncrreg.h from FreeBSD ******************/
/*-----------------------------------------------------------------
@@ -608,6 +660,7 @@ struct ncr_reg {
#define ILF1 0x80 /* sta: data in SIDL register msb[W]*/
#define ORF1 0x40 /* sta: data in SODR register msb[W]*/
#define OLF1 0x20 /* sta: data in SODL register msb[W]*/
+ #define DM 0x04 /* sta: DIFFSENS mismatch (895/6 only) */
#define LDSC 0x02 /* sta: disconnect & reconnect */
/*10*/ u_int32 nc_dsa; /* --> Base page */
@@ -680,6 +733,7 @@ struct ncr_reg {
/*40*/ u_short nc_sien; /* -->: interrupt enable */
/*42*/ u_short nc_sist; /* <--: interrupt status */
+ #define SBMC 0x1000/* sta: SCSI Bus Mode Change (895/6 only) */
#define STO 0x0400/* sta: timeout (select) */
#define GEN 0x0200/* sta: timeout (general) */
#define HTH 0x0100/* sta: timeout (handshake) */
@@ -713,10 +767,17 @@ struct ncr_reg {
/*4f*/ u_char nc_stest3;
#define TE 0x80 /* c: tolerAnt enable */
+ #define HSC 0x20 /* c: Halt SCSI Clock */
#define CSF 0x02 /* c: clear scsi fifo */
/*50*/ u_short nc_sidl; /* Lowlevel: latched from scsi data */
/*52*/ u_char nc_stest4;
+ #define SMODE 0xc0 /* SCSI bus mode (895/6 only) */
+ #define SMODE_HVD 0x40 /* High Voltage Differential */
+ #define SMODE_SE 0x80 /* Single Ended */
+ #define SMODE_LVD 0xc0 /* Low Voltage Differential */
+ #define LCKFRQ 0x20 /* Frequency Lock (895/6 only) */
+
/*53*/ u_char nc_53_;
/*54*/ u_short nc_sodl; /* Lowlevel: data out to scsi data */
/*56*/ u_short nc_56_;
@@ -870,10 +931,18 @@ struct scr_tblsel {
** << source_address >>
** << destination_address >>
**
+** SCR_COPY sets the NO FLUSH option by default.
+** SCR_COPY_F does not set this option.
+**
+** For chips which do not support this option,
+** ncr_copy_and_bind() will remove this bit.
**-----------------------------------------------------------
*/
-#define SCR_COPY(n) (0xc0000000 | (n))
+#define SCR_NO_FLUSH 0x01000000
+
+#define SCR_COPY(n) (0xc0000000 | SCR_NO_FLUSH | (n))
+#define SCR_COPY_F(n) (0xc0000000 | (n))
/*-----------------------------------------------------------
**
@@ -979,6 +1048,7 @@ struct scr_tblsel {
**-----------------------------------------------------------
*/
+#define SCR_NO_OP 0x80000000
#define SCR_JUMP 0x80080000
#define SCR_JUMPR 0x80880000
#define SCR_CALL 0x88080000
diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c
index 54658955f..e9d80501f 100644
--- a/drivers/scsi/qlogicpti.c
+++ b/drivers/scsi/qlogicpti.c
@@ -8,6 +8,8 @@
* An even bigger kudos to John Grana at Performance Technologies
* for providing me with the hardware to write this driver, you rule
* John you really do.
+ *
+ * May, 2, 1997: Added support for QLGC,isp --jj
*/
#include <linux/kernel.h>
@@ -573,6 +575,7 @@ __initfunc(int qlogicpti_detect(Scsi_Host_Template *tpnt))
unsigned char bsizes, bsizes_more;
int nqptis = 0, nqptis_in_use = 0;
int qpti_node;
+ int is_pti;
tpnt->proc_dir = &proc_scsi_qlogicpti;
qptichain = 0;
@@ -584,7 +587,8 @@ __initfunc(int qlogicpti_detect(Scsi_Host_Template *tpnt))
/* Is this a red snapper? */
if(strcmp(qpti_dev->prom_name, "ptisp") &&
- strcmp(qpti_dev->prom_name, "PTI,ptisp"))
+ strcmp(qpti_dev->prom_name, "PTI,ptisp") &&
+ strcmp(qpti_dev->prom_name, "QLGC,isp"))
continue;
/* Yep, register and allocate software state. */
@@ -618,6 +622,8 @@ __initfunc(int qlogicpti_detect(Scsi_Host_Template *tpnt))
prom_getstring(qpti_node, "name", qpti->prom_name,
sizeof(qpti->prom_name));
qpti->prom_node = qpti_node;
+
+ is_pti = strcmp (qpti->prom_name, "QLGC,isp");
/* Setup the reg property for this device. */
prom_apply_sbus_ranges(qpti->qdev->my_bus,
@@ -632,17 +638,19 @@ __initfunc(int qlogicpti_detect(Scsi_Host_Template *tpnt))
qpti->qdev->reg_addrs[0].which_io, 0x0);
if(!qregs)
panic("PTI Qlogic/ISP registers unmappable");
-
- /* Map this one read only. */
- qpti->sreg = sreg = (volatile unsigned char *)
- sparc_alloc_io((qpti->qdev->reg_addrs[0].phys_addr +
- (16 * PAGE_SIZE)), 0,
- sizeof(unsigned char),
- "PTI Qlogic/ISP Status Reg",
- qpti->qdev->reg_addrs[0].which_io, 1);
- if(!sreg)
- panic("PTI Qlogic/ISP status reg unmappable");
- qpti->swsreg = 0;
+
+ if(is_pti) {
+ /* Map this one read only. */
+ qpti->sreg = sreg = (volatile unsigned char *)
+ sparc_alloc_io((qpti->qdev->reg_addrs[0].phys_addr +
+ (16 * PAGE_SIZE)), 0,
+ sizeof(unsigned char),
+ "PTI Qlogic/ISP Status Reg",
+ qpti->qdev->reg_addrs[0].which_io, 1);
+ if(!sreg)
+ panic("PTI Qlogic/ISP status reg unmappable");
+ qpti->swsreg = 0;
+ }
qpti_host->base = (unsigned char *)qregs;
qpti_host->io_port = (unsigned int) qregs;
@@ -713,21 +721,32 @@ qpti_irq_acquired:
/* Set adapter and per-device default values. */
qlogicpti_set_hostdev_defaults(qpti);
-
- /* Load the firmware. */
- if(qlogicpti_load_firmware(qpti))
- panic("PTI Qlogic/ISP firmware load failed");
-
- /* Check the PTI status reg. */
- if(qlogicpti_verify_tmon(qpti))
- panic("PTI Qlogic/ISP tmon verification failed");
+
+ if (is_pti) {
+ /* Load the firmware. */
+ if(qlogicpti_load_firmware(qpti))
+ panic("PTI Qlogic/ISP firmware load failed");
+
+ /* Check the PTI status reg. */
+ if(qlogicpti_verify_tmon(qpti))
+ panic("PTI Qlogic/ISP tmon verification failed");
+ }
/* Reset the ISP and init res/req queues. */
if(qlogicpti_reset_hardware(qpti_host))
panic("PTI Qlogic/ISP cannot be reset");
- printk("(Firmware v%d.%d) [%s Wide, using %s interface]\n",
- qpti->fware_majrev, qpti->fware_minrev,
+ if (is_pti) {
+ printk("(Firmware v%d.%d)",
+ qpti->fware_majrev, qpti->fware_minrev);
+ } else {
+ char buffer[60];
+
+ prom_getstring (qpti_node, "isp-fcode", buffer, 60);
+ printk("(Firmware %s)", buffer);
+ }
+
+ printk (" [%s Wide, using %s interface]\n",
(qpti->ultra ? "Ultra" : "Fast"),
(qpti->differential ? "differential" : "single ended"));
@@ -751,7 +770,9 @@ int qlogicpti_release(struct Scsi_Host *host)
/* Free IRQ handler and unmap Qlogic,ISP and PTI status regs. */
free_irq(host->irq, NULL);
unmapioaddr((unsigned long)qregs);
- unmapioaddr((unsigned long)qpti->sreg);
+ /* QLGC,isp doesn't have status reg */
+ if (strcmp (qpti->prom_name, "QLGC,isp"))
+ unmapioaddr((unsigned long)qpti->sreg);
return 0;
}
diff --git a/drivers/scsi/scsi.h b/drivers/scsi/scsi.h
index 4f9fdad07..c447f8658 100644
--- a/drivers/scsi/scsi.h
+++ b/drivers/scsi/scsi.h
@@ -218,7 +218,13 @@ extern int scsi_dev_init (void);
#include <asm/scatterlist.h>
+#ifdef __mc68000__
+#include <asm/pgtable.h>
+#define CONTIGUOUS_BUFFERS(X,Y) \
+ (VTOP((X)->b_data+(X)->b_size-1)+1 == VTOP((Y)->b_data))
+#else
#define CONTIGUOUS_BUFFERS(X,Y) ((X->b_data+X->b_size) == Y->b_data)
+#endif
/*
diff --git a/drivers/scsi/scsi_proc.c b/drivers/scsi/scsi_proc.c
index aca31e7c7..83c21c20b 100644
--- a/drivers/scsi/scsi_proc.c
+++ b/drivers/scsi/scsi_proc.c
@@ -11,6 +11,9 @@
*
* generic command parser provided by:
* Andreas Heilwagen <crashcar@informatik.uni-koblenz.de>
+ *
+ * generic_proc_info() support of xxxx_info() by:
+ * Michael A. Griffith <grif@acm.org>
*/
/*
@@ -48,7 +51,9 @@ struct scsi_dir {
* Used if the driver currently has no own support for /proc/scsi
*/
int generic_proc_info(char *buffer, char **start, off_t offset,
- int length, int inode, int inout)
+ int length, int inode, int inout,
+ const char *(*info)(struct Scsi_Host *),
+ struct Scsi_Host *sh)
{
int len, pos, begin;
@@ -56,8 +61,13 @@ int generic_proc_info(char *buffer, char **start, off_t offset,
return(-ENOSYS); /* This is a no-op */
begin = 0;
- pos = len = sprintf(buffer,
- "The driver does not yet support the proc-fs\n");
+ if (info && sh) {
+ pos = len = sprintf(buffer, "%s\n", info(sh));
+ }
+ else {
+ pos = len = sprintf(buffer,
+ "The driver does not yet support the proc-fs\n");
+ }
if(pos < offset) {
len = 0;
begin = pos;
@@ -91,7 +101,9 @@ extern int dispatch_scsi_info(int ino, char *buffer, char **start,
if (ino == (hpnt->host_no + PROC_SCSI_FILE)) {
if(hpnt->hostt->proc_info == NULL)
return generic_proc_info(buffer, start, offset, length,
- hpnt->host_no, func);
+ hpnt->host_no, func,
+ hpnt->hostt->info,
+ hpnt);
else
return(hpnt->hostt->proc_info(buffer, start, offset,
length, hpnt->host_no, func));
diff --git a/drivers/scsi/scsiiom.c b/drivers/scsi/scsiiom.c
new file mode 100644
index 000000000..97801d755
--- /dev/null
+++ b/drivers/scsi/scsiiom.c
@@ -0,0 +1,1540 @@
+/***********************************************************************
+ * FILE NAME : SCSIIOM.C *
+ * BY : C.L. Huang, ching@tekram.com.tw *
+ * Description: Device Driver for Tekram DC-390 (T) PCI SCSI *
+ * Bus Master Host Adapter *
+ ***********************************************************************/
+
+
+static USHORT
+DC390_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB )
+{
+ USHORT ioport, rc;
+ UCHAR bval, bval1, i, cnt;
+ PUCHAR ptr;
+ ULONG wlval;
+
+ pSRB->TagNumber = 31;
+ ioport = pACB->IOPortBase;
+ bval = pDCB->UnitSCSIID;
+ outb(bval,ioport+Scsi_Dest_ID);
+ bval = pDCB->SyncPeriod;
+ outb(bval,ioport+Sync_Period);
+ bval = pDCB->SyncOffset;
+ outb(bval,ioport+Sync_Offset);
+ bval = pDCB->CtrlR1;
+ outb(bval,ioport+CtrlReg1);
+ bval = pDCB->CtrlR3;
+ outb(bval,ioport+CtrlReg3);
+ bval = pDCB->CtrlR4;
+ outb(bval,ioport+CtrlReg4);
+ bval = CLEAR_FIFO_CMD; /* Flush FIFO */
+ outb(bval,ioport+ScsiCmd);
+
+ pSRB->ScsiPhase = SCSI_NOP0;
+ bval = pDCB->IdentifyMsg;
+ if( !(pDCB->SyncMode & EN_ATN_STOP) )
+ {
+ if( (pSRB->CmdBlock[0] == INQUIRY) ||
+ (pSRB->CmdBlock[0] == REQUEST_SENSE) ||
+ (pSRB->SRBFlag & AUTO_REQSENSE) )
+ {
+ bval &= 0xBF; /* NO disconnection */
+ outb(bval,ioport+ScsiFifo);
+ bval1 = SELECT_W_ATN;
+ pSRB->SRBState = SRB_START_;
+ if( pDCB->SyncMode & SYNC_ENABLE )
+ {
+ if( !(pDCB->IdentifyMsg & 7) ||
+ (pSRB->CmdBlock[0] != INQUIRY) )
+ {
+ bval1 = SEL_W_ATN_STOP;
+ pSRB->SRBState = SRB_MSGOUT;
+ }
+ }
+ }
+ else
+ {
+ if(pDCB->SyncMode & EN_TAG_QUEUING)
+ {
+ outb(bval,ioport+ScsiFifo);
+ bval = MSG_SIMPLE_QTAG;
+ outb(bval,ioport+ScsiFifo);
+ wlval = 1;
+ bval = 0;
+ while( wlval & pDCB->TagMask )
+ {
+ wlval = wlval << 1;
+ bval++;
+ }
+ outb(bval,ioport+ScsiFifo);
+ pDCB->TagMask |= wlval;
+ pSRB->TagNumber = bval;
+ bval1 = SEL_W_ATN2;
+ pSRB->SRBState = SRB_START_;
+ }
+ else
+ {
+ outb(bval,ioport+ScsiFifo);
+ bval1 = SELECT_W_ATN;
+ pSRB->SRBState = SRB_START_;
+ }
+ }
+
+ if( pSRB->SRBFlag & AUTO_REQSENSE )
+ {
+ bval = REQUEST_SENSE;
+ outb(bval,ioport+ScsiFifo);
+ bval = pDCB->IdentifyMsg << 5;
+ outb(bval,ioport+ScsiFifo);
+ bval = 0;
+ outb(bval,ioport+ScsiFifo);
+ outb(bval,ioport+ScsiFifo);
+ bval = sizeof(pSRB->pcmd->sense_buffer);
+ outb(bval,ioport+ScsiFifo);
+ bval = 0;
+ outb(bval,ioport+ScsiFifo);
+ }
+ else
+ {
+ cnt = pSRB->ScsiCmdLen;
+ ptr = (PUCHAR) pSRB->CmdBlock;
+ for(i=0; i<cnt; i++)
+ {
+ bval = *ptr++;
+ outb(bval,ioport+ScsiFifo);
+ }
+ }
+ }
+ else /* ATN_STOP */
+ {
+ if( (pSRB->CmdBlock[0] == INQUIRY) ||
+ (pSRB->CmdBlock[0] == REQUEST_SENSE) ||
+ (pSRB->SRBFlag & AUTO_REQSENSE) )
+ {
+ bval &= 0xBF;
+ outb(bval,ioport+ScsiFifo);
+ bval1 = SELECT_W_ATN;
+ pSRB->SRBState = SRB_START_;
+ if( pDCB->SyncMode & SYNC_ENABLE )
+ {
+ if( !(pDCB->IdentifyMsg & 7) ||
+ (pSRB->CmdBlock[0] != INQUIRY) )
+ {
+ bval1 = SEL_W_ATN_STOP;
+ pSRB->SRBState = SRB_MSGOUT;
+ }
+ }
+ }
+ else
+ {
+ if(pDCB->SyncMode & EN_TAG_QUEUING)
+ {
+ outb(bval,ioport+ScsiFifo);
+ pSRB->MsgOutBuf[0] = MSG_SIMPLE_QTAG;
+ wlval = 1;
+ bval = 0;
+ while( wlval & pDCB->TagMask )
+ {
+ wlval = wlval << 1;
+ bval++;
+ }
+ pDCB->TagMask |= wlval;
+ pSRB->TagNumber = bval;
+ pSRB->MsgOutBuf[1] = bval;
+ pSRB->MsgCnt = 2;
+ bval1 = SEL_W_ATN_STOP;
+ pSRB->SRBState = SRB_START_;
+ }
+ else
+ {
+ outb(bval,ioport+ScsiFifo);
+ pSRB->MsgOutBuf[0] = MSG_NOP;
+ pSRB->MsgCnt = 1;
+ pSRB->SRBState = SRB_START_;
+ bval1 = SEL_W_ATN_STOP;
+ }
+ }
+ }
+ bval = inb( ioport+Scsi_Status );
+ if( bval & INTERRUPT )
+ {
+ pSRB->SRBState = SRB_READY;
+ pDCB->TagMask &= ~( 1 << pSRB->TagNumber );
+ rc = 1;
+ }
+ else
+ {
+ pSRB->ScsiPhase = SCSI_NOP1;
+ pACB->pActiveDCB = pDCB;
+ pDCB->pActiveSRB = pSRB;
+ rc = 0;
+ outb(bval1,ioport+ScsiCmd);
+ }
+ return( rc );
+}
+
+
+#ifndef VERSION_ELF_1_2_13
+static void
+DC390_Interrupt( int irq, void *dev_id, struct pt_regs *regs)
+#else
+static void
+DC390_Interrupt( int irq, struct pt_regs *regs)
+#endif
+{
+ PACB pACB;
+ PDCB pDCB;
+ PSRB pSRB;
+ USHORT ioport = 0;
+ USHORT phase, i;
+ void (*stateV)( PACB, PSRB, PUCHAR );
+ UCHAR istate = 0;
+ UCHAR sstatus=0, istatus;
+
+ pACB = pACB_start;
+ if( pACB == NULL )
+ return;
+ for( i=0; i < adapterCnt; i++ )
+ {
+ if( pACB->IRQLevel == (UCHAR) irq )
+ {
+ ioport = pACB->IOPortBase;
+ sstatus = inb( ioport+Scsi_Status );
+ if( sstatus & INTERRUPT )
+ break;
+ else
+ pACB = pACB->pNextACB;
+ }
+ else
+ {
+ pACB = pACB->pNextACB;
+ }
+ }
+
+#ifdef DC390_DEBUG1
+ printk("sstatus=%2x,",sstatus);
+#endif
+
+ if( pACB == (PACB )-1 )
+ {
+ printk("DC390: Spurious interrupt detected!\n");
+ return;
+ }
+
+ istate = inb( ioport+Intern_State );
+ istatus = inb( ioport+INT_Status );
+
+#ifdef DC390_DEBUG1
+ printk("Istatus=%2x,",istatus);
+#endif
+
+ if(istatus & DISCONNECTED)
+ {
+ DC390_Disconnect( pACB );
+ return;
+ }
+
+ if(istatus & RESELECTED)
+ {
+ DC390_Reselect( pACB );
+ return;
+ }
+
+ if(istatus & INVALID_CMD)
+ {
+ DC390_InvalidCmd( pACB );
+ return;
+ }
+
+ if(istatus & SCSI_RESET)
+ {
+ DC390_ScsiRstDetect( pACB );
+ return;
+ }
+
+ if( istatus & (SUCCESSFUL_OP+SERVICE_REQUEST) )
+ {
+ pDCB = pACB->pActiveDCB;
+ pSRB = pDCB->pActiveSRB;
+ if( pDCB )
+ {
+ if( pDCB->DCBFlag & ABORT_DEV_ )
+ EnableMsgOut( pACB, pSRB );
+ }
+
+ phase = (USHORT) pSRB->ScsiPhase;
+ stateV = (void *) DC390_phase0[phase];
+ stateV( pACB, pSRB, &sstatus );
+
+ pSRB->ScsiPhase = sstatus & 7;
+ phase = (USHORT) sstatus & 7;
+ stateV = (void *) DC390_phase1[phase];
+ stateV( pACB, pSRB, &sstatus );
+ }
+}
+
+
+static void
+DC390_DataOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
+ UCHAR sstatus, bval;
+ USHORT ioport;
+ PSGL psgl;
+ ULONG ResidCnt, xferCnt;
+
+ ioport = pACB->IOPortBase;
+ sstatus = *psstatus;
+
+ if( !(pSRB->SRBState & SRB_XFERPAD) )
+ {
+ if( sstatus & PARITY_ERR )
+ pSRB->SRBStatus |= PARITY_ERROR;
+
+ if( sstatus & COUNT_2_ZERO )
+ {
+ bval = inb(ioport+DMA_Status);
+ while( !(bval & DMA_XFER_DONE) )
+ bval = inb(ioport+DMA_Status);
+ pSRB->TotalXferredLen += pSRB->SGToBeXferLen;
+ pSRB->SGIndex++;
+ if( pSRB->SGIndex < pSRB->SGcount )
+ {
+ pSRB->pSegmentList++;
+ psgl = pSRB->pSegmentList;
+
+#ifndef VERSION_ELF_1_2_13
+ pSRB->SGPhysAddr = virt_to_phys( psgl->address );
+#else
+ pSRB->SGPhysAddr = (ULONG) psgl->address;
+#endif
+ pSRB->SGToBeXferLen = (ULONG) psgl->length;
+ }
+ else
+ pSRB->SGToBeXferLen = 0;
+ }
+ else
+ {
+ bval = inb( ioport+Current_Fifo );
+ bval &= 0x1f;
+ ResidCnt = (ULONG) inb(ioport+CtcReg_High);
+ ResidCnt = ResidCnt << 8;
+ ResidCnt |= (ULONG) inb(ioport+CtcReg_Mid);
+ ResidCnt = ResidCnt << 8;
+ ResidCnt |= (ULONG) inb(ioport+CtcReg_Low);
+ ResidCnt += (ULONG) bval;
+
+ xferCnt = pSRB->SGToBeXferLen - ResidCnt;
+ pSRB->SGPhysAddr += xferCnt;
+ pSRB->TotalXferredLen += xferCnt;
+ pSRB->SGToBeXferLen = ResidCnt;
+ }
+ }
+ bval = WRITE_DIRECTION+DMA_IDLE_CMD;
+ outb( bval, ioport+DMA_Cmd);
+}
+
+static void
+DC390_DataIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
+ UCHAR sstatus, bval;
+ USHORT i, ioport, residual;
+ PSGL psgl;
+ ULONG ResidCnt, xferCnt;
+ PUCHAR ptr;
+
+
+ ioport = pACB->IOPortBase;
+ sstatus = *psstatus;
+
+ if( !(pSRB->SRBState & SRB_XFERPAD) )
+ {
+ if( sstatus & PARITY_ERR )
+ pSRB->SRBStatus |= PARITY_ERROR;
+
+ if( sstatus & COUNT_2_ZERO )
+ {
+ bval = inb(ioport+DMA_Status);
+ while( !(bval & DMA_XFER_DONE) )
+ bval = inb(ioport+DMA_Status);
+
+ bval = READ_DIRECTION+DMA_IDLE_CMD;
+ outb( bval, ioport+DMA_Cmd);
+
+ pSRB->TotalXferredLen += pSRB->SGToBeXferLen;
+ pSRB->SGIndex++;
+ if( pSRB->SGIndex < pSRB->SGcount )
+ {
+ pSRB->pSegmentList++;
+ psgl = pSRB->pSegmentList;
+
+#ifndef VERSION_ELF_1_2_13
+ pSRB->SGPhysAddr = virt_to_phys( psgl->address );
+#else
+ pSRB->SGPhysAddr = (ULONG) psgl->address;
+#endif
+ pSRB->SGToBeXferLen = (ULONG) psgl->length;
+ }
+ else
+ pSRB->SGToBeXferLen = 0;
+ }
+ else /* phase changed */
+ {
+ residual = 0;
+ bval = inb(ioport+Current_Fifo);
+ while( bval & 0x1f )
+ {
+ if( (bval & 0x1f) == 1 )
+ {
+ for(i=0; i< 0x100; i++)
+ {
+ bval = inb(ioport+Current_Fifo);
+ if( !(bval & 0x1f) )
+ goto din_1;
+ else if( i == 0x0ff )
+ {
+ residual = 1; /* ;1 residual byte */
+ goto din_1;
+ }
+ }
+ }
+ else
+ bval = inb(ioport+Current_Fifo);
+ }
+din_1:
+ bval = READ_DIRECTION+DMA_BLAST_CMD;
+ outb(bval, ioport+DMA_Cmd);
+ for(i=0; i<0x8000; i++)
+ {
+ bval = inb(ioport+DMA_Status);
+ if(bval & BLAST_COMPLETE)
+ break;
+ }
+ bval = READ_DIRECTION+DMA_IDLE_CMD;
+ outb(bval, ioport+DMA_Cmd);
+
+ ResidCnt = (ULONG) inb(ioport+CtcReg_High);
+ ResidCnt = ResidCnt << 8;
+ ResidCnt |= (ULONG) inb(ioport+CtcReg_Mid);
+ ResidCnt = ResidCnt << 8;
+ ResidCnt |= (ULONG) inb(ioport+CtcReg_Low);
+
+ xferCnt = pSRB->SGToBeXferLen - ResidCnt;
+ pSRB->SGPhysAddr += xferCnt;
+ pSRB->TotalXferredLen += xferCnt;
+ pSRB->SGToBeXferLen = ResidCnt;
+
+ if( residual )
+ {
+ bval = inb(ioport+ScsiFifo); /* get residual byte */
+#ifndef VERSION_ELF_1_2_13
+ ptr = (PUCHAR) phys_to_virt( pSRB->SGPhysAddr );
+#else
+ ptr = (PUCHAR) pSRB->SGPhysAddr;
+#endif
+ *ptr = bval;
+ pSRB->SGPhysAddr++;
+ pSRB->TotalXferredLen++;
+ pSRB->SGToBeXferLen--;
+ }
+ }
+ }
+}
+
+static void
+DC390_Command_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
+}
+
+static void
+DC390_Status_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
+ UCHAR bval;
+ USHORT ioport;
+
+ ioport = pACB->IOPortBase;
+ bval = inb(ioport+ScsiFifo);
+ pSRB->TargetStatus = bval;
+ bval++;
+ bval = inb(ioport+ScsiFifo); /* get message */
+ pSRB->EndMessage = bval;
+
+ *psstatus = SCSI_NOP0;
+ pSRB->SRBState = SRB_COMPLETED;
+ bval = MSG_ACCEPTED_CMD;
+ outb(bval, ioport+ScsiCmd);
+}
+
+static void
+DC390_MsgOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
+ if( pSRB->SRBState & (SRB_UNEXPECT_RESEL+SRB_ABORT_SENT) )
+ *psstatus = SCSI_NOP0;
+}
+
+static void
+DC390_MsgIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
+ UCHAR bval;
+ USHORT ioport, wval, wval1;
+ PDCB pDCB;
+ PSRB psrb;
+
+ ioport = pACB->IOPortBase;
+ pDCB = pACB->pActiveDCB;
+
+ bval = inb( ioport+ScsiFifo );
+ if( !(pSRB->SRBState & SRB_MSGIN_MULTI) )
+ {
+ if(bval == MSG_DISCONNECT)
+ {
+ pSRB->SRBState = SRB_DISCONNECT;
+ }
+ else if( bval == MSG_SAVE_PTR )
+ goto min6;
+ else if( (bval == MSG_EXTENDED) || ((bval >= MSG_SIMPLE_QTAG) &&
+ (bval <= MSG_ORDER_QTAG)) )
+ {
+ pSRB->SRBState |= SRB_MSGIN_MULTI;
+ pSRB->MsgInBuf[0] = bval;
+ pSRB->MsgCnt = 1;
+ pSRB->pMsgPtr = &pSRB->MsgInBuf[1];
+ }
+ else if(bval == MSG_REJECT_)
+ {
+ bval = RESET_ATN_CMD;
+ outb(bval, ioport+ScsiCmd);
+ if( pSRB->SRBState & DO_SYNC_NEGO)
+ goto set_async;
+ }
+ else if( bval == MSG_RESTORE_PTR)
+ goto min6;
+ else
+ goto min6;
+ }
+ else
+ { /* minx: */
+
+ *pSRB->pMsgPtr = bval;
+ pSRB->MsgCnt++;
+ pSRB->pMsgPtr++;
+ if( (pSRB->MsgInBuf[0] >= MSG_SIMPLE_QTAG) &&
+ (pSRB->MsgInBuf[0] <= MSG_ORDER_QTAG) )
+ {
+ if( pSRB->MsgCnt == 2)
+ {
+ pSRB->SRBState = 0;
+ bval = pSRB->MsgInBuf[1];
+ pSRB = pDCB->pGoingSRB;
+ psrb = pDCB->pGoingLast;
+ if( pSRB )
+ {
+ for( ;; )
+ {
+ if(pSRB->TagNumber != bval)
+ {
+ if( pSRB == psrb )
+ goto mingx0;
+ pSRB = pSRB->pNextSRB;
+ }
+ else
+ break;
+ }
+ if( pDCB->DCBFlag & ABORT_DEV_ )
+ {
+ pSRB->SRBState = SRB_ABORT_SENT;
+ EnableMsgOut( pACB, pSRB );
+ }
+ if( !(pSRB->SRBState & SRB_DISCONNECT) )
+ goto mingx0;
+ pDCB->pActiveSRB = pSRB;
+ pSRB->SRBState = SRB_DATA_XFER;
+ }
+ else
+ {
+mingx0:
+ pSRB = pACB->pTmpSRB;
+ pSRB->SRBState = SRB_UNEXPECT_RESEL;
+ pDCB->pActiveSRB = pSRB;
+ pSRB->MsgOutBuf[0] = MSG_ABORT_TAG;
+ EnableMsgOut2( pACB, pSRB );
+ }
+ }
+ }
+ else if( (pSRB->MsgInBuf[0] == MSG_EXTENDED) && (pSRB->MsgCnt == 5) )
+ {
+ pSRB->SRBState &= ~(SRB_MSGIN_MULTI+DO_SYNC_NEGO);
+ if( (pSRB->MsgInBuf[1] != 3) || (pSRB->MsgInBuf[2] != 1) )
+ { /* reject_msg: */
+ pSRB->MsgCnt = 1;
+ pSRB->MsgInBuf[0] = MSG_REJECT_;
+ bval = SET_ATN_CMD;
+ outb(bval, ioport+ScsiCmd);
+ }
+ else if( !(pSRB->MsgInBuf[3]) || !(pSRB->MsgInBuf[4]) )
+ {
+set_async:
+ pDCB = pSRB->pSRBDCB;
+ pDCB->SyncMode &= ~(SYNC_ENABLE+SYNC_NEGO_DONE);
+ pDCB->SyncPeriod = 0;
+ pDCB->SyncOffset = 0;
+ pDCB->CtrlR3 = FAST_CLK; /* ;non_fast */
+ pDCB->CtrlR4 &= 0x3f;
+ pDCB->CtrlR4 |= EATER_25NS; /* ; 25ns glitch eater */
+ goto re_prog;
+ }
+ else
+ { /* set_sync: */
+
+ pDCB = pSRB->pSRBDCB;
+ pDCB->SyncMode |= SYNC_ENABLE+SYNC_NEGO_DONE;
+ pDCB->SyncOffset &= 0x0f0;
+ pDCB->SyncOffset |= pSRB->MsgInBuf[4];
+ pDCB->NegoPeriod = pSRB->MsgInBuf[3];
+ wval = (USHORT) pSRB->MsgInBuf[3];
+ wval = wval << 2;
+ wval--;
+ wval1 = wval / 25;
+ if( (wval1 * 25) != wval)
+ wval1++;
+ bval = FAST_CLK+FAST_SCSI;
+ pDCB->CtrlR4 &= 0x3f;
+ if(wval1 >= 8)
+ {
+ wval1--;
+ bval = FAST_CLK; /* ;fast clock/normal scsi */
+ pDCB->CtrlR4 |= EATER_25NS; /* ;25 ns glitch eater */
+ }
+ pDCB->CtrlR3 = bval;
+ pDCB->SyncPeriod = (UCHAR)wval1;
+re_prog:
+ bval = pDCB->SyncPeriod;
+ outb(bval, ioport+Sync_Period);
+ bval = pDCB->SyncOffset;
+ outb(bval, ioport+Sync_Offset);
+ bval = pDCB->CtrlR3;
+ outb(bval, ioport+CtrlReg3);
+ bval = pDCB->CtrlR4;
+ outb(bval, ioport+CtrlReg4);
+ SetXferRate( pACB, pDCB);
+ }
+ }
+ }
+min6:
+ *psstatus = SCSI_NOP0;
+ bval = MSG_ACCEPTED_CMD;
+ outb(bval, ioport+ScsiCmd);
+}
+
+static void
+DataIO_Comm( PACB pACB, PSRB pSRB, UCHAR ioDir)
+{
+ PSGL psgl;
+ UCHAR bval;
+ USHORT ioport;
+ ULONG lval;
+
+
+ ioport = pACB->IOPortBase;
+ if( pSRB->SGIndex < pSRB->SGcount )
+ {
+ bval = DMA_IDLE_CMD | ioDir; /* ;+EN_DMA_INT */
+ outb( bval, ioport+DMA_Cmd);
+ if( !pSRB->SGToBeXferLen )
+ {
+ psgl = pSRB->pSegmentList;
+#ifndef VERSION_ELF_1_2_13
+ pSRB->SGPhysAddr = virt_to_phys( psgl->address );
+#else
+ pSRB->SGPhysAddr = (ULONG) psgl->address;
+#endif
+ pSRB->SGToBeXferLen = (ULONG) psgl->length;
+ }
+ lval = pSRB->SGToBeXferLen;
+ bval = (UCHAR) lval;
+ outb(bval,ioport+CtcReg_Low);
+ lval = lval >> 8;
+ bval = (UCHAR) lval;
+ outb(bval,ioport+CtcReg_Mid);
+ lval = lval >> 8;
+ bval = (UCHAR) lval;
+ outb(bval,ioport+CtcReg_High);
+
+ lval = pSRB->SGToBeXferLen;
+ outl(lval, ioport+DMA_XferCnt);
+
+ lval = pSRB->SGPhysAddr;
+ outl( lval, ioport+DMA_XferAddr);
+
+ bval = DMA_COMMAND+INFO_XFER_CMD;
+ outb(bval, ioport+ScsiCmd);
+
+ pSRB->SRBState = SRB_DATA_XFER;
+
+ bval = DMA_IDLE_CMD | ioDir; /* ;+EN_DMA_INT */
+ outb(bval, ioport+DMA_Cmd);
+
+ bval = DMA_START_CMD | ioDir; /* ;+EN_DMA_INT */
+ outb(bval, ioport+DMA_Cmd);
+ }
+ else /* xfer pad */
+ {
+ if( pSRB->SGcount )
+ {
+ pSRB->AdaptStatus = H_OVER_UNDER_RUN;
+ pSRB->SRBStatus |= OVER_RUN;
+ }
+ bval = 0;
+ outb(bval,ioport+CtcReg_Low);
+ outb(bval,ioport+CtcReg_Mid);
+ outb(bval,ioport+CtcReg_High);
+
+ pSRB->SRBState |= SRB_XFERPAD;
+ bval = DMA_COMMAND+XFER_PAD_BYTE;
+ outb(bval, ioport+ScsiCmd);
+/*
+ bval = DMA_IDLE_CMD | ioDir; ;+EN_DMA_INT
+ outb(bval, ioport+DMA_Cmd);
+ bval = DMA_START_CMD | ioDir; ;+EN_DMA_INT
+ outb(bval, ioport+DMA_Cmd);
+*/
+ }
+}
+
+
+static void
+DC390_DataOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
+ UCHAR ioDir;
+
+ ioDir = WRITE_DIRECTION;
+ DataIO_Comm( pACB, pSRB, ioDir);
+}
+
+static void
+DC390_DataInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
+ UCHAR ioDir;
+
+ ioDir = READ_DIRECTION;
+ DataIO_Comm( pACB, pSRB, ioDir);
+}
+
+static void
+DC390_CommandPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
+ PDCB pDCB;
+ UCHAR bval;
+ PUCHAR ptr;
+ USHORT ioport, i, cnt;
+
+
+ ioport = pACB->IOPortBase;
+ bval = RESET_ATN_CMD;
+ outb(bval, ioport+ScsiCmd);
+ bval = CLEAR_FIFO_CMD;
+ outb(bval, ioport+ScsiCmd);
+ if( !(pSRB->SRBFlag & AUTO_REQSENSE) )
+ {
+ cnt = (USHORT) pSRB->ScsiCmdLen;
+ ptr = (PUCHAR) pSRB->CmdBlock;
+ for(i=0; i < cnt; i++)
+ {
+ outb(*ptr, ioport+ScsiFifo);
+ ptr++;
+ }
+ }
+ else
+ {
+ bval = REQUEST_SENSE;
+ outb(bval, ioport+ScsiFifo);
+ pDCB = pACB->pActiveDCB;
+ bval = pDCB->IdentifyMsg << 5;
+ outb(bval, ioport+ScsiFifo);
+ bval = 0;
+ outb(bval, ioport+ScsiFifo);
+ outb(bval, ioport+ScsiFifo);
+ bval = sizeof(pSRB->pcmd->sense_buffer);
+ outb(bval, ioport+ScsiFifo);
+ bval = 0;
+ outb(bval, ioport+ScsiFifo);
+ }
+ pSRB->SRBState = SRB_COMMAND;
+ bval = INFO_XFER_CMD;
+ outb(bval, ioport+ScsiCmd);
+}
+
+static void
+DC390_StatusPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
+ UCHAR bval;
+ USHORT ioport;
+
+ ioport = pACB->IOPortBase;
+ bval = CLEAR_FIFO_CMD;
+ outb(bval, ioport+ScsiCmd);
+ pSRB->SRBState = SRB_STATUS;
+ bval = INITIATOR_CMD_CMPLTE;
+ outb(bval, ioport+ScsiCmd);
+}
+
+static void
+DC390_MsgOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
+ UCHAR bval;
+ USHORT ioport, i, cnt;
+ PUCHAR ptr;
+ PDCB pDCB;
+
+ ioport = pACB->IOPortBase;
+ bval = CLEAR_FIFO_CMD;
+ outb(bval, ioport+ScsiCmd);
+ pDCB = pACB->pActiveDCB;
+ if( !(pSRB->SRBState & SRB_MSGOUT) )
+ {
+ cnt = pSRB->MsgCnt;
+ if( cnt )
+ {
+ ptr = (PUCHAR) pSRB->MsgOutBuf;
+ for(i=0; i < cnt; i++)
+ {
+ outb(*ptr, ioport+ScsiFifo);
+ ptr++;
+ }
+ pSRB->MsgCnt = 0;
+ if( (pDCB->DCBFlag & ABORT_DEV_) &&
+ (pSRB->MsgOutBuf[0] == MSG_ABORT) )
+ pSRB->SRBState = SRB_ABORT_SENT;
+ }
+ else
+ {
+ bval = MSG_ABORT; /* ??? MSG_NOP */
+ if( (pSRB->CmdBlock[0] == INQUIRY ) ||
+ (pSRB->CmdBlock[0] == REQUEST_SENSE) ||
+ (pSRB->SRBFlag & AUTO_REQSENSE) )
+ {
+ if( pDCB->SyncMode & SYNC_ENABLE )
+ goto mop1;
+ }
+ outb(bval, ioport+ScsiFifo);
+ }
+ bval = INFO_XFER_CMD;
+ outb( bval, ioport+ScsiCmd);
+ }
+ else
+ {
+mop1:
+ bval = MSG_EXTENDED;
+ outb(bval, ioport+ScsiFifo);
+ bval = 3; /* ;length of extended msg */
+ outb(bval, ioport+ScsiFifo);
+ bval = 1; /* ; sync nego */
+ outb(bval, ioport+ScsiFifo);
+ bval = pDCB->NegoPeriod;
+ outb(bval, ioport+ScsiFifo);
+ bval = SYNC_NEGO_OFFSET;
+ outb(bval, ioport+ScsiFifo);
+ pSRB->SRBState |= DO_SYNC_NEGO;
+ bval = INFO_XFER_CMD;
+ outb(bval, ioport+ScsiCmd);
+ }
+}
+
+static void
+DC390_MsgInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
+ UCHAR bval;
+ USHORT ioport;
+
+ ioport = pACB->IOPortBase;
+ bval = CLEAR_FIFO_CMD;
+ outb(bval, ioport+ScsiCmd);
+ if( !(pSRB->SRBState & SRB_MSGIN) )
+ {
+ pSRB->SRBState &= SRB_DISCONNECT;
+ pSRB->SRBState |= SRB_MSGIN;
+ }
+ bval = INFO_XFER_CMD;
+ outb(bval, ioport+ScsiCmd);
+}
+
+static void
+DC390_Nop_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
+}
+
+static void
+DC390_Nop_1( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
+}
+
+
+static void
+SetXferRate( PACB pACB, PDCB pDCB )
+{
+ UCHAR bval;
+ USHORT cnt, i;
+ PDCB ptr;
+
+ if( !(pDCB->IdentifyMsg & 0x07) )
+ {
+ if( pACB->scan_devices )
+ {
+ CurrSyncOffset = pDCB->SyncOffset;
+ }
+ else
+ {
+ ptr = pACB->pLinkDCB;
+ cnt = pACB->DeviceCnt;
+ bval = pDCB->UnitSCSIID;
+ for(i=0; i<cnt; i++)
+ {
+ if( ptr->UnitSCSIID == bval )
+ {
+ ptr->SyncPeriod = pDCB->SyncPeriod;
+ ptr->SyncOffset = pDCB->SyncOffset;
+ ptr->CtrlR3 = pDCB->CtrlR3;
+ ptr->CtrlR4 = pDCB->CtrlR4;
+ ptr->SyncMode = pDCB->SyncMode;
+ }
+ ptr = ptr->pNextDCB;
+ }
+ }
+ }
+ return;
+}
+
+
+static void
+DC390_Disconnect( PACB pACB )
+{
+ PDCB pDCB;
+ PSRB pSRB, psrb;
+ ULONG flags;
+ USHORT ioport, i, cnt;
+ UCHAR bval;
+
+#ifdef DC390_DEBUG0
+ printk("DISC,");
+#endif
+
+ save_flags(flags);
+ cli();
+ ioport = pACB->IOPortBase;
+ pDCB = pACB->pActiveDCB;
+ if (!pDCB)
+ {
+#ifdef DC390_DEBUG0
+ printk("ACB:%08lx->ActiveDCB:%08lx !,",(ULONG)pACB,(ULONG)pDCB);
+#endif
+ restore_flags(flags); return;
+ }
+ pSRB = pDCB->pActiveSRB;
+ pACB->pActiveDCB = 0;
+ pSRB->ScsiPhase = SCSI_NOP0;
+ bval = EN_SEL_RESEL;
+ outb(bval, ioport+ScsiCmd);
+ if( pSRB->SRBState & SRB_UNEXPECT_RESEL )
+ {
+ pSRB->SRBState = 0;
+ DoWaitingSRB( pACB );
+ }
+ else if( pSRB->SRBState & SRB_ABORT_SENT )
+ {
+ pDCB->TagMask = 0;
+ pDCB->DCBFlag = 0;
+ cnt = pDCB->GoingSRBCnt;
+ pDCB->GoingSRBCnt = 0;
+ pSRB = pDCB->pGoingSRB;
+ for( i=0; i < cnt; i++)
+ {
+ psrb = pSRB->pNextSRB;
+ pSRB->pNextSRB = pACB->pFreeSRB;
+ pACB->pFreeSRB = pSRB;
+ pSRB = psrb;
+ }
+ pDCB->pGoingSRB = 0;
+ DoWaitingSRB( pACB );
+ }
+ else
+ {
+ if( (pSRB->SRBState & (SRB_START_+SRB_MSGOUT)) ||
+ !(pSRB->SRBState & (SRB_DISCONNECT+SRB_COMPLETED)) )
+ { /* Selection time out */
+ if( !(pACB->scan_devices) )
+ {
+ pSRB->SRBState = SRB_READY;
+ RewaitSRB( pDCB, pSRB);
+ }
+ else
+ {
+ pSRB->TargetStatus = SCSI_STAT_SEL_TIMEOUT;
+ goto disc1;
+ }
+ }
+ else if( pSRB->SRBState & SRB_DISCONNECT )
+ {
+ DoWaitingSRB( pACB );
+ }
+ else if( pSRB->SRBState & SRB_COMPLETED )
+ {
+disc1:
+ if(pDCB->MaxCommand > 1)
+ {
+ bval = pSRB->TagNumber;
+ pDCB->TagMask &= (~(1 << bval)); /* free tag mask */
+ }
+ pDCB->pActiveSRB = 0;
+ pSRB->SRBState = SRB_FREE;
+ SRBdone( pACB, pDCB, pSRB);
+ }
+ }
+ restore_flags(flags);
+ return;
+}
+
+
+static void
+DC390_Reselect( PACB pACB )
+{
+ PDCB pDCB, pdcb;
+ PSRB pSRB;
+ USHORT ioport, wval;
+ UCHAR bval, bval1;
+
+
+#ifdef DC390_DEBUG0
+ printk("RSEL,");
+#endif
+ ioport = pACB->IOPortBase;
+ pDCB = pACB->pActiveDCB;
+ if( pDCB )
+ { /* Arbitration lost but Reselection win */
+ pSRB = pDCB->pActiveSRB;
+ if( !( pACB->scan_devices ) )
+ {
+ pSRB->SRBState = SRB_READY;
+ RewaitSRB( pDCB, pSRB);
+ }
+ }
+ bval = inb(ioport+ScsiFifo); /* get ID */
+ bval = bval ^ pACB->HostID_Bit;
+ wval = 0;
+ bval1 = 1;
+ for(;;)
+ {
+ if( !(bval & bval1) )
+ {
+ bval1 = bval1 << 1;
+ wval++;
+ }
+ else
+ break;
+ }
+ wval |= ( (USHORT) inb(ioport+ScsiFifo) & 7) << 8; /* get LUN */
+ pDCB = pACB->pLinkDCB;
+ pdcb = pDCB;
+ while( wval != *((PUSHORT) &pDCB->UnitSCSIID) )
+ {
+ pDCB = pDCB->pNextDCB;
+ if( pDCB == pdcb )
+ return;
+ }
+ pACB->pActiveDCB = pDCB;
+ if( pDCB->SyncMode & EN_TAG_QUEUING )
+ {
+ pSRB = pACB->pTmpSRB;
+ pDCB->pActiveSRB = pSRB;
+ }
+ else
+ {
+ pSRB = pDCB->pActiveSRB;
+ if( !pSRB || !(pSRB->SRBState & SRB_DISCONNECT) )
+ {
+ pSRB= pACB->pTmpSRB;
+ pSRB->SRBState = SRB_UNEXPECT_RESEL;
+ pDCB->pActiveSRB = pSRB;
+ EnableMsgOut( pACB, pSRB );
+ }
+ else
+ {
+ if( pDCB->DCBFlag & ABORT_DEV_ )
+ {
+ pSRB->SRBState = SRB_ABORT_SENT;
+ EnableMsgOut( pACB, pSRB );
+ }
+ else
+ pSRB->SRBState = SRB_DATA_XFER;
+ }
+ }
+ pSRB->ScsiPhase = SCSI_NOP0;
+ bval = pDCB->UnitSCSIID;
+ outb( bval, ioport+Scsi_Dest_ID);
+ bval = pDCB->SyncPeriod;
+ outb(bval, ioport+Sync_Period);
+ bval = pDCB->SyncOffset;
+ outb( bval, ioport+Sync_Offset);
+ bval = pDCB->CtrlR1;
+ outb(bval, ioport+CtrlReg1);
+ bval = pDCB->CtrlR3;
+ outb(bval, ioport+CtrlReg3);
+ bval = pDCB->CtrlR4; /* ; Glitch eater */
+ outb(bval, ioport+CtrlReg4);
+ bval = MSG_ACCEPTED_CMD; /* ;to rls the /ACK signal */
+ outb(bval, ioport+ScsiCmd);
+}
+
+
+static void
+SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB )
+{
+ PSRB psrb;
+ UCHAR bval, bval1, i, j, status;
+ PSCSICMD pcmd;
+ PSCSI_INQDATA ptr;
+ USHORT disable_tag;
+ ULONG flags;
+ PSGL ptr2;
+ ULONG swlval;
+
+ pcmd = pSRB->pcmd;
+ status = pSRB->TargetStatus;
+ if(pSRB->SRBFlag & AUTO_REQSENSE)
+ {
+ pSRB->SRBFlag &= ~AUTO_REQSENSE;
+ pSRB->AdaptStatus = 0;
+ pSRB->TargetStatus = SCSI_STAT_CHECKCOND;
+ if(status == SCSI_STAT_CHECKCOND)
+ {
+ pcmd->result = DID_BAD_TARGET << 16;
+ goto ckc_e;
+ }
+ if(pSRB->RetryCnt == 0)
+ {
+ *((PULONG) &(pSRB->CmdBlock[0])) = pSRB->Segment0[0];
+ pSRB->TotalXferredLen = pSRB->Segment1[1];
+ if( (pSRB->TotalXferredLen) &&
+ (pSRB->TotalXferredLen >= pcmd->underflow) )
+ pcmd->result |= (DID_OK << 16);
+ else
+ pcmd->result = (DRIVER_SENSE << 24) | (DRIVER_OK << 16) |
+ SCSI_STAT_CHECKCOND;
+#ifdef DC390_DEBUG0
+ printk("Cmd=%2x,Result=%8x,XferL=%8x,",pSRB->CmdBlock[0],
+ (UINT) pcmd->result, (UINT) pSRB->TotalXferredLen);
+#endif
+ goto ckc_e;
+ }
+ else
+ {
+ pSRB->RetryCnt--;
+ pSRB->AdaptStatus = 0;
+ pSRB->TargetStatus = 0;
+ *((PULONG) &(pSRB->CmdBlock[0])) = pSRB->Segment0[0];
+ *((PULONG) &(pSRB->CmdBlock[4])) = pSRB->Segment0[1];
+ if( pSRB->CmdBlock[0] == TEST_UNIT_READY )
+ {
+ pcmd->result = (DRIVER_SENSE << 24) | (DRIVER_OK << 16) |
+ SCSI_STAT_CHECKCOND;
+ goto ckc_e;
+ }
+ pcmd->result |= (DRIVER_SENSE << 24);
+ pSRB->SGcount = (UCHAR) pSRB->Segment1[0];
+ pSRB->ScsiCmdLen = (UCHAR) (pSRB->Segment1[0] >> 8);
+ pSRB->SGIndex = 0;
+ pSRB->TotalXferredLen = 0;
+ pSRB->SGToBeXferLen = 0;
+ if( pcmd->use_sg )
+ pSRB->pSegmentList = (PSGL) pcmd->request_buffer;
+ else if( pcmd->request_buffer )
+ {
+ pSRB->pSegmentList = (PSGL) &pSRB->Segmentx;
+ pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer;
+ pSRB->Segmentx.length = pcmd->request_bufflen;
+ }
+ if( DC390_StartSCSI( pACB, pDCB, pSRB ) )
+ RewaitSRB( pDCB, pSRB );
+ return;
+ }
+ }
+ if( status )
+ {
+ if( status == SCSI_STAT_CHECKCOND)
+ {
+ if( (pSRB->SGIndex < pSRB->SGcount) && (pSRB->SGcount) && (pSRB->SGToBeXferLen) )
+ {
+ bval = pSRB->SGcount;
+ swlval = 0;
+ ptr2 = pSRB->pSegmentList;
+ for( i=pSRB->SGIndex; i < bval; i++)
+ {
+ swlval += ptr2->length;
+ ptr2++;
+ }
+#ifdef DC390_DEBUG0
+ printk("XferredLen=%8x,NotXferLen=%8x,",
+ (UINT) pSRB->TotalXferredLen, (UINT) swlval);
+#endif
+ }
+ RequestSense( pACB, pDCB, pSRB );
+ return;
+ }
+ else if( status == SCSI_STAT_QUEUEFULL )
+ {
+ bval = (UCHAR) pDCB->GoingSRBCnt;
+ bval--;
+ pDCB->MaxCommand = bval;
+ RewaitSRB( pDCB, pSRB );
+ pSRB->AdaptStatus = 0;
+ pSRB->TargetStatus = 0;
+ return;
+ }
+ else if(status == SCSI_STAT_SEL_TIMEOUT)
+ {
+ pSRB->AdaptStatus = H_SEL_TIMEOUT;
+ pSRB->TargetStatus = 0;
+ pcmd->result = DID_BAD_TARGET << 16;
+ }
+ else
+ {
+ pSRB->AdaptStatus = 0;
+ if( pSRB->RetryCnt )
+ {
+ pSRB->RetryCnt--;
+ pSRB->TargetStatus = 0;
+ pSRB->SGIndex = 0;
+ pSRB->TotalXferredLen = 0;
+ pSRB->SGToBeXferLen = 0;
+ if( pcmd->use_sg )
+ pSRB->pSegmentList = (PSGL) pcmd->request_buffer;
+ else if( pcmd->request_buffer )
+ {
+ pSRB->pSegmentList = (PSGL) &pSRB->Segmentx;
+ pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer;
+ pSRB->Segmentx.length = pcmd->request_bufflen;
+ }
+ if( DC390_StartSCSI( pACB, pDCB, pSRB ) )
+ RewaitSRB( pDCB, pSRB );
+ return;
+ }
+ else
+ {
+ pcmd->result |= (DID_ERROR << 16) | (ULONG) (pSRB->EndMessage << 8) |
+ (ULONG) status;
+ }
+ }
+ }
+ else
+ {
+ status = pSRB->AdaptStatus;
+ if(status & H_OVER_UNDER_RUN)
+ {
+ pSRB->TargetStatus = 0;
+ pcmd->result |= (DID_OK << 16) | (pSRB->EndMessage << 8);
+ }
+ else if( pSRB->SRBStatus & PARITY_ERROR)
+ {
+ pcmd->result |= (DID_PARITY << 16) | (pSRB->EndMessage << 8);
+ }
+ else /* No error */
+ {
+ pSRB->AdaptStatus = 0;
+ pSRB->TargetStatus = 0;
+ pcmd->result |= (DID_OK << 16);
+ }
+ }
+
+ckc_e:
+ if( pACB->scan_devices )
+ {
+ if( pSRB->CmdBlock[0] == TEST_UNIT_READY )
+ {
+ if(pcmd->result != (DID_OK << 16))
+ {
+ if( pcmd->result & SCSI_STAT_CHECKCOND )
+ {
+ goto RTN_OK;
+ }
+ else
+ {
+ pACB->DCBmap[pcmd->target] &= ~(1 << pcmd->lun);
+ pPrevDCB->pNextDCB = pACB->pLinkDCB;
+ if( (pcmd->target == pACB->max_id) &&
+ ((pcmd->lun == 0) || (pcmd->lun == pACB->max_lun)) )
+ {
+ pACB->scan_devices = 0;
+ }
+ }
+ }
+ else
+ {
+RTN_OK:
+ pPrevDCB->pNextDCB = pDCB;
+ pDCB->pNextDCB = pACB->pLinkDCB;
+ if( (pcmd->target == pACB->max_id) && (pcmd->lun == pACB->max_lun) )
+ pACB->scan_devices = END_SCAN;
+ }
+ }
+ else if( pSRB->CmdBlock[0] == INQUIRY )
+ {
+ if( (pcmd->target == pACB->max_id) &&
+ (pcmd->lun == pACB->max_lun) )
+ {
+ pACB->scan_devices = 0;
+ }
+ ptr = (PSCSI_INQDATA) (pcmd->request_buffer);
+ if( pcmd->use_sg )
+ ptr = (PSCSI_INQDATA) (((PSGL) ptr)->address);
+ bval1 = ptr->DevType & SCSI_DEVTYPE;
+ if(bval1 == SCSI_NODEV)
+ {
+ pACB->DCBmap[pcmd->target] &= ~(1 << pcmd->lun);
+ pPrevDCB->pNextDCB = pACB->pLinkDCB;
+ }
+ else
+ {
+ pACB->DeviceCnt++;
+ pPrevDCB = pDCB;
+ pACB->pDCB_free = (PDCB) ((ULONG) (pACB->pDCB_free) + sizeof( DC390_DCB ));
+ pDCB->DevType = bval1;
+ if(bval1 == TYPE_DISK || bval1 == TYPE_MOD)
+ {
+ if( (((ptr->Vers & 0x07) >= 2) || ((ptr->RDF & 0x0F) == 2)) &&
+ (ptr->Flags & SCSI_INQ_CMDQUEUE) &&
+ (pDCB->DevMode & TAG_QUEUING_) &&
+ (pDCB->DevMode & EN_DISCONNECT_) )
+ {
+ disable_tag = 0;
+ for(i=0; i<BADDEVCNT; i++)
+ {
+ for(j=0; j<28; j++)
+ {
+ if( ((PUCHAR)ptr)[8+j] != baddevname1[i][j])
+ break;
+ }
+ if(j == 28)
+ {
+ disable_tag = 1;
+ break;
+ }
+ }
+
+ if( !disable_tag )
+ {
+ pDCB->MaxCommand = pACB->TagMaxNum;
+ pDCB->SyncMode |= EN_TAG_QUEUING;
+ pDCB->TagMask = 0;
+ }
+ else
+ {
+ pDCB->SyncMode |= EN_ATN_STOP;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ save_flags( flags );
+ cli();
+/* ReleaseSRB( pDCB, pSRB ); */
+
+ if(pSRB == pDCB->pGoingSRB )
+ {
+ pDCB->pGoingSRB = pSRB->pNextSRB;
+ }
+ else
+ {
+ psrb = pDCB->pGoingSRB;
+ while( psrb->pNextSRB != pSRB )
+ psrb = psrb->pNextSRB;
+ psrb->pNextSRB = pSRB->pNextSRB;
+ if( pSRB == pDCB->pGoingLast )
+ pDCB->pGoingLast = psrb;
+ }
+ pSRB->pNextSRB = pACB->pFreeSRB;
+ pACB->pFreeSRB = pSRB;
+ pDCB->GoingSRBCnt--;
+
+ DoWaitingSRB( pACB );
+ restore_flags(flags);
+
+/* Notify cmd done */
+ pcmd->scsi_done( pcmd );
+
+ if( pDCB->QIORBCnt )
+ DoNextCmd( pACB, pDCB );
+ return;
+}
+
+
+static void
+DoingSRB_Done( PACB pACB )
+{
+ PDCB pDCB, pdcb;
+ PSRB psrb, psrb2;
+ USHORT cnt, i;
+ PSCSICMD pcmd;
+
+ pDCB = pACB->pLinkDCB;
+ pdcb = pDCB;
+ do
+ {
+ cnt = pdcb->GoingSRBCnt;
+ psrb = pdcb->pGoingSRB;
+ for( i=0; i<cnt; i++)
+ {
+ psrb2 = psrb->pNextSRB;
+ pcmd = psrb->pcmd;
+ pcmd->result = DID_RESET << 16;
+
+/* ReleaseSRB( pDCB, pSRB ); */
+
+ psrb->pNextSRB = pACB->pFreeSRB;
+ pACB->pFreeSRB = psrb;
+
+ pcmd->scsi_done( pcmd );
+ psrb = psrb2;
+ }
+ pdcb->GoingSRBCnt = 0;;
+ pdcb->pGoingSRB = NULL;
+ pdcb->TagMask = 0;
+ pdcb = pdcb->pNextDCB;
+ }
+ while( pdcb != pDCB );
+}
+
+
+static void
+DC390_ResetSCSIBus( PACB pACB )
+{
+ USHORT ioport;
+ UCHAR bval;
+ ULONG flags;
+
+ save_flags(flags);
+ cli();
+ pACB->ACBFlag |= RESET_DEV;
+ ioport = pACB->IOPortBase;
+
+ bval = DMA_IDLE_CMD;
+ outb(bval,ioport+DMA_Cmd);
+
+ bval = RST_SCSI_BUS_CMD;
+ outb(bval,ioport+ScsiCmd);
+
+ restore_flags(flags);
+ return;
+}
+
+
+static void
+DC390_ScsiRstDetect( PACB pACB )
+{
+ ULONG wlval, flags;
+ USHORT ioport;
+ UCHAR bval;
+
+#ifdef DC390_DEBUG0
+ printk("RST_DETEC");
+#endif
+ save_flags(flags);
+ sti();
+ wlval = jiffies + HZ;
+ while( jiffies < wlval ); /* delay 1 sec */
+
+ cli();
+ ioport = pACB->IOPortBase;
+ bval = DMA_IDLE_CMD;
+ outb(bval,ioport+DMA_Cmd);
+ bval = CLEAR_FIFO_CMD;
+ outb(bval,ioport+ScsiCmd);
+
+ if( pACB->ACBFlag & RESET_DEV )
+ pACB->ACBFlag |= RESET_DONE;
+ else
+ {
+ pACB->ACBFlag |= RESET_DETECT;
+
+ ResetDevParam( pACB );
+/* DoingSRB_Done( pACB ); ???? */
+ RecoverSRB( pACB );
+ pACB->pActiveDCB = NULL;
+ pACB->ACBFlag = 0;
+ DoWaitingSRB( pACB );
+ }
+ restore_flags(flags);
+ return;
+}
+
+
+static void
+RequestSense( PACB pACB, PDCB pDCB, PSRB pSRB )
+{
+ PSCSICMD pcmd;
+
+ pSRB->SRBFlag |= AUTO_REQSENSE;
+ pSRB->Segment0[0] = *((PULONG) &(pSRB->CmdBlock[0]));
+ pSRB->Segment0[1] = *((PULONG) &(pSRB->CmdBlock[4]));
+ pSRB->Segment1[0] = (ULONG) ((pSRB->ScsiCmdLen << 8) + pSRB->SGcount);
+ pSRB->Segment1[1] = pSRB->TotalXferredLen;
+ pSRB->AdaptStatus = 0;
+ pSRB->TargetStatus = 0;
+
+ pcmd = pSRB->pcmd;
+
+ pSRB->Segmentx.address = (PUCHAR) &(pcmd->sense_buffer);
+ pSRB->Segmentx.length = sizeof(pcmd->sense_buffer);
+ pSRB->pSegmentList = &pSRB->Segmentx;
+ pSRB->SGcount = 1;
+ pSRB->SGIndex = 0;
+
+ *((PULONG) &(pSRB->CmdBlock[0])) = 0x00000003;
+ pSRB->CmdBlock[1] = pDCB->IdentifyMsg << 5;
+ *((PUSHORT) &(pSRB->CmdBlock[4])) = sizeof(pcmd->sense_buffer);
+ pSRB->ScsiCmdLen = 6;
+
+ pSRB->TotalXferredLen = 0;
+ pSRB->SGToBeXferLen = 0;
+ if( DC390_StartSCSI( pACB, pDCB, pSRB ) )
+ RewaitSRB( pDCB, pSRB );
+}
+
+
+static void
+EnableMsgOut2( PACB pACB, PSRB pSRB )
+{
+ USHORT ioport;
+ UCHAR bval;
+
+ ioport = pACB->IOPortBase;
+ pSRB->MsgCnt = 1;
+ bval = SET_ATN_CMD;
+ outb(bval, ioport+ScsiCmd);
+}
+
+
+static void
+EnableMsgOut( PACB pACB, PSRB pSRB )
+{
+ pSRB->MsgOutBuf[0] = MSG_ABORT;
+ EnableMsgOut2( pACB, pSRB );
+}
+
+
+static void
+DC390_InvalidCmd( PACB pACB )
+{
+ UCHAR bval;
+ USHORT ioport;
+ PSRB pSRB;
+
+ pSRB = pACB->pActiveDCB->pActiveSRB;
+ if( pSRB->SRBState & (SRB_START_+SRB_MSGOUT) )
+ {
+ ioport = pACB->IOPortBase;
+ bval = CLEAR_FIFO_CMD;
+ outb(bval,(ioport+ScsiCmd));
+ }
+}
+
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 919fb7f0f..eb68d383b 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -1047,7 +1047,7 @@ static int sd_init_onedisk(int i)
spintime = 0;
/* Spin up drives, as required. Only do this at boot time */
- if (!MODULE_FLAG){
+ /* Spinup needs to be done for module loads too. */
do{
retries = 0;
while(retries < 3)
@@ -1120,7 +1120,6 @@ static int sd_init_onedisk(int i)
else
printk( "ready\n" );
}
- } /* !MODULE_FLAG */
retries = 3;
do {
diff --git a/drivers/scsi/seagate.c b/drivers/scsi/seagate.c
index 73bff45af..e9c411e48 100644
--- a/drivers/scsi/seagate.c
+++ b/drivers/scsi/seagate.c
@@ -564,36 +564,6 @@ const char *seagate_st0x_info (struct Scsi_Host *shpnt)
return buffer;
}
-int seagate_st0x_proc_info (char *buffer, char **start, off_t offset,
- int length, int hostno, int inout)
-{
- const char *info = seagate_st0x_info (NULL);
- int len;
- int pos;
- int begin;
-
- if (inout)
- return (-ENOSYS);
-
- begin = 0;
- strcpy (buffer, info);
- strcat (buffer, "\n");
-
- pos = len = strlen (buffer);
-
- if (pos < offset)
- {
- len = 0;
- begin = pos;
- }
-
- *start = buffer + (offset - begin);
- len -= (offset - begin);
- if (len > length)
- len = length;
- return (len);
-}
-
/*
* These are our saved pointers for the outstanding command that is
* waiting for a reconnect
diff --git a/drivers/scsi/seagate.h b/drivers/scsi/seagate.h
index 7d677e5ea..f339ea612 100644
--- a/drivers/scsi/seagate.h
+++ b/drivers/scsi/seagate.h
@@ -19,7 +19,6 @@ int seagate_st0x_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
int seagate_st0x_abort(Scsi_Cmnd *);
const char *seagate_st0x_info(struct Scsi_Host *);
int seagate_st0x_reset(Scsi_Cmnd *, unsigned int);
-int seagate_st0x_proc_info(char *,char **,off_t,int,int,int);
#ifndef NULL
#define NULL 0
@@ -28,7 +27,7 @@ int seagate_st0x_proc_info(char *,char **,off_t,int,int,int);
#include <linux/kdev_t.h>
int seagate_st0x_biosparam(Disk *, kdev_t, int*);
-#define SEAGATE_ST0X { NULL, NULL, NULL, seagate_st0x_proc_info, \
+#define SEAGATE_ST0X { NULL, NULL, NULL, NULL, \
NULL, seagate_st0x_detect, \
NULL, \
seagate_st0x_info, seagate_st0x_command, \
diff --git a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c
new file mode 100644
index 000000000..f5ceb1371
--- /dev/null
+++ b/drivers/scsi/tmscsim.c
@@ -0,0 +1,1928 @@
+/***********************************************************************
+ * FILE NAME : TMSCSIM.C *
+ * BY : C.L. Huang, ching@tekram.com.tw *
+ * Description: Device Driver for Tekram DC-390(T) PCI SCSI *
+ * Bus Master Host Adapter *
+ * (C)Copyright 1995-1996 Tekram Technology Co., Ltd. *
+ ***********************************************************************/
+/* Minor enhancements and bugfixes by *
+ * Kurt Garloff <K.Garloff@ping.de> *
+ ***********************************************************************/
+/* HISTORY: *
+ * *
+ * REV# DATE NAME DESCRIPTION *
+ * 1.00 04/24/96 CLH First release *
+ * 1.01 06/12/96 CLH Fixed bug of Media Change for Removable *
+ * Device, scan all LUN. Support Pre2.0.10 *
+ * 1.02 06/18/96 CLH Fixed bug of Command timeout ... *
+ * 1.03 09/25/96 KG Added tmscsim_proc_info() *
+ * 1.04 10/11/96 CLH Updating for support KV 2.0.x *
+ * 1.05 10/18/96 KG Fixed bug in DC390_abort(null ptr deref)*
+ * 1.06 10/25/96 KG Fixed module support *
+ * 1.07 11/09/96 KG Fixed tmscsim_proc_info() *
+ * 1.08 11/18/96 KG Fixed null ptr in DC390_Disconnect() *
+ * 1.09 11/30/96 KG Added register the allocated IO space *
+ * 1.10 12/05/96 CLH Modified tmscsim_proc_info(), and reset *
+ * pending interrupt in DC390_detect() *
+ ***********************************************************************/
+
+
+#define DC390_DEBUG
+
+#define SCSI_MALLOC
+
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <linux/delay.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/bios32.h>
+#include <linux/pci.h>
+#include <linux/proc_fs.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/config.h>
+
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < 66354 /* 1.3.50 */
+#include "../block/blk.h"
+#else
+#include <linux/blk.h>
+#endif
+
+#include "scsi.h"
+#include "hosts.h"
+#include "tmscsim.h"
+#include "constants.h"
+#include "sd.h"
+#include <linux/stat.h>
+
+#include "dc390.h"
+
+#define PCI_DEVICE_ID_AMD53C974 PCI_DEVICE_ID_AMD_SCSI
+
+
+#ifndef VERSION_ELF_1_2_13
+struct proc_dir_entry proc_scsi_tmscsim ={
+ PROC_SCSI_DC390T, 7 ,"tmscsim",
+ S_IFDIR | S_IRUGO | S_IXUGO, 2
+ };
+#endif
+
+static USHORT DC390_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB );
+static void DC390_DataOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void DC390_DataIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void DC390_Command_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void DC390_Status_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void DC390_MsgOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void DC390_MsgIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void DC390_DataOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void DC390_DataInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void DC390_CommandPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void DC390_StatusPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void DC390_MsgOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void DC390_MsgInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void DC390_Nop_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void DC390_Nop_1( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+
+static void SetXferRate( PACB pACB, PDCB pDCB );
+static void DC390_Disconnect( PACB pACB );
+static void DC390_Reselect( PACB pACB );
+static void SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB );
+static void DoingSRB_Done( PACB pACB );
+static void DC390_ScsiRstDetect( PACB pACB );
+static void DC390_ResetSCSIBus( PACB pACB );
+static void RequestSense( PACB pACB, PDCB pDCB, PSRB pSRB );
+static void EnableMsgOut2( PACB pACB, PSRB pSRB );
+static void EnableMsgOut( PACB pACB, PSRB pSRB );
+static void DC390_InvalidCmd( PACB pACB );
+
+int DC390_initAdapter( PSH psh, ULONG io_port, UCHAR Irq, USHORT index );
+void DC390_initDCB( PACB pACB, PDCB pDCB, PSCSICMD cmd );
+
+#ifdef MODULE
+static int DC390_release(struct Scsi_Host *host);
+static int DC390_shutdown (struct Scsi_Host *host);
+#endif
+
+
+static PSHT pSHT_start = NULL;
+static PSH pSH_start = NULL;
+static PSH pSH_current = NULL;
+static PACB pACB_start= NULL;
+static PACB pACB_current = NULL;
+static PDCB pPrevDCB = NULL;
+static USHORT adapterCnt = 0;
+static USHORT InitialTime = 0;
+static USHORT CurrSyncOffset = 0;
+static ULONG mech1addr;
+static UCHAR mech2bus, mech2Agent, mech2CfgSPenR;
+
+static PVOID DC390_phase0[]={
+ DC390_DataOut_0,
+ DC390_DataIn_0,
+ DC390_Command_0,
+ DC390_Status_0,
+ DC390_Nop_0,
+ DC390_Nop_0,
+ DC390_MsgOut_0,
+ DC390_MsgIn_0,
+ DC390_Nop_1
+ };
+
+static PVOID DC390_phase1[]={
+ DC390_DataOutPhase,
+ DC390_DataInPhase,
+ DC390_CommandPhase,
+ DC390_StatusPhase,
+ DC390_Nop_0,
+ DC390_Nop_0,
+ DC390_MsgOutPhase,
+ DC390_MsgInPhase,
+ DC390_Nop_1,
+ };
+
+UCHAR eepromBuf[MAX_ADAPTER_NUM][128];
+
+
+UCHAR clock_period1[] = {4, 5, 6, 7, 8, 10, 13, 20};
+
+UCHAR baddevname1[2][28] ={
+ "SEAGATE ST3390N 9546",
+ "HP C3323-300 4269"};
+
+#define BADDEVCNT 2
+
+
+/***********************************************************************
+ *
+ *
+ *
+ **********************************************************************/
+static void
+QLinkcmd( PSCSICMD cmd, PDCB pDCB )
+{
+ ULONG flags;
+ PSCSICMD pcmd;
+
+ save_flags(flags);
+ cli();
+
+ if( !pDCB->QIORBCnt )
+ {
+ pDCB->pQIORBhead = cmd;
+ pDCB->pQIORBtail = cmd;
+ pDCB->QIORBCnt++;
+ cmd->next = NULL;
+ }
+ else
+ {
+ pcmd = pDCB->pQIORBtail;
+ pcmd->next = cmd;
+ pDCB->pQIORBtail = cmd;
+ pDCB->QIORBCnt++;
+ cmd->next = NULL;
+ }
+
+ restore_flags(flags);
+}
+
+
+static PSCSICMD
+Getcmd( PDCB pDCB )
+{
+ ULONG flags;
+ PSCSICMD pcmd;
+
+ save_flags(flags);
+ cli();
+
+ pcmd = pDCB->pQIORBhead;
+ pDCB->pQIORBhead = pcmd->next;
+ pcmd->next = NULL;
+ pDCB->QIORBCnt--;
+
+ restore_flags(flags);
+ return( pcmd );
+}
+
+
+static PSRB
+GetSRB( PACB pACB )
+{
+ ULONG flags;
+ PSRB pSRB;
+
+ save_flags(flags);
+ cli();
+
+ pSRB = pACB->pFreeSRB;
+ if( pSRB )
+ {
+ pACB->pFreeSRB = pSRB->pNextSRB;
+ pSRB->pNextSRB = NULL;
+ }
+ restore_flags(flags);
+ return( pSRB );
+}
+
+
+static void
+RewaitSRB0( PDCB pDCB, PSRB pSRB )
+{
+ PSRB psrb1;
+ ULONG flags;
+
+ save_flags(flags);
+ cli();
+
+ if( (psrb1 = pDCB->pWaitingSRB) )
+ {
+ pSRB->pNextSRB = psrb1;
+ pDCB->pWaitingSRB = pSRB;
+ }
+ else
+ {
+ pSRB->pNextSRB = NULL;
+ pDCB->pWaitingSRB = pSRB;
+ pDCB->pWaitLast = pSRB;
+ }
+ restore_flags(flags);
+}
+
+
+static void
+RewaitSRB( PDCB pDCB, PSRB pSRB )
+{
+ PSRB psrb1;
+ ULONG flags;
+ UCHAR bval;
+
+ save_flags(flags);
+ cli();
+ pDCB->GoingSRBCnt--;
+ psrb1 = pDCB->pGoingSRB;
+ if( pSRB == psrb1 )
+ {
+ pDCB->pGoingSRB = psrb1->pNextSRB;
+ }
+ else
+ {
+ while( pSRB != psrb1->pNextSRB )
+ psrb1 = psrb1->pNextSRB;
+ psrb1->pNextSRB = pSRB->pNextSRB;
+ if( pSRB == pDCB->pGoingLast )
+ pDCB->pGoingLast = psrb1;
+ }
+ if( (psrb1 = pDCB->pWaitingSRB) )
+ {
+ pSRB->pNextSRB = psrb1;
+ pDCB->pWaitingSRB = pSRB;
+ }
+ else
+ {
+ pSRB->pNextSRB = NULL;
+ pDCB->pWaitingSRB = pSRB;
+ pDCB->pWaitLast = pSRB;
+ }
+
+ bval = pSRB->TagNumber;
+ pDCB->TagMask &= (~(1 << bval)); /* Free TAG number */
+ restore_flags(flags);
+}
+
+
+static void
+DoWaitingSRB( PACB pACB )
+{
+ ULONG flags;
+ PDCB ptr, ptr1;
+ PSRB pSRB;
+
+ save_flags(flags);
+ cli();
+
+ if( !(pACB->pActiveDCB) && !(pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV) ) )
+ {
+ ptr = pACB->pDCBRunRobin;
+ if( !ptr )
+ {
+ ptr = pACB->pLinkDCB;
+ pACB->pDCBRunRobin = ptr;
+ }
+ ptr1 = ptr;
+ for( ;ptr1; )
+ {
+ pACB->pDCBRunRobin = ptr1->pNextDCB;
+ if( !( ptr1->MaxCommand > ptr1->GoingSRBCnt ) ||
+ !( pSRB = ptr1->pWaitingSRB ) )
+ {
+ if(pACB->pDCBRunRobin == ptr)
+ break;
+ ptr1 = ptr1->pNextDCB;
+ }
+ else
+ {
+ if( !DC390_StartSCSI(pACB, ptr1, pSRB) )
+ {
+ ptr1->GoingSRBCnt++;
+ if( ptr1->pWaitLast == pSRB )
+ {
+ ptr1->pWaitingSRB = NULL;
+ ptr1->pWaitLast = NULL;
+ }
+ else
+ {
+ ptr1->pWaitingSRB = pSRB->pNextSRB;
+ }
+ pSRB->pNextSRB = NULL;
+
+ if( ptr1->pGoingSRB )
+ ptr1->pGoingLast->pNextSRB = pSRB;
+ else
+ ptr1->pGoingSRB = pSRB;
+ ptr1->pGoingLast = pSRB;
+ }
+ break;
+ }
+ }
+ }
+ restore_flags(flags);
+ return;
+}
+
+
+static void
+SRBwaiting( PDCB pDCB, PSRB pSRB)
+{
+ if( pDCB->pWaitingSRB )
+ {
+ pDCB->pWaitLast->pNextSRB = pSRB;
+ pDCB->pWaitLast = pSRB;
+ pSRB->pNextSRB = NULL;
+ }
+ else
+ {
+ pDCB->pWaitingSRB = pSRB;
+ pDCB->pWaitLast = pSRB;
+ }
+}
+
+
+static void
+SendSRB( PSCSICMD pcmd, PACB pACB, PSRB pSRB )
+{
+ ULONG flags;
+ PDCB pDCB;
+
+ save_flags(flags);
+ cli();
+
+ pDCB = pSRB->pSRBDCB;
+ if( !(pDCB->MaxCommand > pDCB->GoingSRBCnt) || (pACB->pActiveDCB) ||
+ (pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV)) )
+ {
+ SRBwaiting(pDCB, pSRB);
+ goto SND_EXIT;
+ }
+
+ if( pDCB->pWaitingSRB )
+ {
+ SRBwaiting(pDCB, pSRB);
+/* pSRB = GetWaitingSRB(pDCB); */
+ pSRB = pDCB->pWaitingSRB;
+ pDCB->pWaitingSRB = pSRB->pNextSRB;
+ pSRB->pNextSRB = NULL;
+ }
+
+ if( !DC390_StartSCSI(pACB, pDCB, pSRB) )
+ {
+ pDCB->GoingSRBCnt++;
+ if( pDCB->pGoingSRB )
+ {
+ pDCB->pGoingLast->pNextSRB = pSRB;
+ pDCB->pGoingLast = pSRB;
+ }
+ else
+ {
+ pDCB->pGoingSRB = pSRB;
+ pDCB->pGoingLast = pSRB;
+ }
+ }
+ else
+ RewaitSRB0( pDCB, pSRB );
+
+SND_EXIT:
+ restore_flags(flags);
+ return;
+}
+
+
+/***********************************************************************
+ * Function : static int DC390_queue_command (Scsi_Cmnd *cmd,
+ * void (*done)(Scsi_Cmnd *))
+ *
+ * Purpose : enqueues a SCSI command
+ *
+ * Inputs : cmd - SCSI command, done - function called on completion, with
+ * a pointer to the command descriptor.
+ *
+ * Returns : 0
+ *
+ ***********************************************************************/
+
+int
+DC390_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *))
+{
+ USHORT ioport, i;
+ Scsi_Cmnd *pcmd;
+ struct Scsi_Host *psh;
+ PACB pACB;
+ PDCB pDCB;
+ PSRB pSRB;
+ ULONG flags;
+ PUCHAR ptr,ptr1;
+
+ psh = cmd->host;
+ pACB = (PACB ) psh->hostdata;
+ ioport = pACB->IOPortBase;
+
+#ifdef DC390_DEBUG0
+/* if(pACB->scan_devices) */
+ printk("Cmd=%2x,ID=%d,LUN=%d,",cmd->cmnd[0],cmd->target,cmd->lun);
+#endif
+
+ if( (pACB->scan_devices == END_SCAN) && (cmd->cmnd[0] != INQUIRY) )
+ {
+ pACB->scan_devices = 0;
+ pPrevDCB->pNextDCB = pACB->pLinkDCB;
+ }
+ else if( (pACB->scan_devices) && (cmd->cmnd[0] == 8) )
+ {
+ pACB->scan_devices = 0;
+ pPrevDCB->pNextDCB = pACB->pLinkDCB;
+ }
+
+ if ( ( cmd->target > pACB->max_id ) || (cmd->lun > pACB->max_lun) )
+ {
+/* printk("DC390: Ignore target %d lun %d\n",
+ cmd->target, cmd->lun); */
+ cmd->result = (DID_BAD_TARGET << 16);
+ done(cmd);
+ return( 0 );
+ }
+
+ if( (pACB->scan_devices) && !(pACB->DCBmap[cmd->target] & (1 << cmd->lun)) )
+ {
+ if( pACB->DeviceCnt < MAX_DEVICES )
+ {
+ pACB->DCBmap[cmd->target] |= (1 << cmd->lun);
+ pDCB = pACB->pDCB_free;
+#ifdef DC390_DEBUG0
+ printk("pDCB=%8x,ID=%2x,", (UINT) pDCB, cmd->target);
+#endif
+ DC390_initDCB( pACB, pDCB, cmd );
+ }
+ else /* ???? */
+ {
+/* printk("DC390: Ignore target %d lun %d\n",
+ cmd->target, cmd->lun); */
+ cmd->result = (DID_BAD_TARGET << 16);
+ done(cmd);
+ return(0);
+ }
+ }
+ else if( !(pACB->scan_devices) && !(pACB->DCBmap[cmd->target] & (1 << cmd->lun)) )
+ {
+/* printk("DC390: Ignore target %d lun %d\n",
+ cmd->target, cmd->lun); */
+ cmd->result = (DID_BAD_TARGET << 16);
+ done(cmd);
+ return(0);
+ }
+ else
+ {
+ pDCB = pACB->pLinkDCB;
+ while( (pDCB->UnitSCSIID != cmd->target) ||
+ (pDCB->UnitSCSILUN != cmd->lun) )
+ {
+ pDCB = pDCB->pNextDCB;
+ }
+#ifdef DC390_DEBUG0
+ printk("pDCB=%8x,ID=%2x,", (UINT) pDCB, cmd->target);
+#endif
+ }
+
+ cmd->scsi_done = done;
+ cmd->result = 0;
+
+ save_flags(flags);
+ cli();
+
+ if( pDCB->QIORBCnt )
+ {
+ QLinkcmd( cmd, pDCB );
+ pcmd = Getcmd( pDCB );
+ }
+ else
+ pcmd = cmd;
+
+ pSRB = GetSRB( pACB );
+
+ if( !pSRB )
+ {
+ QLinkcmd( pcmd, pDCB );
+ restore_flags(flags);
+ return(0);
+ }
+
+/* BuildSRB(pSRB); */
+
+ pSRB->pSRBDCB = pDCB;
+ pSRB->pcmd = pcmd;
+ ptr = (PUCHAR) pSRB->CmdBlock;
+ ptr1 = (PUCHAR) pcmd->cmnd;
+ pSRB->ScsiCmdLen = pcmd->cmd_len;
+ for(i=0; i< pcmd->cmd_len; i++)
+ {
+ *ptr = *ptr1;
+ ptr++;
+ ptr1++;
+ }
+ if( pcmd->use_sg )
+ {
+ pSRB->SGcount = (UCHAR) pcmd->use_sg;
+ pSRB->pSegmentList = (PSGL) pcmd->request_buffer;
+ }
+ else if( pcmd->request_buffer )
+ {
+ pSRB->SGcount = 1;
+ pSRB->pSegmentList = (PSGL) &pSRB->Segmentx;
+ pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer;
+ pSRB->Segmentx.length = pcmd->request_bufflen;
+ }
+ else
+ pSRB->SGcount = 0;
+
+ pSRB->SGIndex = 0;
+ pSRB->AdaptStatus = 0;
+ pSRB->TargetStatus = 0;
+ pSRB->MsgCnt = 0;
+ if( pDCB->DevType != TYPE_TAPE )
+ pSRB->RetryCnt = 1;
+ else
+ pSRB->RetryCnt = 0;
+ pSRB->SRBStatus = 0;
+ pSRB->SRBFlag = 0;
+ pSRB->SRBState = 0;
+ pSRB->TotalXferredLen = 0;
+ pSRB->SGPhysAddr = 0;
+ pSRB->SGToBeXferLen = 0;
+ pSRB->ScsiPhase = 0;
+ pSRB->EndMessage = 0;
+ SendSRB( pcmd, pACB, pSRB );
+
+ restore_flags(flags);
+ return(0);
+}
+
+
+static void
+DoNextCmd( PACB pACB, PDCB pDCB )
+{
+ Scsi_Cmnd *pcmd;
+ PSRB pSRB;
+ ULONG flags;
+ PUCHAR ptr,ptr1;
+ USHORT i;
+
+
+ if( pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV) )
+ return;
+ save_flags(flags);
+ cli();
+
+ pcmd = Getcmd( pDCB );
+ pSRB = GetSRB( pACB );
+ if( !pSRB )
+ {
+ QLinkcmd( pcmd, pDCB );
+ restore_flags(flags);
+ return;
+ }
+
+ pSRB->pSRBDCB = pDCB;
+ pSRB->pcmd = pcmd;
+ ptr = (PUCHAR) pSRB->CmdBlock;
+ ptr1 = (PUCHAR) pcmd->cmnd;
+ pSRB->ScsiCmdLen = pcmd->cmd_len;
+ for(i=0; i< pcmd->cmd_len; i++)
+ {
+ *ptr = *ptr1;
+ ptr++;
+ ptr1++;
+ }
+ if( pcmd->use_sg )
+ {
+ pSRB->SGcount = (UCHAR) pcmd->use_sg;
+ pSRB->pSegmentList = (PSGL) pcmd->request_buffer;
+ }
+ else if( pcmd->request_buffer )
+ {
+ pSRB->SGcount = 1;
+ pSRB->pSegmentList = (PSGL) &pSRB->Segmentx;
+ pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer;
+ pSRB->Segmentx.length = pcmd->request_bufflen;
+ }
+ else
+ pSRB->SGcount = 0;
+
+ pSRB->SGIndex = 0;
+ pSRB->AdaptStatus = 0;
+ pSRB->TargetStatus = 0;
+ pSRB->MsgCnt = 0;
+ if( pDCB->DevType != TYPE_TAPE )
+ pSRB->RetryCnt = 1;
+ else
+ pSRB->RetryCnt = 0;
+ pSRB->SRBStatus = 0;
+ pSRB->SRBFlag = 0;
+ pSRB->SRBState = 0;
+ pSRB->TotalXferredLen = 0;
+ pSRB->SGPhysAddr = 0;
+ pSRB->SGToBeXferLen = 0;
+ pSRB->ScsiPhase = 0;
+ pSRB->EndMessage = 0;
+ SendSRB( pcmd, pACB, pSRB );
+
+ restore_flags(flags);
+ return;
+}
+
+
+/***********************************************************************
+ * Function:
+ * DC390_bios_param
+ *
+ * Description:
+ * Return the disk geometry for the given SCSI device.
+ ***********************************************************************/
+#ifdef VERSION_ELF_1_2_13
+int DC390_bios_param(Disk *disk, int devno, int geom[])
+#else
+int DC390_bios_param(Disk *disk, kdev_t devno, int geom[])
+#endif
+{
+ int heads, sectors, cylinders;
+ PACB pACB;
+
+ pACB = (PACB) disk->device->host->hostdata;
+ heads = 64;
+ sectors = 32;
+ cylinders = disk->capacity / (heads * sectors);
+
+ if ( cylinders > 1024)
+ {
+ heads = 255;
+ sectors = 63;
+ cylinders = disk->capacity / (255 * 63);
+ }
+
+ geom[0] = heads;
+ geom[1] = sectors;
+ geom[2] = cylinders;
+
+ return (0);
+}
+
+
+/***********************************************************************
+ * Function : int DC390_abort (Scsi_Cmnd *cmd)
+ *
+ * Purpose : Abort an errant SCSI command
+ *
+ * Inputs : cmd - command to abort
+ *
+ * Returns : 0 on success, -1 on failure.
+ ***********************************************************************/
+
+int
+DC390_abort (Scsi_Cmnd *cmd)
+{
+ ULONG flags;
+ PACB pACB;
+ PDCB pDCB, pdcb;
+ PSRB pSRB, psrb;
+ USHORT count, i;
+ PSCSICMD pcmd, pcmd1;
+ int status;
+
+
+#ifdef DC390_DEBUG0
+ printk("DC390 : Abort Cmd.");
+#endif
+
+ save_flags(flags);
+ cli();
+
+ pACB = (PACB) cmd->host->hostdata;
+ pDCB = pACB->pLinkDCB;
+ pdcb = pDCB;
+ while( (pDCB->UnitSCSIID != cmd->target) ||
+ (pDCB->UnitSCSILUN != cmd->lun) )
+ {
+ pDCB = pDCB->pNextDCB;
+ if( pDCB == pdcb )
+ goto NOT_RUN;
+ }
+
+ if( pDCB->QIORBCnt )
+ {
+ pcmd = pDCB->pQIORBhead;
+ if( pcmd == cmd )
+ {
+ pDCB->pQIORBhead = pcmd->next;
+ pcmd->next = NULL;
+ pDCB->QIORBCnt--;
+ status = SCSI_ABORT_SUCCESS;
+ goto ABO_X;
+ }
+ for( count = pDCB->QIORBCnt, i=0; i<count-1; i++)
+ {
+ if( pcmd->next == cmd )
+ {
+ pcmd1 = pcmd->next;
+ pcmd->next = pcmd1->next;
+ pcmd1->next = NULL;
+ pDCB->QIORBCnt--;
+ status = SCSI_ABORT_SUCCESS;
+ goto ABO_X;
+ }
+ else
+ {
+ pcmd = pcmd->next;
+ }
+ }
+ }
+
+ pSRB = pDCB->pWaitingSRB;
+ if( !pSRB )
+ goto ON_GOING;
+ if( pSRB->pcmd == cmd )
+ {
+ pDCB->pWaitingSRB = pSRB->pNextSRB;
+ goto IN_WAIT;
+ }
+ else
+ {
+ psrb = pSRB;
+ if( !(psrb->pNextSRB) )
+ goto ON_GOING;
+ while( psrb->pNextSRB->pcmd != cmd )
+ {
+ psrb = psrb->pNextSRB;
+ if( !(psrb->pNextSRB) )
+ goto ON_GOING;
+ }
+ pSRB = psrb->pNextSRB;
+ psrb->pNextSRB = pSRB->pNextSRB;
+ if( pSRB == pDCB->pWaitLast )
+ pDCB->pWaitLast = psrb; /* No check for psrb == NULL ? */
+IN_WAIT:
+ pSRB->pNextSRB = pACB->pFreeSRB;
+ pACB->pFreeSRB = pSRB;
+ cmd->next = NULL;
+ status = SCSI_ABORT_SUCCESS;
+ goto ABO_X;
+ }
+
+ON_GOING:
+ pSRB = pDCB->pGoingSRB;
+ for( count = pDCB->GoingSRBCnt, i=0; i<count; i++)
+ {
+ if( pSRB->pcmd != cmd )
+ pSRB = pSRB->pNextSRB;
+ else
+ {
+ if( (pACB->pActiveDCB == pDCB) && (pDCB->pActiveSRB == pSRB) )
+ {
+ status = SCSI_ABORT_BUSY;
+ goto ABO_X;
+ }
+ else
+ {
+ status = SCSI_ABORT_SNOOZE;
+ goto ABO_X;
+ }
+ }
+ }
+
+NOT_RUN:
+ status = SCSI_ABORT_NOT_RUNNING;
+
+ABO_X:
+ cmd->result = DID_ABORT << 16;
+ cmd->scsi_done(cmd);
+ restore_flags(flags);
+ return( status );
+}
+
+
+static void
+ResetDevParam( PACB pACB )
+{
+ PDCB pDCB, pdcb;
+
+ pDCB = pACB->pLinkDCB;
+ if( pDCB == NULL )
+ return;
+ pdcb = pDCB;
+ do
+ {
+ pDCB->SyncMode &= ~SYNC_NEGO_DONE;
+ pDCB->SyncPeriod = 0;
+ pDCB->SyncOffset = 0;
+ pDCB->CtrlR3 = FAST_CLK;
+ pDCB->CtrlR4 &= NEGATE_REQACKDATA;
+ pDCB->CtrlR4 |= EATER_25NS;
+ pDCB = pDCB->pNextDCB;
+ }
+ while( pdcb != pDCB );
+}
+
+
+static void
+RecoverSRB( PACB pACB )
+{
+ PDCB pDCB, pdcb;
+ PSRB psrb, psrb2;
+ USHORT cnt, i;
+
+ pDCB = pACB->pLinkDCB;
+ if( pDCB == NULL )
+ return;
+ pdcb = pDCB;
+ do
+ {
+ cnt = pdcb->GoingSRBCnt;
+ psrb = pdcb->pGoingSRB;
+ for (i=0; i<cnt; i++)
+ {
+ psrb2 = psrb;
+ psrb = psrb->pNextSRB;
+/* RewaitSRB( pDCB, psrb ); */
+ if( pdcb->pWaitingSRB )
+ {
+ psrb2->pNextSRB = pdcb->pWaitingSRB;
+ pdcb->pWaitingSRB = psrb2;
+ }
+ else
+ {
+ pdcb->pWaitingSRB = psrb2;
+ pdcb->pWaitLast = psrb2;
+ psrb2->pNextSRB = NULL;
+ }
+ }
+ pdcb->GoingSRBCnt = 0;
+ pdcb->pGoingSRB = NULL;
+ pdcb->TagMask = 0;
+ pdcb = pdcb->pNextDCB;
+ }
+ while( pdcb != pDCB );
+}
+
+
+/***********************************************************************
+ * Function : int DC390_reset (Scsi_Cmnd *cmd, ...)
+ *
+ * Purpose : perform a hard reset on the SCSI bus
+ *
+ * Inputs : cmd - command which caused the SCSI RESET
+ *
+ * Returns : 0 on success.
+ ***********************************************************************/
+
+#ifdef VERSION_2_0_0
+int DC390_reset(Scsi_Cmnd *cmd, unsigned int resetFlags)
+#else
+int DC390_reset (Scsi_Cmnd *cmd)
+#endif
+{
+ USHORT ioport;
+ unsigned long flags;
+ PACB pACB;
+ UCHAR bval;
+ USHORT i;
+
+
+#ifdef DC390_DEBUG1
+ printk("DC390: RESET,");
+#endif
+
+ pACB = (PACB ) cmd->host->hostdata;
+ ioport = pACB->IOPortBase;
+ save_flags(flags);
+ cli();
+ bval = inb(ioport+CtrlReg1);
+ bval |= DIS_INT_ON_SCSI_RST;
+ outb(bval,ioport+CtrlReg1); /* disable interrupt */
+ DC390_ResetSCSIBus( pACB );
+ for( i=0; i<500; i++ )
+ udelay(1000);
+ bval = inb(ioport+CtrlReg1);
+ bval &= ~DIS_INT_ON_SCSI_RST;
+ outb(bval,ioport+CtrlReg1); /* re-enable interrupt */
+
+ bval = DMA_IDLE_CMD;
+ outb(bval,ioport+DMA_Cmd);
+ bval = CLEAR_FIFO_CMD;
+ outb(bval,ioport+ScsiCmd);
+
+ ResetDevParam( pACB );
+ DoingSRB_Done( pACB );
+ pACB->pActiveDCB = NULL;
+
+ pACB->ACBFlag = 0;
+ DoWaitingSRB( pACB );
+
+ restore_flags(flags);
+#ifdef DC390_DEBUG1
+ printk("DC390: RESET1,");
+#endif
+ return( SCSI_RESET_SUCCESS );
+}
+
+
+#include "scsiiom.c"
+
+
+/***********************************************************************
+ * Function : static void DC390_initDCB
+ *
+ * Purpose : initialize the internal structures for a given DCB
+ *
+ * Inputs : cmd - pointer to this scsi cmd request block structure
+ *
+ ***********************************************************************/
+void DC390_initDCB( PACB pACB, PDCB pDCB, PSCSICMD cmd )
+{
+ PEEprom prom;
+ UCHAR bval;
+ USHORT index;
+
+ if( pACB->DeviceCnt == 0 )
+ {
+ pACB->pLinkDCB = pDCB;
+ pACB->pDCBRunRobin = pDCB;
+ pDCB->pNextDCB = pDCB;
+ pPrevDCB = pDCB;
+ }
+ else
+ pPrevDCB->pNextDCB = pDCB;
+
+ pDCB->pDCBACB = pACB;
+ pDCB->QIORBCnt = 0;
+ pDCB->UnitSCSIID = cmd->target;
+ pDCB->UnitSCSILUN = cmd->lun;
+ pDCB->pWaitingSRB = NULL;
+ pDCB->pGoingSRB = NULL;
+ pDCB->GoingSRBCnt = 0;
+ pDCB->pActiveSRB = NULL;
+ pDCB->TagMask = 0;
+ pDCB->MaxCommand = 1;
+ pDCB->AdaptIndex = pACB->AdapterIndex;
+ index = pACB->AdapterIndex;
+ pDCB->DCBFlag = 0;
+
+ prom = (PEEprom) &eepromBuf[index][cmd->target << 2];
+ pDCB->DevMode = prom->EE_MODE1;
+ pDCB->AdpMode = eepromBuf[index][EE_MODE2];
+
+ if( pDCB->DevMode & EN_DISCONNECT_ )
+ bval = 0xC0;
+ else
+ bval = 0x80;
+ bval |= cmd->lun;
+ pDCB->IdentifyMsg = bval;
+
+ pDCB->SyncMode = 0;
+ if( pDCB->DevMode & SYNC_NEGO_ )
+ {
+ if( !(cmd->lun) || CurrSyncOffset )
+ pDCB->SyncMode = SYNC_ENABLE;
+ }
+
+ pDCB->SyncPeriod = 0;
+ pDCB->SyncOffset = 0;
+ pDCB->NegoPeriod = (clock_period1[prom->EE_SPEED] * 25) >> 2;
+
+ pDCB->CtrlR1 = pACB->AdaptSCSIID;
+ if( pDCB->DevMode & PARITY_CHK_ )
+ pDCB->CtrlR1 |= PARITY_ERR_REPO;
+
+ pDCB->CtrlR3 = FAST_CLK;
+
+ pDCB->CtrlR4 = EATER_25NS;
+ if( pDCB->AdpMode & ACTIVE_NEGATION)
+ pDCB->CtrlR4 |= NEGATE_REQACKDATA;
+}
+
+
+/***********************************************************************
+ * Function : static void DC390_initSRB
+ *
+ * Purpose : initialize the internal structures for a given SRB
+ *
+ * Inputs : psrb - pointer to this scsi request block structure
+ *
+ ***********************************************************************/
+void DC390_initSRB( PSRB psrb )
+{
+#ifndef VERSION_ELF_1_2_13
+#ifdef DC390_DEBUG0
+ printk("DC390 init: %08lx %08lx,",(ULONG)psrb,(ULONG)virt_to_bus(psrb));
+#endif
+ psrb->PhysSRB = virt_to_bus( psrb );
+#else
+ psrb->PhysSRB = (ULONG) psrb;
+#endif
+}
+
+
+void DC390_linkSRB( PACB pACB )
+{
+ USHORT count, i;
+ PSRB psrb;
+
+ count = pACB->SRBCount;
+
+ for( i=0; i< count; i++)
+ {
+ if( i != count - 1)
+ pACB->SRB_array[i].pNextSRB = &pACB->SRB_array[i+1];
+ else
+ pACB->SRB_array[i].pNextSRB = NULL;
+ psrb = (PSRB) &pACB->SRB_array[i];
+ DC390_initSRB( psrb );
+ }
+}
+
+
+/***********************************************************************
+ * Function : static void DC390_initACB
+ *
+ * Purpose : initialize the internal structures for a given SCSI host
+ *
+ * Inputs : psh - pointer to this host adapter's structure
+ *
+ ***********************************************************************/
+void DC390_initACB( PSH psh, ULONG io_port, UCHAR Irq, USHORT index )
+{
+ PACB pACB;
+ USHORT i;
+
+ psh->can_queue = MAX_CMD_QUEUE;
+ psh->cmd_per_lun = MAX_CMD_PER_LUN;
+ psh->this_id = (int) eepromBuf[index][EE_ADAPT_SCSI_ID];
+ psh->io_port = io_port;
+ psh->n_io_port = 0x80;
+ psh->irq = Irq;
+
+ pACB = (PACB) psh->hostdata;
+
+#ifndef VERSION_ELF_1_2_13
+ psh->max_id = 8;
+#ifdef CONFIG_SCSI_MULTI_LUN
+ if( eepromBuf[index][EE_MODE2] & LUN_CHECK )
+ psh->max_lun = 8;
+ else
+#endif
+ psh->max_lun = 1;
+#endif
+
+ pACB->max_id = 7;
+ if( pACB->max_id == eepromBuf[index][EE_ADAPT_SCSI_ID] )
+ pACB->max_id--;
+#ifdef CONFIG_SCSI_MULTI_LUN
+ if( eepromBuf[index][EE_MODE2] & LUN_CHECK )
+ pACB->max_lun = 7;
+ else
+#endif
+ pACB->max_lun = 0;
+
+ pACB->pScsiHost = psh;
+ pACB->IOPortBase = (USHORT) io_port;
+ pACB->pLinkDCB = NULL;
+ pACB->pDCBRunRobin = NULL;
+ pACB->pActiveDCB = NULL;
+ pACB->pFreeSRB = pACB->SRB_array;
+ pACB->SRBCount = MAX_SRB_CNT;
+ pACB->AdapterIndex = index;
+ pACB->status = 0;
+ pACB->AdaptSCSIID = eepromBuf[index][EE_ADAPT_SCSI_ID];
+ pACB->HostID_Bit = (1 << pACB->AdaptSCSIID);
+ pACB->AdaptSCSILUN = 0;
+ pACB->DeviceCnt = 0;
+ pACB->IRQLevel = Irq;
+ pACB->TagMaxNum = eepromBuf[index][EE_TAG_CMD_NUM] << 2;
+ pACB->ACBFlag = 0;
+ pACB->scan_devices = 1;
+ pACB->Gmode2 = eepromBuf[index][EE_MODE2];
+ if( eepromBuf[index][EE_MODE2] & LUN_CHECK )
+ pACB->LUNchk = 1;
+ pACB->pDCB_free = &pACB->DCB_array[0];
+ DC390_linkSRB( pACB );
+ pACB->pTmpSRB = &pACB->TmpSRB;
+ DC390_initSRB( pACB->pTmpSRB );
+ for(i=0; i<MAX_SCSI_ID; i++)
+ pACB->DCBmap[i] = 0;
+}
+
+
+/***********************************************************************
+ * Function : static int DC390_initAdapter
+ *
+ * Purpose : initialize the SCSI chip ctrl registers
+ *
+ * Inputs : psh - pointer to this host adapter's structure
+ *
+ ***********************************************************************/
+int DC390_initAdapter( PSH psh, ULONG io_port, UCHAR Irq, USHORT index )
+{
+ USHORT ioport;
+ UCHAR bval;
+ PACB pACB, pacb;
+ USHORT used_irq = 0;
+
+ pacb = pACB_start;
+ if( pacb != NULL )
+ {
+ for ( ; (pacb != (PACB) -1) ; )
+ {
+ if( pacb->IRQLevel == Irq )
+ {
+ used_irq = 1;
+ break;
+ }
+ else
+ pacb = pacb->pNextACB;
+ }
+ }
+
+ if( !used_irq )
+ {
+#ifdef VERSION_ELF_1_2_13
+ if( request_irq(Irq, DC390_Interrupt, SA_INTERRUPT, "tmscsim"))
+#else
+ if( request_irq(Irq, DC390_Interrupt, SA_INTERRUPT, "tmscsim", NULL))
+#endif
+ {
+ printk("DC390: register IRQ error!\n");
+ return( -1 );
+ }
+ }
+
+ request_region(io_port,psh->n_io_port,"tmscsim");
+
+ ioport = (USHORT) io_port;
+
+ pACB = (PACB) psh->hostdata;
+ bval = SEL_TIMEOUT; /* 250ms selection timeout */
+ outb(bval,ioport+Scsi_TimeOut);
+
+ bval = CLK_FREQ_40MHZ; /* Conversion factor = 0 , 40MHz clock */
+ outb(bval,ioport+Clk_Factor);
+
+ bval = NOP_CMD; /* NOP cmd - clear command register */
+ outb(bval,ioport+ScsiCmd);
+
+ bval = EN_FEATURE+EN_SCSI2_CMD; /* Enable Feature and SCSI-2 */
+ outb(bval,ioport+CtrlReg2);
+
+ bval = FAST_CLK; /* fast clock */
+ outb(bval,ioport+CtrlReg3);
+
+ bval = EATER_25NS;
+ if( eepromBuf[index][EE_MODE2] & ACTIVE_NEGATION )
+ bval |= NEGATE_REQACKDATA;
+ outb(bval,ioport+CtrlReg4);
+
+ bval = DIS_INT_ON_SCSI_RST; /* Disable SCSI bus reset interrupt */
+ outb(bval,ioport+CtrlReg1);
+
+ return(0);
+}
+
+
+void
+DC390_EnableCfg( USHORT mechnum, UCHAR regval )
+{
+ ULONG wlval;
+
+ if(mechnum == 2)
+ {
+ outb(mech2bus, PCI_CFG2_FORWARD_REG);
+ outb(mech2CfgSPenR, PCI_CFG2_ENABLE_REG);
+ }
+ else
+ {
+ regval &= 0xFC;
+ wlval = mech1addr;
+ wlval |= (((ULONG)regval) & 0xff);
+ outl(wlval, PCI_CFG1_ADDRESS_REG);
+ }
+}
+
+
+void
+DC390_DisableCfg( USHORT mechnum )
+{
+
+ if(mechnum == 2)
+ outb(0, PCI_CFG2_ENABLE_REG);
+ else
+ outl(0, PCI_CFG1_ADDRESS_REG);
+}
+
+
+UCHAR
+DC390_inByte( USHORT mechnum, UCHAR regval )
+{
+ UCHAR bval;
+ ULONG wval;
+ ULONG flags;
+
+ save_flags(flags);
+ cli();
+ DC390_EnableCfg( mechnum, regval );
+ if(mechnum == 2)
+ {
+ wval = mech2Agent;
+ wval <<= 8;
+ wval |= ((USHORT) regval) & 0xff;
+ bval = inb(wval);
+ }
+ else
+ {
+ regval &= 3;
+ bval = inb(PCI_CFG1_DATA_REG | regval);
+ }
+ DC390_DisableCfg(mechnum);
+ restore_flags(flags);
+ return(bval);
+}
+
+
+USHORT
+DC390_inWord( USHORT mechnum, UCHAR regval )
+{
+ USHORT wval;
+ ULONG flags;
+
+ save_flags(flags);
+ cli();
+ DC390_EnableCfg(mechnum,regval);
+ if(mechnum == 2)
+ {
+ wval = mech2Agent;
+ wval <<= 8;
+ wval |= regval;
+ wval = inw(wval);
+ }
+ else
+ {
+ regval &= 3;
+ wval = inw(PCI_CFG1_DATA_REG | regval);
+ }
+ DC390_DisableCfg(mechnum);
+ restore_flags(flags);
+ return(wval);
+}
+
+
+ULONG
+DC390_inDword(USHORT mechnum, UCHAR regval )
+{
+ ULONG wlval;
+ ULONG flags;
+ USHORT wval;
+
+ save_flags(flags);
+ cli();
+ DC390_EnableCfg(mechnum,regval);
+ if(mechnum == 2)
+ {
+ wval = mech2Agent;
+ wval <<= 8;
+ wval |= regval;
+ wlval = inl(wval);
+ }
+ else
+ {
+ wlval = inl(PCI_CFG1_DATA_REG);
+ }
+ DC390_DisableCfg(mechnum);
+ restore_flags(flags);
+ return(wlval);
+}
+
+
+void
+DC390_OutB(USHORT mechnum, UCHAR regval, UCHAR bval )
+{
+
+ USHORT wval;
+ ULONG flags;
+
+ save_flags(flags);
+ cli();
+ DC390_EnableCfg(mechnum,regval);
+ if(mechnum == 2)
+ {
+ wval = mech2Agent;
+ wval <<= 8;
+ wval |= regval;
+ outb(bval, wval);
+ }
+ else
+ {
+ regval &= 3;
+ outb(bval, PCI_CFG1_DATA_REG | regval);
+ }
+ DC390_DisableCfg(mechnum);
+ restore_flags(flags);
+}
+
+
+void
+DC390_EnDisableCE( UCHAR mode, USHORT mechnum, PUCHAR regval )
+{
+
+ UCHAR bval;
+
+ bval = 0;
+ if(mode == ENABLE_CE)
+ *regval = 0xc0;
+ else
+ *regval = 0x80;
+ DC390_OutB(mechnum,*regval,bval);
+ if(mode == DISABLE_CE)
+ DC390_OutB(mechnum,*regval,bval);
+ udelay(160);
+}
+
+
+void
+DC390_EEpromOutDI( USHORT mechnum, PUCHAR regval, USHORT Carry )
+{
+ UCHAR bval;
+
+ bval = 0;
+ if(Carry)
+ {
+ bval = 0x40;
+ *regval = 0x80;
+ DC390_OutB(mechnum,*regval,bval);
+ }
+ udelay(160);
+ bval |= 0x80;
+ DC390_OutB(mechnum,*regval,bval);
+ udelay(160);
+ bval = 0;
+ DC390_OutB(mechnum,*regval,bval);
+ udelay(160);
+}
+
+
+UCHAR
+DC390_EEpromInDO( USHORT mechnum )
+{
+ UCHAR bval,regval;
+
+ regval = 0x80;
+ bval = 0x80;
+ DC390_OutB(mechnum,regval,bval);
+ udelay(160);
+ bval = 0x40;
+ DC390_OutB(mechnum,regval,bval);
+ udelay(160);
+ regval = 0x0;
+ bval = DC390_inByte(mechnum,regval);
+ if(bval == 0x22)
+ return(1);
+ else
+ return(0);
+}
+
+
+USHORT
+EEpromGetData1( USHORT mechnum )
+{
+ UCHAR i;
+ UCHAR carryFlag;
+ USHORT wval;
+
+ wval = 0;
+ for(i=0; i<16; i++)
+ {
+ wval <<= 1;
+ carryFlag = DC390_EEpromInDO(mechnum);
+ wval |= carryFlag;
+ }
+ return(wval);
+}
+
+
+void
+DC390_Prepare( USHORT mechnum, PUCHAR regval, UCHAR EEpromCmd )
+{
+ UCHAR i,j;
+ USHORT carryFlag;
+
+ carryFlag = 1;
+ j = 0x80;
+ for(i=0; i<9; i++)
+ {
+ DC390_EEpromOutDI(mechnum,regval,carryFlag);
+ carryFlag = (EEpromCmd & j) ? 1 : 0;
+ j >>= 1;
+ }
+}
+
+
+void
+DC390_ReadEEprom( USHORT mechnum, USHORT index )
+{
+ UCHAR regval,cmd;
+ PUSHORT ptr;
+ USHORT i;
+
+ ptr = (PUSHORT) &eepromBuf[index][0];
+ cmd = EEPROM_READ;
+ for(i=0; i<0x40; i++)
+ {
+ DC390_EnDisableCE(ENABLE_CE, mechnum, &regval);
+ DC390_Prepare(mechnum, &regval, cmd);
+ *ptr = EEpromGetData1(mechnum);
+ ptr++;
+ cmd++;
+ DC390_EnDisableCE(DISABLE_CE,mechnum,&regval);
+ }
+}
+
+
+USHORT
+DC390_CheckEEpromCheckSum( USHORT MechNum, USHORT index )
+{
+ USHORT wval, rc, *ptr;
+ UCHAR i;
+
+ DC390_ReadEEprom( MechNum, index );
+ wval = 0;
+ ptr = (PUSHORT) &eepromBuf[index][0];
+ for(i=0; i<128 ;i+=2, ptr++)
+ wval += *ptr;
+ if( wval == 0x1234 )
+ rc = 0;
+ else
+ rc = -1;
+ return( rc );
+}
+
+
+USHORT
+DC390_ToMech( USHORT Mechnum, USHORT BusDevFunNum )
+{
+ USHORT devnum;
+
+ devnum = BusDevFunNum;
+
+ if(Mechnum == 2)
+ {
+ if(devnum & 0x80)
+ return(-1);
+ mech2bus = (UCHAR)((devnum & 0xff00) >> 8); /* Bus num */
+ mech2Agent = ((UCHAR)(devnum & 0xff)) >> 3; /* Dev num */
+ mech2Agent |= 0xc0;
+ mech2CfgSPenR = ((UCHAR)(devnum & 0xff)) & 0x07; /* Fun num */
+ mech2CfgSPenR = (mech2CfgSPenR << 1) | 0x20;
+ }
+ else /* use mech #1 method */
+ {
+ mech1addr = 0x80000000 | ((ULONG)devnum << 8);
+ }
+ return(0);
+}
+
+/***********************************************************************
+ * Function : static int DC390_init (struct Scsi_Host *host)
+ *
+ * Purpose : initialize the internal structures for a given SCSI host
+ *
+ * Inputs : host - pointer to this host adapter's structure/
+ *
+ * Preconditions : when this function is called, the chip_type
+ * field of the pACB structure MUST have been set.
+ ***********************************************************************/
+
+static int
+DC390_init (PSHT psht, ULONG io_port, UCHAR Irq, USHORT index, USHORT MechNum)
+{
+ PSH psh;
+ PACB pACB;
+
+ if( !DC390_CheckEEpromCheckSum( MechNum, index) )
+ {
+ psh = scsi_register( psht, sizeof(DC390_ACB) );
+ if( !psh )
+ return( -1 );
+ if( !pSH_start )
+ {
+ pSH_start = psh;
+ pSH_current = psh;
+ }
+ else
+ {
+ pSH_current->next = psh;
+ pSH_current = psh;
+ }
+
+#ifdef DC390_DEBUG0
+ printk("DC390: pSH = %8x,", (UINT) psh);
+ printk("DC390: Index %02i,", index);
+#endif
+
+ DC390_initACB( psh, io_port, Irq, index );
+ if( !DC390_initAdapter( psh, io_port, Irq, index ) )
+ {
+ pACB = (PACB) psh->hostdata;
+ if( !pACB_start )
+ {
+ pACB_start = pACB;
+ pACB_current = pACB;
+ pACB->pNextACB = (PACB) -1;
+ }
+ else
+ {
+ pACB_current->pNextACB = pACB;
+ pACB_current = pACB;
+ pACB->pNextACB = (PACB) -1;
+ }
+
+#ifdef DC390_DEBUG0
+ printk("DC390: pACB = %8x, pDCB_array = %8x, pSRB_array = %8x\n",
+ (UINT) pACB, (UINT) pACB->DCB_array, (UINT) pACB->SRB_array);
+ printk("DC390: ACB size= %4x, DCB size= %4x, SRB size= %4x\n",
+ sizeof(DC390_ACB), sizeof(DC390_DCB), sizeof(DC390_SRB) );
+#endif
+
+ }
+ else
+ {
+ pSH_start = NULL;
+ scsi_unregister( psh );
+ return( -1 );
+ }
+ return( 0 );
+ }
+ else
+ {
+ printk("DC390_init: EEPROM reading error!\n");
+ return( -1 );
+ }
+}
+
+
+/***********************************************************************
+ * Function : int DC390_detect(Scsi_Host_Template *psht)
+ *
+ * Purpose : detects and initializes AMD53C974 SCSI chips
+ * that were autoprobed, overridden on the LILO command line,
+ * or specified at compile time.
+ *
+ * Inputs : psht - template for this SCSI adapter
+ *
+ * Returns : number of host adapters detected
+ *
+ ***********************************************************************/
+
+int
+DC390_detect(Scsi_Host_Template *psht)
+{
+#ifdef FOR_PCI_OK
+ UCHAR pci_bus, pci_device_fn;
+ int error = 0;
+ USHORT chipType = 0;
+ USHORT i;
+#endif
+
+ UCHAR irq;
+ UCHAR istatus;
+#ifndef VERSION_ELF_1_2_13
+ UINT io_port;
+#else
+ ULONG io_port;
+#endif
+ USHORT adaptCnt = 0; /* Number of boards detected */
+ USHORT pci_index = 0; /* Device index to PCI BIOS calls */
+ USHORT MechNum, BusDevFunNum;
+ ULONG wlval;
+
+#ifndef VERSION_ELF_1_2_13
+ psht->proc_dir = &proc_scsi_tmscsim;
+#endif
+
+ InitialTime = 1;
+ pSHT_start = psht;
+ pACB_start = NULL;
+
+ MechNum = 1;
+ for( ; (MechNum < 3) && (!adaptCnt); MechNum++)
+ {
+ BusDevFunNum = 0;
+ for (; adaptCnt < MAX_ADAPTER_NUM ;)
+ {
+ if( !DC390_ToMech( MechNum, BusDevFunNum) )
+ {
+ wlval = DC390_inDword( MechNum, PCI_VENDOR_ID);
+ if(wlval == ( (PCI_DEVICE_ID_AMD53C974 << 16)+
+ PCI_VENDOR_ID_AMD) )
+ {
+ io_port =DC390_inDword(MechNum,PCI_BASE_ADDRESS_0) & 0xFFFE;
+ irq = DC390_inByte( MechNum, PCI_INTERRUPT_LINE);
+#ifdef DC390_DEBUG0
+ printk("DC390: IO_PORT=%4x,IRQ=%x,\n",(UINT) io_port, irq);
+#endif
+ if( !DC390_init(psht, io_port, irq, pci_index, MechNum) )
+ {
+ adaptCnt++;
+ pci_index++;
+ istatus = inb( (USHORT)io_port+INT_Status ); /* Reset Pending INT */
+#ifdef DC390_DEBUG0
+ printk("DC390: Mech=%2x,\n",(UCHAR) MechNum);
+#endif
+ }
+ }
+ }
+ if( BusDevFunNum != 0xfff8 )
+ BusDevFunNum += 8; /* next device # */
+ else
+ break;
+ }
+ }
+
+#ifdef FOR_PCI_OK
+ if ( pcibios_present() )
+ {
+ for (i = 0; i < MAX_ADAPTER_NUM; ++i)
+ {
+ if( !pcibios_find_device( PCI_VENDOR_ID_AMD,
+ PCI_DEVICE_ID_AMD53C974,
+ pci_index, &pci_bus, &pci_device_fn) )
+ {
+ chipType = PCI_DEVICE_ID_AMD53C974;
+ pci_index++;
+ }
+
+ if( chipType )
+ {
+
+ error = pcibios_read_config_dword(pci_bus, pci_device_fn,
+ PCI_BASE_ADDRESS_0, &io_port);
+ error |= pcibios_read_config_byte(pci_bus, pci_device_fn,
+ PCI_INTERRUPT_LINE, &irq);
+ if( error )
+ {
+ printk("DC390_detect: reading configuration registers error!\n");
+ InitialTime = 0;
+ return( 0 );
+ }
+
+ (USHORT) io_port = (USHORT) io_port & 0xFFFE;
+#ifdef DC390_DEBUG0
+ printk("DC390: IO_PORT=%4x,IRQ=%x,\n",(UINT) io_port, irq);
+#endif
+ if( !DC390_init(psht, io_port, irq, i) )
+ adaptCnt++;
+ chipType = 0;
+ }
+ else
+ break;
+ }
+ }
+#endif
+
+ InitialTime = 0;
+ adapterCnt = adaptCnt;
+ return( adaptCnt );
+}
+
+
+#ifndef VERSION_ELF_1_2_13
+
+/********************************************************************
+ * Function: tmscsim_set_info()
+ *
+ * Purpose: Set adapter info (!)
+ *
+ * Not yet implemented
+ *
+ *******************************************************************/
+
+int tmscsim_set_info(char *buffer, int length, struct Scsi_Host *shpnt)
+{
+ return(-ENOSYS); /* Currently this is a no-op */
+}
+
+/********************************************************************
+ * Function: tmscsim_proc_info(char* buffer, char **start,
+ * off_t offset, int length, int hostno, int inout)
+ *
+ * Purpose: return SCSI Adapter/Device Info
+ *
+ * Input: buffer: Pointer to a buffer where to write info
+ * start :
+ * offset:
+ * hostno: Host adapter index
+ * inout : Read (=0) or set(!=0) info
+ *
+ * Output: buffer: contains info
+ * length; length of info in buffer
+ *
+ * return value: length
+ *
+ ********************************************************************/
+
+/* KG: proc_info taken from driver aha152x.c */
+
+#undef SPRINTF
+#define SPRINTF(args...) pos += sprintf(pos, ## args)
+
+#define YESNO(YN)\
+if (YN) SPRINTF(" Yes ");\
+else SPRINTF(" No ")
+
+int tmscsim_proc_info(char *buffer, char **start,
+ off_t offset, int length, int hostno, int inout)
+{
+ int dev, spd, spd1;
+ char *pos = buffer;
+ PSH shpnt;
+ PACB acbpnt;
+ PDCB dcbpnt;
+ unsigned long flags;
+/* Scsi_Cmnd *ptr; */
+
+ acbpnt = pACB_start;
+
+ while(acbpnt != (PACB)-1)
+ {
+ shpnt = acbpnt->pScsiHost;
+ if (shpnt->host_no == hostno) break;
+ acbpnt = acbpnt->pNextACB;
+ }
+
+ if (acbpnt == (PACB)-1) return(-ESRCH);
+ if(!shpnt) return(-ESRCH);
+
+ if(inout) // Has data been written to the file ?
+ return(tmscsim_set_info(buffer, length, shpnt));
+
+ SPRINTF("Tekram DC390(T) PCI SCSI Host Adadpter, ");
+ SPRINTF("Driver Version 1.10, 1996/12/05\n");
+
+ save_flags(flags);
+ cli();
+
+ SPRINTF("SCSI Host Nr %i, ", shpnt->host_no);
+ SPRINTF("DC390 Adapter Nr %i\n", acbpnt->AdapterIndex);
+ SPRINTF("IOPortBase 0x%04x, ", acbpnt->IOPortBase);
+ SPRINTF("IRQLevel 0x%02x\n", acbpnt->IRQLevel);
+
+ SPRINTF("MaxID %i, MaxLUN %i, ",acbpnt->max_id, acbpnt->max_lun);
+ SPRINTF("AdapterID %i, AdapterLUN %i\n", acbpnt->AdaptSCSIID, acbpnt->AdaptSCSILUN);
+
+ SPRINTF("TagMaxNum %i, Status %i\n", acbpnt->TagMaxNum, acbpnt->status);
+
+ SPRINTF("Nr of attached devices: %i\n", acbpnt->DeviceCnt);
+
+ SPRINTF("Un ID LUN Prty Sync DsCn SndS TagQ NegoPeriod SyncSpeed SyncOffs\n");
+
+ dcbpnt = acbpnt->pLinkDCB;
+ for (dev = 0; dev < acbpnt->DeviceCnt; dev++)
+ {
+ SPRINTF("%02i %02i %02i ", dev, dcbpnt->UnitSCSIID, dcbpnt->UnitSCSILUN);
+ YESNO(dcbpnt->DevMode & PARITY_CHK_);
+ YESNO(dcbpnt->SyncMode & SYNC_NEGO_DONE);
+ YESNO(dcbpnt->DevMode & EN_DISCONNECT_);
+ YESNO(dcbpnt->DevMode & SEND_START_);
+ YESNO(dcbpnt->SyncMode & EN_TAG_QUEUING);
+ SPRINTF(" %03i ns ", (dcbpnt->NegoPeriod) << 2);
+ if (dcbpnt->SyncOffset & 0x0f)
+ {
+ spd = 1000/(dcbpnt->NegoPeriod <<2);
+ spd1 = 1000%(dcbpnt->NegoPeriod <<2);
+ spd1 = (spd1 * 10)/(dcbpnt->NegoPeriod <<2);
+ SPRINTF(" %2i.%1i M %02i\n", spd, spd1, (dcbpnt->SyncOffset & 0x0f));
+ }
+ else SPRINTF("\n");
+ /* Add more info ...*/
+ dcbpnt = dcbpnt->pNextDCB;
+ }
+
+ restore_flags(flags);
+ *start = buffer + offset;
+
+ if (pos - buffer < offset)
+ return 0;
+ else if (pos - buffer - offset < length)
+ return pos - buffer - offset;
+ else
+ return length;
+}
+#endif /* VERSION_ELF_1_2_13 */
+
+
+#ifdef MODULE
+
+/***********************************************************************
+ * Function : static int DC390_shutdown (struct Scsi_Host *host)
+ *
+ * Purpose : does a clean (we hope) shutdown of the SCSI chip.
+ * Use prior to dumping core, unloading the driver, etc.
+ *
+ * Returns : 0 on success
+ ***********************************************************************/
+static int
+DC390_shutdown (struct Scsi_Host *host)
+{
+ UCHAR bval;
+ USHORT ioport;
+ unsigned long flags;
+ PACB pACB = (PACB)(host->hostdata);
+
+ ioport = (unsigned int) pACB->IOPortBase;
+
+ save_flags (flags);
+ cli();
+
+/* pACB->soft_reset(host); */
+
+#ifdef DC390_DEBUG0
+ printk("DC390: shutdown,");
+#endif
+
+ bval = inb(ioport+CtrlReg1);
+ bval |= DIS_INT_ON_SCSI_RST;
+ outb(bval,ioport+CtrlReg1); /* disable interrupt */
+ DC390_ResetSCSIBus( pACB );
+
+ restore_flags (flags);
+ return( 0 );
+}
+
+
+int DC390_release(struct Scsi_Host *host)
+{
+ int irq_count;
+ struct Scsi_Host *tmp;
+
+ DC390_shutdown (host);
+
+ if (host->irq != IRQ_NONE)
+ {
+ for (irq_count = 0, tmp = pSH_start; tmp; tmp = tmp->next)
+ {
+ if ( tmp->irq == host->irq )
+ ++irq_count;
+ }
+ if (irq_count == 1)
+ {
+#ifdef DC390_DEBUG0
+ printk("DC390: Free IRQ %i.",host->irq);
+#endif
+#ifndef VERSION_ELF_1_2_13
+ free_irq(host->irq,NULL);
+#else
+ free_irq(host->irq);
+#endif
+ }
+ }
+
+ release_region(host->io_port,host->n_io_port);
+
+ return( 1 );
+}
+
+Scsi_Host_Template driver_template = DC390_T;
+#include "scsi_module.c"
+#endif /* def MODULE */
+
diff --git a/drivers/scsi/tmscsim.h b/drivers/scsi/tmscsim.h
new file mode 100644
index 000000000..361c488ac
--- /dev/null
+++ b/drivers/scsi/tmscsim.h
@@ -0,0 +1,680 @@
+/***********************************************************************
+;* File Name : TMSCSIM.H *
+;* TEKRAM DC-390(T) PCI SCSI Bus Master Host Adapter *
+;* Device Driver *
+;***********************************************************************/
+
+#ifndef TMSCSIM_H
+#define TMSCSIM_H
+
+#define IRQ_NONE 255
+
+typedef unsigned char UCHAR;
+typedef unsigned short USHORT;
+typedef unsigned long ULONG;
+typedef unsigned int UINT;
+
+typedef UCHAR *PUCHAR;
+typedef USHORT *PUSHORT;
+typedef ULONG *PULONG;
+typedef Scsi_Host_Template *PSHT;
+typedef struct Scsi_Host *PSH;
+typedef Scsi_Device *PSCSIDEV;
+typedef Scsi_Cmnd *PSCSICMD;
+typedef void *PVOID;
+typedef struct scatterlist *PSGL, SGL;
+
+
+/*;-----------------------------------------------------------------------*/
+typedef struct _SyncMsg
+{
+UCHAR ExtendMsg;
+UCHAR ExtMsgLen;
+UCHAR SyncXferReq;
+UCHAR Period;
+UCHAR ReqOffset;
+} SyncMsg;
+/*;-----------------------------------------------------------------------*/
+typedef struct _Capacity
+{
+ULONG BlockCount;
+ULONG BlockLength;
+} Capacity;
+/*;-----------------------------------------------------------------------*/
+typedef struct _SGentry
+{
+ULONG SGXferDataPtr;
+ULONG SGXferDataLen;
+} SGentry;
+
+typedef struct _SGentry1
+{
+ULONG SGXLen;
+ULONG SGXPtr;
+} SGentry1, *PSGE;
+
+
+#define MAX_ADAPTER_NUM 4
+#define MAX_DEVICES 10
+#define MAX_SG_LIST_BUF 16
+#define MAX_CMD_QUEUE 20
+#define MAX_CMD_PER_LUN 8
+#define MAX_SCSI_ID 8
+#define MAX_SRB_CNT MAX_CMD_QUEUE+4
+#define END_SCAN 2
+
+#define SEL_TIMEOUT 153 /* 250 ms selection timeout (@ 40 MHz) */
+
+/*
+;-----------------------------------------------------------------------
+; SCSI Request Block
+;-----------------------------------------------------------------------
+*/
+struct _SRB
+{
+UCHAR CmdBlock[12];
+
+struct _SRB *pNextSRB;
+struct _DCB *pSRBDCB;
+PSCSICMD pcmd;
+PSGL pSegmentList;
+
+ULONG PhysSRB;
+ULONG TotalXferredLen;
+ULONG SGPhysAddr; /*;a segment starting address */
+ULONG SGToBeXferLen; /*; to be xfer length */
+
+SGL Segmentx; /* make a one entry of S/G list table */
+
+PUCHAR pMsgPtr;
+USHORT SRBState;
+USHORT Revxx2; /* ??? */
+
+UCHAR MsgInBuf[6];
+UCHAR MsgOutBuf[6];
+
+UCHAR AdaptStatus;
+UCHAR TargetStatus;
+UCHAR MsgCnt;
+UCHAR EndMessage;
+UCHAR TagNumber;
+UCHAR SGcount;
+UCHAR SGIndex;
+UCHAR IORBFlag; /*;81h-Reset, 2-retry */
+
+UCHAR SRBStatus;
+UCHAR RetryCnt;
+UCHAR SRBFlag; /*; b0-AutoReqSense,b6-Read,b7-write */
+ /*; b4-settimeout,b5-Residual valid */
+UCHAR ScsiCmdLen;
+UCHAR ScsiPhase;
+UCHAR Reserved3[3]; /*;for dword alignment */
+ULONG Segment0[2];
+ULONG Segment1[2];
+};
+
+typedef struct _SRB DC390_SRB, *PSRB;
+
+/*
+;-----------------------------------------------------------------------
+; Device Control Block
+;-----------------------------------------------------------------------
+*/
+struct _DCB
+{
+struct _DCB *pNextDCB;
+struct _ACB *pDCBACB;
+
+PSCSICMD pQIORBhead;
+PSCSICMD pQIORBtail;
+PSCSICMD AboIORBhead;
+PSCSICMD AboIORBtail;
+USHORT QIORBCnt;
+USHORT AboIORBcnt;
+
+PSRB pWaitingSRB;
+PSRB pWaitLast;
+PSRB pGoingSRB;
+PSRB pGoingLast;
+PSRB pActiveSRB;
+USHORT GoingSRBCnt;
+USHORT WaitSRBCnt; /* ??? */
+
+ULONG TagMask;
+
+USHORT MaxCommand;
+USHORT AdaptIndex; /*; UnitInfo struc start */
+USHORT UnitIndex; /*; nth Unit on this card */
+UCHAR UnitSCSIID; /*; SCSI Target ID (SCSI Only) */
+UCHAR UnitSCSILUN; /*; SCSI Log. Unit (SCSI Only) */
+
+UCHAR IdentifyMsg;
+UCHAR CtrlR1;
+UCHAR CtrlR3;
+UCHAR CtrlR4;
+
+UCHAR InqDataBuf[8];
+UCHAR CapacityBuf[8];
+UCHAR DevMode;
+UCHAR AdpMode;
+UCHAR SyncMode; /*; 0:async mode */
+UCHAR NegoPeriod; /*;for nego. */
+UCHAR SyncPeriod; /*;for reg. */
+UCHAR SyncOffset; /*;for reg. and nego.(low nibble) */
+UCHAR UnitCtrlFlag;
+UCHAR DCBFlag;
+UCHAR DevType;
+UCHAR Reserved2[3]; /*;for dword alignment */
+};
+
+typedef struct _DCB DC390_DCB, *PDCB;
+/*
+;-----------------------------------------------------------------------
+; Adapter Control Block
+;-----------------------------------------------------------------------
+*/
+struct _ACB
+{
+ULONG PhysACB;
+PSH pScsiHost;
+struct _ACB *pNextACB;
+USHORT IOPortBase;
+USHORT Revxx1; /* ??? */
+
+PDCB pLinkDCB;
+PDCB pDCBRunRobin;
+PDCB pActiveDCB;
+PDCB pDCB_free;
+PSRB pFreeSRB;
+PSRB pTmpSRB;
+USHORT SRBCount;
+USHORT AdapterIndex; /*; nth Adapter this driver */
+USHORT max_id;
+USHORT max_lun;
+
+UCHAR msgin123[4];
+UCHAR status;
+UCHAR AdaptSCSIID; /*; Adapter SCSI Target ID */
+UCHAR AdaptSCSILUN; /*; Adapter SCSI LUN */
+UCHAR DeviceCnt;
+UCHAR IRQLevel;
+UCHAR TagMaxNum;
+UCHAR ACBFlag;
+UCHAR Gmode2;
+UCHAR LUNchk;
+UCHAR scan_devices;
+UCHAR HostID_Bit;
+UCHAR Reserved1[1]; /*;for dword alignment */
+UCHAR DCBmap[MAX_SCSI_ID];
+DC390_DCB DCB_array[MAX_DEVICES]; /* +74h, Len=3E8 */
+DC390_SRB SRB_array[MAX_SRB_CNT]; /* +45Ch, Len= */
+DC390_SRB TmpSRB;
+};
+
+typedef struct _ACB DC390_ACB, *PACB;
+
+/*;-----------------------------------------------------------------------*/
+
+
+#define BIT31 0x80000000
+#define BIT30 0x40000000
+#define BIT29 0x20000000
+#define BIT28 0x10000000
+#define BIT27 0x08000000
+#define BIT26 0x04000000
+#define BIT25 0x02000000
+#define BIT24 0x01000000
+#define BIT23 0x00800000
+#define BIT22 0x00400000
+#define BIT21 0x00200000
+#define BIT20 0x00100000
+#define BIT19 0x00080000
+#define BIT18 0x00040000
+#define BIT17 0x00020000
+#define BIT16 0x00010000
+#define BIT15 0x00008000
+#define BIT14 0x00004000
+#define BIT13 0x00002000
+#define BIT12 0x00001000
+#define BIT11 0x00000800
+#define BIT10 0x00000400
+#define BIT9 0x00000200
+#define BIT8 0x00000100
+#define BIT7 0x00000080
+#define BIT6 0x00000040
+#define BIT5 0x00000020
+#define BIT4 0x00000010
+#define BIT3 0x00000008
+#define BIT2 0x00000004
+#define BIT1 0x00000002
+#define BIT0 0x00000001
+
+/*;---UnitCtrlFlag */
+#define UNIT_ALLOCATED BIT0
+#define UNIT_INFO_CHANGED BIT1
+#define FORMATING_MEDIA BIT2
+#define UNIT_RETRY BIT3
+
+/*;---UnitFlags */
+#define DASD_SUPPORT BIT0
+#define SCSI_SUPPORT BIT1
+#define ASPI_SUPPORT BIT2
+
+/*;----SRBState machine definition */
+#define SRB_FREE 0
+#define SRB_WAIT BIT0
+#define SRB_READY BIT1
+#define SRB_MSGOUT BIT2 /*;arbitration+msg_out 1st byte*/
+#define SRB_MSGIN BIT3
+#define SRB_MSGIN_MULTI BIT4
+#define SRB_COMMAND BIT5
+#define SRB_START_ BIT6 /*;arbitration+msg_out+command_out*/
+#define SRB_DISCONNECT BIT7
+#define SRB_DATA_XFER BIT8
+#define SRB_XFERPAD BIT9
+#define SRB_STATUS BIT10
+#define SRB_COMPLETED BIT11
+#define SRB_ABORT_SENT BIT12
+#define DO_SYNC_NEGO BIT13
+#define SRB_UNEXPECT_RESEL BIT14
+
+/*;---ACBFlag */
+#define RESET_DEV BIT0
+#define RESET_DETECT BIT1
+#define RESET_DONE BIT2
+
+/*;---DCBFlag */
+#define ABORT_DEV_ BIT0
+
+/*;---SRBstatus */
+#define SRB_OK BIT0
+#define ABORTION BIT1
+#define OVER_RUN BIT2
+#define UNDER_RUN BIT3
+#define PARITY_ERROR BIT4
+#define SRB_ERROR BIT5
+
+/*;---SRBFlag */
+#define DATAOUT BIT7
+#define DATAIN BIT6
+#define RESIDUAL_VALID BIT5
+#define ENABLE_TIMER BIT4
+#define RESET_DEV0 BIT2
+#define ABORT_DEV BIT1
+#define AUTO_REQSENSE BIT0
+
+/*;---Adapter status */
+#define H_STATUS_GOOD 0
+#define H_SEL_TIMEOUT 0x11
+#define H_OVER_UNDER_RUN 0x12
+#define H_UNEXP_BUS_FREE 0x13
+#define H_TARGET_PHASE_F 0x14
+#define H_INVALID_CCB_OP 0x16
+#define H_LINK_CCB_BAD 0x17
+#define H_BAD_TARGET_DIR 0x18
+#define H_DUPLICATE_CCB 0x19
+#define H_BAD_CCB_OR_SG 0x1A
+#define H_ABORT 0x0FF
+
+/*; SCSI Status byte codes*/
+#define SCSI_STAT_GOOD 0x0 /*; Good status */
+#define SCSI_STAT_CHECKCOND 0x02 /*; SCSI Check Condition */
+#define SCSI_STAT_CONDMET 0x04 /*; Condition Met */
+#define SCSI_STAT_BUSY 0x08 /*; Target busy status */
+#define SCSI_STAT_INTER 0x10 /*; Intermediate status */
+#define SCSI_STAT_INTERCONDMET 0x14 /*; Intermediate condition met */
+#define SCSI_STAT_RESCONFLICT 0x18 /*; Reservation conflict */
+#define SCSI_STAT_CMDTERM 0x22 /*; Command Terminated */
+#define SCSI_STAT_QUEUEFULL 0x28 /*; Queue Full */
+
+#define SCSI_STAT_UNEXP_BUS_F 0xFD /*; Unexpect Bus Free */
+#define SCSI_STAT_BUS_RST_DETECT 0xFE /*; Scsi Bus Reset detected */
+#define SCSI_STAT_SEL_TIMEOUT 0xFF /*; Selection Time out */
+
+/*;---Sync_Mode */
+#define SYNC_DISABLE 0
+#define SYNC_ENABLE BIT0
+#define SYNC_NEGO_DONE BIT1
+#define WIDE_ENABLE BIT2
+#define WIDE_NEGO_DONE BIT3
+#define EN_TAG_QUEUING BIT4
+#define EN_ATN_STOP BIT5
+
+#define SYNC_NEGO_OFFSET 15
+
+/*;---SCSI bus phase*/
+#define SCSI_DATA_OUT 0
+#define SCSI_DATA_IN 1
+#define SCSI_COMMAND 2
+#define SCSI_STATUS_ 3
+#define SCSI_NOP0 4
+#define SCSI_NOP1 5
+#define SCSI_MSG_OUT 6
+#define SCSI_MSG_IN 7
+
+/*;----SCSI MSG BYTE*/
+#define MSG_COMPLETE 0x00
+#define MSG_EXTENDED 0x01
+#define MSG_SAVE_PTR 0x02
+#define MSG_RESTORE_PTR 0x03
+#define MSG_DISCONNECT 0x04
+#define MSG_INITIATOR_ERROR 0x05
+#define MSG_ABORT 0x06
+#define MSG_REJECT_ 0x07
+#define MSG_NOP 0x08
+#define MSG_PARITY_ERROR 0x09
+#define MSG_LINK_CMD_COMPL 0x0A
+#define MSG_LINK_CMD_COMPL_FLG 0x0B
+#define MSG_BUS_RESET 0x0C
+#define MSG_ABORT_TAG 0x0D
+#define MSG_SIMPLE_QTAG 0x20
+#define MSG_HEAD_QTAG 0x21
+#define MSG_ORDER_QTAG 0x22
+#define MSG_IDENTIFY 0x80
+#define MSG_HOST_ID 0x0C0
+
+/*;----SCSI STATUS BYTE*/
+#define STATUS_GOOD 0x00
+#define CHECK_CONDITION_ 0x02
+#define STATUS_BUSY 0x08
+#define STATUS_INTERMEDIATE 0x10
+#define RESERVE_CONFLICT 0x18
+
+/* cmd->result */
+#define STATUS_MASK_ 0xFF
+#define MSG_MASK 0xFF00
+#define RETURN_MASK 0xFF0000
+
+/*
+** Inquiry Data format
+*/
+
+typedef struct _SCSIInqData { /* INQ */
+
+ UCHAR DevType; /* Periph Qualifier & Periph Dev Type*/
+ UCHAR RMB_TypeMod; /* rem media bit & Dev Type Modifier */
+ UCHAR Vers; /* ISO, ECMA, & ANSI versions */
+ UCHAR RDF; /* AEN, TRMIOP, & response data format*/
+ UCHAR AddLen; /* length of additional data */
+ UCHAR Res1; /* reserved */
+ UCHAR Res2; /* reserved */
+ UCHAR Flags; /* RelADr,Wbus32,Wbus16,Sync,etc. */
+ UCHAR VendorID[8]; /* Vendor Identification */
+ UCHAR ProductID[16]; /* Product Identification */
+ UCHAR ProductRev[4]; /* Product Revision */
+
+
+} SCSI_INQDATA, *PSCSI_INQDATA;
+
+
+/* Inquiry byte 0 masks */
+
+
+#define SCSI_DEVTYPE 0x1F /* Peripheral Device Type */
+#define SCSI_PERIPHQUAL 0xE0 /* Peripheral Qualifier */
+
+
+/* Inquiry byte 1 mask */
+
+#define SCSI_REMOVABLE_MEDIA 0x80 /* Removable Media bit (1=removable) */
+
+
+/* Peripheral Device Type definitions */
+
+#define SCSI_DASD 0x00 /* Direct-access Device */
+#define SCSI_SEQACESS 0x01 /* Sequential-access device */
+#define SCSI_PRINTER 0x02 /* Printer device */
+#define SCSI_PROCESSOR 0x03 /* Processor device */
+#define SCSI_WRITEONCE 0x04 /* Write-once device */
+#define SCSI_CDROM 0x05 /* CD-ROM device */
+#define SCSI_SCANNER 0x06 /* Scanner device */
+#define SCSI_OPTICAL 0x07 /* Optical memory device */
+#define SCSI_MEDCHGR 0x08 /* Medium changer device */
+#define SCSI_COMM 0x09 /* Communications device */
+#define SCSI_NODEV 0x1F /* Unknown or no device type */
+
+/*
+** Inquiry flag definitions (Inq data byte 7)
+*/
+
+#define SCSI_INQ_RELADR 0x80 /* device supports relative addressing*/
+#define SCSI_INQ_WBUS32 0x40 /* device supports 32 bit data xfers */
+#define SCSI_INQ_WBUS16 0x20 /* device supports 16 bit data xfers */
+#define SCSI_INQ_SYNC 0x10 /* device supports synchronous xfer */
+#define SCSI_INQ_LINKED 0x08 /* device supports linked commands */
+#define SCSI_INQ_CMDQUEUE 0x02 /* device supports command queueing */
+#define SCSI_INQ_SFTRE 0x01 /* device supports soft resets */
+
+
+/*
+;==========================================================
+; EEPROM byte offset
+;==========================================================
+*/
+typedef struct _EEprom
+{
+UCHAR EE_MODE1;
+UCHAR EE_SPEED;
+UCHAR xx1;
+UCHAR xx2;
+} EEprom, *PEEprom;
+
+#define EE_ADAPT_SCSI_ID 64
+#define EE_MODE2 65
+#define EE_DELAY 66
+#define EE_TAG_CMD_NUM 67
+
+/*; EE_MODE1 bits definition*/
+#define PARITY_CHK_ BIT0
+#define SYNC_NEGO_ BIT1
+#define EN_DISCONNECT_ BIT2
+#define SEND_START_ BIT3
+#define TAG_QUEUING_ BIT4
+
+/*; EE_MODE2 bits definition*/
+#define MORE2_DRV BIT0
+#define GREATER_1G BIT1
+#define RST_SCSI_BUS BIT2
+#define ACTIVE_NEGATION BIT3
+#define NO_SEEK BIT4
+#define LUN_CHECK BIT5
+
+#define ENABLE_CE 1
+#define DISABLE_CE 0
+#define EEPROM_READ 0x80
+
+/*
+;==========================================================
+; AMD 53C974 Registers bit Definition
+;==========================================================
+*/
+/*
+;====================
+; SCSI Register
+;====================
+*/
+
+/*; Command Reg.(+0CH) */
+#define DMA_COMMAND BIT7
+#define NOP_CMD 0
+#define CLEAR_FIFO_CMD 1
+#define RST_DEVICE_CMD 2
+#define RST_SCSI_BUS_CMD 3
+#define INFO_XFER_CMD 0x10
+#define INITIATOR_CMD_CMPLTE 0x11
+#define MSG_ACCEPTED_CMD 0x12
+#define XFER_PAD_BYTE 0x18
+#define SET_ATN_CMD 0x1A
+#define RESET_ATN_CMD 0x1B
+#define SELECT_W_ATN 0x42
+#define SEL_W_ATN_STOP 0x43
+#define EN_SEL_RESEL 0x44
+#define SEL_W_ATN2 0x46
+#define DATA_XFER_CMD INFO_XFER_CMD
+
+
+/*; SCSI Status Reg.(+10H) */
+#define INTERRUPT BIT7
+#define ILLEGAL_OP_ERR BIT6
+#define PARITY_ERR BIT5
+#define COUNT_2_ZERO BIT4
+#define GROUP_CODE_VALID BIT3
+#define SCSI_PHASE_MASK (BIT2+BIT1+BIT0)
+
+/*; Interrupt Status Reg.(+14H) */
+#define SCSI_RESET BIT7
+#define INVALID_CMD BIT6
+#define DISCONNECTED BIT5
+#define SERVICE_REQUEST BIT4
+#define SUCCESSFUL_OP BIT3
+#define RESELECTED BIT2
+#define SEL_ATTENTION BIT1
+#define SELECTED BIT0
+
+/*; Internal State Reg.(+18H) */
+#define SYNC_OFFSET_FLAG BIT3
+#define INTRN_STATE_MASK (BIT2+BIT1+BIT0)
+
+/*; Clock Factor Reg.(+24H) */
+#define CLK_FREQ_40MHZ 0
+#define CLK_FREQ_35MHZ (BIT2+BIT1+BIT0)
+#define CLK_FREQ_30MHZ (BIT2+BIT1)
+#define CLK_FREQ_25MHZ (BIT2+BIT0)
+#define CLK_FREQ_20MHZ BIT2
+#define CLK_FREQ_15MHZ (BIT1+BIT0)
+#define CLK_FREQ_10MHZ BIT1
+
+/*; Control Reg. 1(+20H) */
+#define EXTENDED_TIMING BIT7
+#define DIS_INT_ON_SCSI_RST BIT6
+#define PARITY_ERR_REPO BIT4
+#define SCSI_ID_ON_BUS (BIT2+BIT1+BIT0)
+
+/*; Control Reg. 2(+2CH) */
+#define EN_FEATURE BIT6
+#define EN_SCSI2_CMD BIT3
+
+/*; Control Reg. 3(+30H) */
+#define ID_MSG_CHECK BIT7
+#define EN_QTAG_MSG BIT6
+#define EN_GRP2_CMD BIT5
+#define FAST_SCSI BIT4 /* ;10MB/SEC */
+#define FAST_CLK BIT3 /* ;25 - 40 MHZ */
+
+/*; Control Reg. 4(+34H) */
+#define EATER_12NS 0
+#define EATER_25NS BIT7
+#define EATER_35NS BIT6
+#define EATER_0NS (BIT7+BIT6)
+#define NEGATE_REQACKDATA BIT2
+#define NEGATE_REQACK BIT3
+/*
+;====================
+; DMA Register
+;====================
+*/
+/*; DMA Command Reg.(+40H) */
+#define READ_DIRECTION BIT7
+#define WRITE_DIRECTION 0
+#define EN_DMA_INT BIT6
+#define MAP_TO_MDL BIT5
+#define DIAGNOSTIC BIT4
+#define DMA_IDLE_CMD 0
+#define DMA_BLAST_CMD BIT0
+#define DMA_ABORT_CMD BIT1
+#define DMA_START_CMD (BIT1+BIT0)
+
+/*; DMA Status Reg.(+54H) */
+#define PCI_MS_ABORT BIT6
+#define BLAST_COMPLETE BIT5
+#define SCSI_INTERRUPT BIT4
+#define DMA_XFER_DONE BIT3
+#define DMA_XFER_ABORT BIT2
+#define DMA_XFER_ERROR BIT1
+#define POWER_DOWN BIT0
+
+/*
+; DMA SCSI Bus and Ctrl.(+70H)
+;EN_INT_ON_PCI_ABORT
+*/
+
+/*
+;==========================================================
+; SCSI Chip register address offset
+;==========================================================
+*/
+#define CtcReg_Low 0x00
+#define CtcReg_Mid 0x04
+#define ScsiFifo 0x08
+#define ScsiCmd 0x0C
+#define Scsi_Status 0x10
+#define INT_Status 0x14
+#define Sync_Period 0x18
+#define Sync_Offset 0x1C
+#define CtrlReg1 0x20
+#define Clk_Factor 0x24
+#define CtrlReg2 0x2C
+#define CtrlReg3 0x30
+#define CtrlReg4 0x34
+#define CtcReg_High 0x38
+#define DMA_Cmd 0x40
+#define DMA_XferCnt 0x44
+#define DMA_XferAddr 0x48
+#define DMA_Wk_ByteCntr 0x4C
+#define DMA_Wk_AddrCntr 0x50
+#define DMA_Status 0x54
+#define DMA_MDL_Addr 0x58
+#define DMA_Wk_MDL_Cntr 0x5C
+#define DMA_ScsiBusCtrl 0x70
+
+#define StcReg_Low CtcReg_Low
+#define StcReg_Mid CtcReg_Mid
+#define Scsi_Dest_ID Scsi_Status
+#define Scsi_TimeOut INT_Status
+#define Intern_State Sync_Period
+#define Current_Fifo Sync_Offset
+#define StcReg_High CtcReg_High
+
+#define am_target Scsi_Status
+#define am_timeout INT_Status
+#define am_seq_step Sync_Period
+#define am_fifo_count Sync_Offset
+
+
+#define DC390_read8(address) \
+ inb(DC390_ioport + (address)))
+
+#define DC390_read16(address) \
+ inw(DC390_ioport + (address)))
+
+#define DC390_read32(address) \
+ inl(DC390_ioport + (address)))
+
+#define DC390_write8(address,value) \
+ outb((value), DC390_ioport + (address)))
+
+#define DC390_write16(address,value) \
+ outw((value), DC390_ioport + (address)))
+
+#define DC390_write32(address,value) \
+ outl((value), DC390_ioport + (address)))
+
+
+/* Configuration method #1 */
+#define PCI_CFG1_ADDRESS_REG 0xcf8
+#define PCI_CFG1_DATA_REG 0xcfc
+#define PCI_CFG1_ENABLE 0x80000000
+#define PCI_CFG1_TUPPLE(bus, device, function, register) \
+ (PCI_CFG1_ENABLE | (((bus) << 16) & 0xff0000) | \
+ (((device) << 11) & 0xf800) | (((function) << 8) & 0x700)| \
+ (((register) << 2) & 0xfc))
+
+/* Configuration method #2 */
+#define PCI_CFG2_ENABLE_REG 0xcf8
+#define PCI_CFG2_FORWARD_REG 0xcfa
+#define PCI_CFG2_ENABLE 0x0f0
+#define PCI_CFG2_TUPPLE(function) \
+ (PCI_CFG2_ENABLE | (((function) << 1) & 0xe))
+
+
+#endif /* TMSCSIM_H */
diff --git a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c
index d89a90a7b..6a0076dde 100644
--- a/drivers/scsi/u14-34f.c
+++ b/drivers/scsi/u14-34f.c
@@ -1,6 +1,11 @@
/*
* u14-34f.c - Low-level driver for UltraStor 14F/34F SCSI host adapters.
*
+ * 17 May 1997 rev. 3.10 for linux 2.0.30 and 2.1.38
+ * Use of serial_number_at_timeout in abort and reset processing.
+ * Use of the __initfunc and __initdata macro in setup code.
+ * Minor cleanups in the list_statistics code.
+ *
* 24 Feb 1997 rev. 3.00 for linux 2.0.29 and 2.1.26
* When loading as a module, parameter passing is now supported
* both in 2.0 and in 2.1 style.
@@ -220,10 +225,12 @@
* between increasing or decreasing by minimizing the seek distance between
* the sector of the commands just completed and the sector of the first
* command in the list to be sorted.
- * Trivial math assures that if there are (Q-1) outstanding request for
- * random seeks over S sectors, the unsorted average seek distance is S/2,
- * while the sorted average seek distance is S/(Q-1). The seek distance is
- * hence divided by a factor (Q-1)/2.
+ * Trivial math assures that the unsorted average seek distance when doing
+ * random seeks over S sectors is S/3.
+ * When (Q-1) requests are uniformly distributed over S sectors, the average
+ * distance between two adjacent requests is S/((Q-1) + 1), so the sorted
+ * average seek distance for (Q-1) random requests over S sectors is S/Q.
+ * The elevator sorting hence divides the seek distance by a factor Q/3.
* The above pure geometric remarks are valid in all cases and the
* driver effectively reduces the seek distance by the predicted factor
* when there are Q concurrent read i/o operations on the device, but this
@@ -273,8 +280,16 @@ MODULE_AUTHOR("Dario Ballabio");
#include <asm/dma.h>
#include <asm/irq.h>
#include "u14-34f.h"
-#include<linux/stat.h>
-#include<linux/config.h>
+#include <linux/stat.h>
+#include <linux/config.h>
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,36)
+#include <linux/init.h>
+#else
+#define __initfunc(A) A
+#define __initdata
+#define __init
+#endif
struct proc_dir_entry proc_scsi_u14_34f = {
PROC_SCSI_U14_34F, 6, "u14_34f",
@@ -419,7 +434,7 @@ static struct Scsi_Host *sh[MAX_BOARDS + 1];
static const char *driver_name = "Ux4F";
static unsigned int irqlist[MAX_IRQ], calls[MAX_IRQ];
-static unsigned int io_port[] = {
+static unsigned int io_port[] __initdata = {
/* Space for MAX_INT_PARAM ports usable while loading as a module */
SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP,
@@ -534,8 +549,7 @@ static void select_queue_depths(struct Scsi_Host *host, Scsi_Device *devlist) {
return;
}
-static inline int wait_on_busy(unsigned int iobase) {
- unsigned int loop = MAXLOOP;
+static inline int wait_on_busy(unsigned int iobase, unsigned int loop) {
while (inb(iobase + REG_LCL_INTR) & BSY_ASSERTED)
if (--loop == 0) return TRUE;
@@ -556,7 +570,7 @@ static int board_inquiry(unsigned int j) {
cpp->scsi_cdbs_len = 6;
cpp->scsi_cdbs[0] = HA_CMD_INQUIRY;
- if (wait_on_busy(sh[j]->io_port)) {
+ if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
printk("%s: board_inquiry, adapter busy.\n", BN(j));
return TRUE;
}
@@ -586,8 +600,8 @@ static int board_inquiry(unsigned int j) {
return FALSE;
}
-static inline int port_detect(unsigned int port_base, unsigned int j,
- Scsi_Host_Template *tpnt) {
+__initfunc (static inline int port_detect \
+ (unsigned int port_base, unsigned int j, Scsi_Host_Template *tpnt)) {
unsigned char irq, dma_channel, subversion, i;
unsigned char in_byte;
char *bus_type, dma_name[16];
@@ -748,7 +762,7 @@ static inline int port_detect(unsigned int port_base, unsigned int j,
}
}
- if (dma_channel == NO_DMA) sprintf(dma_name, "%s", "NO DMA");
+ if (dma_channel == NO_DMA) sprintf(dma_name, "%s", "BMST");
else sprintf(dma_name, "DMA %u", dma_channel);
for (i = 0; i < sh[j]->can_queue; i++)
@@ -781,7 +795,7 @@ static inline int port_detect(unsigned int port_base, unsigned int j,
return TRUE;
}
-void u14_34f_setup(char *str, int *ints) {
+__initfunc (void u14_34f_setup(char *str, int *ints)) {
int i, argc = ints[0];
char *cur = str, *pc;
@@ -813,7 +827,7 @@ void u14_34f_setup(char *str, int *ints) {
return;
}
-int u14_34f_detect(Scsi_Host_Template *tpnt) {
+__initfunc (int u14_34f_detect(Scsi_Host_Template *tpnt)) {
unsigned long flags;
unsigned int j = 0, k;
@@ -983,12 +997,12 @@ int u14_34f_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
if (linked_comm && SCpnt->device->queue_depth > 2
&& TLDEV(SCpnt->device->type)) {
HD(j)->cp_stat[i] = READY;
- flush_dev(SCpnt->device, 0, j, FALSE);
+ flush_dev(SCpnt->device, SCpnt->request.sector, j, FALSE);
restore_flags(flags);
return 0;
}
- if (wait_on_busy(sh[j]->io_port)) {
+ if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
SCpnt->result = DID_ERROR << 16;
SCpnt->host_scribble = NULL;
printk("%s: qcomm, target %d.%d:%d, pid %ld, adapter busy, DID_ERROR,"\
@@ -1018,7 +1032,8 @@ int u14_34f_abort(Scsi_Cmnd *SCarg) {
cli();
j = ((struct hostdata *) SCarg->host->hostdata)->board_number;
- if (SCarg->host_scribble == NULL) {
+ if (SCarg->host_scribble == NULL
+ || SCarg->serial_number != SCarg->serial_number_at_timeout) {
printk("%s: abort, target %d.%d:%d, pid %ld inactive.\n",
BN(j), SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid);
restore_flags(flags);
@@ -1032,7 +1047,7 @@ int u14_34f_abort(Scsi_Cmnd *SCarg) {
if (i >= sh[j]->can_queue)
panic("%s: abort, invalid SCarg->host_scribble.\n", BN(j));
- if (wait_on_busy(sh[j]->io_port)) {
+ if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
printk("%s: abort, timeout error.\n", BN(j));
restore_flags(flags);
return SCSI_ABORT_ERROR;
@@ -1101,13 +1116,19 @@ int u14_34f_reset(Scsi_Cmnd *SCarg, unsigned int reset_flags) {
if (SCarg->host_scribble == NULL)
printk("%s: reset, pid %ld inactive.\n", BN(j), SCarg->pid);
+ if (SCarg->serial_number != SCarg->serial_number_at_timeout) {
+ printk("%s: reset, pid %ld, reset not running.\n", BN(j), SCarg->pid);
+ restore_flags(flags);
+ return SCSI_RESET_NOT_RUNNING;
+ }
+
if (HD(j)->in_reset) {
printk("%s: reset, exit, already in reset.\n", BN(j));
restore_flags(flags);
return SCSI_RESET_ERROR;
}
- if (wait_on_busy(sh[j]->io_port)) {
+ if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
printk("%s: reset, exit, timeout error.\n", BN(j));
restore_flags(flags);
return SCSI_RESET_ERROR;
@@ -1158,7 +1179,7 @@ int u14_34f_reset(Scsi_Cmnd *SCarg, unsigned int reset_flags) {
if (SCpnt == SCarg) arg_done = TRUE;
}
- if (wait_on_busy(sh[j]->io_port)) {
+ if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
printk("%s: reset, cannot reset, timeout error.\n", BN(j));
restore_flags(flags);
return SCSI_RESET_ERROR;
@@ -1271,7 +1292,7 @@ static inline void reorder(unsigned int j, unsigned long cursec,
unsigned int rev = FALSE, s = TRUE, r = TRUE;
unsigned int input_only = TRUE, overlap = FALSE;
unsigned long sl[n_ready], pl[n_ready], ll[n_ready];
- unsigned long maxsec = 0, minsec = ULONG_MAX, seek = 0;
+ unsigned long maxsec = 0, minsec = ULONG_MAX, seek = 0, iseek = 0;
static unsigned int flushcount = 0, batchcount = 0, sortcount = 0;
static unsigned int readycount = 0, ovlcount = 0, inputcount = 0;
@@ -1282,8 +1303,8 @@ static inline void reorder(unsigned int j, unsigned long cursec,
printk("fc %d bc %d ic %d oc %d rc %d rs %d sc %d re %d"\
" av %ldK as %ldK.\n", flushcount, batchcount, inputcount,
ovlcount, readycount, readysorted, sortcount, revcount,
- seeknosort / (readycount - batchcount + 1),
- seeksorted / (readycount - batchcount + 1));
+ seeknosort / (readycount + 1),
+ seeksorted / (readycount + 1));
if (n_ready <= 1) return;
@@ -1311,6 +1332,10 @@ static inline void reorder(unsigned int j, unsigned long cursec,
}
+ if (link_statistics) {
+ if (cursec > sl[0]) seek += cursec - sl[0]; else seek += sl[0] - cursec;
+ }
+
if (cursec > ((maxsec + minsec) / 2)) rev = TRUE;
if (!((rev && r) || (!rev && s))) sort(sl, il, n_ready, rev);
@@ -1328,10 +1353,11 @@ static inline void reorder(unsigned int j, unsigned long cursec,
if (overlap) sort(pl, il, n_ready, FALSE);
if (link_statistics) {
+ if (cursec > sl[0]) iseek = cursec - sl[0]; else iseek = sl[0] - cursec;
batchcount++; readycount += n_ready, seeknosort += seek / 1024;
if (input_only) inputcount++;
if (overlap) { ovlcount++; seeksorted += seek / 1024; }
- else seeksorted += (maxsec - minsec) / 1024;
+ else seeksorted += (iseek + maxsec - minsec) / 1024;
if (rev && !r) { revcount++; readysorted += n_ready; }
if (!rev && !s) { sortcount++; readysorted += n_ready; }
}
@@ -1375,7 +1401,7 @@ static void flush_dev(Scsi_Device *dev, unsigned long cursec, unsigned int j,
for (n = 0; n < n_ready; n++) {
k = il[n]; cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt;
- if (wait_on_busy(sh[j]->io_port)) {
+ if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
printk("%s: %s, target %d.%d:%d, pid %ld, Mbox %d, adapter"\
" busy, will abort.\n", BN(j), (ihdlr ? "ihdlr" : "qcomm"),
SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid, k);
diff --git a/drivers/scsi/u14-34f.h b/drivers/scsi/u14-34f.h
index 588259e10..9381f7729 100644
--- a/drivers/scsi/u14-34f.h
+++ b/drivers/scsi/u14-34f.h
@@ -11,7 +11,7 @@ int u14_34f_abort(Scsi_Cmnd *);
int u14_34f_reset(Scsi_Cmnd *, unsigned int);
int u14_34f_biosparam(Disk *, kdev_t, int *);
-#define U14_34F_VERSION "3.00.09"
+#define U14_34F_VERSION "3.10.00"
#define ULTRASTOR_14_34F { \
NULL, /* Ptr for modules */ \
diff --git a/drivers/scsi/wd33c93.c b/drivers/scsi/wd33c93.c
index 29d74ccea..14cb0f37a 100644
--- a/drivers/scsi/wd33c93.c
+++ b/drivers/scsi/wd33c93.c
@@ -84,24 +84,20 @@
#include "scsi.h"
#include "hosts.h"
+#define WD33C93_VERSION "1.24"
+#define WD33C93_DATE "29/Jan/1997"
-#define PROC_INTERFACE /* add code for /proc/scsi/wd33c93/xxx interface */
-#ifdef PROC_INTERFACE
-#define PROC_STATISTICS /* add code for keeping various real time stats */
-#endif
-
-#define SYNC_DEBUG /* extra info on sync negotiation printed */
-#undef DEBUGGING_ON /* enable command-line debugging bitmask */
-#define DEBUG_DEFAULTS 0 /* default debugging bitmask */
-
-#define WD33C93_VERSION "1.23"
-#define WD33C93_DATE "04/Nov/1996"
+/*
+ * Note - the following defines have been moved to 'wd33c93.h':
+ *
+ * PROC_INTERFACE
+ * PROC_STATISTICS
+ * SYNC_DEBUG
+ * DEBUGGING_ON
+ * DEBUG_DEFAULTS
+ *
+ */
-#ifdef DEBUGGING_ON
-#define DB(f,a) if (hostdata->args & (f)) (a)
-#else
-#define DB(f,a)
-#endif
#include "wd33c93.h"
@@ -162,7 +158,7 @@ static char *setup_strings[] =
{"","","","","","","","","","","",""};
-static inline uchar read_wd33c93(wd33c93_regs *regp, uchar reg_num)
+static inline uchar read_wd33c93(wd33c93_regs *regp,uchar reg_num)
{
regp->SASR = reg_num;
return regp->SCMD;
@@ -216,6 +212,31 @@ static inline unsigned long read_wd33c93_count(wd33c93_regs *regp)
return value;
}
+/* The 33c93 needs to be told which direction a command transfers its
+ * data; we use this function to figure it out. Returns true if there
+ * will be a DATA_OUT phase with this command, false otherwise.
+ * (Thanks to Joerg Dorchain for the research and suggestion.)
+ */
+static int is_dir_out(Scsi_Cmnd *cmd)
+{
+ switch (cmd->cmnd[0]) {
+ case WRITE_6: case WRITE_10: case WRITE_12:
+ case WRITE_LONG: case WRITE_SAME: case WRITE_BUFFER:
+ case WRITE_VERIFY: case WRITE_VERIFY_12:
+ case COMPARE: case COPY: case COPY_VERIFY:
+ case SEARCH_EQUAL: case SEARCH_HIGH: case SEARCH_LOW:
+ case SEARCH_EQUAL_12: case SEARCH_HIGH_12: case SEARCH_LOW_12:
+ case FORMAT_UNIT: case REASSIGN_BLOCKS: case RESERVE:
+ case MODE_SELECT: case MODE_SELECT_10: case LOG_SELECT:
+ case SEND_DIAGNOSTIC: case CHANGE_DEFINITION: case UPDATE_BLOCK:
+ case SET_WINDOW: case MEDIUM_SCAN: case SEND_VOLUME_TAG:
+ case 0xea:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
static struct sx_period sx_table[] = {
{ 1, 0x20},
{252, 0x20},
@@ -252,12 +273,13 @@ static inline uchar calc_sync_xfer(unsigned int period, unsigned int offset)
return result;
}
-void wd33c93_execute(struct Scsi_Host *instance);
+static void wd33c93_execute(struct Scsi_Host *instance);
int wd33c93_queuecommand (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
{
struct WD33C93_hostdata *hostdata = CMDHOSTDATA(cmd);
Scsi_Cmnd *tmp;
+ unsigned long flags;
disable_irq(cmd->host->irq);
DB(DB_QCMD,printk("Q-%d-%02x-%ld( ",cmd->target,cmd->cmnd[0],cmd->pid));
@@ -304,6 +326,10 @@ int wd33c93_queuecommand (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
* commands are added to the head of the queue so that the desired
* sense data is not lost before REQUEST_SENSE executes.
*/
+
+ save_flags(flags);
+ cli();
+
if (!(hostdata->input_Q) || (cmd->cmnd[0] == REQUEST_SENSE)) {
cmd->host_scribble = (uchar *) hostdata->input_Q;
hostdata->input_Q = cmd;
@@ -322,7 +348,7 @@ int wd33c93_queuecommand (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
wd33c93_execute(cmd->host);
DB(DB_QCMD,printk(")Q-%ld ",cmd->pid));
- enable_irq(cmd->host->irq);
+ restore_flags(flags);
return 0;
}
@@ -330,17 +356,19 @@ int wd33c93_queuecommand (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
* already connected, we give up immediately. Otherwise, look through
* the input_Q, using the first command we find that's intended
* for a currently non-busy target/lun.
+ *
+ * wd33c93_execute() is always called with interrupts disabled or from
+ * the wd33c93_intr itself, which means that a wd33c93 interrupt
+ * cannot occur while we are in here.
*/
-void wd33c93_execute(struct Scsi_Host *instance)
+static void wd33c93_execute(struct Scsi_Host *instance)
{
struct WD33C93_hostdata *hostdata = INSTHOSTDATA(instance);
wd33c93_regs *regp = hostdata->regp;
Scsi_Cmnd *cmd = (Scsi_Cmnd *) hostdata->input_Q;
Scsi_Cmnd *prev = 0;
- unsigned long flags;
int i;
- disable_irq(instance->irq);
DB(DB_EXECUTE, printk("EX("));
if (hostdata->selecting || hostdata->connected) {
@@ -453,18 +481,16 @@ no:
* to the default/safe value. SS_UNSET means that the
* parameters are undetermined as yet, and that we
* need to send an SDTR message to this device after
- * selection is complete. We set SS_FIRST to tell the
- * interrupt routine to do so, unless we've been asked
- * not to try synchronous transfers on this target
- * (and _all_ luns within it): In this case we set
- * SS_SET to make the defaults final.
+ * selection is complete: We set SS_FIRST to tell the
+ * interrupt routine to do so. If we've been asked not to
+ * try synchronous transfers on this target (and _all_ luns
+ * within it), we'll still send the SDTR message later, but
+ * at that time we'll negotiate for async by specifying a
+ * sync fifo depth of 0.
*/
- if (hostdata->sync_stat[cmd->target] == SS_UNSET) {
- if (hostdata->no_sync & (1 << cmd->target))
- hostdata->sync_stat[cmd->target] = SS_SET;
- else
- hostdata->sync_stat[cmd->target] = SS_FIRST;
- }
+
+ if (hostdata->sync_stat[cmd->target] == SS_UNSET)
+ hostdata->sync_stat[cmd->target] = SS_FIRST;
hostdata->state = S_SELECTING;
/* guarantee a DATA_PHASE interrupt */
@@ -525,11 +551,10 @@ no:
*/
DB(DB_EXECUTE, printk("%s%ld)EX-2 ", (cmd->SCp.phase) ? "d:":"", cmd->pid));
execute_out:
- enable_irq(instance->irq);
}
-void transfer_pio(wd33c93_regs *regp, uchar *buf, int cnt,
- int data_in_dir, struct WD33C93_hostdata *hostdata)
+static void transfer_pio(wd33c93_regs *regp, uchar *buf, int cnt,
+ int data_in_dir, struct WD33C93_hostdata *hostdata)
{
uchar asr;
@@ -561,6 +586,7 @@ void transfer_pio(wd33c93_regs *regp, uchar *buf, int cnt,
static void transfer_bytes(wd33c93_regs *regp, Scsi_Cmnd *cmd, int data_in_dir)
{
struct WD33C93_hostdata *hostdata = CMDHOSTDATA(cmd);
+ unsigned long length;
/* Normally, you'd expect 'this_residual' to be non-zero here.
* In a series of scatter-gather transfers, however, this
@@ -596,8 +622,7 @@ use_transfer_pio:
hostdata->pio_cnt++;
#endif
transfer_pio(regp, (uchar *)cmd->SCp.ptr,
- cmd->SCp.this_residual, cmd->SCp.this_residual,
- data_in_dir, hostdata);
+ cmd->SCp.this_residual, data_in_dir, hostdata);
length = cmd->SCp.this_residual;
cmd->SCp.this_residual = read_wd33c93_count(regp);
cmd->SCp.ptr += (length - cmd->SCp.this_residual);
@@ -637,13 +662,13 @@ void wd33c93_intr (struct Scsi_Host *instance)
wd33c93_regs *regp = hostdata->regp;
Scsi_Cmnd *patch, *cmd;
uchar asr, sr, phs, id, lun, *ucp, msg;
- unsigned long length;
+ unsigned long length, flags;
asr = READ_AUX_STAT();
if (!(asr & ASR_INT) || (asr & ASR_BSY))
return;
- save_flags(flags);
+ save_flags(flags);
#ifdef PROC_STATISTICS
hostdata->int_cnt++;
@@ -669,13 +694,13 @@ void wd33c93_intr (struct Scsi_Host *instance)
* interrupt normally.
*/
if (hostdata->dma == D_DMA_RUNNING) {
- DB(DB_TRANS,printk("[%p/%d:",cmd->SCp.ptr,cmd->SCp.this_residual));
+ DB(DB_TRANSFER,printk("[%p/%d:",cmd->SCp.ptr,cmd->SCp.this_residual));
hostdata->dma_stop(cmd->host, cmd, 1);
hostdata->dma = D_DMA_OFF;
length = cmd->SCp.this_residual;
cmd->SCp.this_residual = read_wd33c93_count(regp);
cmd->SCp.ptr += (length - cmd->SCp.this_residual);
- DB(DB_TRANS,printk("%p/%d]",cmd->SCp.ptr,cmd->SCp.this_residual));
+ DB(DB_TRANSFER,printk("%p/%d]",cmd->SCp.ptr,cmd->SCp.this_residual));
}
/* Respond to the specific WD3393 interrupt - there are quite a few! */
@@ -683,9 +708,6 @@ void wd33c93_intr (struct Scsi_Host *instance)
case CSR_TIMEOUT:
DB(DB_INTR, printk("TIMEOUT"));
-#ifndef NOINTS_IN_WDINTR
- disable_irq(instance->irq);
-#endif
if (hostdata->state == S_RUNNING_LEVEL2) {
hostdata->connected = NULL;
} else {
@@ -698,20 +720,25 @@ void wd33c93_intr (struct Scsi_Host *instance)
hostdata->state = S_UNCONNECTED;
cmd->scsi_done(cmd);
+ /* From esp.c:
+ * There is a window of time within the scsi_done() path
+ * of execution where interrupts are turned back on full
+ * blast and left that way. During that time we could
+ * reconnect to a disconnected command, then we'd bomb
+ * out below. We could also end up executing two commands
+ * at _once_. ...just so you know why the restore_flags()
+ * is here...
+ */
+ restore_flags(flags);
+
/* We are not connected to a target - check to see if there
* are commands waiting to be executed.
*/
-#ifndef NOINTS_IN_WDINTR
- enable_irq(instance->irq);
-#endif
wd33c93_execute(instance);
break;
case CSR_SELECT:
/* Note: this interrupt should not occur in a LEVEL2 command */
-#ifndef NOINTS_IN_WDINTR
- disable_irq(instance->irq);
-#endif
DB(DB_INTR, printk("SELECT"));
hostdata->connected = cmd = (Scsi_Cmnd *) hostdata->selecting;
hostdata->selecting = NULL;
@@ -726,14 +753,24 @@ void wd33c93_intr (struct Scsi_Host *instance)
#endif
hostdata->sync_stat[cmd->target] = SS_WAITING;
- /* tack on a 2nd message to ask about
- * synchronous transfers
- */
+ /* Tack on a 2nd message to ask about synchronous
+ transfers. If we've been asked to do only
+ asynchronous transfers on this device, we request a
+ fifo depth of 0, which is equivalent to async -
+ should solve the problems some people have had with
+ GVP's Guru ROM. */
+
hostdata->outgoing_msg[1] = EXTENDED_MESSAGE;
hostdata->outgoing_msg[2] = 3;
hostdata->outgoing_msg[3] = EXTENDED_SDTR;
- hostdata->outgoing_msg[4] = OPTIMUM_SX_PER/4;
- hostdata->outgoing_msg[5] = OPTIMUM_SX_OFF;
+ if (hostdata->no_sync & (1 << cmd->target)) {
+ hostdata->outgoing_msg[4] = hostdata->default_sx_per/4;
+ hostdata->outgoing_msg[5] = 0;
+ }
+ else {
+ hostdata->outgoing_msg[4] = OPTIMUM_SX_PER/4;
+ hostdata->outgoing_msg[5] = OPTIMUM_SX_OFF;
+ }
hostdata->outgoing_len = 6;
} else {
hostdata->outgoing_len = 1;
@@ -790,9 +827,6 @@ void wd33c93_intr (struct Scsi_Host *instance)
case CSR_SRV_REQ |PHS_MESS_IN:
DB(DB_INTR, printk("MSG_IN="));
-#ifndef NOINTS_IN_WDINTR
- disable_irq(instance->irq);
-#endif
msg = read_1_byte(regp);
sr = read_wd33c93(regp, WD_SCSI_STATUS); /* clear interrupt */
@@ -951,40 +985,11 @@ void wd33c93_intr (struct Scsi_Host *instance)
write_wd33c93_cmd(regp, WD_CMD_NEGATE_ACK);
hostdata->state = S_CONNECTED;
}
+ restore_flags(flags);
break;
-/* The 33c93 needs to be told which direction a command transfers its
- * data; we use this function to figure it out. Returns true if there
- * will be a DATA_OUT phase with this command, false otherwise.
- * (Thanks to Joerg Dorchain for the research and suggestion.)
- */
-static int is_dir_out(Scsi_Cmnd *cmd)
-{
- switch (cmd->cmnd[0]) {
- case WRITE_6: case WRITE_10: case WRITE_12:
- case WRITE_LONG: case WRITE_SAME: case WRITE_BUFFER:
- case WRITE_VERIFY: case WRITE_VERIFY_12:
- case COMPARE: case COPY: case COPY_VERIFY:
- case SEARCH_EQUAL: case SEARCH_HIGH: case SEARCH_LOW:
- case SEARCH_EQUAL_12: case SEARCH_HIGH_12: case SEARCH_LOW_12:
- case FORMAT_UNIT: case REASSIGN_BLOCKS: case RESERVE:
- case MODE_SELECT: case MODE_SELECT_10: case LOG_SELECT:
- case SEND_DIAGNOSTIC: case CHANGE_DEFINITION: case UPDATE_BLOCK:
- case SET_WINDOW: case MEDIUM_SCAN: case SEND_VOLUME_TAG:
- case 0xea:
- return 1;
- default:
- return 0;
- }
-}
-
-
-
case CSR_SEL_XFER_DONE:
/* Note: this interrupt will occur only after a LEVEL2 command */
-#ifndef NOINTS_IN_WDINTR
- disable_irq(instance->irq);
-#endif
/* Make sure that reselection is enabled at this point - it may
* have been turned off for the command that just completed.
@@ -1010,7 +1015,7 @@ static int is_dir_out(Scsi_Cmnd *cmd)
/* We are no longer connected to a target - check to see if
* there are commands waiting to be executed.
*/
- enable_irq(instance->irq);
+ restore_flags(flags);
wd33c93_execute(instance);
} else {
printk("%02x:%02x:%02x-%ld: Unknown SEL_XFER_DONE "
@@ -1062,9 +1067,6 @@ static int is_dir_out(Scsi_Cmnd *cmd)
* in a legal manner (like a command that provokes a request-sense),
* so we treat it as a normal command-complete-disconnect.
*/
-#ifndef NOINTS_IN_WDINTR
- disable_irq(instance->irq);
-#endif
/* Make sure that reselection is enabled at this point - it may
* have been turned off for the command that just completed.
@@ -1088,15 +1090,12 @@ static int is_dir_out(Scsi_Cmnd *cmd)
/* We are no longer connected to a target - check to see if
* there are commands waiting to be executed.
*/
- enable_irq(instance->irq);
wd33c93_execute(instance);
+ /* look above for comments on scsi_done() */
+ restore_flags(flags);
break;
case CSR_DISC:
-#ifndef NOINTS_IN_WDINTR
- disable_irq(instance->irq);
-#endif
-
/* Make sure that reselection is enabled at this point - it may
* have been turned off for the command that just completed.
*/
@@ -1118,6 +1117,7 @@ static int is_dir_out(Scsi_Cmnd *cmd)
cmd->result = ((cmd->result & 0x00ffff) |
(DID_ERROR << 16));
cmd->scsi_done(cmd);
+ restore_flags(flags);
break;
case S_PRE_TMP_DISC:
case S_RUNNING_LEVEL2:
@@ -1134,7 +1134,6 @@ static int is_dir_out(Scsi_Cmnd *cmd)
printk("*** Unexpected DISCONNECT interrupt! ***");
hostdata->state = S_UNCONNECTED;
}
- enable_irq(instance->irq);
/* We are no longer connected to a target - check to see if
* there are commands waiting to be executed.
*/
@@ -1144,9 +1143,6 @@ static int is_dir_out(Scsi_Cmnd *cmd)
case CSR_RESEL_AM:
DB(DB_INTR,printk("RESEL"));
-#ifndef NOINTS_IN_WDINTR
- disable_irq(instance->irq);
-#endif
/* First we have to make sure this reselection didn't
* happen during Arbitration/Selection of some other device.
* If yes, put losing command back on top of input_Q.
@@ -1241,12 +1237,12 @@ static int is_dir_out(Scsi_Cmnd *cmd)
printk("--UNKNOWN INTERRUPT:%02x:%02x:%02x--", asr, sr, phs);
}
-#ifndef NOINTS_IN_WDINTR
- enable_irq(instance->irq);
-#endif
DB(DB_INTR,printk("} "));
}
+/*
+ * Not static 'cause called from outside ...
+ */
void reset_wd33c93(struct Scsi_Host *instance)
{
struct WD33C93_hostdata *hostdata = INSTHOSTDATA(instance);
@@ -1508,7 +1504,7 @@ void wd33c93_setup (char *str, int *ints)
}
/* check_setup_strings() returns index if key found, 0 if not */
-int check_setup_strings(char *key, int *flags, int *val, char *buf)
+static int check_setup_strings(char *key, int *flags, int *val, char *buf)
{
int x;
char *cp;
@@ -1634,10 +1630,9 @@ void wd33c93_init (struct Scsi_Host *instance, wd33c93_regs *regs,
printk("WD93: Driver version %s ", WD33C93_VERSION);
printk("compiled on %s at %s\n", __DATE__, __TIME__);
#ifdef DEBUGGING_ON
- printk(" debug_flags=0x%02x setup_strings=",
- hostdata->args);
+ printk(" debug_flags=0x%02x\n",hostdata->args);
#else
- printk(" debugging=OFF setup_strings=");
+ printk(" debugging=OFF\n");
#endif
#if 0
printk("wd33c93-%d: setup_strings=", instance->host_no);
@@ -1649,7 +1644,7 @@ void wd33c93_init (struct Scsi_Host *instance, wd33c93_regs *regs,
#endif
}
- printk("wd33c93-%d: chip=%s/%d no_sync=0x%x no_dma=%d\n",
+ printk("wd33c93-%d: chip=%s/%d no_sync=0x%x no_dma=%d",
instance->host_no,
(hostdata->chip==C_WD33C93)?"WD33c93":
(hostdata->chip==C_WD33C93A)?"WD33c93A":
@@ -1659,9 +1654,6 @@ void wd33c93_init (struct Scsi_Host *instance, wd33c93_regs *regs,
MOD_INC_USE_COUNT;
}
-
-}
-
int wd33c93_proc_info(char *buf, char **start, off_t off, int len, int hn, int in)
{
#ifdef PROC_INTERFACE
diff --git a/drivers/scsi/wd33c93.h b/drivers/scsi/wd33c93.h
index 3a2cec4ab..3b8b4cf3a 100644
--- a/drivers/scsi/wd33c93.h
+++ b/drivers/scsi/wd33c93.h
@@ -246,13 +246,17 @@ struct WD33C93_hostdata {
uchar sync_stat[8]; /* status of sync negotiation per target */
uchar no_sync; /* bitmask: don't do sync on these targets */
uchar no_dma; /* set this flag to disable DMA */
+#ifdef PROC_INTERFACE
uchar proc; /* bitmask: what's in proc output */
+#ifdef PROC_STATISTICS
unsigned long cmd_cnt[8]; /* # of commands issued per target */
unsigned long int_cnt; /* # of interrupts serviced */
unsigned long pio_cnt; /* # of pio data transfers */
unsigned long dma_cnt; /* # of DMA data transfers */
unsigned long disc_allowed_cnt[8]; /* # of disconnects allowed per target */
unsigned long disc_done_cnt[8]; /* # of disconnects done per target*/
+#endif
+#endif
};
#define CMDHOSTDATA(cmd) ((struct WD33C93_hostdata *) (cmd)->host->hostdata)
@@ -302,7 +306,7 @@ struct WD33C93_hostdata {
#define DB_QCMD (1<<2)
#define DB_EXECUTE (1<<3)
#define DB_INTR (1<<4)
-#define DB_TRANS (1<<5)
+#define DB_TRANSFER (1<<5)
#define DB_MASK (0x3f)
/* defines for hostdata->sync_stat[] */
diff --git a/drivers/sgi/char/sgicons.c b/drivers/sgi/char/sgicons.c
index c5051702d..097ed1359 100644
--- a/drivers/sgi/char/sgicons.c
+++ b/drivers/sgi/char/sgicons.c
@@ -1,14 +1,15 @@
-/* $Id: sgicons.c,v 1.6 1996/07/29 11:10:22 dm Exp $
+/*
* sgicons.c: Setting up and registering console I/O on the SGI.
*
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
*/
+#include <linux/init.h>
#include <linux/kernel.h>
extern void newport_init(void);
extern unsigned long video_mem_base, video_screen_size, video_mem_term;
-unsigned long con_type_init(unsigned long start_mem, const char **name)
+__initfunc(unsigned long con_type_init(unsigned long start_mem, const char **name))
{
extern int serial_console;
@@ -26,3 +27,7 @@ unsigned long con_type_init(unsigned long start_mem, const char **name)
return start_mem;
}
+
+__initfunc(void con_type_init_finish(void))
+{
+}
diff --git a/drivers/sgi/char/sgiserial.c b/drivers/sgi/char/sgiserial.c
index 843870e94..c48c9ac45 100644
--- a/drivers/sgi/char/sgiserial.c
+++ b/drivers/sgi/char/sgiserial.c
@@ -31,6 +31,8 @@
#define NUM_SERIAL 1 /* One chip on board. */
#define NUM_CHANNELS (NUM_SERIAL * 2)
+extern struct wait_queue * keypress_wait;
+
struct sgi_zslayout *zs_chips[NUM_SERIAL] = { 0, };
struct sgi_zschannel *zs_channels[NUM_CHANNELS] = { 0, 0, };
struct sgi_zschannel *zs_conschan;
@@ -351,7 +353,7 @@ static _INLINE_ void rs_sched_event(struct sgi_serial *info,
int event)
{
info->event |= 1 << event;
- queue_task_irq_off(&info->tqueue, &tq_serial);
+ queue_task(&info->tqueue, &tq_serial);
mark_bh(SERIAL_BH);
}
@@ -400,7 +402,7 @@ static _INLINE_ void receive_chars(struct sgi_serial *info, struct pt_regs *regs
goto clear_and_exit;
if (tty->flip.count >= TTY_FLIPBUF_SIZE)
- queue_task_irq_off(&tty->flip.tqueue, &tq_timer);
+ queue_task(&tty->flip.tqueue, &tq_timer);
tty->flip.count++;
if(stat & PAR_ERR)
*tty->flip.flag_buf_ptr++ = TTY_PARITY;
@@ -412,7 +414,7 @@ static _INLINE_ void receive_chars(struct sgi_serial *info, struct pt_regs *regs
*tty->flip.flag_buf_ptr++ = 0; /* XXX */
*tty->flip.char_buf_ptr++ = ch;
- queue_task_irq_off(&tty->flip.tqueue, &tq_timer);
+ queue_task(&tty->flip.tqueue, &tq_timer);
clear_and_exit:
rs_recv_clear(info->zs_channel);
@@ -596,7 +598,7 @@ static void do_softint(void *private_)
if (!tty)
return;
- if (clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
+ if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
tty->ldisc.write_wakeup)
(tty->ldisc.write_wakeup)(tty);
diff --git a/drivers/sound/Config.in b/drivers/sound/Config.in
index f7567a496..fb8a76753 100644
--- a/drivers/sound/Config.in
+++ b/drivers/sound/Config.in
@@ -1,277 +1,15 @@
-bool 'ProAudioSpectrum 16 support' CONFIG_PAS
-bool '_TRUE_ Sound Blaster (SB, SBPro, SB16/32/64, ESS, Jazz16) support' CONFIG_SB
-bool 'Generic OPL2/OPL3 FM synthesizer support' CONFIG_ADLIB
-bool 'Gravis Ultrasound support' CONFIG_GUS
-bool 'MPU-401 support (NOT for SB16)' CONFIG_MPU401
-bool 'PSS (ECHO-ADI2111) support' CONFIG_PSS
-bool '16 bit sampling option of GUS (_NOT_ GUS MAX)' CONFIG_GUS16
-bool 'GUS MAX support' CONFIG_GUSMAX
-bool 'Microsoft Sound System support' CONFIG_MSS
-bool 'Ensoniq SoundScape support' CONFIG_SSCAPE
-bool 'MediaTrix AudioTrix Pro support' CONFIG_TRIX
-bool 'Support for MAD16 and/or Mozart based cards' CONFIG_MAD16
-bool 'Support for Crystal CS4232 based (PnP) cards' CONFIG_CS4232
-bool 'Support for Turtle Beach Wave Front (Maui, Tropez) synthesizers' CONFIG_MAUI
-bool 'FM synthesizer (YM3812/OPL-3) support' CONFIG_YM3812
-
-if [ "$CONFIG_AEDSP16" = "y" ]; then
-hex 'I/O base for Audio Excel DSP 16 220 or 240' AEDSP16_BASE 220
-fi
-
-if [ "$CONFIG_SB" = "y" ]; then
-hex 'I/O base for SB Check from manual of the card' SBC_BASE 220
-fi
-
-if [ "$CONFIG_SB" = "y" ]; then
-int 'Sound Blaster IRQ Check from manual of the card' SBC_IRQ 7
-fi
-
-if [ "$CONFIG_SB" = "y" ]; then
-int 'Sound Blaster DMA 0, 1 or 3' SBC_DMA 1
-fi
-
-if [ "$CONFIG_SB" = "y" ]; then
-int 'Sound Blaster 16 bit DMA (SB16, Jazz16, SMW) 5, 6 or 7 (use 1 for 8 bit cards)' SB_DMA2 5
-fi
-
-if [ "$CONFIG_SB" = "y" ]; then
-hex 'MPU401 I/O base of SB16, Jazz16 and ES1688 Check from manual of the card' SB_MPU_BASE 330
-fi
-
-
-if [ "$CONFIG_SB" = "y" ]; then
-comment 'MPU401 IRQ is only required with Jazz16, SM Wave and ESS1688.'
-fi
-
-
-if [ "$CONFIG_SB" = "y" ]; then
-comment 'Enter -1 to the following question if you have something else such as SB16/32.'
-fi
-
-if [ "$CONFIG_SB" = "y" ]; then
-int 'SB MPU401 IRQ (Jazz16, SM Wave and ES1688) Check from manual of the card' SB_MPU_IRQ -1
-fi
-
-if [ "$CONFIG_PAS" = "y" ]; then
-int 'PAS16 IRQ 3, 4, 5, 7, 9, 10, 11, 12, 14 or 15' PAS_IRQ 10
-fi
-
-if [ "$CONFIG_PAS" = "y" ]; then
-int 'PAS16 DMA 0, 1, 3, 5, 6 or 7' PAS_DMA 3
-fi
-
-if [ "$CONFIG_GUS" = "y" ]; then
-hex 'I/O base for GUS 210, 220, 230, 240, 250 or 260' GUS_BASE 220
-fi
-
-if [ "$CONFIG_GUS" = "y" ]; then
-int 'GUS IRQ 3, 5, 7, 9, 11, 12 or 15' GUS_IRQ 15
-fi
-
-if [ "$CONFIG_GUS" = "y" ]; then
-int 'GUS DMA 1, 3, 5, 6 or 7' GUS_DMA 6
-fi
-
-if [ "$CONFIG_GUS" = "y" ]; then
-int 'Second DMA channel for GUS 1, 3, 5, 6 or 7' GUS_DMA2 -1
-fi
-
-if [ "$CONFIG_GUS16" = "y" ]; then
-hex 'I/O base for the 16 bit daughtercard of GUS 530, 604, E80 or F40' GUS16_BASE 530
-fi
-
-if [ "$CONFIG_GUS16" = "y" ]; then
-int 'GUS 16 bit daughtercard IRQ 3, 4, 5, 7, or 9' GUS16_IRQ 7
-fi
-
-if [ "$CONFIG_GUS16" = "y" ]; then
-int 'GUS DMA 0, 1 or 3' GUS16_DMA 3
-fi
-
-if [ "$CONFIG_MPU401" = "y" ]; then
-hex 'I/O base for MPU401 Check from manual of the card' MPU_BASE 330
-fi
-
-if [ "$CONFIG_MPU401" = "y" ]; then
-int 'MPU401 IRQ Check from manual of the card' MPU_IRQ 9
-fi
-
-
-if [ "$CONFIG_MAUI" = "y" ]; then
-comment 'ERROR! You have to use old sound configuration method with Maui.'
-fi
-
-if [ "$CONFIG_MAUI" = "y" ]; then
-hex 'I/O base for Maui 210, 230, 260, 290, 300, 320, 338 or 330' MAUI_BASE 330
-fi
-
-if [ "$CONFIG_MAUI" = "y" ]; then
-int 'Maui IRQ 5, 9, 12 or 15' MAUI_IRQ 9
-fi
-
-if [ "$CONFIG_UART6850" = "y" ]; then
-hex 'I/O base for UART 6850 MIDI port (Unknown)' U6850_BASE 0
-fi
-
-if [ "$CONFIG_UART6850" = "y" ]; then
-int 'UART6850 IRQ (Unknown)' U6850_IRQ -1
-fi
-
-
-if [ "$CONFIG_PSS" = "y" ]; then
-comment 'ERROR! You have to use old sound configuration method with PSS cards.'
-fi
-
-if [ "$CONFIG_PSS" = "y" ]; then
-hex 'PSS I/O base 220 or 240' PSS_BASE 220
-fi
-
-if [ "$CONFIG_PSS" = "y" ]; then
-hex 'PSS audio I/O base 530, 604, E80 or F40' PSS_MSS_BASE 530
-fi
-
-if [ "$CONFIG_PSS" = "y" ]; then
-int 'PSS audio IRQ 7, 9, 10 or 11' PSS_MSS_IRQ 11
-fi
-
-if [ "$CONFIG_PSS" = "y" ]; then
-int 'PSS audio DMA 0, 1 or 3' PSS_MSS_DMA 3
-fi
-
-if [ "$CONFIG_PSS" = "y" ]; then
-hex 'PSS MIDI I/O base ' PSS_MPU_BASE 330
-fi
-
-if [ "$CONFIG_PSS" = "y" ]; then
-int 'PSS MIDI IRQ 3, 4, 5, 7 or 9' PSS_MPU_IRQ 9
-fi
-
-if [ "$CONFIG_MSS" = "y" ]; then
-hex 'MSS/WSS I/O base 530, 604, E80 or F40' MSS_BASE 530
-fi
-
-if [ "$CONFIG_MSS" = "y" ]; then
-int 'MSS/WSS IRQ 7, 9, 10 or 11' MSS_IRQ 11
-fi
-
-if [ "$CONFIG_MSS" = "y" ]; then
-int 'MSS/WSS DMA 0, 1 or 3' MSS_DMA 3
-fi
-
-if [ "$CONFIG_MSS" = "y" ]; then
-int 'MSS/WSS second DMA (if possible) 0, 1 or 3' MSS_DMA2 -1
-fi
-
-if [ "$CONFIG_SSCAPE" = "y" ]; then
-hex 'SoundScape MIDI I/O base 320, 330, 340 or 350' SSCAPE_BASE 330
-fi
-
-if [ "$CONFIG_SSCAPE" = "y" ]; then
-int 'SoundScape MIDI IRQ ' SSCAPE_IRQ 9
-fi
-
-if [ "$CONFIG_SSCAPE" = "y" ]; then
-int 'SoundScape initialization DMA 0, 1 or 3' SSCAPE_DMA 3
-fi
-
-if [ "$CONFIG_SSCAPE" = "y" ]; then
-hex 'SoundScape audio I/O base 534, 608, E84 or F44' SSCAPE_MSS_BASE 534
-fi
-
-if [ "$CONFIG_SSCAPE" = "y" ]; then
-int 'SoundScape audio IRQ 7, 9, 10 or 11' SSCAPE_MSS_IRQ 11
-fi
-
-
-if [ "$CONFIG_TRIX" = "y" ]; then
-comment 'ERROR! You have to use old sound configuration method with AudioTrix.'
-fi
-
-if [ "$CONFIG_TRIX" = "y" ]; then
-hex 'AudioTrix audio I/O base 530, 604, E80 or F40' TRIX_BASE 530
-fi
-
-if [ "$CONFIG_TRIX" = "y" ]; then
-int 'AudioTrix audio IRQ 7, 9, 10 or 11' TRIX_IRQ 11
-fi
-
-if [ "$CONFIG_TRIX" = "y" ]; then
-int 'AudioTrix audio DMA 0, 1 or 3' TRIX_DMA 0
-fi
-
-if [ "$CONFIG_TRIX" = "y" ]; then
-int 'AudioTrix second (duplex) DMA 0, 1 or 3' TRIX_DMA2 3
-fi
-
-if [ "$CONFIG_TRIX" = "y" ]; then
-hex 'AudioTrix MIDI I/O base 330, 370, 3B0 or 3F0' TRIX_MPU_BASE 330
-fi
-
-if [ "$CONFIG_TRIX" = "y" ]; then
-int 'AudioTrix MIDI IRQ 3, 4, 5, 7 or 9' TRIX_MPU_IRQ 9
-fi
-
-if [ "$CONFIG_TRIX" = "y" ]; then
-hex 'AudioTrix SB I/O base 220, 210, 230, 240, 250, 260 or 270' TRIX_SB_BASE 220
-fi
-
-if [ "$CONFIG_TRIX" = "y" ]; then
-int 'AudioTrix SB IRQ 3, 4, 5 or 7' TRIX_SB_IRQ 7
-fi
-
-if [ "$CONFIG_TRIX" = "y" ]; then
-int 'AudioTrix SB DMA 1 or 3' TRIX_SB_DMA 1
-fi
-
-if [ "$CONFIG_CS4232" = "y" ]; then
-hex 'CS4232 audio I/O base 530, 604, E80 or F40' CS4232_BASE 530
-fi
-
-if [ "$CONFIG_CS4232" = "y" ]; then
-int 'CS4232 audio IRQ 5, 7, 9, 11, 12 or 15' CS4232_IRQ 11
-fi
-
-if [ "$CONFIG_CS4232" = "y" ]; then
-int 'CS4232 audio DMA 0, 1 or 3' CS4232_DMA 0
-fi
-
-if [ "$CONFIG_CS4232" = "y" ]; then
-int 'CS4232 second (duplex) DMA 0, 1 or 3' CS4232_DMA2 3
-fi
-
-if [ "$CONFIG_CS4232" = "y" ]; then
-hex 'CS4232 MIDI I/O base 330, 370, 3B0 or 3F0' CS4232_MPU_BASE 330
-fi
-
-if [ "$CONFIG_CS4232" = "y" ]; then
-int 'CS4232 MIDI IRQ 5, 7, 9, 11, 12 or 15' CS4232_MPU_IRQ 9
-fi
-
-if [ "$CONFIG_MAD16" = "y" ]; then
-hex 'MAD16 audio I/O base 530, 604, E80 or F40' MAD16_BASE 530
-fi
-
-if [ "$CONFIG_MAD16" = "y" ]; then
-int 'MAD16 audio IRQ 7, 9, 10 or 11' MAD16_IRQ 11
-fi
-
-if [ "$CONFIG_MAD16" = "y" ]; then
-int 'MAD16 audio DMA 0, 1 or 3' MAD16_DMA 3
-fi
-
-if [ "$CONFIG_MAD16" = "y" ]; then
-int 'MAD16 second (duplex) DMA 0, 1 or 3' MAD16_DMA2 0
-fi
-
-if [ "$CONFIG_MAD16" = "y" ]; then
-hex 'MAD16 MIDI I/O base 300, 310, 320 or 330 (0 disables)' MAD16_MPU_BASE 330
-fi
-
-if [ "$CONFIG_MAD16" = "y" ]; then
-int 'MAD16 MIDI IRQ 5, 7, 9 or 10' MAD16_MPU_IRQ 9
-fi
#
-$MAKE -C drivers/sound kernelconfig || exit 1
+# Sound driver configuration
+#
+#--------
+# There is another confic script which is compatible with rest of
+# the kernel. It can be activated by running 'make mkscript' in this
+# directory. Please note that this is an _experimental_ feature which
+# doesn't work with all cards (PSS, SM Wave, AudioTriX Pro, Maui).
+#--------
+#
+$MAKE -C drivers/sound config || exit 1
+
bool 'Additional low level drivers' CONFIG_LOWLEVEL_SOUND
if [ "$CONFIG_LOWLEVEL_SOUND" = "y" ]; then
diff --git a/drivers/sound/lowlevel/.cvsignore b/drivers/sound/lowlevel/.cvsignore
new file mode 100644
index 000000000..4671378ae
--- /dev/null
+++ b/drivers/sound/lowlevel/.cvsignore
@@ -0,0 +1 @@
+.depend
diff --git a/fs/affs/Changes b/fs/affs/Changes
new file mode 100644
index 000000000..a65dc326a
--- /dev/null
+++ b/fs/affs/Changes
@@ -0,0 +1,95 @@
+(Note: I consider version numbers as cheap. That means
+that I do not like numbers like 0.1 and the like for
+things that can be used since quite some time. But
+then, 3.1 doesn't mean 'perfectly stable', too.)
+
+Known bugs:
+-----------
+
+- Doesn't work on the alpha. The only 64/32-bit
+ problem that I'm aware of (pointer/int conversion
+ in readdir()) gives compiler warnings but is
+ apparently not causing the failure, as directory
+ reads basically work (but all files are of size 0).
+ Alas, I've got no alpha to debug. :-(
+- If an affs mounted filesystem is exported via
+ nfs, it cannot be written to. No networking to
+ test that, either. :-(
+
+Please direct bug reports to: hjw@zvw.de
+
+Version 3.4
+-----------
+
+- Hash chains are now sorted by block numbers.
+ (Thanks to Kars de Jong for finding this.)
+- Removed all unnecessary external symbols.
+
+Version 3.3
+-----------
+
+- Tried to make all types 'correct' and consistent.
+- Errors and warnings are now reported via a
+ function. They are all prefixed by a severity
+ and have the same appearance:
+ "AFFS: <function>: <error message>"
+ (There's one exception to this, as in that function
+ is no pointer to the super block available.)
+- The filesystem is remounted read-only after an
+ error.
+- The names of newly created filesystem objects are
+ now checked for validity.
+- Minor cleanups in comments.
+- Added this Changes file. At last!
+
+Version 3.2
+-----------
+
+- Extension block cache: Reading/writing of huge files
+ (several MB) is much faster (of course the added
+ overhead slows down opening, but this is hardly
+ noticeable).
+- The same get_block()-routine can now be used for
+ both OFS and FFS.
+- The super block is now searched in the block that
+ was calculated and in the one following. This
+ should remedy the round-off error introduced by
+ the 1-k blocks that Linux uses.
+- Minor changes to adhere to the new VFS interface.
+- The number of used blocks is now also calculated
+ if the filesystem is mounted read-only.
+- Prefixed some constants with AFFS_ to avoid name
+ clashes.
+- Removed 'EXPERIMENTAL' status.
+
+Version 3.1
+-----------
+
+- Fixed a nasty bug which didn't allow read-only
+ mounts.
+- Allow dir-cache filesystems to be mounted
+ read only.
+- OFS support.
+- Several other changes I just cannot remember
+ any more.
+
+Version 3.0
+-----------
+
+- Almost complete rewrite for the new VFS
+ interface in Linux 1.3.
+- Write support.
+- Support for hard and symbolic links.
+- Lots of things I remeber even less ...
+
+Version 2.0
+-----------
+
+- Fixed a few things to get it compiled.
+- Automatic root block calculation.
+- Partition checker for genhd.c
+
+========================================
+
+Let's just call Ray Burr's original affs
+'Version 1.0'.
diff --git a/fs/affs/amigaffs.c b/fs/affs/amigaffs.c
index 63d76a86e..4afd66e49 100644
--- a/fs/affs/amigaffs.c
+++ b/fs/affs/amigaffs.c
@@ -5,8 +5,10 @@
*
* (C) 1993 Ray Burr - Amiga FFS filesystem.
*
+ * Please send bug reports to: hjw@zvw.de
*/
+#include <stdarg.h>
#include <linux/stat.h>
#include <linux/sched.h>
#include <linux/affs_fs.h>
@@ -17,6 +19,8 @@
extern struct timezone sys_tz;
+static char ErrorBuffer[256];
+
/*
* Functions for accessing Amiga-FFS structures.
*
@@ -28,7 +32,7 @@ extern struct timezone sys_tz;
0 is returned. Otherwise, the key number in the next used hash slot
is returned. */
-int
+static int
affs_find_next_hash_entry(int hsize, void *dir_data, int *hash_pos)
{
struct dir_front *dir_front = dir_data;
@@ -54,24 +58,23 @@ affs_get_file_name(int bsize, void *fh_data, char **name)
file_end = GET_END_PTR(struct file_end, fh_data, bsize);
if (file_end->file_name[0] == 0
|| file_end->file_name[0] > 30) {
- printk ("affs_get_file_name: OOPS! bad filename\n");
- printk (" file_end->file_name[0] = %d\n",
+ printk(KERN_WARNING "AFFS: bad filename (length=%d chars)\n",
file_end->file_name[0]);
*name = "***BAD_FILE***";
return 14;
}
- *name = (char *) &file_end->file_name[1];
+ *name = (char *)&file_end->file_name[1];
return file_end->file_name[0];
}
/* Find the predecessor in the hash chain */
int
-affs_fix_hash_pred(struct inode *startino, int startoffset, int key, int newkey)
+affs_fix_hash_pred(struct inode *startino, int startoffset, s32 key, s32 newkey)
{
struct buffer_head *bh = NULL;
- int nextkey;
- int ptype, stype;
+ s32 nextkey;
+ s32 ptype, stype;
int retval;
nextkey = startino->i_ino;
@@ -87,14 +90,14 @@ affs_fix_hash_pred(struct inode *startino, int startoffset, int key, int newkey)
|| ptype != T_SHORT || (stype != ST_FILE && stype != ST_USERDIR &&
stype != ST_LINKFILE && stype != ST_LINKDIR &&
stype != ST_ROOT && stype != ST_SOFTLINK)) {
- printk("AFFS: bad block found in link chain (ptype=%d, stype=%d)\n",
- ptype,stype);
+ affs_error(startino->i_sb,"affs_fix_hash_pred",
+ "Bad block in link chain (ptype=%d, stype=%d)",ptype,stype);
affs_brelse(bh);
break;
}
- nextkey = htonl(((__u32 *)bh->b_data)[startoffset]);
+ nextkey = htonl(((s32 *)bh->b_data)[startoffset]);
if (nextkey == key) {
- ((__u32 *)bh->b_data)[startoffset] = newkey;
+ ((s32 *)bh->b_data)[startoffset] = newkey;
affs_fix_checksum(AFFS_I2BSIZE(startino),bh->b_data,5);
mark_buffer_dirty(bh,1);
affs_brelse(bh);
@@ -112,13 +115,13 @@ affs_fix_hash_pred(struct inode *startino, int startoffset, int key, int newkey)
/* Remove inode from link chain */
int
-affs_fix_link_pred(struct inode *startino, int key, int newkey)
+affs_fix_link_pred(struct inode *startino, s32 key, s32 newkey)
{
struct buffer_head *bh = NULL;
- int nextkey;
+ s32 nextkey;
int offset;
- int etype = 0;
- int ptype, stype;
+ s32 etype = 0;
+ s32 ptype, stype;
int retval;
offset = AFFS_I2BSIZE(startino) / 4 - 10;
@@ -150,7 +153,7 @@ affs_fix_link_pred(struct inode *startino, int key, int newkey)
retval = -EPERM;
break;
}
- nextkey = htonl(((__u32 *)bh->b_data)[offset]);
+ nextkey = htonl(((s32 *)bh->b_data)[offset]);
if (nextkey == key) {
FILE_END(bh->b_data,startino)->link_chain = newkey;
affs_fix_checksum(AFFS_I2BSIZE(startino),bh->b_data,5);
@@ -172,17 +175,17 @@ affs_fix_link_pred(struct inode *startino, int key, int newkey)
(which lets us calculate the block size).
Returns non-zero if the block is not consistent. */
-__u32
-affs_checksum_block(int bsize, void *data, int *ptype, int *stype)
+u32
+affs_checksum_block(int bsize, void *data, s32 *ptype, s32 *stype)
{
- __u32 sum;
- __u32 *p;
+ u32 sum;
+ u32 *p;
bsize /= 4;
if (ptype)
- *ptype = htonl(((__s32 *)data)[0]);
+ *ptype = htonl(((s32 *)data)[0]);
if (stype)
- *stype = htonl(((__s32 *)data)[bsize - 1]);
+ *stype = htonl(((s32 *)data)[bsize - 1]);
sum = 0;
p = data;
@@ -194,20 +197,20 @@ affs_checksum_block(int bsize, void *data, int *ptype, int *stype)
void
affs_fix_checksum(int bsize, void *data, int cspos)
{
- __u32 ocs;
- __u32 cs;
+ u32 ocs;
+ u32 cs;
cs = affs_checksum_block(bsize,data,NULL,NULL);
- ocs = htonl (((__u32 *)data)[cspos]);
+ ocs = htonl (((u32 *)data)[cspos]);
ocs -= cs;
- ((__u32 *)data)[cspos] = htonl(ocs);
+ ((u32 *)data)[cspos] = htonl(ocs);
}
void
-secs_to_datestamp(int secs, struct DateStamp *ds)
+secs_to_datestamp(time_t secs, struct DateStamp *ds)
{
- __u32 days;
- __u32 minute;
+ u32 days;
+ u32 minute;
secs -= sys_tz.tz_minuteswest * 60 +((8 * 365 + 2) * 24 * 60 * 60);
if (secs < 0)
@@ -223,7 +226,7 @@ secs_to_datestamp(int secs, struct DateStamp *ds)
}
int
-prot_to_mode(__u32 prot)
+prot_to_mode(u32 prot)
{
int mode = 0;
@@ -249,10 +252,10 @@ prot_to_mode(__u32 prot)
return mode;
}
-unsigned int
+u32
mode_to_prot(int mode)
{
- unsigned int prot = 0;
+ u32 prot = 0;
if (mode & S_IXUSR)
prot |= FIBF_SCRIPT;
@@ -271,3 +274,32 @@ mode_to_prot(int mode)
return prot;
}
+
+void
+affs_error(struct super_block *sb, const char *function, const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args,fmt);
+ vsprintf(ErrorBuffer,fmt,args);
+ va_end(args);
+
+ printk(KERN_CRIT "AFFS error (device %s): %s(): %s\n",kdevname(sb->s_dev),
+ function,ErrorBuffer);
+ if (!(sb->s_flags & MS_RDONLY))
+ printk(KERN_WARNING "AFFS: Remounting filesystem read-only\n");
+ sb->s_flags |= MS_RDONLY;
+}
+
+void
+affs_warning(struct super_block *sb, const char *function, const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args,fmt);
+ vsprintf(ErrorBuffer,fmt,args);
+ va_end(args);
+
+ printk(KERN_WARNING "AFFS error (device %s): %s(): %s\n",kdevname(sb->s_dev),
+ function,ErrorBuffer);
+}
diff --git a/fs/affs/bitmap.c b/fs/affs/bitmap.c
index 1d69d5a3d..a7382db4c 100644
--- a/fs/affs/bitmap.c
+++ b/fs/affs/bitmap.c
@@ -3,7 +3,6 @@
*
* (c) 1996 Hans-Joachim Widmaier
*
- *
* bitmap.c contains the code that handles all bitmap related stuff -
* block allocation, deallocation, calculation of free space.
*/
@@ -54,7 +53,7 @@ affs_count_free_blocks(struct super_block *s)
}
void
-affs_free_block(struct super_block *sb, int block)
+affs_free_block(struct super_block *sb, s32 block)
{
int bmap;
int bit;
@@ -70,7 +69,7 @@ affs_free_block(struct super_block *sb, int block)
zone_no = (bmap << (sb->s_blocksize_bits - 7)) + bit / 1024;
bm = &sb->u.affs_sb.s_bitmap[bmap];
if (bmap >= sb->u.affs_sb.s_bm_count) {
- printk("AFFS: free_block(): block %d outside partition.\n",block);
+ affs_error(sb,"affs_free_block","Block %d outside partition",block);
return;
}
blk = 0;
@@ -83,15 +82,16 @@ affs_free_block(struct super_block *sb, int block)
if (!bm->bm_bh) {
bm->bm_count--;
unlock_super(sb);
- printk("AFFS: free_block(): Cannot read bitmap block %d\n",bm->bm_key);
+ affs_error(sb,"affs_free_block","Cannot read bitmap block %d",bm->bm_key);
return;
}
}
- if (set_bit(bit ^ BO_EXBITS,bm->bm_bh->b_data + 4))
- printk("AFFS: free_block(): block %d is already free.\n",block);
+ if (test_and_set_bit(bit ^ BO_EXBITS,bm->bm_bh->b_data + 4))
+ affs_warning(sb,"affs_free_block","Trying to free block %d which is already free",
+ block);
else {
sb->u.affs_sb.s_alloc[zone_no].az_free++;
- ((__u32 *)bm->bm_bh->b_data)[0] = ntohl(htonl(((__u32 *)bm->bm_bh->b_data)[0]) - blk);
+ ((u32 *)bm->bm_bh->b_data)[0] = ntohl(htonl(((u32 *)bm->bm_bh->b_data)[0]) - blk);
mark_buffer_dirty(bm->bm_bh,1);
sb->s_dirt = 1;
}
@@ -102,15 +102,15 @@ affs_free_block(struct super_block *sb, int block)
unlock_super(sb);
}
-static int
+static s32
affs_balloc(struct inode *inode, int zone_no)
{
- __u32 w;
- __u32 *bm;
+ u32 w;
+ u32 *bm;
int fb;
int i;
int fwb;
- int block;
+ s32 block;
struct affs_zone *zone;
struct affs_alloc_zone *az;
struct super_block *sb;
@@ -124,7 +124,7 @@ affs_balloc(struct inode *inode, int zone_no)
pr_debug("AFFS: balloc(inode=%lu,zone=%d)\n",inode->i_ino,zone_no);
az = &sb->u.affs_sb.s_alloc[zone->z_az_no];
- bm = (__u32 *)zone->z_bm->bm_bh->b_data;
+ bm = (u32 *)zone->z_bm->bm_bh->b_data;
repeat:
for (i = zone->z_start; i < zone->z_end; i++) {
if (bm[i])
@@ -138,9 +138,9 @@ found:
zone->z_start = i;
w = ~htonl(bm[i]);
fb = find_first_zero_bit(&w,32);
- if (fb > 31 || !clear_bit(fb ^ BO_EXBITS,&bm[i])) {
+ if (fb > 31 || !test_and_clear_bit(fb ^ BO_EXBITS,&bm[i])) {
unlock_super(sb);
- printk("AFFS: balloc(): empty block disappeared somehow\n");
+ affs_warning(sb,"balloc","Empty block disappeared somehow");
goto repeat;
}
block = fwb + fb;
@@ -153,8 +153,8 @@ found:
fb = find_next_zero_bit(&w,32,fb);
if (fb > 31)
break;
- if (!clear_bit(fb ^ BO_EXBITS,&bm[i])) {
- printk("AFFS: balloc(): empty block disappeared\n");
+ if (!test_and_clear_bit(fb ^ BO_EXBITS,&bm[i])) {
+ affs_warning(sb,"balloc","Empty block disappeared somehow");
break;
}
inode->u.affs_i.i_data[inode->u.affs_i.i_pa_last++] = fwb + fb;
@@ -204,7 +204,7 @@ affs_find_new_zone(struct super_block *sb, int zone_no)
if (az->az_count)
az->az_count--;
else
- printk("AFFS: find_new_zone(): az_count=0, but bm used\n");
+ affs_error(sb,"find_new_zone","az_count=0, but bm used");
}
while (1) {
@@ -247,7 +247,7 @@ affs_find_new_zone(struct super_block *sb, int zone_no)
bm->bm_count--;
az->az_count--;
unlock_super(sb);
- printk("AFFS: find_new_zone(): Cannot read bitmap\n");
+ affs_error(sb,"find_new_zone","Cannot read bitmap");
return 0;
}
zone->z_bm = bm;
@@ -261,16 +261,16 @@ affs_find_new_zone(struct super_block *sb, int zone_no)
return az->az_free;
}
-int
+s32
affs_new_header(struct inode *inode)
{
- int block;
+ s32 block;
struct buffer_head *bh;
pr_debug("AFFS: new_header(ino=%lu)\n",inode->i_ino);
if (!(block = affs_balloc(inode,0))) {
- while(affs_find_new_zone(inode->i_sb,0)) {
+ while (affs_find_new_zone(inode->i_sb,0)) {
if ((block = affs_balloc(inode,0)))
goto init_block;
schedule();
@@ -279,7 +279,7 @@ affs_new_header(struct inode *inode)
}
init_block:
if (!(bh = getblk(inode->i_dev,block,AFFS_I2BSIZE(inode)))) {
- printk("AFFS: balloc(): cannot read block %d\n",block);
+ affs_error(inode->i_sb,"new_header","Cannot read block %d",block);
return 0;
}
memset(bh->b_data,0,AFFS_I2BSIZE(inode));
@@ -290,7 +290,7 @@ init_block:
return block;
}
-int
+s32
affs_new_data(struct inode *inode)
{
int empty, old;
@@ -299,7 +299,7 @@ affs_new_data(struct inode *inode)
struct super_block *sb;
struct buffer_head *bh;
int i = 0;
- int block;
+ s32 block;
pr_debug("AFFS: new_data(ino=%lu)\n",inode->i_ino);
@@ -345,7 +345,7 @@ affs_new_data(struct inode *inode)
found:
zone = &sb->u.affs_sb.s_zones[i];
if (!(block = affs_balloc(inode,i))) { /* No data zones left */
- while(affs_find_new_zone(sb,i)) {
+ while (affs_find_new_zone(sb,i)) {
if ((block = affs_balloc(inode,i)))
goto init_block;
schedule();
@@ -357,7 +357,7 @@ found:
init_block:
if (!(bh = getblk(inode->i_dev,block,sb->s_blocksize))) {
- printk("AFFS: balloc(): cannot read block %u\n",block);
+ affs_error(inode->i_sb,"new_data","Cannot read block %d",block);
return 0;
}
memset(bh->b_data,0,sb->s_blocksize);
diff --git a/fs/affs/dir.c b/fs/affs/dir.c
index f7ec42ede..8ae71e5bd 100644
--- a/fs/affs/dir.c
+++ b/fs/affs/dir.c
@@ -64,7 +64,7 @@ struct inode_operations affs_dir_inode_operations = {
};
static long
-affs_dir_read(struct inode * inode, struct file * filp, char * buf, unsigned long count)
+affs_dir_read(struct inode *inode, struct file *filp, char *buf, unsigned long count)
{
return -EISDIR;
}
@@ -73,19 +73,18 @@ static int
affs_readdir(struct inode *inode, struct file *filp, void *dirent, filldir_t filldir)
{
int j, namelen;
- int i;
+ s32 i;
int hash_pos;
int chain_pos;
unsigned long ino;
unsigned long old;
- int stored;
- char *name;
- struct buffer_head *dir_bh;
- struct buffer_head *fh_bh;
- struct inode *dir;
+ int stored;
+ char *name;
+ struct buffer_head *dir_bh;
+ struct buffer_head *fh_bh;
+ struct inode *dir;
pr_debug("AFFS: readdir(ino=%ld,f_pos=%lu)\n",inode->i_ino,filp->f_pos);
-
if (!inode || !S_ISDIR(inode->i_mode))
return -EBADF;
@@ -122,7 +121,7 @@ affs_readdir(struct inode *inode, struct file *filp, void *dirent, filldir_t fil
chain_pos = (filp->f_pos - 2) & 0xffff;
hash_pos = (filp->f_pos - 2) >> 16;
if (chain_pos == 0xffff) {
- printk("AFFS: more than 65535 entries in chain\n");
+ affs_warning(inode->i_sb,"readdir","More than 65535 entries in chain");
chain_pos = 0;
hash_pos++;
filp->f_pos = ((hash_pos << 16) | chain_pos) + 2;
@@ -143,15 +142,15 @@ affs_readdir(struct inode *inode, struct file *filp, void *dirent, filldir_t fil
* we can jump directly to where we left off.
*/
if (filp->private_data && filp->f_version == dir->i_version) {
- i = (int)filp->private_data;
+ i = (s32)filp->private_data;
j = 0;
pr_debug("AFFS: readdir() left off=%d\n",i);
}
filp->f_version = dir->i_version;
- pr_debug("AFFS: hash_pos=%lu chain_pos=%lu\n", hash_pos, chain_pos);
+ pr_debug("AFFS: hash_pos=%d chain_pos=%d\n",hash_pos,chain_pos);
while (i) {
if (!(fh_bh = affs_bread(inode->i_dev,i,AFFS_I2BSIZE(inode)))) {
- printk("AFFS: readdir: Can't get block %d\n",i);
+ affs_error(inode->i_sb,"readdir","Cannot read block %d",i);
goto readdir_done;
}
ino = i;
@@ -164,7 +163,7 @@ affs_readdir(struct inode *inode, struct file *filp, void *dirent, filldir_t fil
}
if (fh_bh) {
namelen = affs_get_file_name(AFFS_I2BSIZE(inode),fh_bh->b_data,&name);
- pr_debug("AFFS: readdir(): filldir(..,\"%.*s\",ino=%lu), i=%lu\n",
+ pr_debug("AFFS: readdir(): filldir(..,\"%.*s\",ino=%lu), i=%d\n",
namelen,name,ino,i);
filp->private_data = (void *)ino;
if (filldir(dirent,name,namelen,filp->f_pos,ino) < 0)
diff --git a/fs/affs/file.c b/fs/affs/file.c
index a450dffce..0fffbf41e 100644
--- a/fs/affs/file.c
+++ b/fs/affs/file.c
@@ -35,6 +35,8 @@
#error PAGE_SIZE must be at least 4096
#endif
+static int affs_bmap(struct inode *inode, int block);
+static struct buffer_head * affs_getblock(struct inode *inode, s32 block);
static long affs_file_read_ofs(struct inode *inode, struct file *filp, char *buf,
unsigned long count);
static long affs_file_write(struct inode *inode, struct file *filp, const char *buf,
@@ -200,7 +202,7 @@ index_to_seqnum(int index)
return 128 + 192 * 2 + 128 * 4 + 64 * 16 + 32 * 64 + 64 * 256 + (index << 9);
}
-static int __inline__
+static s32 __inline__
calc_key(struct inode *inode, int *ext)
{
int index;
@@ -226,28 +228,30 @@ calc_key(struct inode *inode, int *ext)
return inode->u.affs_i.i_ec->ec[index];
}
-int
+static int
affs_bmap(struct inode *inode, int block)
{
struct buffer_head *bh;
- int ext, key, nkey;
- int ptype, stype;
+ s32 key, nkey;
+ s32 ptype, stype;
+ int ext;
int index;
int keycount;
struct key_cache *kc;
struct key_cache *tkc;
struct timeval tv;
- __s32 *keyp;
+ s32 *keyp;
int i;
pr_debug("AFFS: bmap(%lu,%d)\n",inode->i_ino,block);
if (block < 0) {
- printk("affs_bmap: block < 0\n");
+ affs_error(inode->i_sb,"bmap","Block < 0");
return 0;
}
if (!inode->u.affs_i.i_ec) {
- printk("affs_bmap(): No ext_cache!?\n");
+ affs_error(inode->i_sb,"bmap","No extension cache for open file (inode=%lu)",
+ inode->i_ino);
return 0;
}
@@ -334,14 +338,14 @@ affs_bmap(struct inode *inode, int block)
return key;
}
-struct buffer_head *
-affs_getblock(struct inode *inode, int block)
+static struct buffer_head *
+affs_getblock(struct inode *inode, s32 block)
{
struct buffer_head *bh;
struct buffer_head *ebh;
struct buffer_head *pbh;
struct key_cache *kc;
- int key, nkey;
+ s32 key, nkey;
int ext;
int cf, j, pt;
int index;
@@ -372,7 +376,7 @@ affs_getblock(struct inode *inode, int block)
return NULL;
if (affs_checksum_block(AFFS_I2BSIZE(inode),bh->b_data,&cf,&j) ||
cf != pt || j != ST_FILE) {
- printk("AFFS: getblock(): inode %d is not a valid %s\n",key,
+ affs_error(inode->i_sb,"getblock","Inode %d is not a valid %s",key,
pt == T_SHORT ? "file header" : "extension block");
affs_brelse(bh);
return NULL;
@@ -387,7 +391,8 @@ affs_getblock(struct inode *inode, int block)
else
pbh = affs_getblock(inode,inode->u.affs_i.i_lastblock);
if (!pbh) {
- printk("AFFS: getblock(): cannot get last block in file\n");
+ affs_error(inode->i_sb,"getblock",
+ "Cannot get last block in file");
break;
}
}
@@ -397,7 +402,7 @@ affs_getblock(struct inode *inode, int block)
lock_super(inode->i_sb);
if (AFFS_BLOCK(bh->b_data,inode,j)) {
unlock_super(inode->i_sb);
- printk("AFFS: getblock(): block already allocated\n");
+ affs_warning(inode->i_sb,"getblock","Block already allocated");
affs_free_block(inode->i_sb,nkey);
j++;
continue;
@@ -407,7 +412,8 @@ affs_getblock(struct inode *inode, int block)
if (ofs) {
ebh = affs_bread(inode->i_dev,nkey,AFFS_I2BSIZE(inode));
if (!ebh) {
- printk("AFFS: getblock(): cannot get block %d\n",nkey);
+ affs_error(inode->i_sb,"getblock",
+ "Cannot get block %d",nkey);
affs_free_block(inode->i_sb,nkey);
AFFS_BLOCK(bh->b_data,inode,j) = 0;
break;
@@ -492,10 +498,6 @@ affs_getblock(struct inode *inode, int block)
return affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode));
}
-/* This could be made static, regardless of what the former comment said.
- * You cannot directly read affs directories.
- */
-
static long
affs_file_read_ofs(struct inode *inode, struct file *filp, char *buf, unsigned long count)
{
@@ -508,12 +510,12 @@ affs_file_read_ofs(struct inode *inode, struct file *filp, char *buf, unsigned l
pr_debug("AFFS: file_read_ofs(ino=%lu,pos=%lu,%d)\n",inode->i_ino,(long)filp->f_pos,count);
if (!inode) {
- printk("affs_file_read: inode = NULL\n");
+ affs_error(inode->i_sb,"file_read_ofs","Inode = NULL");
return -EINVAL;
}
blocksize = AFFS_I2BSIZE(inode) - 24;
if (!(S_ISREG(inode->i_mode))) {
- pr_debug("affs_file_read: mode = %07o\n",inode->i_mode);
+ pr_debug("affs_file_read: mode = %07o",inode->i_mode);
return -EINVAL;
}
if (filp->f_pos >= inode->i_size || count <= 0)
@@ -524,10 +526,10 @@ affs_file_read_ofs(struct inode *inode, struct file *filp, char *buf, unsigned l
left = MIN (inode->i_size - filp->f_pos,count - (buf - start));
if (!left)
break;
- sector = affs_bmap(inode,(__u32)filp->f_pos / blocksize);
+ sector = affs_bmap(inode,(u32)filp->f_pos / blocksize);
if (!sector)
break;
- offset = (__u32)filp->f_pos % blocksize;
+ offset = (u32)filp->f_pos % blocksize;
bh = affs_bread(inode->i_dev,sector,AFFS_I2BSIZE(inode));
if (!bh)
break;
@@ -554,25 +556,31 @@ affs_file_write(struct inode *inode, struct file *filp, const char *buf, unsigne
struct inode *ino;
char *p;
+ /* Not that I wanted to be POSIX compliant ... */
+ if (!count)
+ return 0;
pr_debug("AFFS: file_write(ino=%lu,pos=%lu,count=%d)\n",inode->i_ino,
(unsigned long)filp->f_pos,count);
ino = NULL;
if (!inode) {
- printk("AFFS: file_write(): inode=NULL\n");
+ affs_error(inode->i_sb,"file_write","Inode = NULL");
return -EINVAL;
}
if (inode->u.affs_i.i_original) {
ino = iget(inode->i_sb,inode->u.affs_i.i_original);
if (!ino) {
- printk("AFFS: could not follow link from inode %lu to %d\n",
- inode->i_ino,inode->u.affs_i.i_original);
+ affs_error(inode->i_sb,"file_write",
+ "Could not follow link from inode %lu to %d",
+ inode->i_ino,inode->u.affs_i.i_original);
return -EINVAL;
}
inode = ino;
}
if (!S_ISREG(inode->i_mode)) {
- printk("AFFS: file_write(): mode=%07o\n",inode->i_mode);
+ affs_error(inode->i_sb,"file_write",
+ "Trying to write to non-regular file (mode=%07o)",
+ inode->i_mode);
iput(inode);
return -EINVAL;
}
@@ -636,22 +644,27 @@ affs_file_write_ofs(struct inode *inode, struct file *filp, const char *buf, uns
pr_debug("AFFS: file_write_ofs(ino=%lu,pos=%lu,count=%d)\n",inode->i_ino,
(unsigned long)filp->f_pos,count);
+ if (!count)
+ return 0;
if (!inode) {
- printk("AFFS: file_write_ofs(): inode=NULL\n");
+ affs_error(inode->i_sb,"file_write_ofs","Inode = NULL");
return -EINVAL;
}
ino = NULL;
if (inode->u.affs_i.i_original) {
ino = iget(inode->i_sb,inode->u.affs_i.i_original);
if (!ino) {
- printk("AFFS: could not follow link from inode %lu to %d\n",
- inode->i_ino,inode->u.affs_i.i_original);
+ affs_error(inode->i_sb,"file_write_ofs",
+ "Could not follow link from inode %lu to %d",
+ inode->i_ino,inode->u.affs_i.i_original);
return -EINVAL;
}
inode = ino;
}
if (!S_ISREG(inode->i_mode)) {
- printk("AFFS: file_write_ofs(): mode=%07o\n",inode->i_mode);
+ affs_error(inode->i_sb,"file_write_ofs",
+ "Trying to write to non-regular file (mode=%07o)",
+ inode->i_mode);
iput(inode);
return -EINVAL;
}
@@ -714,10 +727,10 @@ affs_truncate(struct inode *inode)
struct affs_zone *zone;
int first;
int block;
- int key;
- int *keyp;
- int ekey;
- int ptype, stype;
+ s32 key;
+ s32 *keyp;
+ s32 ekey;
+ s32 ptype, stype;
int freethis;
int blocksize;
int rem;
@@ -729,8 +742,8 @@ affs_truncate(struct inode *inode)
if (inode->u.affs_i.i_original) {
ino = iget(inode->i_sb,inode->u.affs_i.i_original);
if (!ino) {
- printk("AFFS: truncate(): cannot follow link from %lu to %u\n",
- inode->i_ino,inode->u.affs_i.i_original);
+ affs_error(inode->i_sb,"truncate","Cannot follow link from %lu to %d",
+ inode->i_ino,inode->u.affs_i.i_original);
return;
}
inode = ino;
@@ -754,7 +767,7 @@ affs_truncate(struct inode *inode)
unlock_super(inode->i_sb);
}
if (!bh) {
- printk("AFFS: truncate(): Cannot extend file\n");
+ affs_error(inode->i_sb,"truncate","Cannot extend file");
inode->i_size = blocksize * (inode->u.affs_i.i_lastblock + 1);
} else if (inode->i_sb->u.affs_sb.s_flags & SF_OFS) {
rem = inode->i_size % blocksize;
@@ -771,7 +784,7 @@ affs_truncate(struct inode *inode)
while (ekey) {
if (!(bh = affs_bread(inode->i_dev,ekey,AFFS_I2BSIZE(inode)))) {
- printk("AFFS: truncate(): Can't read block %d\n",ekey);
+ affs_error(inode->i_sb,"truncate","Cannot read block %d",ekey);
break;
}
ptype = htonl(((struct file_front *)bh->b_data)->primary_type);
@@ -783,14 +796,14 @@ affs_truncate(struct inode *inode)
break;
}
if (stype != ST_FILE || (ptype != T_SHORT && ptype != T_LIST)) {
- printk("AFFS: truncate(): bad block (ptype=%d, stype=%d)\n",
- ptype,stype);
+ affs_error(inode->i_sb,"truncate","Bad block (ptype=%d, stype=%d)",
+ ptype,stype);
affs_brelse(bh);
break;
}
/* Do not throw away file header */
freethis = first == 0 && ekey != inode->i_ino;
- for ( block = first; block < AFFS_I2HSIZE(inode); block++) {
+ for (block = first; block < AFFS_I2HSIZE(inode); block++) {
keyp = &AFFS_BLOCK(bh->b_data,inode,block);
key = htonl(*keyp);
if (key) {
@@ -853,7 +866,7 @@ static int
affs_open_file(struct inode *inode, struct file *filp)
{
int error;
- int key;
+ u32 key;
int i;
pr_debug("AFFS: open_file(ino=%lu)\n",inode->i_ino);
@@ -864,7 +877,7 @@ affs_open_file(struct inode *inode, struct file *filp)
if (!inode->u.affs_i.i_ec) {
inode->u.affs_i.i_ec = (struct ext_cache *)get_free_page(GFP_KERNEL);
if (!inode->u.affs_i.i_ec) {
- printk("AFFS: cache allocation failed\n");
+ affs_error(inode->i_sb,"open_file","Cache allocation failed");
error = ENOMEM;
} else {
/* We only have to initialize non-zero values.
diff --git a/fs/affs/inode.c b/fs/affs/inode.c
index 9b6626f7d..654a8ca61 100644
--- a/fs/affs/inode.c
+++ b/fs/affs/inode.c
@@ -30,12 +30,26 @@
#include <asm/system.h>
#include <asm/uaccess.h>
+/* AmigaOS allows file names with up to 30 characters length.
+ * Names longer than that will be silently truncated. If you
+ * want to disallow this, comment out the following #define.
+ * Creating filesystem objects with longer names will then
+ * result in an error (ENAMETOOLONG).
+ */
+/*#define NO_TRUNCATE */
+
extern int *blk_size[];
extern struct timezone sys_tz;
#define MIN(a,b) (((a)<(b))?(a):(b))
-void
+static int affs_notify_change(struct inode *inode, struct iattr *attr);
+static void affs_put_inode(struct inode *inode);
+static void affs_read_inode(struct inode *inode);
+static void affs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz);
+static void affs_write_inode(struct inode *inode);
+
+static void
affs_put_super(struct super_block *sb)
{
int i;
@@ -110,13 +124,13 @@ static struct super_operations affs_sops = {
NULL /* remount */
};
-int
+unsigned long
affs_parent_ino(struct inode *dir)
{
int root_ino = (dir->i_sb->u.affs_sb.s_root_block);
if (!S_ISDIR (dir->i_mode)) {
- printk ("affs_parent_ino: argument is not a directory\n");
+ affs_error(dir->i_sb,"parent_ino","Trying to get parent of non-directory");
return root_ino;
}
if (dir->i_ino == root_ino)
@@ -125,7 +139,7 @@ affs_parent_ino(struct inode *dir)
}
static int
-parse_options(char *options, uid_t *uid, gid_t *gid, int *mode, int *reserved, int *root,
+parse_options(char *options, uid_t *uid, gid_t *gid, int *mode, int *reserved, s32 *root,
int *blocksize, char **prefix, char *volume, unsigned long *mount_opts)
{
char *this_char, *value;
@@ -150,14 +164,14 @@ parse_options(char *options, uid_t *uid, gid_t *gid, int *mode, int *reserved, i
*value++ = 0;
if (!strcmp(this_char,"protect")) {
if (value) {
- printk("AFFS: option protect does not take an argument\n");
+ printk("AFFS: Option protect does not take an argument\n");
return 0;
}
*mount_opts |= SF_IMMUTABLE;
}
else if (!strcmp(this_char,"verbose")) {
if (value) {
- printk("AFFS: option verbose does not take an argument\n");
+ printk("AFFS: Option verbose does not take an argument\n");
return 0;
}
*mount_opts |= SF_VERBOSE;
@@ -166,7 +180,7 @@ parse_options(char *options, uid_t *uid, gid_t *gid, int *mode, int *reserved, i
if (!value)
*uid = current->uid;
else if (!*value) {
- printk("AFFS: argument for uid option missing\n");
+ printk("AFFS: Argument for uid option missing\n");
return 0;
} else {
*uid = simple_strtoul(value,&value,0);
@@ -180,7 +194,7 @@ parse_options(char *options, uid_t *uid, gid_t *gid, int *mode, int *reserved, i
if (!value)
*gid = current->gid;
else if (!*value) {
- printk("AFFS: argument for gid option missing\n");
+ printk("AFFS: Argument for gid option missing\n");
return 0;
} else {
*gid = simple_strtoul(value,&value,0);
@@ -248,7 +262,7 @@ parse_options(char *options, uid_t *uid, gid_t *gid, int *mode, int *reserved, i
return 0;
if (*blocksize != 512 && *blocksize != 1024 && *blocksize != 2048
&& *blocksize != 4096) {
- printk ("AFFS: Invalid blocksize (512, 1024, 2048, 4096 allowed).\n");
+ printk ("AFFS: Invalid blocksize (512, 1024, 2048, 4096 allowed)\n");
return 0;
}
}
@@ -270,21 +284,21 @@ parse_options(char *options, uid_t *uid, gid_t *gid, int *mode, int *reserved, i
* hopefully have the guts to do so. Until then: sorry for the mess.
*/
-struct super_block *
+static struct super_block *
affs_read_super(struct super_block *s,void *data, int silent)
{
struct buffer_head *bh = NULL;
struct buffer_head *bb;
kdev_t dev = s->s_dev;
- int root_block;
+ s32 root_block;
int size;
- __u32 chksum;
- __u32 *bm;
- int ptype, stype;
+ u32 chksum;
+ u32 *bm;
+ s32 ptype, stype;
int mapidx;
int num_bm;
int i, j;
- int key;
+ s32 key;
int blocksize;
uid_t uid;
gid_t gid;
@@ -300,7 +314,7 @@ affs_read_super(struct super_block *s,void *data, int silent)
if (!parse_options(data,&uid,&gid,&i,&reserved,&root_block,
&blocksize,&s->u.affs_sb.s_prefix,s->u.affs_sb.s_volume,&mount_flags)) {
s->s_dev = 0;
- printk("AFFS: error parsing options.\n");
+ printk(KERN_ERR "AFFS: Error parsing options\n");
MOD_DEC_USE_COUNT;
return NULL;
}
@@ -324,13 +338,13 @@ affs_read_super(struct super_block *s,void *data, int silent)
if (size == 0) {
s->s_dev = 0;
unlock_super(s);
- printk("affs_read_super: could not determine device size\n");
+ printk(KERN_ERR "AFFS: Could not determine device size\n");
goto out;
}
s->u.affs_sb.s_partition_size = size;
s->u.affs_sb.s_reserved = reserved;
- /* Try to find root block. Its location may depend on the block size. */
+ /* Try to find root block. Its location depends on the block size. */
s->u.affs_sb.s_hashsize = 0;
if (blocksize > 0) {
@@ -358,12 +372,12 @@ affs_read_super(struct super_block *s,void *data, int silent)
* block behind the calculated one. So we check this one, too.
*/
for (num_bm = 0; num_bm < 2; num_bm++) {
- pr_debug("AFFS: Dev %s - trying bs=%d bytes, root at %d, "
+ pr_debug("AFFS: Dev %s - trying bs=%d bytes, root at %u, "
"size=%d blocks, %d reserved\n",kdevname(dev),blocksize,
s->u.affs_sb.s_root_block + num_bm,size,reserved);
bh = affs_bread(dev,s->u.affs_sb.s_root_block + num_bm,blocksize);
if (!bh) {
- printk("AFFS: unable to read root block\n");
+ printk(KERN_ERR "AFFS: Cannot read root block\n");
goto out;
}
if (!affs_checksum_block(blocksize,bh->b_data,&ptype,&stype) &&
@@ -383,7 +397,8 @@ affs_read_super(struct super_block *s,void *data, int silent)
if (!key) {
affs_brelse(bh);
if (!silent)
- printk("AFFS: Can't find a valid root block on device %s\n",kdevname(dev));
+ printk(KERN_ERR "AFFS: Cannot find a valid root block on device %s\n",
+ kdevname(dev));
goto out;
}
root_block = s->u.affs_sb.s_root_block;
@@ -396,7 +411,7 @@ affs_read_super(struct super_block *s,void *data, int silent)
/* Find out which kind of FS we have */
bb = affs_bread(dev,0,s->s_blocksize);
if (bb) {
- chksum = htonl(*(__u32 *)bb->b_data);
+ chksum = htonl(*(u32 *)bb->b_data);
/* Dircache filesystems are compatible with non-dircache ones
* when reading. As long as they aren't supported, writing is
@@ -404,7 +419,8 @@ affs_read_super(struct super_block *s,void *data, int silent)
*/
if ((chksum == FS_DCFFS || chksum == MUFS_DCFFS || chksum == FS_DCOFS
|| chksum == MUFS_DCOFS) && !(s->s_flags & MS_RDONLY)) {
- printk("AFFS: Dircache FS - mounting %s read only.\n",kdevname(dev));
+ printk(KERN_NOTICE "AFFS: Dircache FS - mounting %s read only\n",
+ kdevname(dev));
s->s_flags |= MS_RDONLY;
}
switch (chksum) {
@@ -436,22 +452,22 @@ affs_read_super(struct super_block *s,void *data, int silent)
s->u.affs_sb.s_flags |= SF_INTL | SF_OFS;
break;
default:
- printk("AFFS: Unknown filesystem on device %s: %08X\n",
- kdevname(dev),chksum);
+ printk(KERN_ERR "AFFS: Unknown filesystem on device %s: %08X\n",
+ kdevname(dev),chksum);
affs_brelse(bb);
goto out;
}
affs_brelse(bb);
} else {
- printk("AFFS: Can't get boot block.\n");
+ printk(KERN_ERR "AFFS: Cannot read boot block\n");
goto out;
}
if (mount_flags & SF_VERBOSE) {
chksum = ntohl(chksum);
- printk("AFFS: Mounting volume \"%*s\": Type=%.3s\\%c, Blocksize=%d\n",
- GET_END_PTR(struct root_end,bh->b_data,blocksize)->disk_name[0],
- &GET_END_PTR(struct root_end,bh->b_data,blocksize)->disk_name[1],
- (char *)&chksum,((char *)&chksum)[3] + '0',blocksize);
+ printk(KERN_NOTICE "AFFS: Mounting volume \"%*s\": Type=%.3s\\%c, Blocksize=%d\n",
+ GET_END_PTR(struct root_end,bh->b_data,blocksize)->disk_name[0],
+ &GET_END_PTR(struct root_end,bh->b_data,blocksize)->disk_name[1],
+ (char *)&chksum,((char *)&chksum)[3] + '0',blocksize);
}
s->s_magic = AFFS_SUPER_MAGIC;
@@ -459,7 +475,7 @@ affs_read_super(struct super_block *s,void *data, int silent)
/* Keep super block in cache */
if (!(s->u.affs_sb.s_root_bh = affs_bread(dev,root_block,s->s_blocksize))) {
- printk("AFFS: Can't read root block a second time\n");
+ printk(KERN_ERR "AFFS: Cannot read root block\n");
goto out;
}
@@ -473,7 +489,7 @@ affs_read_super(struct super_block *s,void *data, int silent)
MAX_ZONES * sizeof(struct affs_zone);
pr_debug("num_bm=%d, az_no=%d, sum=%d\n",num_bm,az_no,ptype);
if (!(s->u.affs_sb.s_bitmap = kmalloc(ptype,GFP_KERNEL))) {
- printk("AFFS: Not enough memory.\n");
+ printk(KERN_ERR "AFFS: Not enough memory\n");
goto out;
}
memset(s->u.affs_sb.s_bitmap,0,ptype);
@@ -486,7 +502,8 @@ affs_read_super(struct super_block *s,void *data, int silent)
if (ROOT_END_S(bh->b_data,s)->bm_flag == 0) {
if (!(s->s_flags & MS_RDONLY)) {
- printk("AFFS: Bitmap invalid - mounting %s read only.\n",kdevname(dev));
+ printk(KERN_NOTICE "AFFS: Bitmap invalid - mounting %s read only\n",
+ kdevname(dev));
s->s_flags |= MS_RDONLY;
}
affs_brelse(bh);
@@ -504,17 +521,17 @@ affs_read_super(struct super_block *s,void *data, int silent)
offset = s->u.affs_sb.s_reserved;
az_no = 0;
while (bh) {
- bm = (__u32 *)bh->b_data;
+ bm = (u32 *)bh->b_data;
for (i = ptype; i < stype && bm[i]; i++, mapidx++) {
if (mapidx >= num_bm) {
- printk("AFFS: Not enough bitmap space!?\n");
+ printk(KERN_ERR "AFFS: Not enough bitmap space!?\n");
goto out;
}
bb = affs_bread(s->s_dev,htonl(bm[i]),s->s_blocksize);
if (bb) {
if (affs_checksum_block(s->s_blocksize,bb->b_data,NULL,NULL) &&
!(s->s_flags & MS_RDONLY)) {
- printk("AFFS: Bitmap (%d,key=%lu) invalid - "
+ printk(KERN_WARNING "AFFS: Bitmap (%d,key=%lu) invalid - "
"mounting %s read only.\n",mapidx,htonl(bm[i]),
kdevname(dev));
s->s_flags |= MS_RDONLY;
@@ -525,7 +542,7 @@ affs_read_super(struct super_block *s,void *data, int silent)
key = size & 0x1F; /* used bits */
if (key) {
chksum = ntohl(0x7FFFFFFF >> (31 - key));
- ((__u32 *)bb->b_data)[ptype] &= chksum;
+ ((u32 *)bb->b_data)[ptype] &= chksum;
affs_fix_checksum(s->s_blocksize,bb->b_data,0);
mark_buffer_dirty(bb,1);
}
@@ -551,7 +568,7 @@ affs_read_super(struct super_block *s,void *data, int silent)
}
affs_brelse(bb);
} else {
- printk("AFFS: Can't read bitmap.\n");
+ printk(KERN_ERR "AFFS: Cannot read bitmap\n");
goto out;
}
}
@@ -561,14 +578,14 @@ affs_read_super(struct super_block *s,void *data, int silent)
affs_brelse(bh);
if (key) {
if (!(bh = affs_bread(s->s_dev,key,s->s_blocksize))) {
- printk("AFFS: Can't read bitmap extension.\n");
+ printk(KERN_ERR "AFFS: Cannot read bitmap extension\n");
goto out;
}
} else
bh = NULL;
}
if (mapidx != num_bm) {
- printk("AFFS: Got only %d bitmap blocks, expected %d\n",mapidx,num_bm);
+ printk(KERN_ERR "AFFS: Got only %d bitmap blocks, expected %d\n",mapidx,num_bm);
goto out;
}
nobitmap:
@@ -584,7 +601,7 @@ nobitmap:
if (!(s->s_mounted)) {
s->s_dev = 0;
- printk("AFFS: get root inode failed\n");
+ printk(KERN_ERR "AFFS: get root inode failed\n");
MOD_DEC_USE_COUNT;
return NULL;
}
@@ -615,7 +632,7 @@ nobitmap:
return NULL;
}
-void
+static void
affs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
{
int free;
@@ -635,15 +652,15 @@ affs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
copy_to_user(buf,&tmp,bufsiz);
}
-void
+static void
affs_read_inode(struct inode *inode)
{
struct buffer_head *bh, *lbh;
struct file_front *file_front;
struct file_end *file_end;
- int block;
+ s32 block;
unsigned long prot;
- int ptype, stype;
+ s32 ptype, stype;
unsigned short id;
pr_debug("AFFS: read_inode(%lu)\n",inode->i_ino);
@@ -651,12 +668,12 @@ affs_read_inode(struct inode *inode)
lbh = NULL;
block = inode->i_ino;
if (!(bh = affs_bread(inode->i_dev,block,AFFS_I2BSIZE(inode)))) {
- printk("AFFS: unable to read i-node block %d\n",block);
+ affs_error(inode->i_sb,"read_inode","Cannot read block %d",block);
return;
}
if (affs_checksum_block(AFFS_I2BSIZE(inode),bh->b_data,&ptype,&stype) || ptype != T_SHORT) {
- printk("AFFS: read_inode(): checksum or type (ptype=%d) error on inode %d\n",
- ptype,block);
+ affs_error(inode->i_sb,"read_inode",
+ "Checksum or type (ptype=%d) error on inode %d",ptype,block);
affs_brelse(bh);
return;
}
@@ -735,7 +752,8 @@ affs_read_inode(struct inode *inode)
if (!(lbh = affs_bread(inode->i_dev,inode->u.affs_i.i_original,
AFFS_I2BSIZE(inode)))) {
affs_brelse(bh);
- printk("AFFS: unable to read i-node block %ld\n",inode->i_ino);
+ affs_error(inode->i_sb,"read_inode","Cannot read block %lu",
+ inode->i_ino);
return;
}
file_end = GET_END_PTR(struct file_end,lbh->b_data,AFFS_I2BSIZE(inode));
@@ -776,12 +794,13 @@ affs_read_inode(struct inode *inode)
inode->i_op = &affs_symlink_inode_operations;
}
-void
+static void
affs_write_inode(struct inode *inode)
{
- struct buffer_head *bh;
- struct file_end *file_end;
- short uid, gid;
+ struct buffer_head *bh;
+ struct file_end *file_end;
+ uid_t uid;
+ gid_t gid;
pr_debug("AFFS: write_inode(%lu)\n",inode->i_ino);
@@ -789,8 +808,7 @@ affs_write_inode(struct inode *inode)
if (!inode->i_nlink)
return;
if (!(bh = bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode)))) {
- printk("AFFS: Unable to read block of inode %ld on %s\n",
- inode->i_ino,kdevname(inode->i_dev));
+ affs_error(inode->i_sb,"write_inode","Cannot read block %lu",inode->i_ino);
return;
}
file_end = GET_END_PTR(struct file_end, bh->b_data,AFFS_I2BSIZE(inode));
@@ -820,7 +838,7 @@ affs_write_inode(struct inode *inode)
brelse(bh);
}
-int
+static int
affs_notify_change(struct inode *inode, struct iattr *attr)
{
int error;
@@ -848,7 +866,7 @@ affs_notify_change(struct inode *inode, struct iattr *attr)
return 0;
}
-void
+static void
affs_put_inode(struct inode *inode)
{
pr_debug("AFFS: put_inode(ino=%lu, nlink=%u)\n",inode->i_ino,inode->i_nlink);
@@ -867,7 +885,7 @@ affs_new_inode(const struct inode *dir)
{
struct inode *inode;
struct super_block *sb;
- int block;
+ s32 block;
if (!dir || !(inode = get_empty_inode()))
return NULL;
@@ -918,7 +936,10 @@ affs_add_entry(struct inode *dir, struct inode *link, struct inode *inode,
struct buffer_head *dir_bh;
struct buffer_head *inode_bh;
struct buffer_head *link_bh;
- int hash;
+ struct buffer_head *ibh;
+ int retval;
+ int i;
+ s32 next;
pr_debug("AFFS: add_entry(dir=%lu,inode=%lu,\"%*s\",type=%d\n",dir->i_ino,inode->i_ino,
len,name,type);
@@ -926,34 +947,60 @@ affs_add_entry(struct inode *dir, struct inode *link, struct inode *inode,
dir_bh = affs_bread(dir->i_dev,dir->i_ino,AFFS_I2BSIZE(dir));
inode_bh = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode));
link_bh = NULL;
- if (!dir_bh || !inode_bh) {
- affs_brelse(dir_bh);
- affs_brelse(inode_bh);
- return -ENOSPC;
- }
+ retval = -EIO;
+ if (!dir_bh || !inode_bh)
+ goto addentry_done;
if (link) {
link_bh = affs_bread(link->i_dev,link->i_ino,AFFS_I2BSIZE(link));
- if (!link_bh) {
- affs_brelse(dir_bh);
- affs_brelse(inode_bh);
- return -EINVAL;
- }
+ if (!link_bh)
+ goto addentry_done;
}
((struct dir_front *)inode_bh->b_data)->primary_type = ntohl(T_SHORT);
((struct dir_front *)inode_bh->b_data)->own_key = ntohl(inode->i_ino);
- if (len > 30) /* truncate name quietly */
+ retval = -ENAMETOOLONG;
+ if (len > 30)
+#ifdef NO_TRUNCATE
+ goto addentry_done;
+#else
len = 30;
+#endif
+
+ /* Check if name is valid */
+ retval = -EINVAL;
+ for (i = 0; i < len; i++) {
+ if (name[i] < ' ' || name[i] == ':'
+ || ((unsigned char)name[i] > 0x7e && (unsigned char)name[i] < 0xa0))
+ goto addentry_done;
+ }
+ retval = 0;
DIR_END(inode_bh->b_data,inode)->dir_name[0] = len;
strncpy(DIR_END(inode_bh->b_data,inode)->dir_name + 1,name,len);
DIR_END(inode_bh->b_data,inode)->secondary_type = ntohl(type);
DIR_END(inode_bh->b_data,inode)->parent = ntohl(dir->i_ino);
- hash = affs_hash_name(name,len,AFFS_I2FSTYPE(dir),AFFS_I2HSIZE(dir));
+
+ i = affs_hash_name(name,len,AFFS_I2FSTYPE(dir),AFFS_I2HSIZE(dir)) + 6;
+ next = dir->i_ino;
+
+ /* Alas, we have to search the insertion point with a locked sb */
lock_super(inode->i_sb);
- DIR_END(inode_bh->b_data,inode)->hash_chain =
- ((struct dir_front *)dir_bh->b_data)->hashtable[hash];
- ((struct dir_front *)dir_bh->b_data)->hashtable[hash] = ntohl(inode->i_ino);
+ while (1) {
+ if (!(ibh = affs_bread(dir->i_dev,next,AFFS_I2BSIZE(dir))))
+ goto addentry_done;
+ next = htonl(((s32 *)ibh->b_data)[i]);
+ if (!next || next > inode->i_ino)
+ break;
+ i = AFFS_I2BSIZE(dir) / 4 - 4;
+ affs_brelse(ibh);
+ }
+
+ DIR_END(inode_bh->b_data,inode)->hash_chain = next;
+ ((s32 *)ibh->b_data)[i] = ntohl(inode->i_ino);
+ affs_fix_checksum(AFFS_I2BSIZE(dir),ibh->b_data,5);
+ mark_buffer_dirty(ibh,1);
+ affs_brelse(ibh);
+
if (link_bh) {
LINK_END(inode_bh->b_data,inode)->original = ntohl(link->i_ino);
LINK_END(inode_bh->b_data,inode)->link_chain =
@@ -974,11 +1021,13 @@ affs_add_entry(struct inode *dir, struct inode *link, struct inode *inode,
inode->i_dirt = 1;
mark_buffer_dirty(dir_bh,1);
mark_buffer_dirty(inode_bh,1);
+
+addentry_done:
affs_brelse(dir_bh);
affs_brelse(inode_bh);
affs_brelse(link_bh);
- return 0;
+ return retval;
}
static struct file_system_type affs_fs_type = {
@@ -999,7 +1048,7 @@ EXPORT_NO_SYMBOLS;
int
init_module(void)
{
- return init_affs_fs();
+ return register_filesystem(&affs_fs_type);
}
void
diff --git a/fs/affs/namei.c b/fs/affs/namei.c
index 0f4bced43..6a9b02bac 100644
--- a/fs/affs/namei.c
+++ b/fs/affs/namei.c
@@ -20,6 +20,8 @@
#include <linux/errno.h>
+static int affs_fixup(struct buffer_head *bh, struct inode *inode);
+
/* Simple toupper() for DOS\1 */
static inline unsigned int
@@ -100,7 +102,7 @@ affs_find_entry(struct inode *dir, const char *name, int namelen,
{
struct buffer_head *bh;
int intl;
- int key;
+ s32 key;
pr_debug("AFFS: find_entry(%.*s)=\n",namelen,name);
@@ -222,9 +224,7 @@ affs_create(struct inode *dir, const char *name, int len, int mode, struct inode
pr_debug("AFFS: create(%lu,\"%.*s\",0%o)\n",dir->i_ino,len,name,mode);
-
*result = NULL;
-
if (!dir || !dir->i_sb) {
iput(dir);
return -EINVAL;
@@ -472,7 +472,7 @@ affs_link(struct inode *oldinode, struct inode *dir, const char *name, int len)
iput(oldinode);
oldinode = iget(dir->i_sb,i);
if (!oldinode) {
- printk("AFFS: link(): original does not exist.\n");
+ affs_error(oldinode->i_sb,"link","Cannot get original from link");
iput(dir);
return -ENOENT;
}
@@ -507,7 +507,7 @@ affs_link(struct inode *oldinode, struct inode *dir, const char *name, int len)
}
static int
-subdir(struct inode * new_inode, struct inode * old_inode)
+subdir(struct inode *new_inode, struct inode *old_inode)
{
int ino;
int result;
@@ -650,11 +650,11 @@ end_rename:
return retval;
}
-int
+static int
affs_fixup(struct buffer_head *bh, struct inode *inode)
{
- int key, link_key;
- int type;
+ s32 key, link_key;
+ s32 type;
struct buffer_head *nbh;
struct inode *ofinode;
@@ -663,7 +663,8 @@ affs_fixup(struct buffer_head *bh, struct inode *inode)
key = htonl(LINK_END(bh->b_data,inode)->original);
LINK_END(bh->b_data,inode)->original = 0;
if (!key) {
- printk("AFFS: fixup(): hard link without original: ino=%lu\n",inode->i_ino);
+ affs_error(inode->i_sb,"fixup","Hard link without original: ino=%lu",
+ inode->i_ino);
return -ENOENT;
}
if (!(ofinode = iget(inode->i_sb,key)))
@@ -676,17 +677,18 @@ affs_fixup(struct buffer_head *bh, struct inode *inode)
if ((key = htonl(FILE_END(bh->b_data,inode)->link_chain))) {
/* Get first link, turn it to a file */
if (!(ofinode = iget(inode->i_sb,key))) {
- printk("AFFS: fixup(): cannot read inode %u\n",key);
+ affs_error(inode->i_sb,"fixup","Cannot read block %d",key);
return -ENOENT;
}
if (!ofinode->u.affs_i.i_hlink) {
- printk("AFFS: fixup(): first link to %lu (%u) is not a link?\n",
- inode->i_ino,key);
+ affs_error(inode->i_sb,"fixup",
+ "First link to %lu (%d) is not a link",
+ inode->i_ino,key);
iput(ofinode);
return -ENOENT;
}
if (!(nbh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode)))) {
- printk("AFFS: fixup(): cannot read block %u\n",key);
+ affs_error(inode->i_sb,"fixup","Cannot read block %d",key);
iput(ofinode);
return -ENOENT;
}
@@ -719,13 +721,14 @@ affs_fixup(struct buffer_head *bh, struct inode *inode)
break;
if ((ofinode = iget(inode->i_sb,key))) {
if (!ofinode->u.affs_i.i_hlink)
- printk("AFFS: fixup() inode %u in link chain is "
- "not a link\n",key);
+ affs_error(inode->i_sb,"fixup",
+ "Inode %d in link chain is not a link",
+ key);
ofinode->u.affs_i.i_original = link_key;
ofinode->i_dirt = 1;
FILE_END(nbh->b_data,inode)->original = htonl(link_key);
} else
- printk("AFFS: fixup(): cannot get inode %u\n",key);
+ affs_error(inode->i_sb,"fixup","Cannot read block %d",key);
}
/* Turn old inode to a link */
inode->u.affs_i.i_hlink = 1;
@@ -735,7 +738,7 @@ affs_fixup(struct buffer_head *bh, struct inode *inode)
} else if (type == ST_SOFTLINK) {
return 0;
} else {
- printk("AFFS: fixup(): secondary type=%d\n",type);
+ affs_error(inode->i_sb,"fixup","Bad secondary type (%d)",type);
return -EBADF;
}
}
diff --git a/fs/affs/symlink.c b/fs/affs/symlink.c
index 734df0780..de93eac5c 100644
--- a/fs/affs/symlink.c
+++ b/fs/affs/symlink.c
@@ -82,7 +82,7 @@ affs_follow_link(struct inode *dir, struct inode *inode, int flag, int mode,
i = 0;
j = 0;
if (!bh) {
- printk("AFFS: unable to read i-node block %lu\n",inode->i_ino);
+ affs_error(inode->i_sb,"follow_link","Cannot read block %lu\n",inode->i_ino);
kfree(buffer);
iput(inode);
iput(dir);
@@ -138,7 +138,7 @@ affs_readlink(struct inode *inode, char *buffer, int buflen)
i = 0;
j = 0;
if (!bh) {
- printk("AFFS: unable to read i-node block %lu\n",inode->i_ino);
+ affs_error(inode->i_sb,"readlink","Cannot read block %lu\n",inode->i_ino);
goto symlink_end;
}
lf = (struct slink_front *)bh->b_data;
diff --git a/fs/autofs/.cvsignore b/fs/autofs/.cvsignore
new file mode 100644
index 000000000..4671378ae
--- /dev/null
+++ b/fs/autofs/.cvsignore
@@ -0,0 +1 @@
+.depend
diff --git a/fs/autofs/Makefile b/fs/autofs/Makefile
index 12f302635..1681c3d31 100644
--- a/fs/autofs/Makefile
+++ b/fs/autofs/Makefile
@@ -1,11 +1,7 @@
#
# Makefile for the linux autofs-filesystem routines.
#
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definitions are now in the main makefile...
+# We can build this either out of the kernel tree or the autofs tools tree.
#
O_TARGET := autofs.o
@@ -13,4 +9,27 @@ O_OBJS := dir.o dirhash.o init.o inode.o root.o symlink.o waitq.o
M_OBJS := $(O_TARGET)
+ifdef TOPDIR
+#
+# Part of the kernel code
+#
include $(TOPDIR)/Rules.make
+else
+#
+# Standalone (handy for development)
+#
+include ../Makefile.rules
+
+CFLAGS += -D__KERNEL__ -DMODULE $(KFLAGS) -I../include -I$(KINCLUDE) $(MODFLAGS)
+
+all: $(O_TARGET)
+
+$(O_TARGET): $(O_OBJS)
+ $(LD) -r -o $(O_TARGET) $(O_OBJS)
+
+install: $(O_TARGET)
+ install -c $(O_TARGET) /lib/modules/`uname -r`/fs
+
+clean:
+ rm -f *.o *.s
+endif
diff --git a/fs/autofs/autofs_i.h b/fs/autofs/autofs_i.h
new file mode 100644
index 000000000..d3b6e484f
--- /dev/null
+++ b/fs/autofs/autofs_i.h
@@ -0,0 +1,175 @@
+/* -*- linux-c -*- ------------------------------------------------------- *
+ *
+ * linux/fs/autofs/autofs_i.h
+ *
+ * Copyright 1997 Transmeta Corporation - All Rights Reserved
+ *
+ * This file is part of the Linux kernel and is made available under
+ * the terms of the GNU General Public License, version 2, or at your
+ * option, any later version, incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/* Internal header file for autofs */
+
+#include <linux/auto_fs.h>
+
+/* This is the range of ioctl() numbers we claim as ours */
+#define AUTOFS_IOC_FIRST AUTOFS_IOC_READY
+#define AUTOFS_IOC_COUNT 32
+
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/wait.h>
+
+#define kver(a,b,c) (((a) << 16) + ((b) << 8) + (c))
+
+#if LINUX_VERSION_CODE < kver(2,1,0)
+
+/* Segmentation stuff for pre-2.1 kernels */
+#include <asm/segment.h>
+
+static inline int copy_to_user(void *dst, void *src, unsigned long len)
+{
+ int rv = verify_area(VERIFY_WRITE, dst, len);
+ if ( rv )
+ return -1;
+ memcpy_tofs(dst,src,len);
+ return 0;
+}
+
+static inline int copy_from_user(void *dst, void *src, unsigned long len)
+{
+ int rv = verify_area(VERIFY_READ, src, len);
+ if ( rv )
+ return -1;
+ memcpy_fromfs(dst,src,len);
+ return 0;
+}
+
+#else
+
+/* Segmentation stuff for post-2.1 kernels */
+#include <asm/uaccess.h>
+#define register_symtab(x) ((void)0)
+
+#endif
+
+#ifdef DEBUG
+#define DPRINTK(D) printk D;
+#else
+#define DPRINTK(D)
+#endif
+
+#define AUTOFS_SUPER_MAGIC 0x0187
+
+/* Structures associated with the root directory hash */
+
+#define AUTOFS_HASH_SIZE 67
+
+typedef u32 autofs_hash_t; /* Type returned by autofs_hash() */
+
+struct autofs_dir_ent {
+ autofs_hash_t hash;
+ struct autofs_dir_ent *next;
+ struct autofs_dir_ent **back;
+ char *name;
+ int len;
+ ino_t ino;
+ /* The following entries are for the expiry system */
+ unsigned long last_usage;
+ struct autofs_dir_ent *exp_next;
+ struct autofs_dir_ent *exp_prev;
+};
+
+struct autofs_dirhash {
+ struct autofs_dir_ent *h[AUTOFS_HASH_SIZE];
+ struct autofs_dir_ent expiry_head;
+};
+
+struct autofs_wait_queue {
+ unsigned long wait_queue_token;
+ struct wait_queue *queue;
+ struct autofs_wait_queue *next;
+ /* We use the following to see what we are waiting for */
+ autofs_hash_t hash;
+ int len;
+ char *name;
+ /* This is for status reporting upon return */
+ int status;
+ int wait_ctr;
+};
+
+struct autofs_symlink {
+ int len;
+ char *data;
+ time_t mtime;
+};
+
+#define AUTOFS_MAX_SYMLINKS 256
+
+#define AUTOFS_ROOT_INO 1
+#define AUTOFS_FIRST_SYMLINK 2
+#define AUTOFS_FIRST_DIR_INO (AUTOFS_FIRST_SYMLINK+AUTOFS_MAX_SYMLINKS)
+
+#define AUTOFS_SYMLINK_BITMAP_LEN ((AUTOFS_MAX_SYMLINKS+31)/32)
+
+#ifndef END_OF_TIME
+#define END_OF_TIME ((time_t)((unsigned long)((time_t)(~0UL)) >> 1))
+#endif
+
+struct autofs_sb_info {
+ struct file *pipe;
+ pid_t oz_pgrp;
+ int catatonic;
+ unsigned long exp_timeout;
+ ino_t next_dir_ino;
+ struct autofs_wait_queue *queues; /* Wait queue pointer */
+ struct autofs_dirhash dirhash; /* Root directory hash */
+ struct autofs_symlink symlink[AUTOFS_MAX_SYMLINKS];
+ u32 symlink_bitmap[AUTOFS_SYMLINK_BITMAP_LEN];
+};
+
+/* autofs_oz_mode(): do we see the man behind the curtain? */
+static inline int autofs_oz_mode(struct autofs_sb_info *sbi) {
+ return sbi->catatonic || current->pgrp == sbi->oz_pgrp;
+}
+
+/* Hash operations */
+
+autofs_hash_t autofs_hash(const char *,int);
+void autofs_initialize_hash(struct autofs_dirhash *);
+struct autofs_dir_ent *autofs_hash_lookup(const struct autofs_dirhash *,autofs_hash_t,const char *,int);
+void autofs_hash_insert(struct autofs_dirhash *,struct autofs_dir_ent *);
+void autofs_hash_delete(struct autofs_dir_ent *);
+struct autofs_dir_ent *autofs_hash_enum(const struct autofs_dirhash *,off_t *);
+void autofs_hash_nuke(struct autofs_dirhash *);
+
+/* Expiration-handling functions */
+
+void autofs_update_usage(struct autofs_dirhash *,struct autofs_dir_ent *);
+struct autofs_dir_ent *autofs_expire(struct autofs_dirhash *,unsigned long);
+
+/* Operations structures */
+
+extern struct inode_operations autofs_root_inode_operations;
+extern struct inode_operations autofs_symlink_inode_operations;
+extern struct inode_operations autofs_dir_inode_operations;
+
+/* Initializing function */
+
+struct super_block *autofs_read_super(struct super_block *, void *,int);
+
+/* Queue management functions */
+
+int autofs_wait(struct autofs_sb_info *,autofs_hash_t,const char *,int);
+int autofs_wait_release(struct autofs_sb_info *,unsigned long,int);
+void autofs_catatonic_mode(struct autofs_sb_info *);
+
+#ifdef DEBUG
+void autofs_say(const char *name, int len);
+#else
+#define autofs_say(n,l)
+#endif
diff --git a/fs/autofs/dir.c b/fs/autofs/dir.c
index 22081d1a7..461688e9f 100644
--- a/fs/autofs/dir.c
+++ b/fs/autofs/dir.c
@@ -10,7 +10,7 @@
*
* ------------------------------------------------------------------------- */
-#include <linux/auto_fs.h>
+#include "autofs_i.h"
static int autofs_dir_readdir(struct inode *inode, struct file *filp,
void *dirent, filldir_t filldir)
diff --git a/fs/autofs/dirhash.c b/fs/autofs/dirhash.c
index 8ea5325c4..90c18695a 100644
--- a/fs/autofs/dirhash.c
+++ b/fs/autofs/dirhash.c
@@ -10,9 +10,43 @@
*
* ------------------------------------------------------------------------- */
-#include <linux/string.h>
-#include <linux/malloc.h>
-#include <linux/auto_fs.h>
+#include "autofs_i.h"
+
+/* Functions for maintenance of expiry queue */
+
+static void autofs_init_usage(struct autofs_dirhash *dh,
+ struct autofs_dir_ent *ent)
+{
+ ent->exp_next = &dh->expiry_head;
+ ent->exp_prev = dh->expiry_head.exp_prev;
+ dh->expiry_head.exp_prev->exp_next = ent;
+ dh->expiry_head.exp_prev = ent;
+ ent->last_usage = jiffies;
+}
+
+static void autofs_delete_usage(struct autofs_dir_ent *ent)
+{
+ ent->exp_prev->exp_next = ent->exp_next;
+ ent->exp_next->exp_prev = ent->exp_prev;
+}
+
+void autofs_update_usage(struct autofs_dirhash *dh,
+ struct autofs_dir_ent *ent)
+{
+ autofs_delete_usage(ent); /* Unlink from current position */
+ autofs_init_usage(dh,ent); /* Relink at queue tail */
+}
+
+struct autofs_dir_ent *autofs_expire(struct autofs_dirhash *dh,
+ unsigned long timeout)
+{
+ struct autofs_dir_ent *ent;
+
+ ent = dh->expiry_head.exp_next;
+
+ if ( ent == &(dh->expiry_head) ) return NULL;
+ return (jiffies - ent->last_usage >= timeout) ? ent : NULL;
+}
/* Adapted from the Dragon Book, page 436 */
/* This particular hashing algorithm requires autofs_hash_t == u32 */
@@ -28,6 +62,8 @@ autofs_hash_t autofs_hash(const char *name, int len)
void autofs_initialize_hash(struct autofs_dirhash *dh) {
memset(&dh->h, 0, AUTOFS_HASH_SIZE*sizeof(struct autofs_dir_ent *));
+ dh->expiry_head.exp_next = dh->expiry_head.exp_prev =
+ &dh->expiry_head;
}
struct autofs_dir_ent *autofs_hash_lookup(const struct autofs_dirhash *dh, autofs_hash_t hash, const char *name, int len)
@@ -54,6 +90,8 @@ void autofs_hash_insert(struct autofs_dirhash *dh, struct autofs_dir_ent *ent)
DPRINTK(("autofs_hash_insert: hash = 0x%08x, name = ", ent->hash));
autofs_say(ent->name,ent->len);
+ autofs_init_usage(dh,ent);
+
dhnp = &dh->h[ent->hash % AUTOFS_HASH_SIZE];
ent->next = *dhnp;
ent->back = dhnp;
@@ -63,6 +101,9 @@ void autofs_hash_insert(struct autofs_dirhash *dh, struct autofs_dir_ent *ent)
void autofs_hash_delete(struct autofs_dir_ent *ent)
{
*(ent->back) = ent->next;
+
+ autofs_delete_usage(ent);
+
kfree(ent->name);
kfree(ent);
}
@@ -114,6 +155,8 @@ struct autofs_dir_ent *autofs_hash_enum(const struct autofs_dirhash *dh, off_t *
return ent;
}
+/* Delete everything. This is used on filesystem destruction, so we
+ make no attempt to keep the pointers valid */
void autofs_hash_nuke(struct autofs_dirhash *dh)
{
int i;
diff --git a/fs/autofs/init.c b/fs/autofs/init.c
index a4857cb99..1b3f6f165 100644
--- a/fs/autofs/init.c
+++ b/fs/autofs/init.c
@@ -11,23 +11,24 @@
* ------------------------------------------------------------------------- */
#include <linux/module.h>
-#include <linux/auto_fs.h>
+#include "autofs_i.h"
-struct file_system_type autofs_fs_type = {
+#if LINUX_VERSION_CODE < kver(2,1,36)
+#define __initfunc(X) X
+#else
+#include <linux/init.h>
+#endif
+
+static struct file_system_type autofs_fs_type = {
autofs_read_super, "autofs", 0, NULL
};
-int init_autofs_fs(void)
-{
- return register_filesystem(&autofs_fs_type);
-}
-
#ifdef MODULE
int init_module(void)
{
int status;
- if ((status = init_autofs_fs()) == 0)
+ if ((status = register_filesystem(&autofs_fs_type)) == 0)
register_symtab(0);
return status;
}
@@ -36,7 +37,15 @@ void cleanup_module(void)
{
unregister_filesystem(&autofs_fs_type);
}
-#endif
+
+#else /* MODULE */
+
+__initfunc(int init_autofs_fs(void))
+{
+ return register_filesystem(&autofs_fs_type);
+}
+
+#endif /* !MODULE */
#ifdef DEBUG
void autofs_say(const char *name, int len)
diff --git a/fs/autofs/inode.c b/fs/autofs/inode.c
index 60b805a07..a8c176a02 100644
--- a/fs/autofs/inode.c
+++ b/fs/autofs/inode.c
@@ -15,7 +15,7 @@
#include <linux/file.h>
#include <linux/locks.h>
#include <asm/bitops.h>
-#include <linux/auto_fs.h>
+#include "autofs_i.h"
#define __NO_VERSION__
#include <linux/module.h>
@@ -28,17 +28,19 @@ static void autofs_put_inode(struct inode *inode)
static void autofs_put_super(struct super_block *sb)
{
- struct autofs_sb_info *sbi;
+ struct autofs_sb_info *sbi =
+ (struct autofs_sb_info *) sb->u.generic_sbp;
unsigned int n;
+ if ( !sbi->catatonic )
+ autofs_catatonic_mode(sbi); /* Free wait queues, close pipe */
+
lock_super(sb);
- sbi = (struct autofs_sb_info *) sb->u.generic_sbp;
autofs_hash_nuke(&sbi->dirhash);
for ( n = 0 ; n < AUTOFS_MAX_SYMLINKS ; n++ ) {
if ( test_bit(n, sbi->symlink_bitmap) )
kfree(sbi->symlink[n].data);
}
- fput(sbi->pipe, sbi->pipe->f_inode);
sb->s_dev = 0;
kfree(sb->u.generic_sbp);
@@ -149,6 +151,7 @@ struct super_block *autofs_read_super(struct super_block *s, void *data,
s->u.generic_sbp = sbi;
sbi->catatonic = 0;
+ sbi->exp_timeout = 0;
sbi->oz_pgrp = current->pgrp;
autofs_initialize_hash(&sbi->dirhash);
sbi->queues = NULL;
diff --git a/fs/autofs/root.c b/fs/autofs/root.c
index d9056dcb1..57449e816 100644
--- a/fs/autofs/root.c
+++ b/fs/autofs/root.c
@@ -12,9 +12,8 @@
#include <linux/errno.h>
#include <linux/stat.h>
-#include <linux/malloc.h>
-#include <linux/ioctl.h>
-#include <linux/auto_fs.h>
+#include <linux/param.h>
+#include "autofs_i.h"
static int autofs_root_readdir(struct inode *,struct file *,void *,filldir_t);
static int autofs_root_lookup(struct inode *,const char *,int,struct inode **);
@@ -171,7 +170,8 @@ static int autofs_root_lookup(struct inode *dir, const char *name, int len,
}
}
} while(!res);
-
+ autofs_update_usage(&sbi->dirhash,ent);
+
*result = res;
iput(dir);
return 0;
@@ -229,7 +229,6 @@ static int autofs_root_symlink(struct inode *dir, const char *name, int len, con
ent->ino = AUTOFS_FIRST_SYMLINK + n;
ent->hash = hash;
memcpy(ent->name,name,ent->len = len);
- ent->expiry = END_OF_TIME;
autofs_hash_insert(dh,ent);
@@ -322,7 +321,6 @@ static int autofs_root_mkdir(struct inode *dir, const char *name, int len, int m
ent->hash = hash;
memcpy(ent->name, name, ent->len = len);
ent->ino = sbi->next_dir_ino++;
- ent->expiry = END_OF_TIME;
autofs_hash_insert(dh,ent);
dir->i_nlink++;
iput(dir);
@@ -330,6 +328,75 @@ static int autofs_root_mkdir(struct inode *dir, const char *name, int len, int m
return 0;
}
+/* Get/set timeout ioctl() operation */
+static inline int autofs_get_set_timeout(struct autofs_sb_info *sbi,
+ unsigned long *p)
+{
+ int rv;
+ unsigned long ntimeout;
+
+#if LINUX_VERSION_CODE < kver(2,1,0)
+ if ( (rv = verify_area(VERIFY_WRITE, p, sizeof(unsigned long))) )
+ return rv;
+ ntimeout = get_user(p);
+ put_user(sbi->exp_timeout/HZ, p);
+#else
+ if ( (rv = get_user(ntimeout, p)) ||
+ (rv = put_user(sbi->exp_timeout/HZ, p)) )
+ return rv;
+#endif
+
+ if ( ntimeout > ULONG_MAX/HZ )
+ sbi->exp_timeout = 0;
+ else
+ sbi->exp_timeout = ntimeout * HZ;
+
+ return 0;
+}
+
+/* Return protocol version */
+static inline int autofs_get_protover(int *p)
+{
+#if LINUX_VERSION_CODE < kver(2,1,0)
+ int rv;
+ if ( (rv = verify_area(VERIFY_WRITE, p, sizeof(int))) )
+ return rv;
+ put_user(AUTOFS_PROTO_VERSION, p);
+ return 0;
+#else
+ return put_user(AUTOFS_PROTO_VERSION, p);
+#endif
+}
+
+/* Perform an expiry operation */
+static inline int autofs_expire_run(struct autofs_sb_info *sbi,
+ struct autofs_packet_expire *pkt_p)
+{
+ struct autofs_dir_ent *ent;
+ struct autofs_packet_expire pkt;
+ struct autofs_dirhash *dh = &(sbi->dirhash);
+
+ memset(&pkt,0,sizeof pkt);
+
+ pkt.hdr.proto_version = AUTOFS_PROTO_VERSION;
+ pkt.hdr.type = autofs_ptype_expire;
+
+ if ( !sbi->exp_timeout ||
+ !(ent = autofs_expire(dh,sbi->exp_timeout)) )
+ return -EAGAIN;
+
+ pkt.len = ent->len;
+ memcpy(pkt.name, ent->name, pkt.len);
+ pkt.name[pkt.len] = '\0';
+
+ if ( copy_to_user(pkt_p, &pkt, sizeof(struct autofs_packet_expire)) )
+ return -EFAULT;
+
+ autofs_update_usage(dh,ent);
+
+ return 0;
+}
+
/*
* ioctl()'s on the root directory is the chief method for the daemon to
* generate kernel reactions
@@ -337,26 +404,33 @@ static int autofs_root_mkdir(struct inode *dir, const char *name, int len, int m
static int autofs_root_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- struct autofs_sb_info *sbi = (struct autofs_sb_info *)inode->i_sb->u.generic_sbp;
+ struct autofs_sb_info *sbi =
+ (struct autofs_sb_info *)inode->i_sb->u.generic_sbp;
- DPRINTK(("autofs_ioctl: cmd = %04x, arg = 0x%08lx, sbi = %p, pgrp = %u\n",cmd,arg,sbi,current->pgrp));
+ DPRINTK(("autofs_ioctl: cmd = 0x%08x, arg = 0x%08lx, sbi = %p, pgrp = %u\n",cmd,arg,sbi,current->pgrp));
+ if ( _IOC_TYPE(cmd) != _IOC_TYPE(AUTOFS_IOC_FIRST) ||
+ _IOC_NR(cmd) - _IOC_NR(AUTOFS_IOC_FIRST) >= AUTOFS_IOC_COUNT )
+ return -ENOTTY;
+
+ if ( !autofs_oz_mode(sbi) && !fsuser() )
+ return -EPERM;
+
switch(cmd) {
case AUTOFS_IOC_READY: /* Wait queue: go ahead and retry */
- if ( !autofs_oz_mode(sbi) && !fsuser() )
- return -EPERM;
return autofs_wait_release(sbi,arg,0);
case AUTOFS_IOC_FAIL: /* Wait queue: fail with ENOENT */
- /* Optional: add to failure cache */
- if ( !autofs_oz_mode(sbi) && !fsuser() )
- return -EPERM;
return autofs_wait_release(sbi,arg,-ENOENT);
case AUTOFS_IOC_CATATONIC: /* Enter catatonic mode (daemon shutdown) */
- if ( !autofs_oz_mode(sbi) && !fsuser() )
- return -EPERM;
autofs_catatonic_mode(sbi);
return 0;
+ case AUTOFS_IOC_PROTOVER: /* Get protocol version */
+ return autofs_get_protover((int *)arg);
+ case AUTOFS_IOC_SETTIMEOUT:
+ return autofs_get_set_timeout(sbi,(unsigned long *)arg);
+ case AUTOFS_IOC_EXPIRE:
+ return autofs_expire_run(sbi,(struct autofs_packet_expire *)arg);
default:
- return -ENOTTY; /* Should this be ENOSYS? */
+ return -ENOSYS;
}
}
diff --git a/fs/autofs/symlink.c b/fs/autofs/symlink.c
index 0e932c169..46c333103 100644
--- a/fs/autofs/symlink.c
+++ b/fs/autofs/symlink.c
@@ -12,7 +12,7 @@
#include <linux/string.h>
#include <linux/sched.h>
-#include <linux/auto_fs.h>
+#include "autofs_i.h"
static int autofs_follow_link(struct inode *dir, struct inode *inode,
int flag, int mode, struct inode **res_inode)
diff --git a/fs/autofs/waitq.c b/fs/autofs/waitq.c
index 6dc6d0b13..b37745f19 100644
--- a/fs/autofs/waitq.c
+++ b/fs/autofs/waitq.c
@@ -11,9 +11,10 @@
* ------------------------------------------------------------------------- */
#include <linux/malloc.h>
-#include <linux/signal.h>
#include <linux/sched.h>
-#include <linux/auto_fs.h>
+#include <linux/signal.h>
+#include <linux/file.h>
+#include "autofs_i.h"
/* We make this a static variable rather than a part of the superblock; it
is better if we don't reassign numbers easily even across filesystems */
@@ -36,6 +37,7 @@ void autofs_catatonic_mode(struct autofs_sb_info *sbi)
wake_up(&wq->queue);
wq = nwq;
}
+ fput(sbi->pipe, sbi->pipe->f_inode); /* Close the pipe */
}
static int autofs_write(struct file *file, const void *addr, int bytes)
@@ -43,7 +45,7 @@ static int autofs_write(struct file *file, const void *addr, int bytes)
unsigned short fs;
unsigned long old_signal;
const char *data = (const char *)addr;
- int written;
+ int written = 0;
/** WARNING: this is not safe for writing more than PIPE_BUF bytes! **/
@@ -75,6 +77,8 @@ static void autofs_notify_daemon(struct autofs_sb_info *sbi, struct autofs_wait_
DPRINTK(("autofs_wait: wait id = 0x%08lx, name = ", wq->wait_queue_token));
autofs_say(wq->name,wq->len);
+ memset(&pkt,0,sizeof pkt); /* For security reasons */
+
pkt.hdr.proto_version = AUTOFS_PROTO_VERSION;
pkt.hdr.type = autofs_ptype_missing;
pkt.wait_queue_token = wq->wait_queue_token;
@@ -94,7 +98,7 @@ int autofs_wait(struct autofs_sb_info *sbi, autofs_hash_t hash, const char *name
for ( wq = sbi->queues ; wq ; wq = wq->next ) {
if ( wq->hash == hash &&
wq->len == len &&
- !memcmp(wq->name,name,len) )
+ wq->name && !memcmp(wq->name,name,len) )
break;
}
@@ -113,12 +117,13 @@ int autofs_wait(struct autofs_sb_info *sbi, autofs_hash_t hash, const char *name
init_waitqueue(&wq->queue);
wq->hash = hash;
wq->len = len;
+ wq->status = -EINTR; /* Status return if interrupted */
memcpy(wq->name, name, len);
wq->next = sbi->queues;
sbi->queues = wq;
/* autofs_notify_daemon() may block */
- wq->wait_ctr++;
+ wq->wait_ctr = 1;
autofs_notify_daemon(sbi,wq);
} else
wq->wait_ctr++;
@@ -130,7 +135,8 @@ int autofs_wait(struct autofs_sb_info *sbi, autofs_hash_t hash, const char *name
DPRINTK(("autofs_wait: skipped sleeping\n"));
}
- status = (current->signal & ~current->blocked) ? -EINTR : wq->status;
+ status = wq->status;
+
if ( ! --wq->wait_ctr ) /* Are we the last process to need status? */
kfree(wq);
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 587c44f8f..f12d89ef3 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -49,6 +49,11 @@ extern void dump_thread(struct pt_regs *, struct user *);
extern unsigned long get_unmapped_area(unsigned long addr, unsigned long len);
#endif
+#ifndef elf_addr_t
+#define elf_addr_t unsigned long
+#define elf_caddr_t char *
+#endif
+
/*
* If we don't support core dumping, then supply a NULL so we
* don't even try.
@@ -61,6 +66,7 @@ static int elf_core_dump(long signr, struct pt_regs * regs);
#define ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(ELF_EXEC_PAGESIZE-1))
#define ELF_PAGEOFFSET(_v) ((_v) & (ELF_EXEC_PAGESIZE-1))
+#define ELF_PAGEALIGN(_v) (((_v) + ELF_EXEC_PAGESIZE - 1) & ~(ELF_EXEC_PAGESIZE - 1))
static struct linux_binfmt elf_format = {
#ifndef MODULE
@@ -93,8 +99,8 @@ static void print_elf_p_type(Elf32_Word p_type)
static void set_brk(unsigned long start, unsigned long end)
{
- start = PAGE_ALIGN(start);
- end = PAGE_ALIGN(end);
+ start = ELF_PAGEALIGN(start);
+ end = ELF_PAGEALIGN(end);
if (end <= start)
return;
do_mmap(NULL, start, end - start,
@@ -113,28 +119,30 @@ static void padzero(unsigned long elf_bss)
{
unsigned long nbyte;
- nbyte = elf_bss & (PAGE_SIZE-1);
+ nbyte = ELF_PAGEOFFSET(elf_bss);
if (nbyte) {
- nbyte = PAGE_SIZE - nbyte;
+ nbyte = ELF_EXEC_PAGESIZE - nbyte;
clear_user((void *) elf_bss, nbyte);
}
}
-unsigned long * create_elf_tables(char *p, int argc, int envc,
- struct elfhdr * exec,
- unsigned long load_addr,
- unsigned long interp_load_addr, int ibcs)
+static elf_addr_t *
+create_elf_tables(char *p, int argc, int envc,
+ struct elfhdr * exec,
+ unsigned long load_addr,
+ unsigned long interp_load_addr, int ibcs)
{
- char **argv, **envp;
- unsigned long *sp;
+ elf_caddr_t *argv;
+ elf_caddr_t *envp;
+ elf_addr_t *sp;
/*
* Force 16 byte alignment here for generality.
*/
- sp = (unsigned long *) (~15UL & (unsigned long) p);
+ sp = (elf_addr_t *) (~15UL & (unsigned long) p);
#if defined(__mips__) || defined(__sparc__)
{
- unsigned long *csp;
+ elf_addr_t *csp;
csp = sp;
csp -= exec ? DLINFO_ITEMS*2 : 2;
csp -= envc+1;
@@ -160,36 +168,36 @@ unsigned long * create_elf_tables(char *p, int argc, int envc,
NEW_AUX_ENT (0, AT_PHDR, load_addr + exec->e_phoff);
NEW_AUX_ENT (1, AT_PHENT, sizeof (struct elf_phdr));
NEW_AUX_ENT (2, AT_PHNUM, exec->e_phnum);
- NEW_AUX_ENT (3, AT_PAGESZ, PAGE_SIZE);
+ NEW_AUX_ENT (3, AT_PAGESZ, ELF_EXEC_PAGESIZE);
NEW_AUX_ENT (4, AT_BASE, interp_load_addr);
NEW_AUX_ENT (5, AT_FLAGS, 0);
- NEW_AUX_ENT (6, AT_ENTRY, (unsigned long) exec->e_entry);
- NEW_AUX_ENT (7, AT_UID, (unsigned long) current->uid);
- NEW_AUX_ENT (8, AT_EUID, (unsigned long) current->euid);
- NEW_AUX_ENT (9, AT_GID, (unsigned long) current->gid);
- NEW_AUX_ENT (10, AT_EGID, (unsigned long) current->egid);
+ NEW_AUX_ENT (6, AT_ENTRY, (elf_addr_t) exec->e_entry);
+ NEW_AUX_ENT (7, AT_UID, (elf_addr_t) current->uid);
+ NEW_AUX_ENT (8, AT_EUID, (elf_addr_t) current->euid);
+ NEW_AUX_ENT (9, AT_GID, (elf_addr_t) current->gid);
+ NEW_AUX_ENT (10, AT_EGID, (elf_addr_t) current->egid);
}
#undef NEW_AUX_ENT
sp -= envc+1;
- envp = (char **) sp;
+ envp = (elf_caddr_t *) sp;
sp -= argc+1;
- argv = (char **) sp;
+ argv = (elf_caddr_t *) sp;
if (!ibcs) {
- __put_user((unsigned long) envp,--sp);
- __put_user((unsigned long) argv,--sp);
+ __put_user((elf_addr_t)(unsigned long) envp,--sp);
+ __put_user((elf_addr_t)(unsigned long) argv,--sp);
}
- __put_user((unsigned long)argc,--sp);
+ __put_user((elf_addr_t)argc,--sp);
current->mm->arg_start = (unsigned long) p;
while (argc-->0) {
- __put_user(p,argv++);
+ __put_user((elf_caddr_t)(unsigned long)p,argv++);
p += strlen_user(p);
}
__put_user(NULL, argv);
current->mm->arg_end = current->mm->env_start = (unsigned long) p;
while (envc-->0) {
- __put_user(p,envp++);
+ __put_user((elf_caddr_t)(unsigned long)p,envp++);
p += strlen_user(p);
}
__put_user(NULL, envp);
@@ -236,14 +244,16 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
/* Now read in all of the header information */
- if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > PAGE_SIZE)
+ if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > ELF_EXEC_PAGESIZE) {
return ~0UL;
+ }
elf_phdata = (struct elf_phdr *)
kmalloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum,
GFP_KERNEL);
- if (!elf_phdata)
+ if (!elf_phdata) {
return ~0UL;
+ }
/*
* If the size of this structure has changed, then punt, since
@@ -389,7 +399,9 @@ static unsigned long load_aout_interp(struct exec * interp_ex,
interp_ex->a_bss,
PROT_READ|PROT_WRITE|PROT_EXEC,
MAP_FIXED|MAP_PRIVATE, 0);
- if (retval < 0) return ~0UL;
+ if (retval < 0) {
+ return ~0UL;
+ }
return elf_entry;
}
@@ -611,6 +623,9 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
/* Do this so that we can load the interpreter, if need be. We will
change some of these later */
current->mm->rss = 0;
+#ifdef ELF_FLAGS_INIT
+ ELF_FLAGS_INIT;
+#endif
bprm->p = setup_arg_pages(bprm->p, bprm);
current->mm->start_stack = bprm->p;
@@ -828,7 +843,7 @@ do_load_elf_library(int fd){
/* Now read in all of the header information */
- if (sizeof(struct elf_phdr) * elf_ex.e_phnum > PAGE_SIZE)
+ if (sizeof(struct elf_phdr) * elf_ex.e_phnum > ELF_EXEC_PAGESIZE)
return -ENOEXEC;
elf_phdata = (struct elf_phdr *)
@@ -932,6 +947,10 @@ static inline int maydump(struct vm_area_struct *vma)
{
if (!(vma->vm_flags & (VM_READ|VM_WRITE|VM_EXEC)))
return 0;
+
+ /* Do not dump I/O mapped devices! -DaveM */
+ if(vma->vm_flags & VM_IO)
+ return 0;
#if 1
if (vma->vm_flags & (VM_WRITE|VM_GROWSUP|VM_GROWSDOWN))
return 1;
@@ -1041,7 +1060,7 @@ static int elf_core_dump(long signr, struct pt_regs * regs)
elf_fpregset_t fpu; /* NT_PRFPREG */
struct elf_prpsinfo psinfo; /* NT_PRPSINFO */
- if (!current->dumpable || limit < PAGE_SIZE || current->mm->count != 1)
+ if (!current->dumpable || limit < ELF_EXEC_PAGESIZE || current->mm->count != 1)
return 0;
current->dumpable = 0;
@@ -1143,14 +1162,14 @@ static int elf_core_dump(long signr, struct pt_regs * regs)
psinfo.pr_ppid = prstatus.pr_ppid = current->p_pptr->pid;
psinfo.pr_pgrp = prstatus.pr_pgrp = current->pgrp;
psinfo.pr_sid = prstatus.pr_sid = current->session;
- prstatus.pr_utime.tv_sec = CT_TO_SECS(current->utime);
- prstatus.pr_utime.tv_usec = CT_TO_USECS(current->utime);
- prstatus.pr_stime.tv_sec = CT_TO_SECS(current->stime);
- prstatus.pr_stime.tv_usec = CT_TO_USECS(current->stime);
- prstatus.pr_cutime.tv_sec = CT_TO_SECS(current->cutime);
- prstatus.pr_cutime.tv_usec = CT_TO_USECS(current->cutime);
- prstatus.pr_cstime.tv_sec = CT_TO_SECS(current->cstime);
- prstatus.pr_cstime.tv_usec = CT_TO_USECS(current->cstime);
+ prstatus.pr_utime.tv_sec = CT_TO_SECS(current->times.tms_utime);
+ prstatus.pr_utime.tv_usec = CT_TO_USECS(current->times.tms_utime);
+ prstatus.pr_stime.tv_sec = CT_TO_SECS(current->times.tms_stime);
+ prstatus.pr_stime.tv_usec = CT_TO_USECS(current->times.tms_stime);
+ prstatus.pr_cutime.tv_sec = CT_TO_SECS(current->times.tms_cutime);
+ prstatus.pr_cutime.tv_usec = CT_TO_USECS(current->times.tms_cutime);
+ prstatus.pr_cstime.tv_sec = CT_TO_SECS(current->times.tms_cstime);
+ prstatus.pr_cstime.tv_usec = CT_TO_USECS(current->times.tms_cstime);
/*
* This transfers the registers from regs into the standard
@@ -1162,7 +1181,7 @@ static int elf_core_dump(long signr, struct pt_regs * regs)
if (sizeof(elf_gregset_t) != sizeof(struct pt_regs))
{
printk("sizeof(elf_gregset_t) (%ld) != sizeof(struct pt_regs) (%ld)\n",
- sizeof(elf_gregset_t), sizeof(struct pt_regs));
+ (long)sizeof(elf_gregset_t), (long)sizeof(struct pt_regs));
}
else
*(struct pt_regs *)&prstatus.pr_reg = *regs;
@@ -1190,7 +1209,8 @@ static int elf_core_dump(long signr, struct pt_regs * regs)
set_fs(fs);
len = current->mm->arg_end - current->mm->arg_start;
- len = len >= ELF_PRARGSZ ? ELF_PRARGSZ : len;
+ if (len >= ELF_PRARGSZ)
+ len = ELF_PRARGSZ-1;
copy_from_user(&psinfo.pr_psargs,
(const char *)current->mm->arg_start, len);
for(i = 0; i < len; i++)
@@ -1243,7 +1263,7 @@ static int elf_core_dump(long signr, struct pt_regs * regs)
}
/* Page-align dumped data */
- dataoff = offset = roundup(offset, PAGE_SIZE);
+ dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE);
/* Write program headers for segments dump */
for(vma = current->mm->mmap, i = 0;
@@ -1265,7 +1285,7 @@ static int elf_core_dump(long signr, struct pt_regs * regs)
phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0;
if (vma->vm_flags & VM_WRITE) phdr.p_flags |= PF_W;
if (vma->vm_flags & VM_EXEC) phdr.p_flags |= PF_X;
- phdr.p_align = PAGE_SIZE;
+ phdr.p_align = ELF_EXEC_PAGESIZE;
DUMP_WRITE(&phdr, sizeof(phdr));
}
diff --git a/fs/buffer.c b/fs/buffer.c
index 27950290a..0b35d6e00 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -591,8 +591,9 @@ void set_blocksize(kdev_t dev, int size)
continue;
if (bh->b_size == size)
continue;
-
+ bhnext->b_count++;
wait_on_buffer(bh);
+ bhnext->b_count--;
if (bh->b_dev == dev && bh->b_size != size) {
clear_bit(BH_Dirty, &bh->b_state);
clear_bit(BH_Uptodate, &bh->b_state);
@@ -612,8 +613,7 @@ static inline int can_reclaim(struct buffer_head *bh, int size)
buffer_locked(bh))
return 0;
- if (atomic_read(&mem_map[MAP_NR((unsigned long) bh->b_data)].count) != 1 ||
- buffer_dirty(bh)) {
+ if (buffer_dirty(bh)) {
refile_buffer(bh);
return 0;
}
@@ -644,8 +644,7 @@ static struct buffer_head *find_candidate(struct buffer_head *list,
continue;
}
- if (buffer_locked(bh) &&
- (bh->b_list == BUF_LOCKED || bh->b_list == BUF_LOCKED1)) {
+ if (buffer_locked(bh) && bh->b_list == BUF_LOCKED) {
/* Buffers are written in the order they are placed
* on the locked list. If we encounter a locked
* buffer here, this means that the rest of them
@@ -845,9 +844,6 @@ void refile_buffer(struct buffer_head * buf)
if(dispose != buf->b_list) {
if(dispose == BUF_DIRTY)
buf->b_lru_time = jiffies;
- if(dispose == BUF_LOCKED &&
- (buf->b_flushtime - buf->b_lru_time) <= bdf_prm.b_un.age_super)
- dispose = BUF_LOCKED1;
remove_from_queues(buf);
buf->b_list = dispose;
insert_into_queues(buf);
@@ -1120,11 +1116,11 @@ no_grow:
/* Run the hooks that have to be done when a page I/O has completed. */
static inline void after_unlock_page (struct page * page)
{
- if (clear_bit(PG_decr_after, &page->flags))
+ if (test_and_clear_bit(PG_decr_after, &page->flags))
atomic_dec(&nr_async_pages);
- if (clear_bit(PG_free_after, &page->flags))
+ if (test_and_clear_bit(PG_free_after, &page->flags))
__free_page(page);
- if (clear_bit(PG_swap_unlock_after, &page->flags))
+ if (test_and_clear_bit(PG_swap_unlock_after, &page->flags))
swap_after_unlock_page(page->swap_unlock_entry);
}
@@ -1467,7 +1463,7 @@ int try_to_free_buffer(struct buffer_head * bh, struct buffer_head ** bhp,
buffermem -= PAGE_SIZE;
mem_map[MAP_NR(page)].buffers = NULL;
free_page(page);
- return !atomic_read(&mem_map[MAP_NR(page)].count);
+ return 1;
}
/* ================== Debugging =================== */
@@ -1478,7 +1474,7 @@ void show_buffers(void)
int found = 0, locked = 0, dirty = 0, used = 0, lastused = 0;
int protected = 0;
int nlist;
- static char *buf_types[NR_LIST] = {"CLEAN","LOCKED","LOCKED1","DIRTY"};
+ static char *buf_types[NR_LIST] = {"CLEAN","LOCKED","DIRTY"};
printk("Buffer memory: %6dkB\n",buffermem>>10);
printk("Buffer heads: %6d\n",nr_buffer_heads);
@@ -1526,7 +1522,7 @@ void buffer_init(void)
bh_cachep = kmem_cache_create("buffer_head",
sizeof(struct buffer_head),
- sizeof(unsigned long) * 4,
+ 0,
SLAB_HWCACHE_ALIGN, NULL, NULL);
if(!bh_cachep)
panic("Cannot create buffer head SLAB cache\n");
@@ -1611,6 +1607,7 @@ asmlinkage int sync_old_buffers(void)
ndirty++;
if(bh->b_flushtime > jiffies) continue;
nwritten++;
+ next->b_count++;
bh->b_count++;
bh->b_flushtime = 0;
#ifdef DEBUG
@@ -1618,6 +1615,7 @@ asmlinkage int sync_old_buffers(void)
#endif
ll_rw_block(WRITE, 1, &bh);
bh->b_count--;
+ next->b_count--;
}
}
#ifdef DEBUG
@@ -1756,6 +1754,7 @@ int bdflush(void * unused)
currently dirty buffers are not shared, so it does not matter */
if (refilled && major == LOOP_MAJOR)
continue;
+ next->b_count++;
bh->b_count++;
ndirty++;
bh->b_flushtime = 0;
@@ -1771,6 +1770,7 @@ int bdflush(void * unused)
if(nlist != BUF_DIRTY) ncount++;
#endif
bh->b_count--;
+ next->b_count--;
}
}
#ifdef DEBUG
diff --git a/fs/dcache.c b/fs/dcache.c
index 2dc317aad..f6ab04693 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -153,17 +153,24 @@ static inline void add_hash(struct dir_cache_entry * de, struct dir_cache_entry
/*
* Find a directory cache entry given all the necessary info.
*/
-static inline struct dir_cache_entry * find_entry(struct inode * dir, const char * name, int len, struct dir_cache_entry ** hash)
+static inline struct dir_cache_entry * find_entry(struct inode * dir, const char * name, unsigned char len, struct dir_cache_entry ** hash)
{
struct dir_cache_entry *de;
- for(de = *hash; de; de = de->next)
+ de = *hash;
+ goto inside;
+ for (;;) {
+ de = de->next;
+inside:
+ if (!de)
+ break;
if((de->name_len == (unsigned char) len) &&
(de->dc_dev == dir->i_dev) &&
(de->dir == dir->i_ino) &&
(de->version == dir->i_version) &&
(!memcmp(de->name, name, len)))
break;
+ }
return de;
}
@@ -195,7 +202,7 @@ int dcache_lookup(struct inode * dir, const char * name, int len, unsigned long
struct dir_cache_entry *de;
spin_lock(&dcache_lock);
- de = find_entry(dir, name, len, hash);
+ de = find_entry(dir, name, (unsigned char) len, hash);
if(de) {
*ino = de->ino;
move_to_level2(de, hash);
@@ -213,7 +220,7 @@ void dcache_add(struct inode * dir, const char * name, int len, unsigned long in
struct dir_cache_entry *de;
spin_lock(&dcache_lock);
- de = find_entry(dir, name, len, hash);
+ de = find_entry(dir, name, (unsigned char) len, hash);
if (de) {
de->ino = ino;
update_lru(de);
diff --git a/fs/dquot.c b/fs/dquot.c
index 5236ed38e..dda3f642a 100644
--- a/fs/dquot.c
+++ b/fs/dquot.c
@@ -33,6 +33,7 @@
#include <linux/fcntl.h>
#include <linux/stat.h>
#include <linux/tty.h>
+#include <linux/file.h>
#include <linux/malloc.h>
#include <linux/mount.h>
#include <linux/smp.h>
@@ -989,7 +990,7 @@ int quota_on(kdev_t dev, short type, char *path)
}
} else
error = -EIO;
- filp->f_count--;
+ put_filp(filp);
} else
error = -EMFILE;
iput(inode);
diff --git a/fs/exec.c b/fs/exec.c
index 9817bd67d..3a3bfb1bc 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -27,6 +27,7 @@
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/slab.h>
+#include <linux/file.h>
#include <linux/mman.h>
#include <linux/a.out.h>
#include <linux/errno.h>
@@ -36,7 +37,6 @@
#include <linux/fcntl.h>
#include <linux/ptrace.h>
#include <linux/user.h>
-#include <linux/malloc.h>
#include <linux/binfmts.h>
#include <linux/personality.h>
#include <linux/smp.h>
@@ -152,7 +152,7 @@ int open_inode(struct inode * inode, int mode)
if (f->f_op->open) {
int error = f->f_op->open(inode,f);
if (error) {
- f->f_count--;
+ put_filp(f);
put_unused_fd(fd);
return error;
}
@@ -388,7 +388,7 @@ static void exec_mmap(void)
* (the oom is wrong there, too, IMHO)
*/
if (current->mm->count > 1) {
- struct mm_struct *mm = kmalloc(sizeof(*mm), GFP_KERNEL);
+ struct mm_struct *mm = kmem_cache_alloc(mm_cachep, SLAB_KERNEL);
if (!mm) {
/* this is wrong, I think. */
oom(current);
@@ -397,9 +397,9 @@ static void exec_mmap(void)
*mm = *current->mm;
init_new_context(mm);
mm->def_flags = 0; /* should future lockings be kept? */
+ mm->cpu_vm_mask = (1 << smp_processor_id());
mm->count = 1;
- mm->mmap = NULL;
- mm->mmap_avl = NULL;
+ mm->mmap = mm->mmap_cache = NULL;
mm->total_vm = 0;
mm->rss = 0;
current->mm->count--;
diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c
index 61b5b1a39..171de1cf5 100644
--- a/fs/ext2/balloc.c
+++ b/fs/ext2/balloc.c
@@ -177,6 +177,7 @@ void ext2_free_blocks (const struct inode * inode, unsigned long block,
unsigned long bit;
unsigned long i;
int bitmap_nr;
+ unsigned long overflow;
struct super_block * sb;
struct ext2_group_desc * gdp;
struct ext2_super_block * es;
@@ -199,14 +200,20 @@ void ext2_free_blocks (const struct inode * inode, unsigned long block,
ext2_debug ("freeing block %lu\n", block);
+do_more:
+ overflow = 0;
block_group = (block - le32_to_cpu(es->s_first_data_block)) /
EXT2_BLOCKS_PER_GROUP(sb);
- bit = (block - le32_to_cpu(es->s_first_data_block)) % EXT2_BLOCKS_PER_GROUP(sb);
- if (bit + count > EXT2_BLOCKS_PER_GROUP(sb))
- ext2_panic (sb, "ext2_free_blocks",
- "Freeing blocks across group boundary - "
- "Block = %lu, count = %lu",
- block, count);
+ bit = (block - le32_to_cpu(es->s_first_data_block)) %
+ EXT2_BLOCKS_PER_GROUP(sb);
+ /*
+ * Check to see if we are freeing blocks across a group
+ * boundary.
+ */
+ if (bit + count > EXT2_BLOCKS_PER_GROUP(sb)) {
+ overflow = bit + count - EXT2_BLOCKS_PER_GROUP(sb);
+ count -= overflow;
+ }
bitmap_nr = load_block_bitmap (sb, block_group);
bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr];
gdp = get_group_desc (sb, block_group, &bh2);
@@ -246,6 +253,11 @@ void ext2_free_blocks (const struct inode * inode, unsigned long block,
ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh);
}
+ if (overflow) {
+ block += count;
+ count = overflow;
+ goto do_more;
+ }
sb->s_dirt = 1;
unlock_super (sb);
return;
@@ -546,6 +558,19 @@ static inline int block_in_use (unsigned long block,
EXT2_BLOCKS_PER_GROUP(sb), map);
}
+static int test_root(int a, int b)
+{
+ if (a == 0)
+ return 1;
+ while (1) {
+ if (a == 1)
+ return 1;
+ if (a % b)
+ return 0;
+ a = a / b;
+ }
+}
+
void ext2_check_blocks_bitmap (struct super_block * sb)
{
struct buffer_head * bh;
@@ -569,15 +594,21 @@ void ext2_check_blocks_bitmap (struct super_block * sb)
bitmap_nr = load_block_bitmap (sb, i);
bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr];
- if (!ext2_test_bit (0, bh->b_data))
- ext2_error (sb, "ext2_check_blocks_bitmap",
- "Superblock in group %d is marked free", i);
-
- for (j = 0; j < desc_blocks; j++)
- if (!ext2_test_bit (j + 1, bh->b_data))
+ if (!(sb->u.ext2_sb.s_feature_ro_compat &
+ EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER) ||
+ (test_root(i, 3) || test_root(i, 5) || test_root(i, 7))) {
+ if (!ext2_test_bit (0, bh->b_data))
ext2_error (sb, "ext2_check_blocks_bitmap",
+ "Superblock in group %d "
+ "is marked free", i);
+
+ for (j = 0; j < desc_blocks; j++)
+ if (!ext2_test_bit (j + 1, bh->b_data))
+ ext2_error (sb,
+ "ext2_check_blocks_bitmap",
"Descriptor block #%d in group "
"%d is marked free", j, i);
+ }
if (!block_in_use (le32_to_cpu(gdp->bg_block_bitmap), sb, bh->b_data))
ext2_error (sb, "ext2_check_blocks_bitmap",
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index 5a876261e..f2dbff2d1 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -503,12 +503,23 @@ void ext2_read_inode (struct inode * inode)
inode->i_op = &blkdev_inode_operations;
else if (S_ISFIFO(inode->i_mode))
init_fifo(inode);
- if (inode->u.ext2_i.i_flags & EXT2_SYNC_FL)
+ inode->i_attr_flags = 0;
+ if (inode->u.ext2_i.i_flags & EXT2_SYNC_FL) {
+ inode->i_attr_flags |= ATTR_FLAG_SYNCRONOUS;
inode->i_flags |= MS_SYNCHRONOUS;
- if (inode->u.ext2_i.i_flags & EXT2_APPEND_FL)
+ }
+ if (inode->u.ext2_i.i_flags & EXT2_APPEND_FL) {
+ inode->i_attr_flags |= ATTR_FLAG_APPEND;
inode->i_flags |= S_APPEND;
- if (inode->u.ext2_i.i_flags & EXT2_IMMUTABLE_FL)
+ }
+ if (inode->u.ext2_i.i_flags & EXT2_IMMUTABLE_FL) {
+ inode->i_attr_flags |= ATTR_FLAG_IMMUTABLE;
inode->i_flags |= S_IMMUTABLE;
+ }
+ if (inode->u.ext2_i.i_flags & EXT2_NOATIME_FL) {
+ inode->i_attr_flags |= ATTR_FLAG_NOATIME;
+ inode->i_flags |= MS_NOATIME;
+ }
}
static int ext2_update_inode(struct inode * inode, int do_sync)
@@ -597,11 +608,71 @@ static int ext2_update_inode(struct inode * inode, int do_sync)
void ext2_write_inode (struct inode * inode)
{
+#if 0
+ printk("ext2_write(%04x:%06d)...", inode->i_dev, inode->i_ino);
+#endif
ext2_update_inode (inode, 0);
}
int ext2_sync_inode (struct inode *inode)
{
+#if 0
+ printk("ext2_sync(%04x:%06d)...", inode->i_dev, inode->i_ino);
+#endif
return ext2_update_inode (inode, 1);
}
+int ext2_notify_change(struct inode *inode, struct iattr *iattr)
+{
+ int retval;
+ unsigned int flags;
+
+ if ((iattr->ia_attr_flags &
+ (ATTR_FLAG_APPEND | ATTR_FLAG_IMMUTABLE)) ^
+ (inode->u.ext2_i.i_flags &
+ (EXT2_APPEND_FL | EXT2_IMMUTABLE_FL))) {
+ if (!fsuser() || securelevel > 0)
+ return -EPERM;
+ } else
+ if ((current->fsuid != inode->i_uid) && !fsuser())
+ return -EPERM;
+
+ if ((retval = inode_change_ok(inode, iattr)) != 0)
+ return retval;
+
+ inode_setattr(inode, iattr);
+
+ flags = iattr->ia_attr_flags;
+ if (flags & ATTR_FLAG_SYNCRONOUS) {
+ inode->i_flags |= MS_SYNCHRONOUS;
+ inode->u.ext2_i.i_flags = EXT2_SYNC_FL;
+ } else {
+ inode->i_flags &= ~MS_SYNCHRONOUS;
+ inode->u.ext2_i.i_flags &= ~EXT2_SYNC_FL;
+ }
+ if (flags & ATTR_FLAG_NOATIME) {
+ inode->i_flags |= MS_NOATIME;
+ inode->u.ext2_i.i_flags = EXT2_NOATIME_FL;
+ } else {
+ inode->i_flags &= ~MS_NOATIME;
+ inode->u.ext2_i.i_flags &= ~EXT2_NOATIME_FL;
+ }
+ if (flags & ATTR_FLAG_APPEND) {
+ inode->i_flags |= S_APPEND;
+ inode->u.ext2_i.i_flags = EXT2_APPEND_FL;
+ } else {
+ inode->i_flags &= ~S_APPEND;
+ inode->u.ext2_i.i_flags &= ~EXT2_APPEND_FL;
+ }
+ if (flags & ATTR_FLAG_IMMUTABLE) {
+ inode->i_flags |= S_IMMUTABLE;
+ inode->u.ext2_i.i_flags = EXT2_IMMUTABLE_FL;
+ } else {
+ inode->i_flags &= ~S_IMMUTABLE;
+ inode->u.ext2_i.i_flags &= ~EXT2_IMMUTABLE_FL;
+ }
+ inode->i_dirt = 1;
+
+ return 0;
+}
+
diff --git a/fs/ext2/ioctl.c b/fs/ext2/ioctl.c
index 0892ce79f..387600bbf 100644
--- a/fs/ext2/ioctl.c
+++ b/fs/ext2/ioctl.c
@@ -45,6 +45,10 @@ int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
if (IS_RDONLY(inode))
return -EROFS;
inode->u.ext2_i.i_flags = flags;
+ if (flags & EXT2_SYNC_FL)
+ inode->i_flags |= MS_SYNCHRONOUS;
+ else
+ inode->i_flags &= ~MS_SYNCHRONOUS;
if (flags & EXT2_APPEND_FL)
inode->i_flags |= S_APPEND;
else
@@ -53,6 +57,10 @@ int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
inode->i_flags |= S_IMMUTABLE;
else
inode->i_flags &= ~S_IMMUTABLE;
+ if (flags & EXT2_NOATIME_FL)
+ inode->i_flags |= MS_NOATIME;
+ else
+ inode->i_flags &= ~MS_NOATIME;
inode->i_ctime = CURRENT_TIME;
inode->i_dirt = 1;
return 0;
diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c
index e48fc8706..39716678a 100644
--- a/fs/ext2/namei.c
+++ b/fs/ext2/namei.c
@@ -583,7 +583,7 @@ static int empty_dir (struct inode * inode)
offset = le16_to_cpu(de->rec_len) + le16_to_cpu(de1->rec_len);
de = (struct ext2_dir_entry *) ((char *) de1 + le16_to_cpu(de1->rec_len));
while (offset < inode->i_size ) {
- if ((void *) de >= (void *) (bh->b_data + sb->s_blocksize)) {
+ if (!bh || (void *) de >= (void *) (bh->b_data + sb->s_blocksize)) {
brelse (bh);
bh = ext2_bread (inode, offset >> EXT2_BLOCK_SIZE_BITS(sb), 1, &err);
if (!bh) {
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index 26e18852e..5885e3067 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -508,6 +508,9 @@ struct super_block * ext2_read_super (struct super_block * sb, void * data,
goto failed_mount;
}
}
+ sb->u.ext2_sb.s_feature_compat = es->s_feature_compat;
+ sb->u.ext2_sb.s_feature_incompat = es->s_feature_incompat;
+ sb->u.ext2_sb.s_feature_ro_compat = es->s_feature_ro_compat;
sb->u.ext2_sb.s_frag_size = EXT2_MIN_FRAG_SIZE <<
(__s32) le32_to_cpu(es->s_log_frag_size);
if (sb->u.ext2_sb.s_frag_size)
diff --git a/fs/fcntl.c b/fs/fcntl.c
index bedc02e89..6418a5d83 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -163,6 +163,7 @@ asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
if (current->pgrp == -arg || current->pid == arg)
goto fasync_ok;
+ read_lock(&tasklist_lock);
for_each_task(p) {
if ((p->pid == arg) || (p->pid == -arg) ||
(p->pgrp == -arg)) {
@@ -171,11 +172,14 @@ asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
if ((p->session != current->session) &&
(p->uid != current->uid) &&
(p->euid != current->euid) &&
- !suser())
+ !suser()) {
+ read_unlock(&tasklist_lock);
goto out;
+ }
break;
}
}
+ read_unlock(&tasklist_lock);
err = -EINVAL;
if ((task_found == 0) && !suser())
break;
diff --git a/fs/file_table.c b/fs/file_table.c
index 17a670f59..b8c8d4155 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -2,143 +2,104 @@
* linux/fs/file_table.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
*/
#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
#include <linux/fs.h>
+#include <linux/file.h>
#include <linux/string.h>
#include <linux/mm.h>
+#include <linux/slab.h>
-/*
- * first_file points to a doubly linked list of all file structures in
- * the system.
- * nr_files holds the length of this list.
- */
-struct file * first_file = NULL;
+/* SLAB cache for filp's. */
+static kmem_cache_t *filp_cache;
+
+/* sysctl tunables... */
int nr_files = 0;
int max_files = NR_FILE;
-/*
- * Insert a new file structure at the head of the list of available ones.
- */
-static inline void insert_file_free(struct file *file)
-{
- struct file *next, *prev;
-
- next = first_file;
- first_file = file;
- file->f_count = 0;
- prev = next->f_prev;
- file->f_next = next;
- next->f_prev = file;
- file->f_prev = prev;
- prev->f_next = file;
-}
+/* Free list management, if you are here you must have f_count == 0 */
+static struct file * free_filps = NULL;
-/*
- * Remove a file structure from the list of available ones.
- */
-static inline void remove_file_free(struct file *file)
+void insert_file_free(struct file *file)
{
- struct file *next, *prev;
-
- next = file->f_next;
- prev = file->f_prev;
- file->f_next = file->f_prev = NULL;
- if (first_file == file)
- first_file = next;
- next->f_prev = prev;
- prev->f_next = next;
+ if((file->f_next = free_filps) != NULL)
+ free_filps->f_pprev = &file->f_next;
+ free_filps = file;
+ file->f_pprev = &free_filps;
}
-/*
- * Insert a file structure at the end of the list of available ones.
- */
-static inline void put_last_free(struct file *file)
+/* The list of in-use filp's must be exported (ugh...) */
+struct file *inuse_filps = NULL;
+
+static inline void put_inuse(struct file *file)
{
- struct file *next, *prev;
-
- next = first_file;
- file->f_next = next;
- prev = next->f_prev;
- next->f_prev = file;
- file->f_prev = prev;
- prev->f_next = file;
+ if((file->f_next = inuse_filps) != NULL)
+ inuse_filps->f_pprev = &file->f_next;
+ inuse_filps = file;
+ file->f_pprev = &inuse_filps;
}
-/*
- * Allocate a new memory page for file structures and
- * insert the new structures into the global list.
- * Returns 0, if there is no more memory, 1 otherwise.
- */
+/* Get more free filp's. */
static int grow_files(void)
{
- struct file * file;
- int i;
-
- /*
- * We don't have to clear the page because we only look into
- * f_count, f_prev and f_next and they get initialized in
- * insert_file_free. The rest of the file structure is cleared
- * by get_empty_filp before it is returned.
- */
- file = (struct file *) __get_free_page(GFP_KERNEL);
-
- if (!file)
- return 0;
-
- nr_files += i = PAGE_SIZE/sizeof(struct file);
-
- if (!first_file)
- file->f_count = 0,
- file->f_next = file->f_prev = first_file = file++,
- i--;
-
- for (; i ; i--)
- insert_file_free(file++);
+ int i = 16;
+
+ while(i--) {
+ struct file * file = kmem_cache_alloc(filp_cache, SLAB_KERNEL);
+ if(!file) {
+ if(i == 15)
+ return 0;
+ goto got_some;
+ }
+ insert_file_free(file);
+ nr_files++;
+ }
+got_some:
return 1;
}
-unsigned long file_table_init(unsigned long start, unsigned long end)
+void file_table_init(void)
{
- return start;
+ filp_cache = kmem_cache_create("filp", sizeof(struct file),
+ 0,
+ SLAB_HWCACHE_ALIGN, NULL, NULL);
+ if(!filp_cache)
+ panic("VFS: Cannot alloc filp SLAB cache.");
}
-/*
- * Find an unused file structure and return a pointer to it.
+/* Find an unused file structure and return a pointer to it.
* Returns NULL, if there are no more free file structures or
* we run out of memory.
*/
struct file * get_empty_filp(void)
{
- int i;
- int max = max_files;
struct file * f;
- /*
- * Reserve a few files for the super-user..
- */
- if (current->euid)
- max -= 10;
-
- /* if the return is taken, we are in deep trouble */
- if (!first_file && !grow_files())
- return NULL;
-
- do {
- for (f = first_file, i=0; i < nr_files; i++, f = f->f_next)
- if (!f->f_count) {
- remove_file_free(f);
- memset(f,0,sizeof(*f));
- put_last_free(f);
- f->f_count = 1;
- f->f_version = ++event;
- return f;
- }
- } while (nr_files < max && grow_files());
-
- return NULL;
+again:
+ if((f = free_filps) != NULL) {
+ remove_filp(f);
+ memset(f, 0, sizeof(*f));
+ f->f_count = 1;
+ f->f_version = ++event;
+ put_inuse(f);
+ } else {
+ int max = max_files;
+
+ /* Reserve a few files for the super-user.. */
+ if (current->euid)
+ max -= 10;
+
+ if (nr_files < max && grow_files())
+ goto again;
+
+ /* Big problems... */
+ }
+ return f;
}
#ifdef CONFIG_QUOTA
@@ -146,10 +107,9 @@ struct file * get_empty_filp(void)
void add_dquot_ref(kdev_t dev, short type)
{
struct file *filp;
- int cnt;
- for (filp = first_file, cnt = 0; cnt < nr_files; cnt++, filp = filp->f_next) {
- if (!filp->f_count || !filp->f_inode || filp->f_inode->i_dev != dev)
+ for (filp = inuse_filps; filp; filp = filp->f_next) {
+ if (!filp->f_inode || filp->f_inode->i_dev != dev)
continue;
if (filp->f_mode & FMODE_WRITE && filp->f_inode->i_sb->dq_op) {
filp->f_inode->i_sb->dq_op->initialize(filp->f_inode, type);
@@ -161,10 +121,9 @@ void add_dquot_ref(kdev_t dev, short type)
void reset_dquot_ptrs(kdev_t dev, short type)
{
struct file *filp;
- int cnt;
- for (filp = first_file, cnt = 0; cnt < nr_files; cnt++, filp = filp->f_next) {
- if (!filp->f_count || !filp->f_inode || filp->f_inode->i_dev != dev)
+ for (filp = inuse_filps; filp; filp = filp->f_next) {
+ if (!filp->f_inode || filp->f_inode->i_dev != dev)
continue;
if (IS_WRITABLE(filp->f_inode)) {
filp->f_inode->i_dquot[type] = NODQUOT;
diff --git a/fs/inode.c b/fs/inode.c
index b1d9bda4e..307b76063 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -232,12 +232,10 @@ repeat:
int fs_may_remount_ro(kdev_t dev)
{
struct file * file;
- int i;
/* Check that no files are currently opened for writing. */
- for (file = first_file, i=0; i<nr_files; i++, file=file->f_next) {
- if (!file->f_count || !file->f_inode ||
- file->f_inode->i_dev != dev)
+ for (file = inuse_filps; file; file = file->f_next) {
+ if (!file->f_inode || file->f_inode->i_dev != dev)
continue;
if (S_ISREG(file->f_inode->i_mode) && (file->f_mode & 2))
return 0;
@@ -288,7 +286,7 @@ int inode_change_ok(struct inode *inode, struct iattr *attr)
((attr->ia_valid & ATTR_GID) &&
(!in_group_p(attr->ia_gid) &&
- (attr->ia_gid != inode->i_gid))) ||
+ (attr->ia_gid != inode->i_gid)) && not_fsuser) ||
((attr->ia_valid & (ATTR_ATIME_SET | ATTR_MTIME_SET)) &&
(fsuid != iuid) && not_fsuser))
@@ -325,6 +323,8 @@ void inode_setattr(struct inode *inode, struct iattr *attr)
if (!fsuser() && !in_group_p(inode->i_gid))
inode->i_mode &= ~S_ISGID;
}
+ if (attr->ia_valid & ATTR_ATTR_FLAG)
+ inode->i_attr_flags = attr->ia_attr_flags;
inode->i_dirt = 1;
}
@@ -647,7 +647,7 @@ void inode_init(void)
int i;
inode_cachep = kmem_cache_create("inode", sizeof(struct inode),
- sizeof(unsigned long) * 4,
+ 0,
SLAB_HWCACHE_ALIGN, NULL, NULL);
if(!inode_cachep)
panic("Cannot create inode SLAB cache\n");
diff --git a/fs/isofs/dir.c b/fs/isofs/dir.c
index 7a4943ede..30d0bf4c4 100644
--- a/fs/isofs/dir.c
+++ b/fs/isofs/dir.c
@@ -121,6 +121,11 @@ static int do_isofs_readdir(struct inode *inode, struct file *filp,
char *name;
struct iso_directory_record *de;
+ if( filp->f_pos >= inode->i_size ) {
+ return 0;
+
+ }
+
offset = filp->f_pos & (bufsize - 1);
block = isofs_bmap(inode, filp->f_pos >> bufbits);
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c
index 8d9ce9d96..708198a00 100644
--- a/fs/isofs/inode.c
+++ b/fs/isofs/inode.c
@@ -138,13 +138,7 @@ static int parse_options(char *options, struct iso9660_options * popt)
!strcmp(this_char,"uid") ||
!strcmp(this_char,"gid"))) {
char * vpnt = value;
- unsigned int ivalue;
- ivalue = 0;
- while(*vpnt){
- if(*vpnt < '0' || *vpnt > '9') break;
- ivalue = ivalue * 10 + (*vpnt - '0');
- vpnt++;
- }
+ unsigned int ivalue = simple_strtoul(vpnt, &vpnt, 0);
if (*vpnt) return 0;
switch(*this_char) {
case 'b':
diff --git a/fs/isofs/namei.c b/fs/isofs/namei.c
index 71f816b47..06ccfde5c 100644
--- a/fs/isofs/namei.c
+++ b/fs/isofs/namei.c
@@ -65,7 +65,6 @@ static struct buffer_head * isofs_find_entry(struct inode * dir,
unsigned char bufbits = ISOFS_BUFFER_BITS(dir);
unsigned int block, i, f_pos, offset, inode_number;
struct buffer_head * bh;
- void * cpnt = NULL;
unsigned int old_offset;
unsigned int backlink;
int dlen, rrflag, match;
@@ -117,21 +116,8 @@ static struct buffer_head * isofs_find_entry(struct inode * dir,
/* Handle case where the directory entry spans two blocks.
Usually 1024 byte boundaries */
if (offset >= bufsize) {
- unsigned int frag1;
- frag1 = bufsize - old_offset;
- cpnt = kmalloc(*((unsigned char *) de),GFP_KERNEL);
- if (!cpnt) return 0;
- memcpy(cpnt, bh->b_data + old_offset, frag1);
-
- de = (struct iso_directory_record *) cpnt;
- brelse(bh);
- offset = f_pos & (bufsize - 1);
- block = isofs_bmap(dir,f_pos>>bufbits);
- if (!block || !(bh = bread(dir->i_dev,block,bufsize))) {
- kfree(cpnt);
- return 0;
- };
- memcpy((char *)cpnt+frag1, bh->b_data, offset);
+ printk("Directory entry extends past end of iso9660 block\n");
+ return 0;
}
/* Handle the '.' case */
@@ -190,12 +176,6 @@ static struct buffer_head * isofs_find_entry(struct inode * dir,
match = isofs_match(namelen,name,dpnt,dlen);
}
- if (cpnt)
- {
- kfree(cpnt);
- cpnt = NULL;
- }
-
if(rrflag) kfree(dpnt);
if (match) {
if(inode_number == -1) {
@@ -217,8 +197,6 @@ static struct buffer_head * isofs_find_entry(struct inode * dir,
}
}
out:
- if (cpnt)
- kfree(cpnt);
brelse(bh);
return NULL;
}
diff --git a/fs/isofs/rock.c b/fs/isofs/rock.c
index 6f4539045..a9bb95f52 100644
--- a/fs/isofs/rock.c
+++ b/fs/isofs/rock.c
@@ -60,21 +60,6 @@
block = cont_extent; \
offset = cont_offset; \
offset1 = 0; \
- if(ISOFS_BUFFER_SIZE(DEV) == 1024) { \
- block <<= 1; \
- if (offset >= 1024) block++; \
- offset &= 1023; \
- if(offset + cont_size >= 1024) { \
- bh = bread(DEV->i_dev, block++, ISOFS_BUFFER_SIZE(DEV)); \
- if(!bh) {printk("Unable to read continuation Rock Ridge record\n"); \
- kfree(buffer); \
- buffer = NULL; } else { \
- memcpy(buffer, bh->b_data + offset, 1024 - offset); \
- brelse(bh); \
- offset1 = 1024 - offset; \
- offset = 0;} \
- } \
- }; \
if(buffer) { \
bh = bread(DEV->i_dev, block, ISOFS_BUFFER_SIZE(DEV)); \
if(bh){ \
@@ -429,7 +414,6 @@ char * get_rock_ridge_symlink(struct inode * inode)
unsigned char bufbits = ISOFS_BUFFER_BITS(inode);
struct buffer_head * bh;
unsigned char * pnt;
- void * cpnt = NULL;
char * rpnt;
struct iso_directory_record * raw_inode;
CONTINUE_DECLS;
@@ -455,24 +439,12 @@ char * get_rock_ridge_symlink(struct inode * inode)
raw_inode = ((struct iso_directory_record *) pnt);
+ /*
+ * If we go past the end of the buffer, there is some sort of error.
+ */
if ((inode->i_ino & (bufsize - 1)) + *pnt > bufsize){
- int frag1, offset;
-
- offset = (inode->i_ino & (bufsize - 1));
- frag1 = bufsize - offset;
- cpnt = kmalloc(*pnt,GFP_KERNEL);
- if(!cpnt) return NULL;
- memcpy(cpnt, bh->b_data + offset, frag1);
- brelse(bh);
- if (!(bh = bread(inode->i_dev,++block, bufsize))) {
- kfree(cpnt);
- printk("unable to read i-node block");
- return NULL;
- };
- offset += *pnt - bufsize;
- memcpy((char *)cpnt+frag1, bh->b_data, offset);
- pnt = ((unsigned char *) cpnt);
- raw_inode = ((struct iso_directory_record *) pnt);
+ printk("symlink spans iso9660 blocks\n");
+ return NULL;
};
/* Now test for possible Rock Ridge extensions which will override some of
@@ -558,11 +530,6 @@ char * get_rock_ridge_symlink(struct inode * inode)
MAYBE_CONTINUE(repeat,inode);
brelse(bh);
- if (cpnt) {
- kfree(cpnt);
- cpnt = NULL;
- };
-
return rpnt;
out:
if(buffer) kfree(buffer);
diff --git a/fs/lockd/.cvsignore b/fs/lockd/.cvsignore
new file mode 100644
index 000000000..4671378ae
--- /dev/null
+++ b/fs/lockd/.cvsignore
@@ -0,0 +1 @@
+.depend
diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c
index 24093a615..afc3fb2f0 100644
--- a/fs/lockd/svcsubs.c
+++ b/fs/lockd/svcsubs.c
@@ -228,12 +228,12 @@ nlm_release_file(struct nlm_file *file)
down(&nlm_file_sema);
/* If there are no more locks etc, delete the file */
- if (--(file->f_count) == 0
- && !nlm_inspect_file(NULL, file, NLM_ACT_CHECK))
- nlm_delete_file(file);
+ if(--file->f_count == 0) {
+ if(!nlm_inspect_file(NULL, file, NLM_ACT_CHECK))
+ nlm_delete_file(file);
+ }
up(&nlm_file_sema);
- return;
}
/*
diff --git a/fs/locks.c b/fs/locks.c
index 3aa530897..8ca8aa183 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -100,6 +100,9 @@
*
* Some adaptations for NFS support.
* Olaf Kirch (okir@monad.swb.de), Dec 1996,
+ *
+ * Fixed /proc/locks interface so that we can't overrun the buffer we are handed.
+ * Andy Walker (andy@lysaker.kvaerner.no), May 12, 1997.
*/
#include <linux/malloc.h>
@@ -132,7 +135,7 @@ static int posix_locks_deadlock(struct file_lock *caller,
static struct file_lock *locks_alloc_lock(struct file_lock *fl);
static void locks_insert_lock(struct file_lock **pos, struct file_lock *fl);
static void locks_delete_lock(struct file_lock **thisfl_p, unsigned int wait);
-static char *lock_get_status(struct file_lock *fl, char *p, int id, char *pfx);
+static char *lock_get_status(struct file_lock *fl, int id, char *pfx);
static void locks_insert_block(struct file_lock *blocker, struct file_lock *waiter);
static void locks_delete_block(struct file_lock *blocker, struct file_lock *waiter);
@@ -227,6 +230,7 @@ void
posix_block_lock(struct file_lock *blocker, struct file_lock *waiter)
{
locks_insert_block(blocker, waiter);
+ return;
}
void
@@ -234,6 +238,7 @@ posix_unblock_lock(struct file_lock *waiter)
{
if (waiter->fl_prevblock)
locks_delete_block(waiter->fl_prevblock, waiter);
+ return;
}
/* Wake up processes blocked waiting for blocker.
@@ -269,20 +274,20 @@ asmlinkage int sys_flock(unsigned int fd, unsigned int cmd)
{
struct file_lock file_lock;
struct file *filp;
- int err;
+ int error;
lock_kernel();
if ((fd >= NR_OPEN) || !(filp = current->files->fd[fd]))
- err = -EBADF;
+ error = -EBADF;
else if (!flock_make_lock(filp, &file_lock, cmd))
- err = -EINVAL;
+ error = -EINVAL;
else if ((file_lock.fl_type != F_UNLCK) && !(filp->f_mode & 3))
- err = -EBADF;
+ error = -EBADF;
else
- err = flock_lock_file(filp, &file_lock,
- (cmd & (LOCK_UN | LOCK_NB)) ? 0 : 1);
+ error = flock_lock_file(filp, &file_lock,
+ (cmd & (LOCK_UN | LOCK_NB)) ? 0 : 1);
unlock_kernel();
- return err;
+ return (error);
}
/* Report the first existing lock that would conflict with l.
@@ -298,7 +303,7 @@ int fcntl_getlk(unsigned int fd, struct flock *l)
if ((fd >= NR_OPEN) || !(filp = current->files->fd[fd]))
return (-EBADF);
if (copy_from_user(&flock, l, sizeof(flock)))
- return -EFAULT;
+ return (-EFAULT);
if ((flock.l_type != F_RDLCK) && (flock.l_type != F_WRLCK))
return (-EINVAL);
@@ -308,9 +313,9 @@ int fcntl_getlk(unsigned int fd, struct flock *l)
if (filp->f_op->lock) {
error = filp->f_op->lock(filp->f_inode, filp,
- F_GETLK, &file_lock);
+ F_GETLK, &file_lock);
if (error < 0)
- return error;
+ return (error);
fl = &file_lock;
} else {
fl = posix_test_lock(filp, &file_lock);
@@ -323,12 +328,12 @@ int fcntl_getlk(unsigned int fd, struct flock *l)
fl->fl_end - fl->fl_start + 1;
flock.l_whence = 0;
flock.l_type = fl->fl_type;
- return copy_to_user(l, &flock, sizeof(flock)) ? -EFAULT : 0;
+ return (copy_to_user(l, &flock, sizeof(flock)) ? -EFAULT : 0);
} else {
flock.l_type = F_UNLCK;
}
- return copy_to_user(l, &flock, sizeof(flock)) ? -EFAULT : 0;
+ return (copy_to_user(l, &flock, sizeof(flock)) ? -EFAULT : 0);
}
/* Apply the lock described by l to an open file descriptor.
@@ -361,12 +366,11 @@ int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l)
do {
if (vma->vm_flags & VM_MAYSHARE)
return (-EAGAIN);
- vma = vma->vm_next_share;
- } while (vma != inode->i_mmap);
+ } while ((vma = vma->vm_next_share) != NULL);
}
if (copy_from_user(&flock, l, sizeof(flock)))
- return -EFAULT;
+ return (-EFAULT);
if (!posix_make_lock(filp, &file_lock, &flock))
return (-EINVAL);
@@ -399,13 +403,13 @@ int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l)
break;
#endif
default:
- return -EINVAL;
+ return (-EINVAL);
}
if (filp->f_op->lock != NULL) {
error = filp->f_op->lock(filp->f_inode, filp, cmd, &file_lock);
if (error < 0)
- return error;
+ return (error);
}
return (posix_lock_file(filp, &file_lock, cmd == F_SETLKW));
@@ -457,7 +461,7 @@ posix_test_lock(struct file *filp, struct file_lock *fl)
break;
}
- return cfl;
+ return (cfl);
}
int locks_verify_locked(struct inode *inode)
@@ -1044,16 +1048,18 @@ static void locks_delete_lock(struct file_lock **thisfl_p, unsigned int wait)
}
-static char *lock_get_status(struct file_lock *fl, char *p, int id, char *pfx)
+static char *lock_get_status(struct file_lock *fl, int id, char *pfx)
{
+ static char temp[129];
+ char *p = temp;
struct inode *inode;
inode = fl->fl_file->f_inode;
p += sprintf(p, "%d:%s ", id, pfx);
if (fl->fl_flags & FL_POSIX) {
- p += sprintf(p, "%s %s ",
- (fl->fl_flags & FL_ACCESS) ? "ACCESS" : "POSIX",
+ p += sprintf(p, "%6s %s ",
+ (fl->fl_flags & FL_ACCESS) ? "ACCESS" : "POSIX ",
(IS_MANDLOCK(inode) &&
(inode->i_mode & (S_IXGRP | S_ISGID)) == S_ISGID) ?
"MANDATORY" : "ADVISORY ");
@@ -1066,28 +1072,68 @@ static char *lock_get_status(struct file_lock *fl, char *p, int id, char *pfx)
fl->fl_pid,
kdevname(inode->i_dev), inode->i_ino, fl->fl_start,
fl->fl_end);
- p += sprintf(p, "%08lx %08lx %08lx %08lx %08lx\n",
- (long)fl, (long)fl->fl_prevlink, (long)fl->fl_nextlink,
- (long)fl->fl_next, (long)fl->fl_nextblock);
- return (p);
+ sprintf(p, "%08lx %08lx %08lx %08lx %08lx\n",
+ (long)fl, (long)fl->fl_prevlink, (long)fl->fl_nextlink,
+ (long)fl->fl_next, (long)fl->fl_nextblock);
+ return (temp);
}
-int get_locks_status(char *buf)
+static inline int copy_lock_status(char *p, char **q, off_t pos, int len,
+ off_t offset, int length)
+{
+ int i;
+
+ i = pos - offset;
+ if (i > 0) {
+ if (i >= length) {
+ i = len + length - i;
+ memcpy(*q, p, i);
+ *q += i;
+ return (0);
+ }
+ if (i < len) {
+ p += len - i;
+ }
+ else
+ i = len;
+ memcpy(*q, p, i);
+ *q += i;
+ }
+
+ return (1);
+}
+
+int get_locks_status(char *buffer, char **start, off_t offset, int length)
{
struct file_lock *fl;
struct file_lock *bfl;
char *p;
+ char *q = buffer;
int i;
+ int len;
+ off_t pos = 0;
- p = buf;
for (fl = file_lock_table, i = 1; fl != NULL; fl = fl->fl_nextlink, i++) {
- p = lock_get_status(fl, p, i, "");
+ p = lock_get_status(fl, i, "");
+ len = strlen(p);
+ pos += len;
+ if (!copy_lock_status(p, &q, pos, len, offset, length))
+ goto done;
if ((bfl = fl->fl_nextblock) == NULL)
continue;
do {
- p = lock_get_status(bfl, p, i, " ->");
+ p = lock_get_status(bfl, i, " ->");
+ len = strlen(p);
+ pos += len;
+ if (!copy_lock_status(p, &q, pos, len, offset, length))
+ goto done;
} while ((bfl = bfl->fl_nextblock) != fl);
}
- return (p - buf);
+done:
+ if (q != buffer)
+ *start = buffer;
+ return (q - buffer);
}
+
+
diff --git a/fs/msdos/msdosfs_syms.c b/fs/msdos/msdosfs_syms.c
index 914a178a9..9e2c26bd6 100644
--- a/fs/msdos/msdosfs_syms.c
+++ b/fs/msdos/msdosfs_syms.c
@@ -30,7 +30,7 @@ EXPORT_SYMBOL(msdos_read_super);
EXPORT_SYMBOL(msdos_put_super);
-static struct file_system_type msdos_fs_type = {
+struct file_system_type msdos_fs_type = {
msdos_read_super, "msdos", 1, NULL
};
diff --git a/fs/namei.c b/fs/namei.c
index aeaca8f45..35ebbd4f4 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -124,24 +124,16 @@ int permission(struct inode * inode,int mask)
* put_write_access() releases this write permission.
* This is used for regular files.
* We cannot support write (and maybe mmap read-write shared) accesses and
- * MAP_DENYWRITE mmappings simultaneously.
+ * MAP_DENYWRITE mmappings simultaneously. The i_writecount field of an inode
+ * can have the following values:
+ * 0: no writers, no VM_DENYWRITE mappings
+ * < 0: (-i_writecount) vm_area_structs with VM_DENYWRITE set exist
+ * > 0: (i_writecount) users are writing to the file.
*/
int get_write_access(struct inode * inode)
{
- struct task_struct * p;
-
- if ((inode->i_count > 1) && S_ISREG(inode->i_mode)) /* shortcut */
- for_each_task(p) {
- struct vm_area_struct * mpnt;
- if (!p->mm)
- continue;
- for(mpnt = p->mm->mmap; mpnt; mpnt = mpnt->vm_next) {
- if (inode != mpnt->vm_inode)
- continue;
- if (mpnt->vm_flags & VM_DENYWRITE)
- return -ETXTBSY;
- }
- }
+ if (inode->i_writecount < 0)
+ return -ETXTBSY;
inode->i_writecount++;
return 0;
}
diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c
index 1db0dcc78..4cf65f8a9 100644
--- a/fs/ncpfs/inode.c
+++ b/fs/ncpfs/inode.c
@@ -21,6 +21,7 @@
#include <linux/stat.h>
#include <linux/errno.h>
#include <linux/locks.h>
+#include <linux/file.h>
#include <linux/fcntl.h>
#include <linux/malloc.h>
#include <linux/init.h>
@@ -177,7 +178,7 @@ struct super_block *
printk("ncp_read_super: could not alloc ncp_server\n");
return NULL;
}
- ncp_filp->f_count += 1;
+ ncp_filp->f_count++;
lock_super(sb);
@@ -256,7 +257,7 @@ struct super_block *
ncp_unlock_server(server);
ncp_kfree_s(server->packet, server->packet_size);
fail:
- ncp_filp->f_count -= 1;
+ put_filp(ncp_filp);
ncp_kfree_s(NCP_SBP(sb), sizeof(struct ncp_server));
return NULL;
}
diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c
index 732874d7f..d68dca70d 100644
--- a/fs/nfs/nfsroot.c
+++ b/fs/nfs/nfsroot.c
@@ -228,6 +228,8 @@ root_dev_chg_route(int op, struct device *dev, __u32 dest, __u32 mask, __u32 gw)
unsigned long oldfs;
int err;
+ memset(&route, 0, sizeof(struct rtentry)); /* or else! */
+
route.rt_dev = dev->name;
route.rt_mtu = dev->mtu;
route.rt_flags = RTF_UP;
@@ -247,9 +249,15 @@ root_dev_chg_route(int op, struct device *dev, __u32 dest, __u32 mask, __u32 gw)
set_fs(KERNEL_DS);
err = ip_rt_ioctl(op, &route);
set_fs(oldfs);
- printk(KERN_NOTICE "%s route %s %s %s: res %d\n",
- (op == SIOCADDRT? "add" : "del"),
- in_ntoa(dest), in_ntoa(mask), in_ntoa(gw), err);
+
+ /* in_ntoa in ipv4/utils.c uses a single static buffer, so
+ * must make multiple printk calls, one for each in_ntoa
+ * invocation...
+ */
+ printk(KERN_NOTICE "%s route ", (op == SIOCADDRT ? "addr" : "del"));
+ printk("%s ", in_ntoa(dest));
+ printk("%s ", in_ntoa(mask));
+ printk("%s: res %d\n", in_ntoa(gw), err);
return err;
}
@@ -280,8 +288,10 @@ static void root_dev_close(void)
nextp = openp->next;
openp->next = NULL;
if (openp->dev != root_dev) {
- if (!(openp->old_flags & IFF_UP))
+ if (!(openp->old_flags & IFF_UP)) {
dev_close(openp->dev);
+ }
+
openp->dev->flags = openp->old_flags;
}
kfree_s(openp, sizeof(struct open_dev));
@@ -1323,6 +1333,13 @@ static int root_nfs_setup(void)
root_dev->pa_brdaddr = root_dev->pa_addr | ~root_dev->pa_mask;
root_dev->pa_dstaddr = 0;
+ /* Sticky situation, but it has a solution. We opened it earlier,
+ * but before we knew what pa_addr etc. to give to it, thus the
+ * routing code did not add a RTF_LOCAL route for it (how could
+ * it?) so we send the pseudo device state change event now. -DaveM
+ */
+ ip_rt_event(NETDEV_CHANGE, root_dev);
+
/*
* Now add a route to the server. If there is no gateway given,
* the server is on the same subnet, so we establish only a route to
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index f48df4571..3c17b6eec 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -130,9 +130,9 @@ nfs_unlock_page(struct page *page)
#ifdef CONFIG_NFS_SWAP
/* async swap-out support */
- if (clear_bit(PG_decr_after, &page->flags))
+ if (test_and_clear_bit(PG_decr_after, &page->flags))
atomic_dec(&page->count);
- if (clear_bit(PG_swap_unlock_after, &page->flags))
+ if (test_and_clear_bit(PG_swap_unlock_after, &page->flags))
swap_after_unlock_page(page->swap_unlock_entry);
#endif
}
@@ -530,7 +530,7 @@ nfs_flush_request(struct nfs_wreq *req)
page->offset);
req->wb_flags |= NFS_WRITE_WANTLOCK;
- if (!set_bit(PG_locked, &page->flags)) {
+ if (!test_and_set_bit(PG_locked, &page->flags)) {
transfer_page_lock(req);
} else {
printk(KERN_WARNING "NFS oops in %s: can't lock page!\n",
@@ -719,7 +719,7 @@ nfs_wback_lock(struct rpc_task *task)
if (!WB_HAVELOCK(req))
req->wb_flags |= NFS_WRITE_WANTLOCK;
- if (WB_WANTLOCK(req) && set_bit(PG_locked, &page->flags)) {
+ if (WB_WANTLOCK(req) && test_and_set_bit(PG_locked, &page->flags)) {
dprintk("NFS: page already locked in writeback_lock!\n");
task->tk_timeout = 2 * HZ;
rpc_sleep_on(&write_queue, task, NULL, NULL);
diff --git a/fs/nfsd/.cvsignore b/fs/nfsd/.cvsignore
new file mode 100644
index 000000000..4671378ae
--- /dev/null
+++ b/fs/nfsd/.cvsignore
@@ -0,0 +1 @@
+.depend
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index ecec8a22b..6327cee48 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -285,6 +285,10 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
if (err) {
if (wflag)
put_write_access(inode);
+
+ /* I nearly added put_filp() call here, but this filp
+ * is really on callers stack frame. -DaveM
+ */
filp->f_count--;
return nfserrno(-err);
}
diff --git a/fs/open.c b/fs/open.c
index e81c5fbf5..a6a51799a 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -605,7 +605,7 @@ cleanup_all:
cleanup_inode:
iput(inode);
cleanup_file:
- f->f_count--;
+ put_filp(f);
return error;
}
diff --git a/fs/pipe.c b/fs/pipe.c
index 9cf3c7a6d..5fa5d6e91 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -11,6 +11,7 @@
#include <linux/fcntl.h>
#include <linux/termios.h>
#include <linux/mm.h>
+#include <linux/file.h>
#include <asm/poll.h>
#include <asm/uaccess.h>
@@ -74,7 +75,10 @@ static long pipe_read(struct inode * inode, struct file * filp,
PIPE_LOCK(*inode)--;
wake_up_interruptible(&PIPE_WAIT(*inode));
if (read) {
- inode->i_atime = CURRENT_TIME;
+ if (DO_UPDATE_ATIME(inode)) {
+ inode->i_atime = CURRENT_TIME;
+ inode->i_dirt = 1;
+ }
return read;
}
if (PIPE_WRITERS(*inode))
@@ -128,6 +132,7 @@ static long pipe_write(struct inode * inode, struct file * filp,
free = 1;
}
inode->i_ctime = inode->i_mtime = CURRENT_TIME;
+ inode->i_dirt = 1;
return written;
}
@@ -440,9 +445,9 @@ close_f12_inode:
inode->i_count--;
iput(inode);
close_f12:
- f2->f_count--;
+ put_filp(f2);
close_f1:
- f1->f_count--;
+ put_filp(f1);
no_files:
return error;
}
diff --git a/fs/proc/array.c b/fs/proc/array.c
index 4671f1a98..f8d5d3464 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -154,9 +154,7 @@ static long read_profile(struct inode *inode, struct file *file,
return read;
}
-#ifdef __SMP__
-extern int setup_profiling_timer (unsigned int multiplier);
/*
* Writing to /proc/profile resets the counters
@@ -168,6 +166,8 @@ static long write_profile(struct inode * inode, struct file * file,
const char * buf, unsigned long count)
{
int i=prof_len;
+#ifdef __SMP__
+ extern int setup_profiling_timer (unsigned int multiplier);
if (count==sizeof(int)) {
unsigned int multiplier;
@@ -178,14 +178,12 @@ static long write_profile(struct inode * inode, struct file * file,
if (setup_profiling_timer(multiplier))
return -EINVAL;
}
+#endif
while (i--)
prof_buffer[i]=0UL;
return count;
}
-#else
-#define write_profile NULL
-#endif
static struct file_operations proc_profile_operations = {
NULL, /* lseek */
@@ -270,7 +268,7 @@ static int get_uptime(char * buffer)
unsigned long idle;
uptime = jiffies;
- idle = task[0]->utime + task[0]->stime;
+ idle = task[0]->times.tms_utime + task[0]->times.tms_stime;
/* The formula for the fraction parts really is ((t * 100) / HZ) % 100, but
that would overflow about every five days at HZ == 100.
@@ -344,18 +342,6 @@ static int get_cmdline(char * buffer)
return sprintf(buffer, "%s\n", saved_command_line);
}
-static struct task_struct ** get_task(pid_t pid)
-{
- struct task_struct ** p;
-
- p = task;
- while (++p < task+NR_TASKS) {
- if (*p && (*p)->pid == pid)
- return p;
- }
- return NULL;
-}
-
static unsigned long get_phys_addr(struct task_struct * p, unsigned long ptr)
{
pgd_t *page_dir;
@@ -386,7 +372,7 @@ static unsigned long get_phys_addr(struct task_struct * p, unsigned long ptr)
return pte_page(pte) + (ptr & ~PAGE_MASK);
}
-static int get_array(struct task_struct ** p, unsigned long start, unsigned long end, char * buffer)
+static int get_array(struct task_struct *p, unsigned long start, unsigned long end, char * buffer)
{
unsigned long addr;
int size = 0, result = 0;
@@ -395,7 +381,7 @@ static int get_array(struct task_struct ** p, unsigned long start, unsigned long
if (start >= end)
return result;
for (;;) {
- addr = get_phys_addr(*p, start);
+ addr = get_phys_addr(p, start);
if (!addr)
return result;
do {
@@ -417,20 +403,20 @@ static int get_array(struct task_struct ** p, unsigned long start, unsigned long
static int get_env(int pid, char * buffer)
{
- struct task_struct ** p = get_task(pid);
+ struct task_struct *p = find_task_by_pid(pid);
- if (!p || !*p || !(*p)->mm)
+ if (!p || !p->mm)
return 0;
- return get_array(p, (*p)->mm->env_start, (*p)->mm->env_end, buffer);
+ return get_array(p, p->mm->env_start, p->mm->env_end, buffer);
}
static int get_arg(int pid, char * buffer)
{
- struct task_struct ** p = get_task(pid);
+ struct task_struct *p = find_task_by_pid(pid);
- if (!p || !*p || !(*p)->mm)
+ if (!p || !p->mm)
return 0;
- return get_array(p, (*p)->mm->arg_start, (*p)->mm->arg_end, buffer);
+ return get_array(p, p->mm->arg_start, p->mm->arg_end, buffer);
}
static unsigned long get_wchan(struct task_struct *p)
@@ -443,7 +429,7 @@ static unsigned long get_wchan(struct task_struct *p)
unsigned long stack_page;
int count = 0;
- stack_page = p->kernel_stack_page;
+ stack_page = 4096 + (unsigned long)p;
if (!stack_page)
return 0;
ebp = p->tss.ebp;
@@ -523,15 +509,16 @@ static unsigned long get_wchan(struct task_struct *p)
}
#if defined(__i386__)
-# define KSTK_EIP(tsk) (((unsigned long *)tsk->kernel_stack_page)[1019])
-# define KSTK_ESP(tsk) (((unsigned long *)tsk->kernel_stack_page)[1022])
+# define KSTK_EIP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)))[1019])
+# define KSTK_ESP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)))[1022])
#elif defined(__alpha__)
/*
* See arch/alpha/kernel/ptrace.c for details.
*/
# define PT_REG(reg) (PAGE_SIZE - sizeof(struct pt_regs) \
+ (long)&((struct pt_regs *)0)->reg)
-# define KSTK_EIP(tsk) (*(unsigned long *)(tsk->kernel_stack_page + PT_REG(pc)))
+# define KSTK_EIP(tsk) \
+ (*(unsigned long *)(PT_REG(pc) + PAGE_SIZE + (unsigned long)(tsk)))
# define KSTK_ESP(tsk) ((tsk) == current ? rdusp() : (tsk)->tss.usp)
#elif defined(__mc68000__)
#define KSTK_EIP(tsk) \
@@ -702,9 +689,9 @@ static inline char * task_sig(struct task_struct *p, char *buffer)
static int get_status(int pid, char * buffer)
{
char * orig = buffer;
- struct task_struct ** p = get_task(pid), *tsk;
+ struct task_struct *tsk = find_task_by_pid(pid);
- if (!p || (tsk = *p) == NULL)
+ if (!tsk)
return 0;
buffer = task_name(tsk, buffer);
buffer = task_state(tsk, buffer);
@@ -715,14 +702,14 @@ static int get_status(int pid, char * buffer)
static int get_stat(int pid, char * buffer)
{
- struct task_struct ** p = get_task(pid), *tsk;
+ struct task_struct *tsk = find_task_by_pid(pid);
unsigned long sigignore=0, sigcatch=0, wchan;
unsigned long vsize, eip, esp;
long priority, nice;
int i,tty_pgrp;
char state;
- if (!p || (tsk = *p) == NULL)
+ if (!tsk)
return 0;
if (tsk->state < 0 || tsk->state > 5)
state = '.';
@@ -735,10 +722,8 @@ static int get_stat(int pid, char * buffer)
vsize += vma->vm_end - vma->vm_start;
vma = vma->vm_next;
}
- if (tsk->kernel_stack_page) {
- eip = KSTK_EIP(tsk);
- esp = KSTK_ESP(tsk);
- }
+ eip = KSTK_EIP(tsk);
+ esp = KSTK_ESP(tsk);
}
wchan = get_wchan(tsk);
if (tsk->sig) {
@@ -784,10 +769,10 @@ static int get_stat(int pid, char * buffer)
tsk->cmin_flt,
tsk->maj_flt,
tsk->cmaj_flt,
- tsk->utime,
- tsk->stime,
- tsk->cutime,
- tsk->cstime,
+ tsk->times.tms_utime,
+ tsk->times.tms_stime,
+ tsk->times.tms_cutime,
+ tsk->times.tms_cstime,
priority,
nice,
tsk->timeout,
@@ -885,10 +870,10 @@ static void statm_pgd_range(pgd_t * pgd, unsigned long address, unsigned long en
static int get_statm(int pid, char * buffer)
{
- struct task_struct ** p = get_task(pid), *tsk;
+ struct task_struct *tsk = find_task_by_pid(pid);
int size=0, resident=0, share=0, trs=0, lrs=0, drs=0, dt=0;
- if (!p || (tsk = *p) == NULL)
+ if (!tsk)
return 0;
if (tsk->mm && tsk->mm != &init_mm) {
struct vm_area_struct * vma = tsk->mm->mmap;
@@ -953,17 +938,17 @@ static int get_statm(int pid, char * buffer)
static long read_maps (int pid, struct file * file,
char * buf, unsigned long count)
{
- struct task_struct ** p = get_task(pid);
+ struct task_struct *p = find_task_by_pid(pid);
char * destptr;
loff_t lineno;
int column;
struct vm_area_struct * map;
int i;
- if (!p || !*p)
+ if (!p)
return -EINVAL;
- if (!(*p)->mm || (*p)->mm == &init_mm || count == 0)
+ if (!p->mm || p->mm == &init_mm || count == 0)
return 0;
/* decode f_pos */
@@ -971,7 +956,7 @@ static long read_maps (int pid, struct file * file,
column = file->f_pos & (MAPS_LINE_LENGTH-1);
/* quickly go to line lineno */
- for (map = (*p)->mm->mmap, i = 0; map && (i < lineno); map = map->vm_next, i++)
+ for (map = p->mm->mmap, i = 0; map && (i < lineno); map = map->vm_next, i++)
continue;
destptr = buf;
@@ -1032,7 +1017,7 @@ static long read_maps (int pid, struct file * file,
/* By writing to user space, we might have slept.
* Stop the loop, to avoid a race condition.
*/
- if (*p != current)
+ if (p != current)
break;
}
@@ -1055,7 +1040,7 @@ extern int get_cpuinfo(char *);
extern int get_pci_list(char*);
extern int get_md_status (char *);
extern int get_rtc_status (char *);
-extern int get_locks_status (char *);
+extern int get_locks_status (char *, char **, off_t, int);
extern int get_swaparea_info (char *);
#ifdef __SMP_PROF__
extern int get_smp_prof_list(char *);
@@ -1142,7 +1127,7 @@ static long get_root_array(char * page, int type, char **start,
return get_rtc_status(page);
#endif
case PROC_LOCKS:
- return get_locks_status(page);
+ return get_locks_status(page, start, offset, length);
#ifdef CONFIG_ZORRO
case PROC_ZORRO:
return zorro_get_list(page);
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 28cd61f5f..7e9a65e08 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -52,17 +52,14 @@ static struct inode_operations proc_base_inode_operations = {
static void proc_pid_fill_inode(struct inode * inode)
{
- struct task_struct * p;
+ struct task_struct *p;
int pid = inode->i_ino >> 16;
int ino = inode->i_ino & 0xffff;
- for_each_task(p) {
- if (p->pid == pid) {
- if (p->dumpable || ino == PROC_PID_INO) {
- inode->i_uid = p->euid;
- inode->i_gid = p->gid;
- }
- return;
+ if ((p = find_task_by_pid(pid)) != NULL) {
+ if (p->dumpable || ino == PROC_PID_INO) {
+ inode->i_uid = p->euid;
+ inode->i_gid = p->gid;
}
}
}
diff --git a/fs/proc/fd.c b/fs/proc/fd.c
index e5e4fd9a8..fd262bc9d 100644
--- a/fs/proc/fd.c
+++ b/fs/proc/fd.c
@@ -58,7 +58,6 @@ static int proc_lookupfd(struct inode * dir, const char * name, int len,
unsigned int ino, pid, fd, c;
struct task_struct * p;
struct super_block * sb;
- int i;
*result = NULL;
ino = dir->i_ino;
@@ -100,10 +99,8 @@ static int proc_lookupfd(struct inode * dir, const char * name, int len,
break;
}
}
- for (i = 0 ; i < NR_TASKS ; i++)
- if ((p = task[i]) && p->pid == pid)
- break;
- if (!pid || i >= NR_TASKS)
+ p = find_task_by_pid(pid);
+ if (!pid || !p)
return -ENOENT;
/*
@@ -112,8 +109,11 @@ static int proc_lookupfd(struct inode * dir, const char * name, int len,
* is NULL
*/
- if (fd >= NR_OPEN || !p->files || !p->files->fd[fd] || !p->files->fd[fd]->f_inode)
- return -ENOENT;
+ if (fd >= NR_OPEN ||
+ !p->files ||
+ !p->files->fd[fd] ||
+ !p->files->fd[fd]->f_inode)
+ return -ENOENT;
ino = (pid << 16) + (PROC_PID_FD_DIR << 8) + fd;
@@ -128,8 +128,7 @@ static int proc_readfd(struct inode * inode, struct file * filp,
void * dirent, filldir_t filldir)
{
char buf[NUMBUF];
- int task_nr;
- struct task_struct * p;
+ struct task_struct * p, **tarrayp;
unsigned int fd, pid, ino;
unsigned long i,j;
@@ -149,13 +148,10 @@ static int proc_readfd(struct inode * inode, struct file * filp,
return 0;
}
- task_nr = 1;
- for (;;) {
- if ((p = task[task_nr]) && p->pid == pid)
- break;
- if (++task_nr >= NR_TASKS)
- return 0;
- }
+ p = find_task_by_pid(pid);
+ if(!p)
+ return 0;
+ tarrayp = p->tarray_ptr;
for (fd -= 2 ; fd < NR_OPEN; fd++, filp->f_pos++) {
if (!p->files)
@@ -176,7 +172,7 @@ static int proc_readfd(struct inode * inode, struct file * filp,
break;
/* filldir() might have slept, so we must re-validate "p" */
- if (p != task[task_nr] || p->pid != pid)
+ if (p != *tarrayp || p->pid != pid)
break;
}
return 0;
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index 0ff6a4f5c..943137bf4 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -81,7 +81,6 @@ static int parse_options(char *options,uid_t *uid,gid_t *gid)
struct inode * proc_get_inode(struct super_block * s, int ino, struct proc_dir_entry * de)
{
struct inode * inode = iget(s, ino);
- struct task_struct *p;
#ifdef CONFIG_SUN_OPENPROMFS_MODULE
if ((inode->i_ino >= PROC_OPENPROM_FIRST)
@@ -111,9 +110,14 @@ struct inode * proc_get_inode(struct super_block * s, int ino, struct proc_dir_e
* Fixup the root inode's nlink value
*/
if (inode->i_ino == PROC_ROOT_INO) {
- for_each_task(p)
- if (p && p->pid)
+ struct task_struct *p;
+
+ read_lock(&tasklist_lock);
+ for_each_task(p) {
+ if (p->pid)
inode->i_nlink++;
+ }
+ read_unlock(&tasklist_lock);
}
return inode;
}
@@ -155,7 +159,6 @@ void proc_read_inode(struct inode * inode)
{
unsigned long ino, pid;
struct task_struct * p;
- int i;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
inode->i_blocks = 0;
@@ -170,13 +173,8 @@ void proc_read_inode(struct inode * inode)
inode->i_nlink = 1;
inode->i_size = 0;
pid = ino >> 16;
- if (!pid)
- return;
- p = task[0];
- for (i = 0; i < NR_TASKS ; i++)
- if ((p = task[i]) && (p->pid == pid))
- break;
- if (!p || i >= NR_TASKS)
+
+ if (!pid || ((p = find_task_by_pid(pid)) == NULL))
return;
ino &= 0x0000ffff;
@@ -198,7 +196,6 @@ void proc_read_inode(struct inode * inode)
inode->i_mode |= S_IWUSR | S_IXUSR;
return;
}
- return;
}
void proc_write_inode(struct inode * inode)
diff --git a/fs/proc/link.c b/fs/proc/link.c
index bbaab7c41..d5c08eafd 100644
--- a/fs/proc/link.c
+++ b/fs/proc/link.c
@@ -68,7 +68,7 @@ static int proc_follow_link(struct inode * dir, struct inode * inode,
unsigned int pid, ino;
struct task_struct * p;
struct inode * new_inode;
- int i, error;
+ int error;
*res_inode = NULL;
if (dir)
@@ -82,10 +82,9 @@ static int proc_follow_link(struct inode * dir, struct inode * inode,
ino = inode->i_ino;
pid = ino >> 16;
ino &= 0x0000ffff;
- for (i = 0 ; i < NR_TASKS ; i++)
- if ((p = task[i]) && p->pid == pid)
- break;
- if (i >= NR_TASKS) {
+
+ p = find_task_by_pid(pid);
+ if (!p) {
iput(inode);
return -ENOENT;
}
diff --git a/fs/proc/mem.c b/fs/proc/mem.c
index ccd67566f..97acb5ee8 100644
--- a/fs/proc/mem.c
+++ b/fs/proc/mem.c
@@ -55,16 +55,10 @@ static struct task_struct * get_task(int pid)
struct task_struct * tsk = current;
if (pid != tsk->pid) {
- int i;
- tsk = NULL;
- for (i = 1 ; i < NR_TASKS ; i++)
- if (task[i] && task[i]->pid == pid) {
- tsk = task[i];
- break;
- }
- /*
- * allow accesses only under the same circumstances
- * that we would allow ptrace to work
+ tsk = find_task_by_pid(pid);
+
+ /* Allow accesses only under the same circumstances
+ * that we would allow ptrace to work.
*/
if (tsk) {
if (!(tsk->flags & PF_PTRACED)
@@ -291,10 +285,10 @@ int mem_mmap(struct inode * inode, struct file * file,
return -ENOMEM;
if (!pte_present(*src_table))
- do_no_page(tsk, src_vma, stmp, 1);
+ handle_mm_fault(tsk, src_vma, stmp, 1);
if ((vma->vm_flags & VM_WRITE) && !pte_write(*src_table))
- do_wp_page(tsk, src_vma, stmp, 1);
+ handle_mm_fault(tsk, src_vma, stmp, 1);
set_pte(src_table, pte_mkdirty(*src_table));
set_pte(dest_table, *src_table);
diff --git a/fs/proc/root.c b/fs/proc/root.c
index e5bb9d51b..11c27699a 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -683,16 +683,20 @@ static int proc_root_lookup(struct inode * dir,const char * name, int len,
struct inode ** result)
{
unsigned int pid, c;
- int i, ino, retval;
+ int ino, retval;
struct task_struct *p;
dir->i_count++;
if (dir->i_ino == PROC_ROOT_INO) { /* check for safety... */
dir->i_nlink = proc_root.nlink;
- for_each_task(p)
- if (p && p->pid)
+
+ read_lock(&tasklist_lock);
+ for_each_task(p) {
+ if (p->pid)
dir->i_nlink++;
+ }
+ read_unlock(&tasklist_lock);
}
retval = proc_lookup(dir, name, len, result);
@@ -716,10 +720,8 @@ static int proc_root_lookup(struct inode * dir,const char * name, int len,
break;
}
}
- for (i = 0 ; i < NR_TASKS ; i++)
- if (task[i] && task[i]->pid == pid)
- break;
- if (!pid || i >= NR_TASKS) {
+ p = find_task_by_pid(pid);
+ if (!pid || !p) {
iput(dir);
return -ENOENT;
}
@@ -796,34 +798,40 @@ int proc_readdir(struct inode * inode, struct file * filp,
static int proc_root_readdir(struct inode * inode, struct file * filp,
void * dirent, filldir_t filldir)
{
+ struct task_struct *p;
char buf[NUMBUF];
- unsigned int nr,pid;
- unsigned long i,j;
+ unsigned int nr = filp->f_pos;
- nr = filp->f_pos;
if (nr < FIRST_PROCESS_ENTRY) {
int error = proc_readdir(inode, filp, dirent, filldir);
if (error <= 0)
return error;
- filp->f_pos = nr = FIRST_PROCESS_ENTRY;
+ filp->f_pos = FIRST_PROCESS_ENTRY;
}
+ nr = FIRST_PROCESS_ENTRY;
- for (nr -= FIRST_PROCESS_ENTRY; nr < NR_TASKS; nr++, filp->f_pos++) {
- struct task_struct * p = task[nr];
+ read_lock(&tasklist_lock);
+ for_each_task(p) {
+ unsigned int pid;
- if (!p || !(pid = p->pid))
+ if(nr++ < filp->f_pos)
continue;
- j = NUMBUF;
- i = pid;
- do {
- j--;
- buf[j] = '0' + (i % 10);
- i /= 10;
- } while (i);
+ if((pid = p->pid) != 0) {
+ unsigned long j = NUMBUF, i = pid;
- if (filldir(dirent, buf+j, NUMBUF-j, filp->f_pos, (pid << 16) + PROC_PID_INO) < 0)
- break;
+ do {
+ j--;
+ buf[j] = '0' + (i % 10);
+ i /= 10;
+ } while (i);
+
+ if (filldir(dirent, buf+j, NUMBUF-j,
+ filp->f_pos, (pid << 16) + PROC_PID_INO) < 0)
+ break;
+ }
+ filp->f_pos++;
}
+ read_unlock(&tasklist_lock);
return 0;
}
diff --git a/fs/romfs/.cvsignore b/fs/romfs/.cvsignore
new file mode 100644
index 000000000..4671378ae
--- /dev/null
+++ b/fs/romfs/.cvsignore
@@ -0,0 +1 @@
+.depend
diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c
index 7ab7d15ff..1943045bb 100644
--- a/fs/smbfs/inode.c
+++ b/fs/smbfs/inode.c
@@ -17,6 +17,7 @@
#include <linux/stat.h>
#include <linux/errno.h>
#include <linux/locks.h>
+#include <linux/file.h>
#include <linux/fcntl.h>
#include <linux/malloc.h>
#include <linux/init.h>
@@ -242,7 +243,7 @@ smb_read_super(struct super_block *sb, void *raw_data, int silent)
printk("smb_read_super: could not alloc smb_sb_info\n");
return NULL;
}
- filp->f_count += 1;
+ filp->f_count++;
lock_super(sb);
@@ -319,7 +320,7 @@ smb_read_super(struct super_block *sb, void *raw_data, int silent)
smb_vfree(server->packet);
server->packet = NULL;
}
- filp->f_count -= 1;
+ put_filp(filp);
smb_dont_catch_keepalive(server);
smb_kfree_s(SMB_SBP(sb), sizeof(struct smb_sb_info));
return NULL;
diff --git a/fs/super.c b/fs/super.c
index 053c6321a..d24776cca 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -33,6 +33,7 @@
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/fd.h>
+#include <linux/init.h>
#include <asm/system.h>
#include <asm/uaccess.h>
@@ -552,7 +553,7 @@ kdev_t get_unnamed_dev(void)
int i;
for (i = 1; i < 256; i++) {
- if (!set_bit(i,unnamed_dev_in_use))
+ if (!test_and_set_bit(i,unnamed_dev_in_use))
return MKDEV(UNNAMED_MAJOR, i);
}
return 0;
@@ -562,7 +563,7 @@ void put_unnamed_dev(kdev_t dev)
{
if (!dev || MAJOR(dev) != UNNAMED_MAJOR)
return;
- if (clear_bit(MINOR(dev), unnamed_dev_in_use))
+ if (test_and_clear_bit(MINOR(dev), unnamed_dev_in_use))
return;
printk("VFS: put_unnamed_dev: freeing unused device %s\n",
kdevname(dev));
@@ -937,7 +938,11 @@ out:
return retval;
}
+#ifdef CONFIG_BLK_DEV_INITRD
static void do_mount_root(void)
+#else
+__initfunc(static void do_mount_root(void))
+#endif
{
struct file_system_type * fs_type;
struct super_block * sb;
@@ -1046,7 +1051,7 @@ static void do_mount_root(void)
}
-void mount_root(void)
+__initfunc(void mount_root(void))
{
memset(super_blocks, 0, sizeof(super_blocks));
do_mount_root();
diff --git a/fs/umsdos/namei.c b/fs/umsdos/namei.c
index 51cfb0809..c4c9e73ba 100644
--- a/fs/umsdos/namei.c
+++ b/fs/umsdos/namei.c
@@ -301,6 +301,9 @@ static void umsdos_ren_init(
,*(unsigned long *)current->kernel_stack_page \
,__LINE__); \
}
+
+#undef chkstk
+#define chkstk() do { } while (0)
/*
Rename a file (move) in the file system.
diff --git a/fs/vfat/namei.c b/fs/vfat/namei.c
index badb6c7e2..e3db004cc 100644
--- a/fs/vfat/namei.c
+++ b/fs/vfat/namei.c
@@ -174,10 +174,12 @@ check_stack(const char *fname, int lineno)
printk("------- vfat kstack ok in %s line %d: SL=%d\n",
fname, lineno, stack_level);
#endif
+#if 0
if (*(unsigned long *) current->kernel_stack_page != STACK_MAGIC) {
printk("******* vfat stack corruption detected in %s at line %d\n",
fname, lineno);
}
+#endif
}
static int debug = 0;
diff --git a/include/asm-alpha/atomic.h b/include/asm-alpha/atomic.h
index 2485cd781..16366d055 100644
--- a/include/asm-alpha/atomic.h
+++ b/include/asm-alpha/atomic.h
@@ -41,9 +41,9 @@ extern __inline__ void atomic_add(int i, atomic_t * v)
" addl %0,%2,%0\n"
" stl_c %0,%1\n"
" beq %0,2f\n"
- ".text 2\n"
+ ".section .text2,\"ax\"\n"
"2: br 1b\n"
- ".text"
+ ".previous"
:"=&r" (temp), "=m" (__atomic_fool_gcc(v))
:"Ir" (i), "m" (__atomic_fool_gcc(v)));
}
@@ -56,9 +56,9 @@ extern __inline__ void atomic_sub(int i, atomic_t * v)
" subl %0,%2,%0\n"
" stl_c %0,%1\n"
" beq %0,2f\n"
- ".text 2\n"
+ ".section .text2,\"ax\"\n"
"2: br 1b\n"
- ".text"
+ ".previous"
:"=&r" (temp), "=m" (__atomic_fool_gcc(v))
:"Ir" (i), "m" (__atomic_fool_gcc(v)));
}
@@ -75,9 +75,9 @@ extern __inline__ long atomic_add_return(int i, atomic_t * v)
" mov %0,%2\n"
" stl_c %0,%1\n"
" beq %0,2f\n"
- ".text 2\n"
+ ".section .text2,\"ax\"\n"
"2: br 1b\n"
- ".text"
+ ".previous"
:"=&r" (temp), "=m" (__atomic_fool_gcc(v)), "=&r" (result)
:"Ir" (i), "m" (__atomic_fool_gcc(v)));
return result;
@@ -92,9 +92,9 @@ extern __inline__ long atomic_sub_return(int i, atomic_t * v)
" mov %0,%2\n"
" stl_c %0,%1\n"
" beq %0,2f\n"
- ".text 2\n"
+ ".section .text2,\"ax\"\n"
"2: br 1b\n"
- ".text"
+ ".previous"
:"=&r" (temp), "=m" (__atomic_fool_gcc(v)), "=&r" (result)
:"Ir" (i), "m" (__atomic_fool_gcc(v)));
return result;
diff --git a/include/asm-alpha/bitops.h b/include/asm-alpha/bitops.h
index 2a6f33a64..bec44fe54 100644
--- a/include/asm-alpha/bitops.h
+++ b/include/asm-alpha/bitops.h
@@ -17,7 +17,7 @@
* bit 0 is the LSB of addr; bit 64 is the LSB of (addr+1).
*/
-extern __inline__ unsigned long set_bit(unsigned long nr, void * addr)
+extern __inline__ void set_bit(unsigned long nr, void * addr)
{
unsigned long oldbit;
unsigned long temp;
@@ -31,16 +31,75 @@ extern __inline__ unsigned long set_bit(unsigned long nr, void * addr)
" stl_c %0,%1\n"
" beq %0,3f\n"
"2:\n"
- ".text 2\n"
+ ".section .text2,\"ax\"\n"
"3: br 1b\n"
- ".text"
+ ".previous"
+ :"=&r" (temp), "=m" (*m), "=&r" (oldbit)
+ :"Ir" (1UL << (nr & 31)), "m" (*m));
+}
+
+extern __inline__ void clear_bit(unsigned long nr, void * addr)
+{
+ unsigned long oldbit;
+ unsigned long temp;
+ unsigned int * m = ((unsigned int *) addr) + (nr >> 5);
+
+ __asm__ __volatile__(
+ "1: ldl_l %0,%1\n"
+ " and %0,%3,%2\n\t"
+ " beq %2,2f\n\t"
+ " xor %0,%3,%0\n\t"
+ " stl_c %0,%1\n\t"
+ " beq %0,3f\n"
+ "2:\n"
+ ".section .text2,\"ax\"\n"
+ "3: br 1b\n"
+ ".previous"
+ :"=&r" (temp), "=m" (*m), "=&r" (oldbit)
+ :"Ir" (1UL << (nr & 31)), "m" (*m));
+}
+
+extern __inline__ void change_bit(unsigned long nr, void * addr)
+{
+ unsigned long temp;
+ unsigned int * m = ((unsigned int *) addr) + (nr >> 5);
+
+ __asm__ __volatile__(
+ "1: ldl_l %0,%1\n"
+ " xor %0,%2,%0\n\t"
+ " stl_c %0,%1\n\t"
+ " beq %0,3f\n"
+ ".section .text2,\"ax\"\n"
+ "3: br 1b\n"
+ ".previous"
+ :"=&r" (temp), "=m" (*m)
+ :"Ir" (1UL << (nr & 31)), "m" (*m));
+}
+
+extern __inline__ unsigned long test_and_set_bit(unsigned long nr, void * addr)
+{
+ unsigned long oldbit;
+ unsigned long temp;
+ unsigned int * m = ((unsigned int *) addr) + (nr >> 5);
+
+ __asm__ __volatile__(
+ "1: ldl_l %0,%1\n"
+ " and %0,%3,%2\n"
+ " bne %2,2f\n"
+ " xor %0,%3,%0\n"
+ " stl_c %0,%1\n"
+ " beq %0,3f\n"
+ "2:\n"
+ ".section .text2,\"ax\"\n"
+ "3: br 1b\n"
+ ".previous"
:"=&r" (temp), "=m" (*m), "=&r" (oldbit)
:"Ir" (1UL << (nr & 31)), "m" (*m));
return oldbit != 0;
}
-extern __inline__ unsigned long clear_bit(unsigned long nr, void * addr)
+extern __inline__ unsigned long test_and_clear_bit(unsigned long nr, void * addr)
{
unsigned long oldbit;
unsigned long temp;
@@ -54,16 +113,16 @@ extern __inline__ unsigned long clear_bit(unsigned long nr, void * addr)
" stl_c %0,%1\n\t"
" beq %0,3f\n"
"2:\n"
- ".text 2\n"
+ ".section .text2,\"ax\"\n"
"3: br 1b\n"
- ".text"
+ ".previous"
:"=&r" (temp), "=m" (*m), "=&r" (oldbit)
:"Ir" (1UL << (nr & 31)), "m" (*m));
return oldbit != 0;
}
-extern __inline__ unsigned long change_bit(unsigned long nr, void * addr)
+extern __inline__ unsigned long test_and_change_bit(unsigned long nr, void * addr)
{
unsigned long oldbit;
unsigned long temp;
@@ -75,9 +134,9 @@ extern __inline__ unsigned long change_bit(unsigned long nr, void * addr)
" xor %0,%3,%0\n\t"
" stl_c %0,%1\n\t"
" beq %0,3f\n"
- ".text 2\n"
+ ".section .text2,\"ax\"\n"
"3: br 1b\n"
- ".text"
+ ".previous"
:"=&r" (temp), "=m" (*m), "=&r" (oldbit)
:"Ir" (1UL << (nr & 31)), "m" (*m));
@@ -166,15 +225,15 @@ found_middle:
#ifdef __KERNEL__
-#define ext2_set_bit set_bit
-#define ext2_clear_bit clear_bit
+#define ext2_set_bit test_and_set_bit
+#define ext2_clear_bit test_and_clear_bit
#define ext2_test_bit test_bit
#define ext2_find_first_zero_bit find_first_zero_bit
#define ext2_find_next_zero_bit find_next_zero_bit
/* Bitmap functions for the minix filesystem. */
-#define minix_set_bit(nr,addr) set_bit(nr,addr)
-#define minix_clear_bit(nr,addr) clear_bit(nr,addr)
+#define minix_set_bit(nr,addr) test_and_set_bit(nr,addr)
+#define minix_clear_bit(nr,addr) test_and_clear_bit(nr,addr)
#define minix_test_bit(nr,addr) test_bit(nr,addr)
#define minix_find_first_zero_bit(addr,size) find_first_zero_bit(addr,size)
diff --git a/include/asm-alpha/current.h b/include/asm-alpha/current.h
index 56d12724b..8db6dd06e 100644
--- a/include/asm-alpha/current.h
+++ b/include/asm-alpha/current.h
@@ -1,12 +1,6 @@
#ifndef _ALPHA_CURRENT_H
#define _ALPHA_CURRENT_H
-/* Some architectures may want to do something "clever" here since
- * this is the most frequently accessed piece of data in the entire
- * kernel.
- */
-extern struct task_struct *current_set[NR_CPUS];
-
register struct task_struct *current __asm__("$8");
#endif /* !(_ALPHA_CURRENT_H) */
diff --git a/include/asm-alpha/io.h b/include/asm-alpha/io.h
index 3084c9f26..a81f5289e 100644
--- a/include/asm-alpha/io.h
+++ b/include/asm-alpha/io.h
@@ -39,7 +39,7 @@ extern struct hae {
extern inline void set_hae(unsigned long new_hae)
{
unsigned long ipl;
- swpipl(ipl,7);
+ ipl = swpipl(7);
hae.cache = new_hae;
*hae.reg = new_hae;
mb();
diff --git a/include/asm-alpha/keyboard.h b/include/asm-alpha/keyboard.h
index bd3eda91d..1edaa52bb 100644
--- a/include/asm-alpha/keyboard.h
+++ b/include/asm-alpha/keyboard.h
@@ -1,177 +1,63 @@
/*
- * CPU specific parts of the keyboard driver
+ * linux/include/asm-alpha/keyboard.h
*
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
+ * Created 3 Nov 1996 by Geert Uytterhoeven
*/
-#ifndef __ASM_ALPHA_KEYBOARD_H
-#define __ASM_ALPHA_KEYBOARD_H
+/*
+ * This file contains the alpha architecture specific keyboard definitions
+ */
+
+#ifndef _ALPHA_KEYBOARD_H
+#define _ALPHA_KEYBOARD_H
+
+#ifdef __KERNEL__
+
+#include <linux/ioport.h>
#include <asm/io.h>
-#define KEYBOARD_IRQ 1
+#define KEYBOARD_IRQ 1
+#define DISABLE_KBD_DURING_INTERRUPTS 0
#define KBD_REPORT_ERR
+#define KBD_REPORT_UNKN
+/* #define KBD_IS_FOCUS_9000 */
+
+extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
+extern int pckbd_getkeycode(unsigned int scancode);
+extern int pckbd_pretranslate(unsigned char scancode, char raw_mode);
+extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
+ char raw_mode);
+extern char pckbd_unexpected_up(unsigned char keycode);
+extern void pckbd_leds(unsigned char leds);
+extern void pckbd_init_hw(void);
+
+#define kbd_setkeycode pckbd_setkeycode
+#define kbd_getkeycode pckbd_getkeycode
+#define kbd_pretranslate pckbd_pretranslate
+#define kbd_translate pckbd_translate
+#define kbd_unexpected_up pckbd_unexpected_up
+#define kbd_leds pckbd_leds
+#define kbd_init_hw pckbd_init_hw
+
+#define INIT_KBD
-__initfunc(static int initialize_kbd(void));
+/*
+ * keyboard controller registers
+ */
+#define KBD_STATUS_REG (unsigned int) 0x64
+#define KBD_CNTL_REG (unsigned int) 0x64
+#define KBD_DATA_REG (unsigned int) 0x60
#define kbd_inb_p(port) inb_p(port)
#define kbd_inb(port) inb(port)
#define kbd_outb_p(data,port) outb_p(data,port)
#define kbd_outb(data,port) outb(data,port)
-static int
-kbd_wait_for_input(void)
-{
- int n;
- int status, data;
-
- n = TIMEOUT_CONST;
- do {
- status = kbd_inb(KBD_STATUS_REG);
- /*
- * Wait for input data to become available. This bit will
- * then be cleared by the following read of the DATA
- * register.
- */
-
- if (!(status & KBD_OBF))
- continue;
-
- data = kbd_inb(KBD_DATA_REG);
-
- /*
- * Check to see if a timeout error has occurred. This means
- * that transmission was started but did not complete in the
- * normal time cycle. PERR is set when a parity error occurred
- * in the last transmission.
- */
- if (status & (KBD_GTO | KBD_PERR)) {
- continue;
- }
- return (data & 0xff);
- } while (--n);
- return (-1); /* timed-out if fell through to here... */
-}
-
-static void
-kbd_write(int address, int data)
-{
- int status;
-
- do {
- status = kbd_inb(KBD_STATUS_REG); /* spin until input buffer empty*/
- } while (status & KBD_IBF);
- kbd_outb(data, address); /* write out the data*/
-}
-
-__initfunc(static int initialize_kbd(void))
-{
- unsigned long flags;
-
- save_flags(flags); cli();
-
- /* Flush any pending input. */
- while (kbd_wait_for_input() != -1)
- continue;
-
- /*
- * Test the keyboard interface.
- * This seems to be the only way to get it going.
- * If the test is successful a x55 is placed in the input buffer.
- */
- kbd_write(KBD_CNTL_REG, KBD_SELF_TEST);
- if (kbd_wait_for_input() != 0x55) {
- printk(KERN_WARNING "initialize_kbd: "
- "keyboard failed self test.\n");
- restore_flags(flags);
- return(-1);
- }
-
- /*
- * Perform a keyboard interface test. This causes the controller
- * to test the keyboard clock and data lines. The results of the
- * test are placed in the input buffer.
- */
- kbd_write(KBD_CNTL_REG, KBD_SELF_TEST2);
- if (kbd_wait_for_input() != 0x00) {
- printk(KERN_WARNING "initialize_kbd: "
- "keyboard failed self test 2.\n");
- restore_flags(flags);
- return(-1);
- }
-
- /* Enable the keyboard by allowing the keyboard clock to run. */
- kbd_write(KBD_CNTL_REG, KBD_CNTL_ENABLE);
-
- /*
- * Reset keyboard. If the read times out
- * then the assumption is that no keyboard is
- * plugged into the machine.
- * This defaults the keyboard to scan-code set 2.
- */
- kbd_write(KBD_DATA_REG, KBD_RESET);
- if (kbd_wait_for_input() != KBD_ACK) {
- printk(KERN_WARNING "initialize_kbd: "
- "reset kbd failed, no ACK.\n");
- restore_flags(flags);
- return(-1);
- }
-
- /*
- * Give the keyboard some time to breathe ...
- * ... or it fucks up the floppy controller, too. Wiered.
- */
- udelay(20);
-
- if (kbd_wait_for_input() != KBD_POR) {
- printk(KERN_WARNING "initialize_kbd: "
- "reset kbd failed, not POR.\n");
- restore_flags(flags);
- return(-1);
- }
-
- /*
- * now do a DEFAULTS_DISABLE always
- */
- kbd_write(KBD_DATA_REG, KBD_DISABLE);
- if (kbd_wait_for_input() != KBD_ACK) {
- printk(KERN_WARNING "initialize_kbd: "
- "disable kbd failed, no ACK.\n");
- restore_flags(flags);
- return(-1);
- }
-
- /*
- * Enable keyboard interrupt, operate in "sys" mode,
- * enable keyboard (by clearing the disable keyboard bit),
- * disable mouse, do conversion of keycodes.
- */
- kbd_write(KBD_CNTL_REG, KBD_WRITE_MODE);
- kbd_write(KBD_DATA_REG, KBD_EKI|KBD_SYS|KBD_DMS|KBD_KCC);
-
- /*
- * now ENABLE the keyboard to set it scanning...
- */
- kbd_write(KBD_DATA_REG, KBD_ENABLE);
- if (kbd_wait_for_input() != KBD_ACK) {
- printk(KERN_WARNING "initialize_kbd: "
- "keyboard enable failed.\n");
- restore_flags(flags);
- return(-1);
- }
-
- restore_flags(flags);
-
- return (1);
-}
-
-extern __inline__ void
-keyboard_setup()
+extern __inline__ void keyboard_setup()
{
request_region(0x60,16,"keyboard");
- initialize_kbd();
}
+#endif /* __KERNEL__ */
#endif /* __ASM_ALPHA_KEYBOARD_H */
diff --git a/include/asm-alpha/processor.h b/include/asm-alpha/processor.h
index fe0cc681c..93bc9e31a 100644
--- a/include/asm-alpha/processor.h
+++ b/include/asm-alpha/processor.h
@@ -49,7 +49,7 @@ struct thread_struct {
};
#define INIT_MMAP { &init_mm, 0xfffffc0000000000, 0xfffffc0010000000, \
- PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC }
+ PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap }
#define INIT_TSS { \
0, 0, 0, \
@@ -85,11 +85,13 @@ extern void start_thread(struct pt_regs *, unsigned long, unsigned long);
/* Free all resources held by a thread. */
extern void release_thread(struct task_struct *);
-/* Allocation and freeing of basic task resources. */
-#define alloc_task_struct() kmalloc(sizeof(struct task_struct), GFP_KERNEL)
-#define alloc_kernel_stack(p) __get_free_page(GFP_KERNEL)
-#define free_task_struct(p) kfree(p)
-#define free_kernel_stack(page) free_page((page))
+/* NOTE: The task struct and the stack go together! */
+#define alloc_task_struct() \
+ ((struct task_struct *) __get_free_pages(GFP_KERNEL,1,0))
+#define free_task_struct(p) free_pages((unsigned long)(p),1)
+
+#define init_task (init_task_union.task)
+#define init_stack (init_task_union.stack)
/*
* Return_address is a replacement for __builtin_return_address(count)
diff --git a/include/asm-alpha/semaphore.h b/include/asm-alpha/semaphore.h
index b94573f13..29cbb4a33 100644
--- a/include/asm-alpha/semaphore.h
+++ b/include/asm-alpha/semaphore.h
@@ -47,9 +47,9 @@ static inline int waking_non_zero(struct semaphore *sem)
" stl_c %0,%2\n"
" beq %0,3f\n"
"2:\n"
- ".text 2\n"
+ ".section .text2,\"ax\"\n"
"3: br 1b\n"
- ".text"
+ ".previous"
: "=r"(ret), "=r"(tmp), "=m"(__atomic_fool_gcc(&sem->waking))
: "0"(0));
diff --git a/include/asm-alpha/softirq.h b/include/asm-alpha/softirq.h
index fa8124c38..f267f6ceb 100644
--- a/include/asm-alpha/softirq.h
+++ b/include/asm-alpha/softirq.h
@@ -17,9 +17,9 @@ static inline void clear_active_bhs(unsigned long x)
" and %0,%2,%0\n"
" stq_c %0,%1\n"
" beq %0,2f\n"
- ".text 2\n"
+ ".section .text2,\"ax\"\n"
"2: br 1b\n"
- ".text"
+ ".previous"
:"=&r" (temp), "=m" (bh_active)
:"Ir" (x), "m" (bh_active));
}
diff --git a/include/asm-alpha/spinlock.h b/include/asm-alpha/spinlock.h
index 9e58e0e4d..a38477426 100644
--- a/include/asm-alpha/spinlock.h
+++ b/include/asm-alpha/spinlock.h
@@ -3,8 +3,9 @@
#ifndef __SMP__
-typedef struct { } spinlock_t;
-#define SPIN_LOCK_UNLOCKED { }
+/* gcc 2.7.2 can crash initializing an empty structure. */
+typedef struct { int dummy; } spinlock_t;
+#define SPIN_LOCK_UNLOCKED { 0 }
#define spin_lock_init(lock) do { } while(0)
#define spin_lock(lock) do { } while(0)
@@ -14,7 +15,7 @@ typedef struct { } spinlock_t;
#define spin_lock_irq(lock) setipl(7)
#define spin_unlock_irq(lock) setipl(0)
-#define spin_lock_irqsave(lock, flags) swpipl(flags,7)
+#define spin_lock_irqsave(lock, flags) do { (flags) = swpipl(7); } while (0)
#define spin_unlock_irqrestore(lock, flags) setipl(flags)
/*
@@ -27,8 +28,8 @@ typedef struct { } spinlock_t;
* irq-safe write-lock, but readers can get non-irqsafe
* read-locks.
*/
-typedef struct { } rwlock_t;
-#define RW_LOCK_UNLOCKED { }
+typedef struct { int dummy; } rwlock_t;
+#define RW_LOCK_UNLOCKED { 0 }
#define read_lock(lock) do { } while(0)
#define read_unlock(lock) do { } while(0)
@@ -39,10 +40,10 @@ typedef struct { } rwlock_t;
#define write_lock_irq(lock) cli()
#define write_unlock_irq(lock) sti()
-#define read_lock_irqsave(lock, flags) save_and_cli(flags)
-#define read_unlock_irqrestore(lock, flags) restore_flags(flags)
-#define write_lock_irqsave(lock, flags) save_and_cli(flags)
-#define write_unlock_irqrestore(lock, flags) restore_flags(flags)
+#define read_lock_irqsave(lock, flags) do { (flags) = swpipl(7); } while (0)
+#define read_unlock_irqrestore(lock, flags) setipl(flags)
+#define write_lock_irqsave(lock, flags) do { (flags) = swpipl(7); } while (0)
+#define write_unlock_irqrestore(lock, flags) setipl(flags)
#else
@@ -89,13 +90,13 @@ l1:
" stq_c %0,%1\n"
" beq %0,3f\n"
"4: mb\n"
- ".text 2\n"
+ ".section .text2,\"ax\"\n"
"2: ldq %0,%1\n"
" subq %2,1,%2\n"
"3: blt %2,4b\n"
" blbs %0,2b\n"
" br 1b\n"
- ".text"
+ ".previous"
: "=r" (tmp),
"=m" (__dummy_lock(lock)),
"=r" (stuck)
@@ -107,7 +108,7 @@ l1:
lock->previous = (unsigned long) &&l1;
}
-#define spin_trylock(lock) (!set_bit(0,(lock)))
+#define spin_trylock(lock) (!test_and_set_bit(0,(lock)))
#define spin_lock_irq(lock) \
do { __cli(); spin_lock(lock); } while (0)
@@ -116,7 +117,7 @@ l1:
do { spin_unlock(lock); __sti(); } while (0)
#define spin_lock_irqsave(lock, flags) \
- do { swpipl(flags,7); spin_lock(lock); } while (0)
+ do { flags = swpipl(7); spin_lock(lock); } while (0)
#define spin_unlock_irqrestore(lock, flags) \
do { spin_unlock(lock); setipl(flags); } while (0)
diff --git a/include/asm-alpha/system.h b/include/asm-alpha/system.h
index 782120686..cde066b66 100644
--- a/include/asm-alpha/system.h
+++ b/include/asm-alpha/system.h
@@ -56,63 +56,95 @@ extern void wrmces (unsigned long);
#define halt() __asm__ __volatile__ ("call_pal %0" : : "i" (PAL_halt) : "memory")
#define switch_to(prev,next) do { \
- current_set[0] = current = next; \
+ current = next; \
alpha_switch_to((unsigned long) &current->tss - 0xfffffc0000000000); \
} while (0)
extern void alpha_switch_to(unsigned long pctxp);
-extern void imb(void);
-
#define mb() \
__asm__ __volatile__("mb": : :"memory")
+#define imb() \
+__asm__ __volatile__ ("call_pal %0" : : "i" (PAL_imb) : "memory")
+
#define draina() \
__asm__ __volatile__ ("call_pal %0" : : "i" (PAL_draina) : "memory")
-#define getipl(__old_ipl) \
-__asm__ __volatile__( \
- "call_pal 54\n\t" \
- "bis $0,$0,%0" \
- : "=r" (__old_ipl) \
- : : "$0", "$1", "$16", "$22", "$23", "$24", "$25")
-
-#define setipl(__new_ipl) \
-__asm__ __volatile__( \
- "bis %0,%0,$16\n\t" \
- "call_pal 53" \
- : : "r" (__new_ipl) \
- : "$0", "$1", "$16", "$22", "$23", "$24", "$25", "memory")
-
-#define swpipl(__old_ipl,__new_ipl) \
-__asm__ __volatile__( \
- "bis %1,%1,$16\n\t" \
- "call_pal 53\n\t" \
- "bis $0,$0,%0" \
- : "=r" (__old_ipl) \
- : "r" (__new_ipl) \
- : "$0", "$1", "$16", "$22", "$23", "$24", "$25", "memory")
+#define call_pal1(palno,arg) \
+({ \
+ register unsigned long __r0 __asm__("$0"); \
+ register unsigned long __r16 __asm__("$16"); __r16 = arg; \
+ __asm__ __volatile__( \
+ "call_pal %3" \
+ :"=r" (__r0),"=r" (__r16) \
+ :"1" (__r16),"i" (palno) \
+ :"$1", "$22", "$23", "$24", "$25", "memory"); \
+ __r0; \
+})
+
+#define getipl() \
+({ \
+ register unsigned long r0 __asm__("$0"); \
+ __asm__ __volatile__( \
+ "call_pal %1" \
+ :"=r" (r0) \
+ :"i" (PAL_rdps) \
+ :"$1", "$16", "$22", "$23", "$24", "$25", "memory"); \
+ r0; \
+})
+
+#define setipl(ipl) \
+do { \
+ register unsigned long __r16 __asm__("$16") = (ipl); \
+ __asm__ __volatile__( \
+ "call_pal %2" \
+ :"=r" (__r16) \
+ :"0" (__r16),"i" (PAL_swpipl) \
+ :"$0", "$1", "$22", "$23", "$24", "$25", "memory"); \
+} while (0)
+
+#define swpipl(ipl) \
+({ \
+ register unsigned long __r0 __asm__("$0"); \
+ register unsigned long __r16 __asm__("$16") = (ipl); \
+ __asm__ __volatile__( \
+ "call_pal %3" \
+ :"=r" (__r0),"=r" (__r16) \
+ :"1" (__r16),"i" (PAL_swpipl) \
+ :"$1", "$22", "$23", "$24", "$25", "memory"); \
+ __r0; \
+})
#define __cli() setipl(7)
#define __sti() setipl(0)
-#define __save_flags(flags) getipl(flags)
+#define __save_flags(flags) do { (flags) = getipl(); } while (0)
#define __restore_flags(flags) setipl(flags)
#define cli() setipl(7)
#define sti() setipl(0)
-#define save_flags(flags) getipl(flags)
+#define save_flags(flags) do { (flags) = getipl(); } while (0)
#define restore_flags(flags) setipl(flags)
/*
* TB routines..
*/
-extern void tbi(long type, ...);
+#define __tbi(nr,arg,arg1...) do { \
+ register unsigned long __r16 __asm__("$16") = (nr); \
+ register unsigned long __r17 __asm__("$17"); arg; \
+ __asm__ __volatile__( \
+ "call_pal %3" \
+ :"=r" (__r16),"=r" (__r17) \
+ :"0" (__r16),"i" (PAL_tbi) ,##arg1 \
+ :"$0", "$1", "$22", "$23", "$24", "$25"); \
+} while (0)
-#define tbisi(x) tbi(1,(x))
-#define tbisd(x) tbi(2,(x))
-#define tbis(x) tbi(3,(x))
-#define tbiap() tbi(-1)
-#define tbia() tbi(-2)
+#define tbi(x,y) __tbi(x,__r17=(y),"1" (__r17))
+#define tbisi(x) __tbi(1,__r17=(x),"1" (__r17))
+#define tbisd(x) __tbi(2,__r17=(x),"1" (__r17))
+#define tbis(x) __tbi(3,__r17=(x),"1" (__r17))
+#define tbiap() __tbi(-1, /* no second argument */)
+#define tbia() __tbi(-2, /* no second argument */)
/*
* Give prototypes to shut up gcc.
@@ -129,9 +161,9 @@ extern __inline__ unsigned long xchg_u32(volatile int * m, unsigned long val)
" bis %3,%3,%1\n"
" stl_c %1,%2\n"
" beq %1,2f\n"
- ".text 2\n"
+ ".section .text2,\"ax\"\n"
"2: br 1b\n"
- ".text"
+ ".previous"
: "=&r" (val), "=&r" (dummy), "=m" (*m)
: "r" (val), "m" (*m));
@@ -147,9 +179,9 @@ extern __inline__ unsigned long xchg_u64(volatile long * m, unsigned long val)
" bis %3,%3,%1\n"
" stq_c %1,%2\n"
" beq %1,2f\n"
- ".text 2\n"
+ ".section .text2,\"ax\"\n"
"2: br 1b\n"
- ".text"
+ ".previous"
: "=&r" (val), "=&r" (dummy), "=m" (*m)
: "r" (val), "m" (*m));
diff --git a/include/asm-i386/bitops.h b/include/asm-i386/bitops.h
index 8e6d484e4..ee24aa79f 100644
--- a/include/asm-i386/bitops.h
+++ b/include/asm-i386/bitops.h
@@ -26,7 +26,31 @@ struct __dummy { unsigned long a[100]; };
#define ADDR (*(struct __dummy *) addr)
#define CONST_ADDR (*(const struct __dummy *) addr)
-extern __inline__ int set_bit(int nr, volatile void * addr)
+extern __inline__ void set_bit(int nr, volatile void * addr)
+{
+ __asm__ __volatile__( LOCK_PREFIX
+ "btsl %1,%0"
+ :"=m" (ADDR)
+ :"ir" (nr));
+}
+
+extern __inline__ void clear_bit(int nr, volatile void * addr)
+{
+ __asm__ __volatile__( LOCK_PREFIX
+ "btrl %1,%0"
+ :"=m" (ADDR)
+ :"ir" (nr));
+}
+
+extern __inline__ void change_bit(int nr, volatile void * addr)
+{
+ __asm__ __volatile__( LOCK_PREFIX
+ "btcl %1,%0"
+ :"=m" (ADDR)
+ :"ir" (nr));
+}
+
+extern __inline__ int test_and_set_bit(int nr, volatile void * addr)
{
int oldbit;
@@ -37,7 +61,7 @@ extern __inline__ int set_bit(int nr, volatile void * addr)
return oldbit;
}
-extern __inline__ int clear_bit(int nr, volatile void * addr)
+extern __inline__ int test_and_clear_bit(int nr, volatile void * addr)
{
int oldbit;
@@ -48,7 +72,7 @@ extern __inline__ int clear_bit(int nr, volatile void * addr)
return oldbit;
}
-extern __inline__ int change_bit(int nr, volatile void * addr)
+extern __inline__ int test_and_change_bit(int nr, volatile void * addr)
{
int oldbit;
@@ -150,15 +174,15 @@ extern __inline__ unsigned long ffz(unsigned long word)
#ifdef __KERNEL__
-#define ext2_set_bit set_bit
-#define ext2_clear_bit clear_bit
+#define ext2_set_bit test_and_set_bit
+#define ext2_clear_bit test_and_clear_bit
#define ext2_test_bit test_bit
#define ext2_find_first_zero_bit find_first_zero_bit
#define ext2_find_next_zero_bit find_next_zero_bit
/* Bitmap functions for the minix filesystem. */
-#define minix_set_bit(nr,addr) set_bit(nr,addr)
-#define minix_clear_bit(nr,addr) clear_bit(nr,addr)
+#define minix_set_bit(nr,addr) test_and_set_bit(nr,addr)
+#define minix_clear_bit(nr,addr) test_and_clear_bit(nr,addr)
#define minix_test_bit(nr,addr) test_bit(nr,addr)
#define minix_find_first_zero_bit(addr,size) find_first_zero_bit(addr,size)
diff --git a/include/asm-i386/current.h b/include/asm-i386/current.h
index 01ba3e9a0..976320d75 100644
--- a/include/asm-i386/current.h
+++ b/include/asm-i386/current.h
@@ -1,12 +1,14 @@
#ifndef _I386_CURRENT_H
#define _I386_CURRENT_H
-/* Some architectures may want to do something "clever" here since
- * this is the most frequently accessed piece of data in the entire
- * kernel. For an example, see the Sparc implementation where an
- * entire register is hard locked to contain the value of current.
- */
-extern struct task_struct *current_set[NR_CPUS];
-#define current (current_set[smp_processor_id()]) /* Current on this processor */
+static inline unsigned long get_esp(void)
+{
+ unsigned long esp;
+ __asm__("movl %%esp,%0":"=r" (esp));
+ return esp;
+}
+
+#define current ((struct task_struct *)(get_esp() & ~8191UL))
+
#endif /* !(_I386_CURRENT_H) */
diff --git a/include/asm-i386/delay.h b/include/asm-i386/delay.h
index e22e8d6b2..3435e4d1b 100644
--- a/include/asm-i386/delay.h
+++ b/include/asm-i386/delay.h
@@ -30,21 +30,26 @@ extern __inline__ void __delay(int loops)
* first constant multiplications gets optimized away if the delay is
* a constant)
*/
-extern __inline__ void udelay(unsigned long usecs)
+extern __inline__ void __udelay(unsigned long usecs, unsigned long lps)
{
usecs *= 0x000010c6; /* 2**32 / 1000000 */
__asm__("mull %0"
:"=d" (usecs)
-#ifdef __SMP__
- :"a" (usecs),"0" (cpu_data[smp_processor_id()].udelay_val)
-#else
- :"a" (usecs),"0" (loops_per_sec)
-#endif
+ :"a" (usecs),"0" (lps)
:"ax");
__delay(usecs);
}
+#ifdef __SMP__
+#define __udelay_val cpu_data[smp_processor_id()].udelay_val
+#else
+#define __udelay_val loops_per_sec
+#endif
+
+#define udelay(usecs) __udelay((usecs),__udelay_val)
+
+
extern __inline__ unsigned long muldiv(unsigned long a, unsigned long b, unsigned long c)
{
__asm__("mull %1 ; divl %2"
diff --git a/include/asm-i386/hardirq.h b/include/asm-i386/hardirq.h
index bdaad9b35..0ceef9108 100644
--- a/include/asm-i386/hardirq.h
+++ b/include/asm-i386/hardirq.h
@@ -58,7 +58,6 @@ static inline int hardirq_trylock(int cpu)
return 0;
}
++local_irq_count[cpu];
- __sti();
return 1;
}
diff --git a/include/asm-i386/keyboard.h b/include/asm-i386/keyboard.h
index ed6c7d472..180d747e5 100644
--- a/include/asm-i386/keyboard.h
+++ b/include/asm-i386/keyboard.h
@@ -1,18 +1,43 @@
/*
- * CPU specific parts of the keyboard driver
+ * linux/include/asm-i386/keyboard.h
*
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
+ * Created 3 Nov 1996 by Geert Uytterhoeven
*/
-#ifndef __ASM_i386_KEYBOARD_H
-#define __ASM_i386_KEYBOARD_H
+
+/*
+ * This file contains the i386 architecture specific keyboard definitions
+ */
+
+#ifndef _I386_KEYBOARD_H
+#define _I386_KEYBOARD_H
+
+#ifdef __KERNEL__
#include <asm/io.h>
-#define KEYBOARD_IRQ 1
+#define KEYBOARD_IRQ 1
+#define DISABLE_KBD_DURING_INTERRUPTS 0
#define KBD_REPORT_ERR
+#define KBD_REPORT_UNKN
+/* #define KBD_IS_FOCUS_9000 */
+
+extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
+extern int pckbd_getkeycode(unsigned int scancode);
+extern int pckbd_pretranslate(unsigned char scancode, char raw_mode);
+extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
+ char raw_mode);
+extern char pckbd_unexpected_up(unsigned char keycode);
+extern void pckbd_leds(unsigned char leds);
+extern void pckbd_init_hw(void);
+
+#define kbd_setkeycode pckbd_setkeycode
+#define kbd_getkeycode pckbd_getkeycode
+#define kbd_pretranslate pckbd_pretranslate
+#define kbd_translate pckbd_translate
+#define kbd_unexpected_up pckbd_unexpected_up
+#define kbd_leds pckbd_leds
+#define kbd_init_hw pckbd_init_hw
#define kbd_inb_p(port) inb_p(port)
#define kbd_inb(port) inb(port)
@@ -25,4 +50,5 @@ keyboard_setup()
request_region(0x60,16,"keyboard");
}
+#endif /* __KERNEL__ */
#endif /* __ASM_i386_KEYBOARD_H */
diff --git a/include/asm-i386/processor.h b/include/asm-i386/processor.h
index 9c6830f68..b4f26c73c 100644
--- a/include/asm-i386/processor.h
+++ b/include/asm-i386/processor.h
@@ -119,14 +119,15 @@ struct thread_struct {
/* virtual 86 mode info */
struct vm86_struct * vm86_info;
unsigned long screen_bitmap;
- unsigned long v86flags, v86mask, v86mode;
+ unsigned long v86flags, v86mask, v86mode, saved_esp0;
};
-#define INIT_MMAP { &init_mm, 0xC0000000, 0xFFFFF000, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC }
+#define INIT_MMAP \
+{ &init_mm, 0, 0, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap }
#define INIT_TSS { \
0,0, \
- sizeof(init_kernel_stack) + (long) &init_kernel_stack, \
+ sizeof(init_stack) + (long) &init_stack, \
KERNEL_DS, 0, \
0,0,0,0,0,0, \
(long) &swapper_pg_dir - PAGE_OFFSET, \
@@ -137,7 +138,7 @@ struct thread_struct {
{~0, }, /* ioperm */ \
_TSS(0), 0, 0, 0, KERNEL_DS, \
{ { 0, }, }, /* 387 state */ \
- NULL, 0, 0, 0, 0 /* vm86_info */, \
+ NULL, 0, 0, 0, 0, 0 /* vm86_info */, \
}
#define start_thread(regs, new_eip, new_esp) do {\
@@ -164,10 +165,15 @@ extern inline unsigned long thread_saved_pc(struct thread_struct *t)
}
/* Allocation and freeing of basic task resources. */
-#define alloc_task_struct() kmalloc(sizeof(struct task_struct), GFP_KERNEL)
-#define alloc_kernel_stack(p) __get_free_page(GFP_KERNEL)
-#define free_task_struct(p) kfree(p)
-#define free_kernel_stack(page) free_page((page))
+/*
+ * NOTE! The task struct and the stack go together
+ */
+#define alloc_task_struct() \
+ ((struct task_struct *) __get_free_pages(GFP_KERNEL,1,0))
+#define free_task_struct(p) free_pages((unsigned long)(p),1)
+
+#define init_task (init_task_union.task)
+#define init_stack (init_task_union.stack)
/*
* Return_address is a replacement for __builtin_return_address(count)
diff --git a/include/asm-i386/semaphore.h b/include/asm-i386/semaphore.h
index 4395dfce0..3ba3f8af5 100644
--- a/include/asm-i386/semaphore.h
+++ b/include/asm-i386/semaphore.h
@@ -85,44 +85,45 @@ extern inline void down(struct semaphore * sem)
{
__asm__ __volatile__(
"# atomic down operation\n\t"
- "movl $1f,%%eax\n\t"
#ifdef __SMP__
"lock ; "
#endif
"decl 0(%0)\n\t"
- "js " SYMBOL_NAME_STR(__down_failed)
- "\n1:"
+ "js 2f\n"
+ "1:\n"
+ ".section .text.lock,\"ax\"\n"
+ "2:\tpushl $1b\n\t"
+ "jmp __down_failed\n"
+ ".previous"
:/* no outputs */
:"c" (sem)
- :"ax","memory");
+ :"memory");
}
-/*
- * This version waits in interruptible state so that the waiting
- * process can be killed. The down_failed_interruptible routine
- * returns negative for signalled and zero for semaphore acquired.
- */
extern inline int down_interruptible(struct semaphore * sem)
{
- int ret;
+ int result;
__asm__ __volatile__(
"# atomic interruptible down operation\n\t"
- "movl $1f,%0\n\t"
#ifdef __SMP__
"lock ; "
#endif
"decl 0(%1)\n\t"
- "js " SYMBOL_NAME_STR(__down_failed_interruptible) "\n\t"
- "xorl %0,%0"
- "\n1:"
- :"=a" (ret)
+ "js 2f\n\t"
+ "xorl %0,%0\n"
+ "1:\n"
+ ".section .text.lock,\"ax\"\n"
+ "2:\tpushl $1b\n\t"
+ "jmp __down_failed_interruptible\n"
+ ".previous"
+ :"=a" (result)
:"c" (sem)
:"memory");
-
- return ret;
+ return result;
}
+
/*
* Note! This is subtle. We jump to wake people up only if
* the semaphore was negative (== somebody was waiting on it).
@@ -133,16 +134,19 @@ extern inline void up(struct semaphore * sem)
{
__asm__ __volatile__(
"# atomic up operation\n\t"
- "movl $1f,%%eax\n\t"
#ifdef __SMP__
"lock ; "
#endif
"incl 0(%0)\n\t"
- "jle " SYMBOL_NAME_STR(__up_wakeup)
- "\n1:"
+ "jle 2f\n"
+ "1:\n"
+ ".section .text.lock,\"ax\"\n"
+ "2:\tpushl $1b\n\t"
+ "jmp __up_wakeup\n"
+ ".previous"
:/* no outputs */
:"c" (sem)
- :"ax", "memory");
+ :"memory");
}
#endif
diff --git a/include/asm-i386/smp.h b/include/asm-i386/smp.h
index f1d977f22..0f7ae1224 100644
--- a/include/asm-i386/smp.h
+++ b/include/asm-i386/smp.h
@@ -178,7 +178,6 @@ extern int smp_found_config;
extern int smp_scan_config(unsigned long, unsigned long);
extern unsigned long smp_alloc_memory(unsigned long mem_base);
extern unsigned char *apic_reg;
-extern unsigned char *kernel_stacks[NR_CPUS];
extern unsigned char boot_cpu_id;
extern unsigned long cpu_present_map;
extern volatile int cpu_number_map[NR_CPUS];
@@ -192,6 +191,9 @@ extern void smp_message_irq(int cpl, void *dev_id, struct pt_regs *regs);
extern void smp_reschedule_irq(int cpl, struct pt_regs *regs);
extern unsigned long ipi_count;
extern void smp_invalidate_rcv(void); /* Process an NMI */
+extern void smp_local_timer_interrupt(struct pt_regs * regs);
+extern void setup_APIC_clock (void);
+
/*
* General functions that each host system must provide.
@@ -228,7 +230,9 @@ extern __inline unsigned long apic_read(unsigned long reg)
* the apic we get the right answer). Hopefully other processors are more sensible 8)
*/
-extern __inline int smp_processor_id(void)
+#define smp_processor_id() (current->processor)
+
+extern __inline int hard_smp_processor_id(void)
{
/* we don't want to mark this access volatile - bad code generation */
return GET_APIC_ID(*(unsigned long *)(apic_reg+APIC_ID));
diff --git a/include/asm-i386/smp_lock.h b/include/asm-i386/smp_lock.h
index 160e3562d..4f78f97fb 100644
--- a/include/asm-i386/smp_lock.h
+++ b/include/asm-i386/smp_lock.h
@@ -31,14 +31,11 @@ do { \
#define reacquire_kernel_lock(task, cpu, depth) \
do { if (depth) __asm__ __volatile__( \
"cli\n\t" \
- "movl $0f,%%eax\n\t" \
- "jmp __lock_kernel\n" \
- "0:\t" \
+ "call __lock_kernel\n\t" \
"movl %2,%0\n\t" \
"sti" \
: "=m" (task->lock_depth) \
- : "d" (cpu), "c" (depth) \
- : "ax"); \
+ : "d" (cpu), "c" (depth)); \
} while (0)
@@ -62,14 +59,12 @@ l2: printk("Ugh at %p\n", &&l2);
cli
cmpl $0, %0
jne 0f
- movl $0f, %%eax
- jmp __lock_kernel
-0:
- incl %0
+ call __lock_kernel
+0: incl %0
popfl
" :
- : "m" (current_set[cpu]->lock_depth), "d" (cpu)
- : "ax", "memory");
+ : "m" (current->lock_depth), "d" (cpu)
+ : "memory");
}
extern __inline__ void unlock_kernel(void)
diff --git a/include/asm-i386/spinlock.h b/include/asm-i386/spinlock.h
index 27630b21d..af6cf8c9c 100644
--- a/include/asm-i386/spinlock.h
+++ b/include/asm-i386/spinlock.h
@@ -77,13 +77,15 @@ typedef struct { unsigned long a[100]; } __dummy_lock_t;
#define spin_lock(lock) \
__asm__ __volatile__( \
- "jmp 2f\n" \
- "1:\t" \
- "testb $1,%0\n\t" \
- "jne 1b\n" \
- "2:\t" \
+ "\n1:\t" \
"lock ; btsl $0,%0\n\t" \
- "jc 1b" \
+ "jc 2f\n" \
+ ".section .text.lock,\"ax\"\n" \
+ "2:\t" \
+ "testb $1,%0\n\t" \
+ "jne 2b\n\t" \
+ "jmp 1b\n" \
+ ".previous" \
:"=m" (__dummy_lock(lock)))
#define spin_unlock(lock) \
@@ -91,33 +93,7 @@ __asm__ __volatile__( \
"lock ; btrl $0,%0" \
:"=m" (__dummy_lock(lock)))
-#undef spin_lock
-static inline void spin_lock(spinlock_t * lock)
-{
- __label__ l1;
- int stuck = 10000000;
-l1:
- __asm__ __volatile__(
- "jmp 2f\n"
- "1:\t"
- "decl %1\n\t"
- "je 3f\n\t"
- "testb $1,%0\n\t"
- "jne 1b\n"
- "2:\t"
- "lock ; btsl $0,%0\n\t"
- "jc 1b\n"
- "3:"
- :"=m" (__dummy_lock(lock)),
- "=r" (stuck)
- :"1" (stuck));
- if (!stuck) {
- printk("spinlock stuck at %p (%lx)\n",&&l1,lock->previous);
- } else
- lock->previous = (unsigned long) &&l1;
-}
-
-#define spin_trylock(lock) (!set_bit(0,(lock)))
+#define spin_trylock(lock) (!test_and_set_bit(0,(lock)))
#define spin_lock_irq(lock) \
do { __cli(); spin_lock(lock); } while (0)
@@ -158,12 +134,12 @@ typedef struct {
asm volatile("\n1:\t" \
"lock ; incl %0\n\t" \
"js 2f\n" \
- ".text 2\n" \
+ ".section .text.lock,\"ax\"\n" \
"2:\tlock ; decl %0\n" \
"3:\tcmpl $0,%0\n\t" \
"js 3b\n\t" \
"jmp 1b\n" \
- ".text" \
+ ".previous" \
:"=m" (__dummy_lock(&(rw)->lock)))
#define read_unlock(rw) \
@@ -173,19 +149,15 @@ typedef struct {
#define write_lock(rw) \
asm volatile("\n1:\t" \
"lock ; btsl $31,%0\n\t" \
- "jc 3f\n\t" \
- "testl $0x7fffffff,%0\n\t" \
- "jne 4f\n" \
- "2:\n" \
- ".text 2\n" \
- "3:\ttestl $-1,%0\n\t" \
- "js 3b\n\t" \
- "lock ; btsl $31,%0\n\t" \
- "jc 3b\n" \
- "4:\ttestl $0x7fffffff,%0\n\t" \
+ "jc 4f\n" \
+ "2:\ttestl $0x7fffffff,%0\n\t" \
+ "jne 3f\n" \
+ ".section .text.lock,\"ax\"\n" \
+ "3:\tlock ; btrl $31,%0\n" \
+ "4:\tcmp $0,%0\n\t" \
"jne 4b\n\t" \
- "jmp 2b\n" \
- ".text" \
+ "jmp 1b\n" \
+ ".previous" \
:"=m" (__dummy_lock(&(rw)->lock)))
#define write_unlock(rw) \
diff --git a/include/asm-i386/system.h b/include/asm-i386/system.h
index a3daf450d..94e01ec2a 100644
--- a/include/asm-i386/system.h
+++ b/include/asm-i386/system.h
@@ -73,7 +73,6 @@ __asm__("str %%ax\n\t" \
__asm__ __volatile__("fwait"); \
prev->flags&=~PF_USEDFPU; \
} \
- current_set[this_cpu] = next; \
__asm__("ljmp %0\n\t" \
: /* no output */ \
:"m" (*(((char *)&next->tss.tr)-4)), \
@@ -91,8 +90,7 @@ __asm__("ljmp %0\n\t" \
#else
#define switch_to(prev,next) do { \
-__asm__("movl %2,"SYMBOL_NAME_STR(current_set)"\n\t" \
- "ljmp %0\n\t" \
+__asm__("ljmp %0\n\t" \
"cmpl %1,"SYMBOL_NAME_STR(last_task_used_math)"\n\t" \
"jne 1f\n\t" \
"clts\n" \
diff --git a/include/asm-m68k/atomic.h b/include/asm-m68k/atomic.h
index b57cc9cb0..39236e060 100644
--- a/include/asm-m68k/atomic.h
+++ b/include/asm-m68k/atomic.h
@@ -11,7 +11,7 @@
*/
typedef struct { int counter; } atomic_t;
-#define ATOMIC_INIT { 0 }
+#define ATOMIC_INIT(i) { (i) }
#define atomic_read(v) ((v)->counter)
#define atomic_set(v, i) (((v)->counter) = i)
diff --git a/include/asm-m68k/bitops.h b/include/asm-m68k/bitops.h
index b63496040..00e23b352 100644
--- a/include/asm-m68k/bitops.h
+++ b/include/asm-m68k/bitops.h
@@ -14,7 +14,7 @@
* They use the standard big-endian m680x0 bit ordering.
*/
-extern __inline__ int set_bit(int nr,void * vaddr)
+extern __inline__ int test_and_set_bit(int nr,void * vaddr)
{
char retval;
@@ -24,7 +24,13 @@ extern __inline__ int set_bit(int nr,void * vaddr)
return retval;
}
-extern __inline__ int clear_bit(int nr, void * vaddr)
+extern __inline__ void set_bit(int nr, void * vaddr)
+{
+ __asm__ __volatile__ ("bfset %1@{%0:#1}"
+ : : "d" (nr^31), "a" (vaddr));
+}
+
+extern __inline__ int test_and_clear_bit(int nr, void * vaddr)
{
char retval;
@@ -34,7 +40,13 @@ extern __inline__ int clear_bit(int nr, void * vaddr)
return retval;
}
-extern __inline__ int change_bit(int nr, void * vaddr)
+extern __inline__ void clear_bit(int nr, void * vaddr)
+{
+ __asm__ __volatile__ ("bfclr %1@{%0:#1}"
+ : : "d" (nr^31), "a" (vaddr));
+}
+
+extern __inline__ int test_and_change_bit(int nr, void * vaddr)
{
char retval;
@@ -44,6 +56,12 @@ extern __inline__ int change_bit(int nr, void * vaddr)
return retval;
}
+extern __inline__ void change_bit(int nr, void * vaddr)
+{
+ __asm__ __volatile__ ("bfchg %1@{%0:#1}"
+ : : "d" (nr^31), "a" (vaddr));
+}
+
extern __inline__ int test_bit(int nr, const void * vaddr)
{
return ((1UL << (nr & 31)) & (((const unsigned int *) vaddr)[nr >> 5])) != 0;
diff --git a/include/asm-m68k/current.h b/include/asm-m68k/current.h
index 9d542c79d..8de8f8ced 100644
--- a/include/asm-m68k/current.h
+++ b/include/asm-m68k/current.h
@@ -1,12 +1,6 @@
#ifndef _M68K_CURRENT_H
#define _M68K_CURRENT_H
-/* Some architectures may want to do something "clever" here since
- * this is the most frequently accessed piece of data in the entire
- * kernel. For an example, see the Sparc implementation where an
- * entire register is hard locked to contain the value of current.
- */
-extern struct task_struct *current_set[NR_CPUS];
-#define current (current_set[smp_processor_id()]) /* Current on this processor */
+register struct task_struct *current __asm__("%a2");
#endif /* !(_M68K_CURRENT_H) */
diff --git a/include/asm-m68k/dsp56k.h b/include/asm-m68k/dsp56k.h
index e035055bc..ab3dd33e2 100644
--- a/include/asm-m68k/dsp56k.h
+++ b/include/asm-m68k/dsp56k.h
@@ -33,38 +33,3 @@ struct dsp56k_host_flags {
#define DSP56K_SET_RX_WSIZE 3 /* Host receive word size (1-4) */
#define DSP56K_HOST_FLAGS 4 /* Host flag registers */
#define DSP56K_HOST_CMD 5 /* Trig Host Command (0-31) */
-/*
- * linux/include/asm-m68k/dsp56k.h - defines and declarations for
- * DSP56k device driver
- *
- * Copyright (C) 1996,1997 Fredrik Noring, lars brinkhoff & Tomas Berndtsson
- *
- * 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.
- */
-
-
-/* Used for uploading DSP binary code */
-struct dsp56k_upload {
- int len;
- char *bin;
-};
-
-/* For the DSP host flags */
-struct dsp56k_host_flags {
- int dir; /* Bit field. 1 = write output bit, 0 = do nothing.
- * 0x0000 means reading only, 0x0011 means
- * writing the bits stored in `out' on HF0 and HF1.
- * Note that HF2 and HF3 can only be read.
- */
- int out; /* Bit field like above. */
- int status; /* Host register's current state is returned */
-};
-
-/* ioctl command codes */
-#define DSP56K_UPLOAD 1 /* Upload DSP binary program */
-#define DSP56K_SET_TX_WSIZE 2 /* Host transmit word size (1-4) */
-#define DSP56K_SET_RX_WSIZE 3 /* Host receive word size (1-4) */
-#define DSP56K_HOST_FLAGS 4 /* Host flag registers */
-#define DSP56K_HOST_CMD 5 /* Trig Host Command (0-31) */
diff --git a/include/asm-m68k/elf.h b/include/asm-m68k/elf.h
index 8ccf73858..570521687 100644
--- a/include/asm-m68k/elf.h
+++ b/include/asm-m68k/elf.h
@@ -44,6 +44,7 @@ typedef struct user_m68kfp_struct elf_fpregset_t;
pr_reg[4] = regs->d5; \
pr_reg[7] = regs->a0; \
pr_reg[8] = regs->a1; \
+ pr_reg[9] = regs->a2; \
pr_reg[14] = regs->d0; \
pr_reg[15] = rdusp(); \
pr_reg[16] = regs->orig_d0; \
@@ -54,7 +55,6 @@ typedef struct user_m68kfp_struct elf_fpregset_t;
struct switch_stack *sw = ((struct switch_stack *)regs) - 1; \
pr_reg[5] = sw->d6; \
pr_reg[6] = sw->d7; \
- pr_reg[9] = sw->a2; \
pr_reg[10] = sw->a3; \
pr_reg[11] = sw->a4; \
pr_reg[12] = sw->a5; \
diff --git a/include/asm-m68k/fpu.h b/include/asm-m68k/fpu.h
index fc47dac02..717ecfa7f 100644
--- a/include/asm-m68k/fpu.h
+++ b/include/asm-m68k/fpu.h
@@ -18,23 +18,3 @@
#endif
#endif /* __M68K_FPU_H */
-#ifndef __M68K_FPU_H
-#define __M68K_FPU_H
-
-#include <linux/config.h>
-
-/*
- * MAX floating point unit state size (FSAVE/FRESTORE)
- */
-
-#if defined(CONFIG_M68020) || defined(CONFIG_M68030)
-#define FPSTATESIZE (216/sizeof(unsigned char))
-#elif defined(CONFIG_M68040)
-#define FPSTATESIZE (96/sizeof(unsigned char))
-#elif defined(CONFIG_M68060)
-#define FPSTATESIZE (12/sizeof(unsigned char))
-#else
-#define FPSTATESIZE error no_cpu_type_configured
-#endif
-
-#endif /* __M68K_FPU_H */
diff --git a/include/asm-m68k/hardirq.h b/include/asm-m68k/hardirq.h
index e9d0136c3..512e0b054 100644
--- a/include/asm-m68k/hardirq.h
+++ b/include/asm-m68k/hardirq.h
@@ -1,24 +1,13 @@
#ifndef __M68K_HARDIRQ_H
#define __M68K_HARDIRQ_H
-extern unsigned int local_irq_count[NR_CPUS];
-#define in_interrupt() (local_irq_count[smp_processor_id()] != 0)
-
-#define hardirq_trylock(cpu) ((cpu)==0) /* always true */
-#define hardirq_endlock(cpu) do { } while (0)
-
-#define hardirq_enter(cpu) (local_irq_count[cpu]++)
-#define hardirq_exit(cpu) (local_irq_count[cpu]--)
-
-#endif
-#ifndef __M68K_HARDIRQ_H
-#define __M68K_HARDIRQ_H
+#include <linux/tasks.h>
extern unsigned int local_irq_count[NR_CPUS];
#define in_interrupt() (local_irq_count[smp_processor_id()] != 0)
-#define hardirq_trylock(cpu) ((cpu)==0) /* always true */
-#define hardirq_endlock(cpu) do { } while (0)
+#define hardirq_trylock(cpu) (++local_irq_count[cpu], (cpu) == 0)
+#define hardirq_endlock(cpu) (--local_irq_count[cpu])
#define hardirq_enter(cpu) (local_irq_count[cpu]++)
#define hardirq_exit(cpu) (local_irq_count[cpu]--)
diff --git a/include/asm-m68k/init.h b/include/asm-m68k/init.h
index 42938ae89..93a323fd6 100644
--- a/include/asm-m68k/init.h
+++ b/include/asm-m68k/init.h
@@ -1,14 +1,14 @@
#ifndef _M68K_INIT_H
#define _M68K_INIT_H
-/* Throwing the initialization code and data out is not supported yet... */
-
-#define __init
-#define __initdata
-#define __initfunc(__arginit) __arginit
+#define __init __attribute__ ((__section__ (".text.init")))
+#define __initdata __attribute__ ((__section__ (".data.init")))
+#define __initfunc(__arginit) \
+ __arginit __init; \
+ __arginit
/* For assembly routines */
-#define __INIT
-#define __FINIT
-#define __INITDATA
+#define __INIT .section ".text.init",#alloc,#execinstr
+#define __FINIT .previous
+#define __INITDATA .section ".data.init",#alloc,#write
#endif
diff --git a/include/asm-m68k/keyboard.h b/include/asm-m68k/keyboard.h
index 6c8c0abff..e4c602263 100644
--- a/include/asm-m68k/keyboard.h
+++ b/include/asm-m68k/keyboard.h
@@ -13,10 +13,44 @@
#ifdef __KERNEL__
-#define TRANSLATE_SCANCODES 0
-#define USE_MACHDEP_ABSTRACTION 1
#include <asm/machdep.h>
+static __inline__ int kbd_setkeycode(unsigned int scancode,
+ unsigned int keycode)
+{
+ return -EOPNOTSUPP;
+}
+
+static __inline__ int kbd_getkeycode(unsigned int scancode)
+{
+ return -EOPNOTSUPP;
+}
+
+static __inline__ int kbd_pretranslate(unsigned char scancode, char raw_mode)
+{
+ return 1;
+}
+
+static __inline__ int kbd_translate(unsigned char scancode,
+ unsigned char *keycode, char raw_mode)
+{
+ *keycode = scancode;
+ return 1;
+}
+
+static __inline__ char kbd_unexpected_up(unsigned char keycode)
+{
+ return 0200;
+}
+
+static __inline__ void kbd_leds(unsigned char leds)
+{
+ if (mach_kbd_leds)
+ mach_kbd_leds(leds);
+}
+
+#define kbd_init_hw mach_keyb_init
+
#endif /* __KERNEL__ */
#endif /* __ASMm68k_KEYBOARD_H */
diff --git a/include/asm-m68k/namei.h b/include/asm-m68k/namei.h
index 516066f1a..13502e13e 100644
--- a/include/asm-m68k/namei.h
+++ b/include/asm-m68k/namei.h
@@ -19,24 +19,3 @@
do { } while (0)
#endif
-/*
- * linux/include/asm-m68k/namei.h
- *
- * Included from linux/fs/namei.c
- */
-
-#ifndef __M68K_NAMEI_H
-#define __M68K_NAMEI_H
-
-/* These dummy routines maybe changed to something useful
- * for /usr/gnemul/ emulation stuff.
- * Look at asm-sparc/namei.h for details.
- */
-
-#define translate_namei(pathname, base, follow_links, res_inode) \
- do { } while (0)
-
-#define translate_open_namei(pathname, flag, mode, res_inode, base) \
- do { } while (0)
-
-#endif
diff --git a/include/asm-m68k/pgtable.h b/include/asm-m68k/pgtable.h
index cd5cef191..9463700a3 100644
--- a/include/asm-m68k/pgtable.h
+++ b/include/asm-m68k/pgtable.h
@@ -175,7 +175,7 @@ extern inline void flush_pages_to_ram (unsigned long address, int n)
}
/*
- * flush all atc entries (user-space entries only for the 680[46]0).
+ * flush all user-space atc entries.
*/
static inline void __flush_tlb(void)
{
@@ -184,7 +184,7 @@ static inline void __flush_tlb(void)
"pflushan\n\t"
".chip 68k");
else
- __asm__ __volatile__("pflusha");
+ __asm__ __volatile__("pflush #0,#4");
}
static inline void __flush_tlb_one(unsigned long addr)
diff --git a/include/asm-m68k/poll.h b/include/asm-m68k/poll.h
index 9b52915d0..f66153a74 100644
--- a/include/asm-m68k/poll.h
+++ b/include/asm-m68k/poll.h
@@ -19,24 +19,3 @@ struct pollfd {
};
#endif
-#ifndef __m68k_POLL_H
-#define __m68k_POLL_H
-
-#define POLLIN 1
-#define POLLPRI 2
-#define POLLOUT 4
-#define POLLERR 8
-#define POLLHUP 16
-#define POLLNVAL 32
-#define POLLRDNORM 64
-#define POLLWRNORM POLLOUT
-#define POLLRDBAND 128
-#define POLLWRBAND 256
-
-struct pollfd {
- int fd;
- short events;
- short revents;
-};
-
-#endif
diff --git a/include/asm-m68k/processor.h b/include/asm-m68k/processor.h
index 7b6622e89..9ec6df6e8 100644
--- a/include/asm-m68k/processor.h
+++ b/include/asm-m68k/processor.h
@@ -44,10 +44,10 @@ struct thread_struct {
unsigned char fpstate[FPSTATESIZE]; /* floating point state */
};
-#define INIT_MMAP { &init_mm, 0, 0x40000000, __pgprot(_PAGE_PRESENT|_PAGE_ACCESSED), VM_READ | VM_WRITE | VM_EXEC }
+#define INIT_MMAP { &init_mm, 0, 0x40000000, __pgprot(_PAGE_PRESENT|_PAGE_ACCESSED), VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap }
#define INIT_TSS { \
- sizeof(init_kernel_stack) + (long) init_kernel_stack, 0, \
+ sizeof(init_stack) + (unsigned long) init_stack, 0, \
PS_S, KERNEL_DS, \
{0, 0}, 0, {0,}, {0, 0, 0}, {0,}, \
}
@@ -93,10 +93,12 @@ extern inline unsigned long thread_saved_pc(struct thread_struct *t)
}
/* Allocation and freeing of basic task resources. */
-#define alloc_task_struct() kmalloc(sizeof(struct task_struct), GFP_KERNEL)
-#define alloc_kernel_stack(p) __get_free_page(GFP_KERNEL)
-#define free_task_struct(p) kfree(p)
-#define free_kernel_stack(page) free_page((page))
+#define alloc_task_struct() \
+ ((struct task_struct *) __get_free_pages(GFP_KERNEL,1,0))
+#define free_task_struct(p) free_pages((unsigned long)(p),1)
+
+#define init_task (init_task_union.task)
+#define init_stack (init_task_union.stack)
/*
* Return_address is a replacement for __builtin_return_address(count)
diff --git a/include/asm-m68k/ptrace.h b/include/asm-m68k/ptrace.h
index 449b7bd8e..e0c9d0ac2 100644
--- a/include/asm-m68k/ptrace.h
+++ b/include/asm-m68k/ptrace.h
@@ -34,6 +34,7 @@ struct pt_regs {
long d5;
long a0;
long a1;
+ long a2;
long d0;
long orig_d0;
long stkadj;
@@ -50,7 +51,6 @@ struct pt_regs {
struct switch_stack {
unsigned long d6;
unsigned long d7;
- unsigned long a2;
unsigned long a3;
unsigned long a4;
unsigned long a5;
diff --git a/include/asm-m68k/semaphore.h b/include/asm-m68k/semaphore.h
index c4e3068fa..7890c4f19 100644
--- a/include/asm-m68k/semaphore.h
+++ b/include/asm-m68k/semaphore.h
@@ -1,6 +1,7 @@
#ifndef _M68K_SEMAPHORE_H
#define _M68K_SEMAPHORE_H
+#include <linux/config.h>
#include <linux/linkage.h>
#include <asm/system.h>
#include <asm/atomic.h>
@@ -38,6 +39,7 @@ static inline void wake_one_more(struct semaphore * sem)
static inline int waking_non_zero(struct semaphore *sem)
{
+#ifndef CONFIG_RMW_INSNS
unsigned long flags;
int ret = 0;
@@ -48,6 +50,21 @@ static inline int waking_non_zero(struct semaphore *sem)
ret = 1;
}
restore_flags(flags);
+#else
+ int ret, tmp;
+
+ __asm__ __volatile__
+ ("1: movel %2,%0\n"
+ " jeq 3f\n"
+ "2: movel %0,%1\n"
+ " subql #1,%1\n"
+ " casl %0,%1,%2\n"
+ " jeq 3f\n"
+ " tstl %0\n"
+ " jne 2b\n"
+ "3:"
+ : "=d" (ret), "=d" (tmp), "=m" (sem->waking));
+#endif
return ret;
}
@@ -56,41 +73,26 @@ static inline int waking_non_zero(struct semaphore *sem)
* "down_failed" is a special asm handler that calls the C
* routine that actually waits. See arch/m68k/lib/semaphore.S
*/
-extern inline void down(struct semaphore * sem)
+extern inline void do_down(struct semaphore * sem, void (*failed)(void))
{
register struct semaphore *sem1 __asm__ ("%a1") = sem;
__asm__ __volatile__(
"| atomic down operation\n\t"
- "lea %%pc@(1f),%%a0\n\t"
"subql #1,%0@\n\t"
- "jmi " SYMBOL_NAME_STR(__down_failed) "\n"
- "1:"
+ "jmi 2f\n"
+ "1:\n"
+ ".section .text.lock,\"ax\"\n"
+ ".even\n"
+ "2:\tpea 1b\n\t"
+ "jbra %1\n"
+ ".previous"
: /* no outputs */
- : "a" (sem1)
- : "%a0", "memory");
+ : "a" (sem1), "m" (*(unsigned char *)failed)
+ : "memory");
}
-/*
- * This version waits in interruptible state so that the waiting
- * process can be killed. The down_failed_interruptible routine
- * returns negative for signalled and zero for semaphore acquired.
- */
-extern inline int down_interruptible(struct semaphore * sem)
-{
- register int ret __asm__ ("%d0");
- register struct semaphore *sem1 __asm__ ("%a1") = sem;
- __asm__ __volatile__(
- "| atomic interruptible down operation\n\t"
- "lea %%pc@(1f),%%a0\n\t"
- "subql #1,%1@\n\t"
- "jmi " SYMBOL_NAME_STR(__down_failed_interruptible) "\n\t"
- "clrl %0\n"
- "1:"
- : "=d" (ret)
- : "a" (sem1)
- : "%d0", "%a0", "memory");
- return ret;
-}
+#define down(sem) do_down((sem),__down_failed)
+#define down_interruptible(sem) do_down((sem),__down_failed_interruptible)
/*
* Note! This is subtle. We jump to wake people up only if
@@ -103,13 +105,17 @@ extern inline void up(struct semaphore * sem)
register struct semaphore *sem1 __asm__ ("%a1") = sem;
__asm__ __volatile__(
"| atomic up operation\n\t"
- "lea %%pc@(1f),%%a0\n\t"
- "addql #1,%0\n\t"
- "jle " SYMBOL_NAME_STR(__up_wakeup) "\n"
- "1:"
+ "addql #1,%0@\n\t"
+ "jle 2f\n"
+ "1:\n"
+ ".section .text.lock,\"ax\"\n"
+ ".even\n"
+ "2:\tpea 1b\n\t"
+ "jbra %1\n"
+ ".previous"
: /* no outputs */
- : "m" (sem->count), "a" (sem1)
- : "%a0", "memory");
+ : "a" (sem1), "m" (*(unsigned char *)__up_wakeup)
+ : "memory");
}
#endif
diff --git a/include/asm-m68k/sigcontext.h b/include/asm-m68k/sigcontext.h
index 9c13b0951..a2d28c218 100644
--- a/include/asm-m68k/sigcontext.h
+++ b/include/asm-m68k/sigcontext.h
@@ -1,8 +1,6 @@
#ifndef _ASM_M68k_SIGCONTEXT_H
#define _ASM_M68k_SIGCONTEXT_H
-#include<asm/fpu.h>
-
struct sigcontext {
unsigned long sc_mask; /* old sigmask */
unsigned long sc_usp; /* old user stack pointer */
@@ -15,7 +13,7 @@ struct sigcontext {
unsigned short sc_formatvec;
unsigned long sc_fpregs[2*3]; /* room for two fp registers */
unsigned long sc_fpcntl[3];
- unsigned char sc_fpstate[FPSTATESIZE];
+ unsigned char sc_fpstate[216];
};
#endif
diff --git a/include/asm-m68k/smp_lock.h b/include/asm-m68k/smp_lock.h
index 158de0988..6bc9a781b 100644
--- a/include/asm-m68k/smp_lock.h
+++ b/include/asm-m68k/smp_lock.h
@@ -12,17 +12,3 @@
#define reacquire_kernel_lock(task, cpu, depth) do { } while(0)
#endif
-#ifndef __M68K_SMPLOCK_H
-#define __M68K_SMPLOCK_H
-
-/*
- * We don't do SMP so this is again one of these silly dummy files
- * to keep the kernel source looking nice ;-(.
- */
-
-#define lock_kernel() do { } while(0)
-#define unlock_kernel() do { } while(0)
-#define release_kernel_lock(task, cpu, depth) ((depth) = 1)
-#define reaquire_kernel_lock(task, cpu, depth) do { } while(0)
-
-#endif
diff --git a/include/asm-m68k/softirq.h b/include/asm-m68k/softirq.h
index 32f12c0d5..1cc0cbb81 100644
--- a/include/asm-m68k/softirq.h
+++ b/include/asm-m68k/softirq.h
@@ -4,6 +4,9 @@
/*
* Software interrupts.. no SMP here either.
*/
+
+#include <asm/atomic.h>
+
#define get_active_bhs() (bh_mask & bh_active)
#define clear_active_bhs(x) atomic_clear_mask((x),&bh_active)
@@ -14,12 +17,6 @@ extern inline void init_bh(int nr, void (*routine)(void))
bh_mask |= 1 << nr;
}
-extern inline void remove_bh(int nr)
-{
- bh_base[nr] = NULL;
- bh_mask &= ~(1 << nr);
-}
-
extern inline void mark_bh(int nr)
{
set_bit(nr, &bh_active);
@@ -41,60 +38,10 @@ extern inline void enable_bh(int nr)
bh_mask |= 1 << nr;
}
-extern int __m68k_bh_counter;
-
-extern inline void start_bh_atomic(void)
-{
- __m68k_bh_counter++;
- barrier();
-}
-
-extern inline void end_bh_atomic(void)
-{
- barrier();
- __m68k_bh_counter--;
-}
-
-/* These are for the irq's testing the lock */
-#define softirq_trylock() (__m68k_bh_counter ? 0 : (__m68k_bh_counter=1))
-#define softirq_endlock() (__m68k_bh_counter = 0)
-
-#endif
-#ifndef __M68K_SOFTIRQ_H
-#define __M68K_SOFTIRQ_H
-
-/*
- * Software interrupts.. no SMP here either.
- */
-#define get_active_bhs() (bh_mask & bh_active)
-#define clear_active_bhs(x) atomic_clear_mask((x),&bh_active)
-
-extern inline void init_bh(int nr, void (*routine)(void))
-{
- bh_base[nr] = routine;
- bh_mask_count[nr] = 0;
- bh_mask |= 1 << nr;
-}
-
-extern inline void mark_bh(int nr)
-{
- set_bit(nr, &bh_active);
-}
-
-/*
- * These use a mask count to correctly handle
- * nested disable/enable calls
- */
-extern inline void disable_bh(int nr)
+extern inline void remove_bh(int nr)
{
+ bh_base[nr] = NULL;
bh_mask &= ~(1 << nr);
- bh_mask_count[nr]++;
-}
-
-extern inline void enable_bh(int nr)
-{
- if (!--bh_mask_count[nr])
- bh_mask |= 1 << nr;
}
extern int __m68k_bh_counter;
diff --git a/include/asm-m68k/spinlock.h b/include/asm-m68k/spinlock.h
index cbae3d62d..83a04ac7f 100644
--- a/include/asm-m68k/spinlock.h
+++ b/include/asm-m68k/spinlock.h
@@ -5,8 +5,8 @@
* We don't do SMP on the m68k .... at least not yet.
*/
-typedef struct { } spinlock_t;
-#define SPIN_LOCK_UNLOCKED { }
+typedef struct { int dummy; } spinlock_t;
+#define SPIN_LOCK_UNLOCKED { 0 }
#define spin_lock_init(lock) do { } while(0)
#define spin_lock(lock) do { } while(0)
@@ -31,8 +31,8 @@ typedef struct { } spinlock_t;
* irq-safe write-lock, but readers can get non-irqsafe
* read-locks.
*/
-typedef struct { } rwlock_t;
-#define RW_LOCK_UNLOCKED { }
+typedef struct { int dummy; } rwlock_t;
+#define RW_LOCK_UNLOCKED { 0 }
#define read_lock(lock) do { } while(0)
#define read_unlock(lock) do { } while(0)
@@ -49,26 +49,3 @@ typedef struct { } rwlock_t;
#define write_unlock_irqrestore(lock, flags) restore_flags(flags)
#endif
-#ifndef __M68K_SPINLOCK_H
-#define __M68K_SPINLOCK_H
-
-/*
- * We don't do SMP on the m68k .... at least not yet.
- */
-
-typedef struct { } spinlock_t;
-#define SPIN_LOCK_UNLOCKED { }
-
-#define spin_lock_init(lock) do { } while(0)
-#define spin_lock(lock) do { } while(0)
-#define spin_trylock(lock) do { } while(0)
-#define spin_unlock(lock) do { } while(0)
-#define spin_lock_irq(lock) cli()
-#define spin_unlock_irq(lock) sti()
-
-#define spin_lock_irqsave(lock, flags) \
- do { save_flags(flags); cli(); } while (0)
-#define spin_unlock_irqrestore(lock, flags) \
- restore_flags(flags)
-
-#endif
diff --git a/include/asm-m68k/system.h b/include/asm-m68k/system.h
index dc9024b73..fd2eb8991 100644
--- a/include/asm-m68k/system.h
+++ b/include/asm-m68k/system.h
@@ -83,6 +83,7 @@ __asm__ __volatile__("movew %0,%/sr": /* no outputs */ :"d" (x) : "memory")
#define sti() __sti()
#define save_flags(x) __save_flags(x)
#define restore_flags(x) __restore_flags(x)
+#define save_and_cli(flags) do { save_flags(flags); cli(); } while(0)
#ifndef CONFIG_RMW_INSNS
static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
diff --git a/include/asm-m68k/unistd.h b/include/asm-m68k/unistd.h
index c526da9ef..9ebe62ff4 100644
--- a/include/asm-m68k/unistd.h
+++ b/include/asm-m68k/unistd.h
@@ -322,9 +322,11 @@ static inline pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long f
set_fs (KERNEL_DS);
__asm__ __volatile__
- ("trap #0\n\t" /* Linux/m68k system call */
+ ("clrl %%d2\n\t"
+ "trap #0\n\t" /* Linux/m68k system call */
"tstl %0\n\t" /* child or parent */
"jne 1f\n\t" /* parent - jump */
+ "lea %%sp@(-8192),%6\n\t" /* reload current */
"movel %3,%%sp@-\n\t" /* push argument */
"jsr %4@\n\t" /* call fn */
"movel %0,%%d1\n\t" /* pass exit value */
@@ -333,8 +335,8 @@ static inline pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long f
"1:"
: "=d" (retval)
: "0" (__NR_clone), "i" (__NR_exit),
- "r" (arg), "a" (fn), "d" (clone_arg)
- : "d0");
+ "r" (arg), "a" (fn), "d" (clone_arg), "r" (current)
+ : "d0", "d2");
set_fs (fs);
return retval;
diff --git a/include/asm-mips/bitops.h b/include/asm-mips/bitops.h
index d28a881a4..59a6ccbba 100644
--- a/include/asm-mips/bitops.h
+++ b/include/asm-mips/bitops.h
@@ -19,15 +19,15 @@
* Only disable interrupt for kernel mode stuff to keep usermode stuff
* that dares to use kernel include files alive.
*/
-#define __flags unsigned long flags
-#define __cli() cli()
-#define __save_flags(x) save_flags(x)
-#define __restore_flags(x) restore_flags(x)
+#define __bi_flags unsigned long flags
+#define __bi_cli() __cli()
+#define __bi_save_flags(x) __save_flags(x)
+#define __bi_restore_flags(x) __restore_flags(x)
#else
-#define __flags
-#define __cli()
-#define __save_flags(x)
-#define __restore_flags(x)
+#define __bi_flags
+#define __bi_cli()
+#define __bi_save_flags(x)
+#define __bi_restore_flags(x)
#endif /* __KERNEL__ */
/*
@@ -35,9 +35,13 @@
* elements. With respect to a future 64 bit implementation it is
* wrong to use long *. Use u32 * or int *.
*/
-extern __inline__ int set_bit(int nr, void *addr);
-extern __inline__ int clear_bit(int nr, void *addr);
-extern __inline__ int change_bit(int nr, void *addr);
+extern __inline__ void set_bit(int nr, void *addr);
+extern __inline__ void clear_bit(int nr, void *addr);
+extern __inline__ void change_bit(int nr, void *addr);
+extern __inline__ int test_and_set_bit(int nr, void *addr);
+extern __inline__ int test_and_clear_bit(int nr, void *addr);
+extern __inline__ int test_and_change_bit(int nr, void *addr);
+
extern __inline__ int test_bit(int nr, const void *addr);
#ifndef __MIPSEB__
extern __inline__ int find_first_zero_bit (void *addr, unsigned size);
@@ -57,7 +61,42 @@ extern __inline__ unsigned long ffz(unsigned long word);
/*
* The following functions will only work for the R4000!
*/
-extern __inline__ int set_bit(int nr, void *addr)
+
+extern __inline__ void set_bit(int nr, void *addr)
+{
+ int mask, mw;
+
+ addr += ((nr >> 3) & ~3);
+ mask = 1 << (nr & 0x1f);
+ do {
+ mw = load_linked(addr);
+ } while (!store_conditional(addr, mw|mask));
+}
+
+extern __inline__ void clear_bit(int nr, void *addr)
+{
+ int mask, mw;
+
+ addr += ((nr >> 3) & ~3);
+ mask = 1 << (nr & 0x1f);
+ do {
+ mw = load_linked(addr);
+ }
+ while (!store_conditional(addr, mw & ~mask));
+}
+
+extern __inline__ void change_bit(int nr, void *addr)
+{
+ int mask, mw;
+
+ addr += ((nr >> 3) & ~3);
+ mask = 1 << (nr & 0x1f);
+ do {
+ mw = load_linked(addr);
+ } while (!store_conditional(addr, mw ^ mask));
+}
+
+extern __inline__ int test_and_set_bit(int nr, void *addr)
{
int mask, retval, mw;
@@ -71,7 +110,7 @@ extern __inline__ int set_bit(int nr, void *addr)
return retval;
}
-extern __inline__ int clear_bit(int nr, void *addr)
+extern __inline__ int test_and_clear_bit(int nr, void *addr)
{
int mask, retval, mw;
@@ -86,7 +125,7 @@ extern __inline__ int clear_bit(int nr, void *addr)
return retval;
}
-extern __inline__ int change_bit(int nr, void *addr)
+extern __inline__ int test_and_change_bit(int nr, void *addr)
{
int mask, retval, mw;
@@ -102,61 +141,103 @@ extern __inline__ int change_bit(int nr, void *addr)
#else /* MIPS I */
-extern __inline__ int set_bit(int nr, void * addr)
+extern __inline__ void set_bit(int nr, void * addr)
+{
+ int mask;
+ int *a = addr;
+ __bi_flags;
+
+ a += nr >> 5;
+ mask = 1 << (nr & 0x1f);
+ __bi_save_flags(flags);
+ __bi_cli();
+ *a |= mask;
+ __bi_restore_flags(flags);
+}
+
+extern __inline__ void clear_bit(int nr, void * addr)
+{
+ int mask;
+ int *a = addr;
+ __bi_flags;
+
+ a += nr >> 5;
+ mask = 1 << (nr & 0x1f);
+ __bi_save_flags(flags);
+ __bi_cli();
+ *a &= ~mask;
+ __bi_restore_flags(flags);
+}
+
+extern __inline__ void change_bit(int nr, void * addr)
+{
+ int mask;
+ int *a = addr;
+ __bi_flags;
+
+ a += nr >> 5;
+ mask = 1 << (nr & 0x1f);
+ __bi_save_flags(flags);
+ __bi_cli();
+ *a ^= mask;
+ __bi_restore_flags(flags);
+}
+
+extern __inline__ int test_and_set_bit(int nr, void * addr)
{
int mask, retval;
int *a = addr;
- __flags;
+ __bi_flags;
a += nr >> 5;
mask = 1 << (nr & 0x1f);
- __save_flags(flags);
- __cli();
+ __bi_save_flags(flags);
+ __bi_cli();
retval = (mask & *a) != 0;
*a |= mask;
- __restore_flags(flags);
+ __bi_restore_flags(flags);
return retval;
}
-extern __inline__ int clear_bit(int nr, void * addr)
+extern __inline__ int test_and_clear_bit(int nr, void * addr)
{
int mask, retval;
int *a = addr;
- __flags;
+ __bi_flags;
a += nr >> 5;
mask = 1 << (nr & 0x1f);
- __save_flags(flags);
- __cli();
+ __bi_save_flags(flags);
+ __bi_cli();
retval = (mask & *a) != 0;
*a &= ~mask;
- __restore_flags(flags);
+ __bi_restore_flags(flags);
return retval;
}
-extern __inline__ int change_bit(int nr, void * addr)
+extern __inline__ int test_and_change_bit(int nr, void * addr)
{
int mask, retval;
int *a = addr;
- __flags;
+ __bi_flags;
a += nr >> 5;
mask = 1 << (nr & 0x1f);
- __save_flags(flags);
- __cli();
+ __bi_save_flags(flags);
+ __bi_cli();
retval = (mask & *a) != 0;
*a ^= mask;
- __restore_flags(flags);
+ __bi_restore_flags(flags);
return retval;
}
-#undef __flags
-#undef __cli()
-#undef __save_flags(x)
-#undef __restore_flags(x)
+#undef __bi_flags
+#undef __bi_cli()
+#undef __bi_save_flags(x)
+#undef __bi_restore_flags(x)
#endif /* MIPS I */
@@ -443,8 +524,8 @@ found_middle:
#else /* !(__MIPSEB__) */
/* Native ext2 byte ordering, just collapse using defines. */
-#define ext2_set_bit(nr, addr) set_bit((nr), (addr))
-#define ext2_clear_bit(nr, addr) clear_bit((nr), (addr))
+#define ext2_set_bit(nr, addr) test_and_set_bit((nr), (addr))
+#define ext2_clear_bit(nr, addr) test_and_clear_bit((nr), (addr))
#define ext2_test_bit(nr, addr) test_bit((nr), (addr))
#define ext2_find_first_zero_bit(addr, size) find_first_zero_bit((addr), (size))
#define ext2_find_next_zero_bit(addr, size, offset) \
@@ -454,8 +535,8 @@ found_middle:
* Bitmap functions for the minix filesystem.
* FIXME: These assume that Minix uses the native byte/bitorder.
*/
-#define minix_set_bit(nr,addr) set_bit(nr,addr)
-#define minix_clear_bit(nr,addr) clear_bit(nr,addr)
+#define minix_set_bit(nr,addr) test_and_set_bit(nr,addr)
+#define minix_clear_bit(nr,addr) test_and_clear_bit(nr,addr)
#define minix_test_bit(nr,addr) test_bit(nr,addr)
#define minix_find_first_zero_bit(addr,size) find_first_zero_bit(addr,size)
#endif /* __KERNEL__ */
diff --git a/include/asm-mips/bootinfo.h b/include/asm-mips/bootinfo.h
index 2816e599f..e723cae21 100644
--- a/include/asm-mips/bootinfo.h
+++ b/include/asm-mips/bootinfo.h
@@ -5,7 +5,7 @@
* Stoned Elipot and Paul M. Antoine.
*
* This file is subject to the terms and conditions of the GNU General Public
- * License. See the file README.legal in the main directory of this archive
+ * License. See the file COPYING in the main directory of this archive
* for more details.
*/
#ifndef __ASM_MIPS_BOOTINFO_H
diff --git a/include/asm-mips/current.h b/include/asm-mips/current.h
index 7955aad50..743f91902 100644
--- a/include/asm-mips/current.h
+++ b/include/asm-mips/current.h
@@ -1,13 +1,34 @@
#ifndef __ASM_MIPS_CURRENT_H
#define __ASM_MIPS_CURRENT_H
+#ifdef __LANGUAGE_C__
+
+static inline struct task_struct *__get_current(void)
+{
+ struct task_struct *__current;
+
+ __asm__("ori\t%0,$29,%1\n\t"
+ "xori\t%0,%1"
+ :"=r" (__current)
+ :"ir" (8191UL));
+
+ return __current;
+}
+
+#define current __get_current()
+
+#endif /* __LANGUAGE_C__ */
+#ifdef __LANGUAGE_ASSEMBLY__
+
/*
- * Some architectures may want to do something "clever" here since
- * this is the most frequently accessed piece of data in the entire
- * kernel. For an example, see the Sparc implementation where an
- * entire register is hard locked to contain the value of current.
+ * Get current task pointer
*/
-extern struct task_struct *current_set[NR_CPUS];
-#define current (current_set[smp_processor_id()]) /* Current on this processor */
+#define GET_CURRENT(reg) \
+ lui reg, %hi(kernelsp); \
+ lw reg, %lo(kernelsp)(reg); \
+ ori reg, 8191; \
+ xori reg, 8191
+
+#endif
#endif /* __ASM_MIPS_CURRENT_H */
diff --git a/include/asm-mips/delay.h b/include/asm-mips/delay.h
index d7d6e269d..ec2ad70f3 100644
--- a/include/asm-mips/delay.h
+++ b/include/asm-mips/delay.h
@@ -22,16 +22,24 @@ extern __inline__ void __delay(int loops)
* first constant multiplications gets optimized away if the delay is
* a constant)
*/
-extern __inline__ void udelay(unsigned long usecs)
+extern __inline__ void __udelay(unsigned long usecs, unsigned long lps)
{
usecs *= 0x000010c6; /* 2**32 / 1000000 */
__asm__("multu\t%0,%1\n\t"
"mfhi\t%0"
:"=r" (usecs)
- :"0" (usecs),"r" (loops_per_sec));
+ :"0" (usecs),"r" (lps));
__delay(usecs);
}
+#ifdef __SMP__
+#define __udelay_val cpu_data[smp_processor_id()].udelay_val
+#else
+#define __udelay_val loops_per_sec
+#endif
+
+#define udelay(usecs) __udelay((usecs),__udelay_val)
+
/*
* The different variants for 32/64 bit are pure paranoia. The typical
* range of numbers that appears for MIPS machines avoids overflows.
diff --git a/include/asm-mips/io.h b/include/asm-mips/io.h
index 28ec2f73f..be0d068a4 100644
--- a/include/asm-mips/io.h
+++ b/include/asm-mips/io.h
@@ -1,6 +1,11 @@
#ifndef __ASM_MIPS_IO_H
#define __ASM_MIPS_IO_H
+/*
+ * Slowdown I/O port space accesses for antique hardware.
+ */
+#undef CONF_SLOWDOWN_IO
+
#include <asm/mipsconfig.h>
#include <asm/addrspace.h>
@@ -35,6 +40,7 @@
* I feel a bit unsafe about using 0x80 (should be safe, though)
*
* Linus
+ *
*/
#define __SLOW_DOWN_IO \
@@ -42,11 +48,15 @@
"sb\t$0,0x80(%0)" \
: : "r" (PORT_BASE));
+#ifdef CONF_SLOWDOWN_IO
#ifdef REALLY_SLOW_IO
#define SLOW_DOWN_IO { __SLOW_DOWN_IO; __SLOW_DOWN_IO; __SLOW_DOWN_IO; __SLOW_DOWN_IO; }
#else
#define SLOW_DOWN_IO __SLOW_DOWN_IO
#endif
+#else
+#define SLOW_DOWN_IO
+#endif
/*
* Change virtual addresses to physical addresses and vv.
@@ -54,12 +64,12 @@
*/
extern inline unsigned long virt_to_phys(volatile void * address)
{
- return (unsigned long) address - KSEG0;
+ return PHYSADDR(address);
}
extern inline void * phys_to_virt(unsigned long address)
{
- return (void *) address + KSEG0;
+ return (void *)KSEG0ADDR(address);
}
extern void * ioremap(unsigned long phys_addr, unsigned long size);
@@ -67,10 +77,16 @@ extern void iounmap(void *addr);
/*
* IO bus memory addresses are also 1:1 with the physical address
- * FIXME: This assumption is wrong for the Deskstation Tyne
*/
-#define virt_to_bus virt_to_phys
-#define bus_to_virt phys_to_virt
+extern inline unsigned long virt_to_bus(volatile void * address)
+{
+ return PHYSADDR(address);
+}
+
+extern inline void * bus_to_virt(unsigned long address)
+{
+ return (void *)KSEG0ADDR(address);
+}
/*
* isa_slot_offset is the address where E(ISA) busaddress 0 is is mapped
@@ -111,6 +127,10 @@ extern inline void iounmap(void *addr)
{
}
+/*
+ * XXX We need system specific versions of these to handle EISA address bits
+ * 24-31 on SNI.
+ */
#define readb(addr) (*(volatile unsigned char *) (isa_slot_offset + (unsigned long)(addr)))
#define readw(addr) (*(volatile unsigned short *) (isa_slot_offset + (unsigned long)(addr)))
#define readl(addr) (*(volatile unsigned int *) (isa_slot_offset + (unsigned long)(addr)))
diff --git a/include/asm-mips/jazz.h b/include/asm-mips/jazz.h
index 2f6e4b225..41ab89634 100644
--- a/include/asm-mips/jazz.h
+++ b/include/asm-mips/jazz.h
@@ -311,4 +311,6 @@ extern inline unsigned int r4030_write_reg32(unsigned addr, unsigned val)
#define JAZZ_RTC_BASE 0xe0004000
#define JAZZ_PORT_BASE 0xe2000000
+#define JAZZ_EISA_BASE 0xe3000000
+
#endif /* __ASM_MIPS_JAZZ_H */
diff --git a/include/asm-mips/keyboard.h b/include/asm-mips/keyboard.h
index 04dada787..2c4396f04 100644
--- a/include/asm-mips/keyboard.h
+++ b/include/asm-mips/keyboard.h
@@ -4,12 +4,34 @@
* 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.
+ *
+ * This file is a mess. Put on your peril sensitive glasses.
*/
#ifndef __ASM_MIPS_KEYBOARD_H
#define __ASM_MIPS_KEYBOARD_H
+#ifdef __KERNEL__
+
#include <linux/config.h>
#include <linux/delay.h>
+#include <linux/ioport.h>
+
+extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
+extern int pckbd_getkeycode(unsigned int scancode);
+extern int pckbd_pretranslate(unsigned char scancode, char raw_mode);
+extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
+ char raw_mode);
+extern char pckbd_unexpected_up(unsigned char keycode);
+extern void pckbd_leds(unsigned char leds);
+extern void pckbd_init_hw(void);
+
+#define kbd_setkeycode pckbd_setkeycode
+#define kbd_getkeycode pckbd_getkeycode
+#define kbd_pretranslate pckbd_pretranslate
+#define kbd_translate pckbd_translate
+#define kbd_unexpected_up pckbd_unexpected_up
+#define kbd_leds pckbd_leds
+#define kbd_init_hw pckbd_init_hw
/*
* The default IO slowdown is doing 'inb()'s from 0x61, which should be
@@ -21,6 +43,13 @@
#define SLOW_IO_BY_JUMPING
#include <asm/io.h>
+/*
+ * keyboard controller registers
+ */
+#define KBD_STATUS_REG (unsigned int) 0x64
+#define KBD_CNTL_REG (unsigned int) 0x64
+#define KBD_DATA_REG (unsigned int) 0x60
+
#ifdef CONFIG_SGI
#include <asm/segment.h>
#include <asm/sgihpc.h>
@@ -44,8 +73,8 @@
#ifndef CONFIG_SGI
#define KBD_REPORT_ERR
#endif
-
-__initfunc(int initialize_kbd(void));
+#define KBD_REPORT_UNKN
+/* #define KBD_IS_FOCUS_9000 */
int (*kbd_inb_p)(unsigned short port);
int (*kbd_inb)(unsigned short port);
@@ -60,14 +89,16 @@ void (*kbd_outb)(unsigned char data, unsigned short port);
/* XXX Define both and ... */
#ifdef CONFIG_MIPS_JAZZ
#define INIT_KBD /* full initialization for the keyboard controller. */
-static volatile keyboard_hardware *kh = (void *) JAZZ_KEYBOARD_ADDRESS;
+#define __khtype keyboard_hardware
#endif
#ifdef CONFIG_SGI
#define INIT_KBD /* full initialization for the keyboard controller. */
-volatile struct hpc_keyb *kh = (struct hpc_keyb *) (KSEG1 + 0x1fbd9800 + 64);
+#define __khtype struct hpc_keyb
#endif
+static volatile __khtype *kh;
+
static int
jazz_kbd_inb_p(unsigned short port)
{
@@ -147,158 +178,14 @@ port_kbd_outb(unsigned char data, unsigned short port)
return outb(data, port);
}
-#ifdef INIT_KBD
-static int
-kbd_wait_for_input(void)
-{
- int n;
- int status, data;
-
- n = TIMEOUT_CONST;
- do {
- status = kbd_inb(KBD_STATUS_REG);
- /*
- * Wait for input data to become available. This bit will
- * then be cleared by the following read of the DATA
- * register.
- */
-
- if (!(status & KBD_OBF))
- continue;
-
- data = kbd_inb(KBD_DATA_REG);
-
- /*
- * Check to see if a timeout error has occurred. This means
- * that transmission was started but did not complete in the
- * normal time cycle. PERR is set when a parity error occurred
- * in the last transmission.
- */
- if (status & (KBD_GTO | KBD_PERR)) {
- continue;
- }
- return (data & 0xff);
- } while (--n);
- return (-1); /* timed-out if fell through to here... */
-}
-
-static void kbd_write(int address, int data)
-{
- int status;
-
- do {
- status = kbd_inb(KBD_STATUS_REG); /* spin until input buffer empty*/
- } while (status & KBD_IBF);
- kbd_outb(data, address); /* write out the data*/
-}
-
-__initfunc(int initialize_kbd(void))
-{
- unsigned long flags;
-
- save_flags(flags); cli();
-
- /* Flush any pending input. */
- while (kbd_wait_for_input() != -1)
- continue;
+static inline void kb_wait(void);
+static int send_data(unsigned char data);
- /*
- * Test the keyboard interface.
- * This seems to be the only way to get it going.
- * If the test is successful a x55 is placed in the input buffer.
- */
- kbd_write(KBD_CNTL_REG, KBD_SELF_TEST);
- if (kbd_wait_for_input() != 0x55) {
- printk(KERN_WARNING "initialize_kbd: "
- "keyboard failed self test.\n");
- restore_flags(flags);
- return(-1);
- }
-
- /*
- * Perform a keyboard interface test. This causes the controller
- * to test the keyboard clock and data lines. The results of the
- * test are placed in the input buffer.
- */
- kbd_write(KBD_CNTL_REG, KBD_SELF_TEST2);
- if (kbd_wait_for_input() != 0x00) {
- printk(KERN_WARNING "initialize_kbd: "
- "keyboard failed self test 2.\n");
- restore_flags(flags);
- return(-1);
- }
-
- /* Enable the keyboard by allowing the keyboard clock to run. */
- kbd_write(KBD_CNTL_REG, KBD_CNTL_ENABLE);
-
- /*
- * Reset keyboard. If the read times out
- * then the assumption is that no keyboard is
- * plugged into the machine.
- * This defaults the keyboard to scan-code set 2.
- */
- kbd_write(KBD_DATA_REG, KBD_RESET);
- if (kbd_wait_for_input() != KBD_ACK) {
- printk(KERN_WARNING "initialize_kbd: "
- "reset kbd failed, no ACK.\n");
- restore_flags(flags);
- return(-1);
- }
-
- /*
- * Give the keyboard some time to breathe ...
- * ... or it fucks up the floppy controller, too. Wiered.
- */
- udelay(20);
-
- if (kbd_wait_for_input() != KBD_POR) {
- printk(KERN_WARNING "initialize_kbd: "
- "reset kbd failed, not POR.\n");
- restore_flags(flags);
- return(-1);
- }
-
- /*
- * now do a DEFAULTS_DISABLE always
- */
- kbd_write(KBD_DATA_REG, KBD_DISABLE);
- if (kbd_wait_for_input() != KBD_ACK) {
- printk(KERN_WARNING "initialize_kbd: "
- "disable kbd failed, no ACK.\n");
- restore_flags(flags);
- return(-1);
- }
-
- /*
- * Enable keyboard interrupt, operate in "sys" mode,
- * enable keyboard (by clearing the disable keyboard bit),
- * disable mouse, do conversion of keycodes.
- */
- kbd_write(KBD_CNTL_REG, KBD_WRITE_MODE);
- kbd_write(KBD_DATA_REG, KBD_EKI|KBD_SYS|KBD_DMS|KBD_KCC);
-
- /*
- * now ENABLE the keyboard to set it scanning...
- */
- kbd_write(KBD_DATA_REG, KBD_ENABLE);
- if (kbd_wait_for_input() != KBD_ACK) {
- printk(KERN_WARNING "initialize_kbd: "
- "keyboard enable failed.\n");
- restore_flags(flags);
- return(-1);
- }
-
- restore_flags(flags);
-
- return (1);
-}
-#endif
-
-extern __inline__ void
-keyboard_setup(void)
+extern __inline__ void keyboard_setup(void)
{
#ifdef CONFIG_MIPS_JAZZ
if (mips_machgroup == MACH_GROUP_JAZZ) {
+ kh = (void *) JAZZ_KEYBOARD_ADDRESS;
kbd_inb_p = jazz_kbd_inb_p;
kbd_inb = jazz_kbd_inb;
kbd_outb_p = jazz_kbd_outb_p;
@@ -308,7 +195,6 @@ keyboard_setup(void)
*/
*((volatile u16 *)JAZZ_IO_IRQ_ENABLE) |= JAZZ_IE_KEYBOARD;
set_cp0_status(IE_IRQ1, IE_IRQ1);
- initialize_kbd();
} else
#endif
if (mips_machgroup == MACH_GROUP_ARC || /* this is for Deskstation */
@@ -334,6 +220,12 @@ keyboard_setup(void)
if (!send_data(0xf0) || !send_data(0x02))
printk("Scanmode 2 change failed\n");
}
+#ifdef CONFIG_SGI
+ if (mips_machgroup == MACH_SGI_INDY) {
+ kh = (struct hpc_keyb *) (KSEG1 + 0x1fbd9800 + 64);
+ }
+#endif
}
+#endif /* __KERNEL */
#endif /* __ASM_MIPS_KEYBOARD_H */
diff --git a/include/asm-mips/mipsprom.h b/include/asm-mips/mipsprom.h
new file mode 100644
index 000000000..ce7cff7f1
--- /dev/null
+++ b/include/asm-mips/mipsprom.h
@@ -0,0 +1,74 @@
+#ifndef __ASM_MIPS_PROM_H
+#define __ASM_MIPS_PROM_H
+
+#define PROM_RESET 0
+#define PROM_EXEC 1
+#define PROM_RESTART 2
+#define PROM_REINIT 3
+#define PROM_REBOOT 4
+#define PROM_AUTOBOOT 5
+#define PROM_OPEN 6
+#define PROM_READ 7
+#define PROM_WRITE 8
+#define PROM_IOCTL 9
+#define PROM_CLOSE 10
+#define PROM_GETCHAR 11
+#define PROM_PUTCHAR 12
+#define PROM_SHOWCHAR 13 /* XXX */
+#define PROM_GETS 14 /* XXX */
+#define PROM_PUTS 15 /* XXX */
+#define PROM_PRINTF 16 /* XXX */
+
+/* What are these for? */
+#define PROM_INITPROTO 17 /* XXX */
+#define PROM_PROTOENABLE 18 /* XXX */
+#define PROM_PROTODISABLE 19 /* XXX */
+#define PROM_GETPKT 20 /* XXX */
+#define PROM_PUTPKT 21 /* XXX */
+
+/* More PROM shit. Probably has to do with VME RMW cycles??? */
+#define PROM_ORW_RMW 22 /* XXX */
+#define PROM_ORH_RMW 23 /* XXX */
+#define PROM_ORB_RMW 24 /* XXX */
+#define PROM_ANDW_RMW 25 /* XXX */
+#define PROM_ANDH_RMW 26 /* XXX */
+#define PROM_ANDB_RMW 27 /* XXX */
+
+/* Cache handling stuff */
+#define PROM_FLUSHCACHE 28 /* XXX */
+#define PROM_CLEARCACHE 29 /* XXX */
+
+/* Libc alike stuff */
+#define PROM_SETJMP 30 /* XXX */
+#define PROM_LONGJMP 31 /* XXX */
+#define PROM_BEVUTLB 32 /* XXX */
+#define PROM_GETENV 33 /* XXX */
+#define PROM_SETENV 34 /* XXX */
+#define PROM_ATOB 35 /* XXX */
+#define PROM_STRCMP 36 /* XXX */
+#define PROM_STRLEN 37 /* XXX */
+#define PROM_STRCPY 38 /* XXX */
+#define PROM_STRCAT 39 /* XXX */
+
+/* Misc stuff */
+#define PROM_PARSER 40 /* XXX */
+#define PROM_RANGE 41 /* XXX */
+#define PROM_ARGVIZE 42 /* XXX */
+#define PROM_HELP 43 /* XXX */
+
+/* Entry points for some PROM commands */
+#define PROM_DUMPCMD 44 /* XXX */
+#define PROM_SETENVCMD 45 /* XXX */
+#define PROM_UNSETENVCMD 46 /* XXX */
+#define PROM_PRINTENVCMD 47 /* XXX */
+#define PROM_BEVEXCEPT 48 /* XXX */
+#define PROM_ENABLECMD 49 /* XXX */
+#define PROM_DISABLECMD 50 /* XXX */
+
+#define PROM_CLEARNOFAULT 51 /* XXX */
+#define PROM_NOTIMPLEMENT 52 /* XXX */
+
+#define PROM_NV_GET 53 /* XXX */
+#define PROM_NV_SET 54 /* XXX */
+
+#endif /* __ASM_MIPS_PROM_H */
diff --git a/include/asm-mips/offset.h b/include/asm-mips/offset.h
index c5e6f37fa..0f6e63a25 100644
--- a/include/asm-mips/offset.h
+++ b/include/asm-mips/offset.h
@@ -48,12 +48,11 @@
/* MIPS task_struct offsets. */
#define TASK_STATE 0
+#define TASK_COUNTER 4
#define TASK_PRIORITY 8
#define TASK_SIGNAL 12
#define TASK_BLOCKED 16
#define TASK_FLAGS 20
-#define TASK_SAVED_KSTACK 84
-#define TASK_KSTACK_PG 88
#define TASK_MM 912
/* MIPS specific thread_struct offsets. */
@@ -82,8 +81,8 @@
#define THREAD_OLDCTX 896
/* Linux mm_struct offsets. */
-#define MM_COUNT 0
-#define MM_PGD 4
-#define MM_CONTEXT 8
+#define MM_COUNT 12
+#define MM_PGD 8
+#define MM_CONTEXT 28
#endif /* !(_MIPS_OFFSET_H) */
diff --git a/include/asm-mips/poll.h b/include/asm-mips/poll.h
index a1d2a47d3..12c1a5ec3 100644
--- a/include/asm-mips/poll.h
+++ b/include/asm-mips/poll.h
@@ -11,7 +11,7 @@
#define POLLRDNORM 0x0040
#define POLLRDBAND 0x0080
-#define POLLWRNORM POLLOUT /* XXX */
+#define POLLWRNORM POLLOUT
#define POLLWRBAND 0x0100
/* XXX This one seems to be more-or-less nonstandard. */
diff --git a/include/asm-mips/processor.h b/include/asm-mips/processor.h
index b202ac4ca..0c47c2580 100644
--- a/include/asm-mips/processor.h
+++ b/include/asm-mips/processor.h
@@ -109,7 +109,7 @@ struct thread_struct {
#endif /* !defined (__LANGUAGE_ASSEMBLY__) */
#define INIT_MMAP { &init_mm, KSEG0, KSEG1, PAGE_SHARED, \
- VM_READ | VM_WRITE | VM_EXEC }
+ VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap }
#define INIT_TSS { \
/* \
@@ -128,7 +128,7 @@ struct thread_struct {
/* \
* Other stuff associated with the process \
*/ \
- 0, 0, 0, sizeof(init_kernel_stack) + (unsigned long)init_kernel_stack - 8, \
+ 0, 0, 0, (unsigned long)&init_task_union + KERNEL_STACK_SIZE - 8, \
(unsigned long) swapper_pg_dir, \
/* \
* For now the default is to fix address errors \
@@ -167,9 +167,8 @@ extern void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long
#define alloc_task_struct() kmalloc(sizeof(struct task_struct), GFP_KERNEL)
#define free_task_struct(p) kfree(p)
-/* Kernel stack allocation/freeing. */
-extern unsigned long alloc_kernel_stack(struct task_struct *tsk);
-extern void free_kernel_stack(unsigned long stack);
+#define init_task (init_task_union.task)
+#define init_stack (init_task_union.stack)
#endif /* !defined (__LANGUAGE_ASSEMBLY__) */
#endif /* __KERNEL__ */
diff --git a/include/asm-mips/sgidefs.h b/include/asm-mips/sgidefs.h
index 23dc0447f..72d25346a 100644
--- a/include/asm-mips/sgidefs.h
+++ b/include/asm-mips/sgidefs.h
@@ -1,6 +1,4 @@
/*
- * Makefile for MIPS Linux main source directory
- *
* 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.
@@ -18,12 +16,32 @@
* problem. The kernel sources are aware of this problem, so we don't warn
* when compiling the kernel.
*/
+#if !defined(_MIPS_ISA) && !defined(__KERNEL__)
+#warning "Macro _MIPS_ISA has not been defined by specs file"
+#endif
+
+#if !defined(_MIPS_SIM) && !defined(__KERNEL__)
+#warning "Macro _MIPS_SIM has not been defined by specs file"
+#endif
+
+#if !defined(_MIPS_SZINT) && !defined(__KERNEL__)
+#warning "Macro _MIPS_SZINT has not been defined by specs file"
+#endif
+
+#if !defined(_MIPS_SZLONG) && !defined(__KERNEL__)
+#warning "Macro _MIPS_SZLONG has not been defined by specs file"
+#endif
+
+#if !defined(_MIPS_SZPTR) && !defined(__KERNEL__)
+#warning "Macro _MIPS_SZPTR has not been defined by specs file"
+#endif
+
#if (!defined(_MIPS_ISA) || \
!defined(_MIPS_SIM) || \
!defined(_MIPS_SZINT) || \
!defined(_MIPS_SZLONG) || \
!defined(_MIPS_SZPTR)) && !defined(__KERNEL__)
-#warning "Please update your GCC to GCC 2.7.2-3 or newer"
+#warning "Please update your GCC to GCC 2.7.2-4 or newer"
#endif
/*
diff --git a/include/asm-mips/sni.h b/include/asm-mips/sni.h
index 6a43b65f4..9ed5919d2 100644
--- a/include/asm-mips/sni.h
+++ b/include/asm-mips/sni.h
@@ -83,4 +83,9 @@
#define PCIMT_IRQ_INTD 24
#define PCIMT_IRQ_SCSI 25
+/*
+ * Base address for the mapped 16mb EISA bus segment.
+ */
+#define PCIMT_EISA_BASE 0xb0000000
+
#endif /* __ASM_MIPS_SNI_H */
diff --git a/include/asm-mips/spinlock.h b/include/asm-mips/spinlock.h
index d1f67424f..85376edfd 100644
--- a/include/asm-mips/spinlock.h
+++ b/include/asm-mips/spinlock.h
@@ -3,6 +3,8 @@
#ifndef __SMP__
+/* gcc 2.7.2 can crash initializing an empty structure. For now we
+ try to do though ... */
typedef struct { } spinlock_t;
#define SPIN_LOCK_UNLOCKED { }
diff --git a/include/asm-mips/system.h b/include/asm-mips/system.h
index 2d4d27871..daf477459 100644
--- a/include/asm-mips/system.h
+++ b/include/asm-mips/system.h
@@ -15,7 +15,7 @@
#include <linux/kernel.h>
extern __inline__ void
-sti(void)
+__sti(void)
{
__asm__ __volatile__(
".set\tnoreorder\n\t"
@@ -39,7 +39,7 @@ sti(void)
* no nops at all.
*/
extern __inline__ void
-cli(void)
+__cli(void)
{
__asm__ __volatile__(
".set\tnoreorder\n\t"
@@ -58,7 +58,7 @@ cli(void)
: "$1", "memory");
}
-#define save_flags(x) \
+#define __save_flags(x) \
__asm__ __volatile__( \
".set\tnoreorder\n\t" \
"mfc0\t%0,$12\n\t" \
@@ -67,7 +67,7 @@ __asm__ __volatile__( \
: /* no inputs */ \
: "memory")
-#define save_and_cli(x) \
+#define __save_and_cli(x) \
__asm__ __volatile__( \
".set\tnoreorder\n\t" \
".set\tnoat\n\t" \
@@ -85,7 +85,7 @@ __asm__ __volatile__( \
: "$1", "memory")
extern void __inline__
-restore_flags(int flags)
+__restore_flags(int flags)
{
__asm__ __volatile__(
".set\tnoreorder\n\t"
@@ -99,6 +99,15 @@ restore_flags(int flags)
: "memory");
}
+/*
+ * Non-SMP versions ...
+ */
+#define sti() __sti()
+#define cli() __cli()
+#define save_flags(x) __save_flags(x)
+#define save_and_cli(x) __save_and_cli(x)
+#define restore_flags(x) __restore_flags(x)
+
#define sync_mem() \
__asm__ __volatile__( \
".set\tnoreorder\n\t" \
diff --git a/include/asm-ppc/keyboard.h b/include/asm-ppc/keyboard.h
new file mode 100644
index 000000000..6cd1391de
--- /dev/null
+++ b/include/asm-ppc/keyboard.h
@@ -0,0 +1,49 @@
+/*
+ * linux/include/asm-ppc/keyboard.h
+ *
+ * Created 3 Nov 1996 by Geert Uytterhoeven
+ */
+
+/*
+ * This file contains the ppc architecture specific keyboard definitions
+ */
+
+#ifndef __ASMPPC_KEYBOARD_H
+#define __ASMPPC_KEYBOARD_H
+
+#ifdef __KERNEL__
+
+#define KEYBOARD_IRQ 1
+#define DISABLE_KBD_DURING_INTERRUPTS 0
+
+#define KBD_REPORT_ERR
+#define KBD_REPORT_UNKN
+/* #define KBD_IS_FOCUS_9000 */
+
+extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
+extern int pckbd_getkeycode(unsigned int scancode);
+extern int pckbd_pretranslate(unsigned char scancode, char raw_mode);
+extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
+ char raw_mode);
+extern char pckbd_unexpected_up(unsigned char keycode);
+extern void pckbd_leds(unsigned char leds);
+extern void pckbd_init_hw(void);
+
+#define kbd_setkeycode pckbd_setkeycode
+#define kbd_getkeycode pckbd_getkeycode
+#define kbd_pretranslate pckbd_pretranslate
+#define kbd_translate pckbd_translate
+#define kbd_unexpected_up pckbd_unexpected_up
+#define kbd_leds pckbd_leds
+#define kbd_init_hw pckbd_init_hw
+
+#define INIT_KBD
+
+extern __inline__ void keyboard_setup()
+{
+ request_region(0x60,16,"keyboard");
+}
+
+#endif /* __KERNEL__ */
+
+#endif /* __ASMPPC_KEYBOARD_H */
diff --git a/include/asm-ppc/processor.h b/include/asm-ppc/processor.h
index ef797b4a7..e3c715c0d 100644
--- a/include/asm-ppc/processor.h
+++ b/include/asm-ppc/processor.h
@@ -116,7 +116,7 @@ struct thread_struct
}
#define INIT_MMAP { &init_mm, 0, 0x40000000, \
- PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC }
+ PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap }
/* Free all resources held by a thread. */
extern void release_thread(struct task_struct *);
diff --git a/include/asm-sparc/asm_offsets.h b/include/asm-sparc/asm_offsets.h
index 3b0abf580..b90462a69 100644
--- a/include/asm-sparc/asm_offsets.h
+++ b/include/asm-sparc/asm_offsets.h
@@ -30,123 +30,125 @@
#define ASIZ_task_next_run 0x00000004
#define AOFF_task_prev_run 0x00000050
#define ASIZ_task_prev_run 0x00000004
-#define AOFF_task_saved_kernel_stack 0x00000054
-#define ASIZ_task_saved_kernel_stack 0x00000004
-#define AOFF_task_kernel_stack_page 0x00000058
-#define ASIZ_task_kernel_stack_page 0x00000004
-#define AOFF_task_exit_code 0x0000005c
+#define AOFF_task_exit_code 0x00000054
#define ASIZ_task_exit_code 0x00000004
-#define AOFF_task_exit_signal 0x00000060
+#define AOFF_task_exit_signal 0x00000058
#define ASIZ_task_exit_signal 0x00000004
-#define AOFF_task_personality 0x00000064
+#define AOFF_task_personality 0x0000005c
#define ASIZ_task_personality 0x00000004
-#define AOFF_task_pid 0x0000006c
+#define AOFF_task_pid 0x00000064
#define ASIZ_task_pid 0x00000004
-#define AOFF_task_pgrp 0x00000070
+#define AOFF_task_pgrp 0x00000068
#define ASIZ_task_pgrp 0x00000004
-#define AOFF_task_tty_old_pgrp 0x00000074
+#define AOFF_task_tty_old_pgrp 0x0000006c
#define ASIZ_task_tty_old_pgrp 0x00000004
-#define AOFF_task_session 0x00000078
+#define AOFF_task_session 0x00000070
#define ASIZ_task_session 0x00000004
-#define AOFF_task_leader 0x0000007c
+#define AOFF_task_leader 0x00000074
#define ASIZ_task_leader 0x00000004
-#define AOFF_task_ngroups 0x00000080
+#define AOFF_task_ngroups 0x00000078
#define ASIZ_task_ngroups 0x00000004
-#define AOFF_task_groups 0x00000084
+#define AOFF_task_groups 0x0000007c
#define ASIZ_task_groups 0x00000040
-#define AOFF_task_p_opptr 0x000000c4
+#define AOFF_task_p_opptr 0x000000bc
#define ASIZ_task_p_opptr 0x00000004
-#define AOFF_task_p_pptr 0x000000c8
+#define AOFF_task_p_pptr 0x000000c0
#define ASIZ_task_p_pptr 0x00000004
-#define AOFF_task_p_cptr 0x000000cc
+#define AOFF_task_p_cptr 0x000000c4
#define ASIZ_task_p_cptr 0x00000004
-#define AOFF_task_p_ysptr 0x000000d0
+#define AOFF_task_p_ysptr 0x000000c8
#define ASIZ_task_p_ysptr 0x00000004
-#define AOFF_task_p_osptr 0x000000d4
+#define AOFF_task_p_osptr 0x000000cc
#define ASIZ_task_p_osptr 0x00000004
-#define AOFF_task_wait_chldexit 0x000000d8
+#define AOFF_task_pidhash_next 0x000000d0
+#define ASIZ_task_pidhash_next 0x00000004
+#define AOFF_task_pidhash_pprev 0x000000d4
+#define ASIZ_task_pidhash_pprev 0x00000004
+#define AOFF_task_tarray_ptr 0x000000d8
+#define ASIZ_task_tarray_ptr 0x00000004
+#define AOFF_task_wait_chldexit 0x000000dc
#define ASIZ_task_wait_chldexit 0x00000004
-#define AOFF_task_uid 0x000000dc
+#define AOFF_task_uid 0x000000e0
#define ASIZ_task_uid 0x00000002
-#define AOFF_task_euid 0x000000de
+#define AOFF_task_euid 0x000000e2
#define ASIZ_task_euid 0x00000002
-#define AOFF_task_suid 0x000000e0
+#define AOFF_task_suid 0x000000e4
#define ASIZ_task_suid 0x00000002
-#define AOFF_task_fsuid 0x000000e2
+#define AOFF_task_fsuid 0x000000e6
#define ASIZ_task_fsuid 0x00000002
-#define AOFF_task_gid 0x000000e4
+#define AOFF_task_gid 0x000000e8
#define ASIZ_task_gid 0x00000002
-#define AOFF_task_egid 0x000000e6
+#define AOFF_task_egid 0x000000ea
#define ASIZ_task_egid 0x00000002
-#define AOFF_task_sgid 0x000000e8
+#define AOFF_task_sgid 0x000000ec
#define ASIZ_task_sgid 0x00000002
-#define AOFF_task_fsgid 0x000000ea
+#define AOFF_task_fsgid 0x000000ee
#define ASIZ_task_fsgid 0x00000002
-#define AOFF_task_timeout 0x000000ec
+#define AOFF_task_timeout 0x000000f0
#define ASIZ_task_timeout 0x00000004
-#define AOFF_task_policy 0x000000f0
+#define AOFF_task_policy 0x000000f4
#define ASIZ_task_policy 0x00000004
-#define AOFF_task_rt_priority 0x000000f4
+#define AOFF_task_rt_priority 0x000000f8
#define ASIZ_task_rt_priority 0x00000004
-#define AOFF_task_it_real_value 0x000000f8
+#define AOFF_task_it_real_value 0x000000fc
#define ASIZ_task_it_real_value 0x00000004
-#define AOFF_task_it_prof_value 0x000000fc
+#define AOFF_task_it_prof_value 0x00000100
#define ASIZ_task_it_prof_value 0x00000004
-#define AOFF_task_it_virt_value 0x00000100
+#define AOFF_task_it_virt_value 0x00000104
#define ASIZ_task_it_virt_value 0x00000004
-#define AOFF_task_it_real_incr 0x00000104
+#define AOFF_task_it_real_incr 0x00000108
#define ASIZ_task_it_real_incr 0x00000004
-#define AOFF_task_it_prof_incr 0x00000108
+#define AOFF_task_it_prof_incr 0x0000010c
#define ASIZ_task_it_prof_incr 0x00000004
-#define AOFF_task_it_virt_incr 0x0000010c
+#define AOFF_task_it_virt_incr 0x00000110
#define ASIZ_task_it_virt_incr 0x00000004
-#define AOFF_task_real_timer 0x00000110
+#define AOFF_task_real_timer 0x00000114
#define ASIZ_task_real_timer 0x00000014
-#define AOFF_task_utime 0x00000124
+#define AOFF_task_utime 0x00000128
#define ASIZ_task_utime 0x00000004
-#define AOFF_task_stime 0x00000128
+#define AOFF_task_stime 0x0000012c
#define ASIZ_task_stime 0x00000004
-#define AOFF_task_cutime 0x0000012c
+#define AOFF_task_cutime 0x00000130
#define ASIZ_task_cutime 0x00000004
-#define AOFF_task_cstime 0x00000130
+#define AOFF_task_cstime 0x00000134
#define ASIZ_task_cstime 0x00000004
-#define AOFF_task_start_time 0x00000134
+#define AOFF_task_start_time 0x00000138
#define ASIZ_task_start_time 0x00000004
-#define AOFF_task_min_flt 0x00000138
+#define AOFF_task_min_flt 0x0000013c
#define ASIZ_task_min_flt 0x00000004
-#define AOFF_task_maj_flt 0x0000013c
+#define AOFF_task_maj_flt 0x00000140
#define ASIZ_task_maj_flt 0x00000004
-#define AOFF_task_nswap 0x00000140
+#define AOFF_task_nswap 0x00000144
#define ASIZ_task_nswap 0x00000004
-#define AOFF_task_cmin_flt 0x00000144
+#define AOFF_task_cmin_flt 0x00000148
#define ASIZ_task_cmin_flt 0x00000004
-#define AOFF_task_cmaj_flt 0x00000148
+#define AOFF_task_cmaj_flt 0x0000014c
#define ASIZ_task_cmaj_flt 0x00000004
-#define AOFF_task_cnswap 0x0000014c
+#define AOFF_task_cnswap 0x00000150
#define ASIZ_task_cnswap 0x00000004
-#define AOFF_task_swap_address 0x00000154
+#define AOFF_task_swap_address 0x00000158
#define ASIZ_task_swap_address 0x00000004
-#define AOFF_task_old_maj_flt 0x00000158
+#define AOFF_task_old_maj_flt 0x0000015c
#define ASIZ_task_old_maj_flt 0x00000004
-#define AOFF_task_dec_flt 0x0000015c
+#define AOFF_task_dec_flt 0x00000160
#define ASIZ_task_dec_flt 0x00000004
-#define AOFF_task_swap_cnt 0x00000160
+#define AOFF_task_swap_cnt 0x00000164
#define ASIZ_task_swap_cnt 0x00000004
-#define AOFF_task_rlim 0x00000164
+#define AOFF_task_rlim 0x00000168
#define ASIZ_task_rlim 0x00000050
-#define AOFF_task_used_math 0x000001b4
+#define AOFF_task_used_math 0x000001b8
#define ASIZ_task_used_math 0x00000002
-#define AOFF_task_comm 0x000001b6
+#define AOFF_task_comm 0x000001ba
#define ASIZ_task_comm 0x00000010
-#define AOFF_task_link_count 0x000001c8
+#define AOFF_task_link_count 0x000001cc
#define ASIZ_task_link_count 0x00000004
-#define AOFF_task_tty 0x000001cc
+#define AOFF_task_tty 0x000001d0
#define ASIZ_task_tty 0x00000004
-#define AOFF_task_semundo 0x000001d0
+#define AOFF_task_semundo 0x000001d4
#define ASIZ_task_semundo 0x00000004
-#define AOFF_task_semsleeping 0x000001d4
+#define AOFF_task_semsleeping 0x000001d8
#define ASIZ_task_semsleeping 0x00000004
-#define AOFF_task_ldt 0x000001d8
+#define AOFF_task_ldt 0x000001dc
#define ASIZ_task_ldt 0x00000004
#define AOFF_task_tss 0x000001e0
#define ASIZ_task_tss 0x00000390
@@ -158,56 +160,60 @@
#define ASIZ_task_mm 0x00000004
#define AOFF_task_sig 0x0000057c
#define ASIZ_task_sig 0x00000004
-#define AOFF_task_processor 0x00000580
+#define AOFF_task_has_cpu 0x00000580
+#define ASIZ_task_has_cpu 0x00000004
+#define AOFF_task_processor 0x00000584
#define ASIZ_task_processor 0x00000004
-#define AOFF_task_last_processor 0x00000584
+#define AOFF_task_last_processor 0x00000588
#define ASIZ_task_last_processor 0x00000004
-#define AOFF_task_lock_depth 0x00000588
+#define AOFF_task_lock_depth 0x0000058c
#define ASIZ_task_lock_depth 0x00000004
-#define AOFF_mm_count 0x00000000
-#define ASIZ_mm_count 0x00000004
-#define AOFF_mm_pgd 0x00000004
+#define AOFF_task_sigmask_lock 0x00000590
+#define ASIZ_task_sigmask_lock 0x00000000
+#define AOFF_mm_mmap 0x00000000
+#define ASIZ_mm_mmap 0x00000004
+#define AOFF_mm_mmap_cache 0x00000004
+#define ASIZ_mm_mmap_cache 0x00000004
+#define AOFF_mm_pgd 0x00000008
#define ASIZ_mm_pgd 0x00000004
-#define AOFF_mm_context 0x00000008
+#define AOFF_mm_count 0x0000000c
+#define ASIZ_mm_count 0x00000004
+#define AOFF_mm_mmap_sem 0x00000010
+#define ASIZ_mm_mmap_sem 0x0000000c
+#define AOFF_mm_context 0x0000001c
#define ASIZ_mm_context 0x00000004
-#define AOFF_mm_start_code 0x0000000c
+#define AOFF_mm_start_code 0x00000020
#define ASIZ_mm_start_code 0x00000004
-#define AOFF_mm_end_code 0x00000010
+#define AOFF_mm_end_code 0x00000024
#define ASIZ_mm_end_code 0x00000004
-#define AOFF_mm_start_data 0x00000014
+#define AOFF_mm_start_data 0x00000028
#define ASIZ_mm_start_data 0x00000004
-#define AOFF_mm_end_data 0x00000018
+#define AOFF_mm_end_data 0x0000002c
#define ASIZ_mm_end_data 0x00000004
-#define AOFF_mm_start_brk 0x0000001c
+#define AOFF_mm_start_brk 0x00000030
#define ASIZ_mm_start_brk 0x00000004
-#define AOFF_mm_brk 0x00000020
+#define AOFF_mm_brk 0x00000034
#define ASIZ_mm_brk 0x00000004
-#define AOFF_mm_start_stack 0x00000024
+#define AOFF_mm_start_stack 0x00000038
#define ASIZ_mm_start_stack 0x00000004
-#define AOFF_mm_start_mmap 0x00000028
+#define AOFF_mm_start_mmap 0x0000003c
#define ASIZ_mm_start_mmap 0x00000004
-#define AOFF_mm_arg_start 0x0000002c
+#define AOFF_mm_arg_start 0x00000040
#define ASIZ_mm_arg_start 0x00000004
-#define AOFF_mm_arg_end 0x00000030
+#define AOFF_mm_arg_end 0x00000044
#define ASIZ_mm_arg_end 0x00000004
-#define AOFF_mm_env_start 0x00000034
+#define AOFF_mm_env_start 0x00000048
#define ASIZ_mm_env_start 0x00000004
-#define AOFF_mm_env_end 0x00000038
+#define AOFF_mm_env_end 0x0000004c
#define ASIZ_mm_env_end 0x00000004
-#define AOFF_mm_rss 0x0000003c
+#define AOFF_mm_rss 0x00000050
#define ASIZ_mm_rss 0x00000004
-#define AOFF_mm_total_vm 0x00000040
+#define AOFF_mm_total_vm 0x00000054
#define ASIZ_mm_total_vm 0x00000004
-#define AOFF_mm_locked_vm 0x00000044
+#define AOFF_mm_locked_vm 0x00000058
#define ASIZ_mm_locked_vm 0x00000004
-#define AOFF_mm_def_flags 0x00000048
+#define AOFF_mm_def_flags 0x0000005c
#define ASIZ_mm_def_flags 0x00000004
-#define AOFF_mm_mmap 0x0000004c
-#define ASIZ_mm_mmap 0x00000004
-#define AOFF_mm_mmap_avl 0x00000050
-#define ASIZ_mm_mmap_avl 0x00000004
-#define AOFF_mm_mmap_sem 0x00000054
-#define ASIZ_mm_mmap_sem 0x0000000c
#define AOFF_thread_uwinmask 0x00000000
#define ASIZ_thread_uwinmask 0x00000004
#define AOFF_thread_kregs 0x00000004
diff --git a/include/asm-sparc/asmmacro.h b/include/asm-sparc/asmmacro.h
index 25211c93f..40c71b0d6 100644
--- a/include/asm-sparc/asmmacro.h
+++ b/include/asm-sparc/asmmacro.h
@@ -6,22 +6,22 @@
#ifndef _SPARC_ASMMACRO_H
#define _SPARC_ASMMACRO_H
-/* #define SMP_DEBUG */
-
#define GET_PROCESSOR_ID(reg) \
rd %tbr, %reg; \
srl %reg, 12, %reg; \
and %reg, 3, %reg;
#define GET_PROCESSOR_MID(reg, tmp) \
- GET_PROCESSOR_ID(reg) \
- set C_LABEL(mid_xlate), %tmp; \
+ rd %tbr, %reg; \
+ sethi C_LABEL(mid_xlate), %tmp; \
+ srl %reg, 12, %reg; \
+ or %tmp, %lo(C_LABEL(mid_xlate)), %tmp; \
+ and %reg, 3, %reg; \
ldub [%tmp + %reg], %reg;
#define GET_PROCESSOR_OFFSET(reg) \
- rd %tbr, %reg; \
- srl %reg, 10, %reg; \
- and %reg, 0xc, %reg;
+ GET_PROCESSOR_ID(reg) \
+ sll %reg, 2, %reg;
#define PROCESSOR_OFFSET_TO_ID(reg) \
srl %reg, 2, %reg;
diff --git a/include/asm-sparc/auxio.h b/include/asm-sparc/auxio.h
index f5b9d5591..f70a447bf 100644
--- a/include/asm-sparc/auxio.h
+++ b/include/asm-sparc/auxio.h
@@ -1,4 +1,4 @@
-/* $Id: auxio.h,v 1.16 1997/01/31 23:26:05 tdyas Exp $
+/* $Id: auxio.h,v 1.17 1997/05/01 01:42:02 davem Exp $
* auxio.h: Definitions and code for the Auxiliary I/O register.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -43,30 +43,27 @@ extern unsigned char *auxio_register;
#define FLPY_TCNTOFF if (AUXREG) *AUXREG = ((*AUXREG | AUXIO_ORMEIN) & (~AUXIO_FLPY_TCNT))
#ifndef __ASSEMBLY__
-extern __inline__ void set_auxio(unsigned char bits_on, unsigned char bits_off)
-{
- unsigned char regval;
- unsigned long flags;
-
- save_flags(flags); cli();
-
- switch(sparc_cpu_model) {
- case sun4c:
- regval = *AUXREG;
- *AUXREG = ((regval | bits_on) & ~bits_off) | AUXIO_ORMEIN;
- break;
- case sun4m:
- if(!AUXREG)
- break; /* VME chassic sun4m, no auxio. */
- regval = *AUXREG;
- *AUXREG = ((regval | bits_on) & ~bits_off) | AUXIO_ORMEIN4M;
- break;
- default:
- panic("Can't set AUXIO register on this machine.");
- };
-
- restore_flags(flags);
-}
+#define set_auxio(bits_on, bits_off) \
+do { \
+ unsigned char regval; \
+ unsigned long flags; \
+ save_flags(flags); cli(); \
+ switch(sparc_cpu_model) { \
+ case sun4c: \
+ regval = *AUXREG; \
+ *AUXREG = ((regval | bits_on) & ~bits_off) | AUXIO_ORMEIN; \
+ break; \
+ case sun4m: \
+ if(!AUXREG) \
+ break; /* VME chassic sun4m, no auxio. */ \
+ regval = *AUXREG; \
+ *AUXREG = ((regval | bits_on) & ~bits_off) | AUXIO_ORMEIN4M; \
+ break; \
+ default: \
+ panic("Can't set AUXIO register on this machine."); \
+ }; \
+ restore_flags(flags); \
+} while(0)
#endif /* !(__ASSEMBLY__) */
diff --git a/include/asm-sparc/bitops.h b/include/asm-sparc/bitops.h
index f78b3b22a..cd4a8ef8c 100644
--- a/include/asm-sparc/bitops.h
+++ b/include/asm-sparc/bitops.h
@@ -1,4 +1,4 @@
-/* $Id: bitops.h,v 1.46 1997/04/13 06:38:24 davem Exp $
+/* $Id: bitops.h,v 1.47 1997/05/14 20:47:56 davem Exp $
* bitops.h: Bit string operations on the Sparc.
*
* Copyright 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -95,7 +95,7 @@ extern __inline__ unsigned long change_bit(unsigned long nr, void *addr)
* all bit-ops return 0 if bit was previously clear and != 0 otherwise.
*/
-extern __inline__ unsigned long set_bit(unsigned long nr, __SMPVOL void *addr)
+extern __inline__ unsigned long test_and_set_bit(unsigned long nr, __SMPVOL void *addr)
{
register unsigned long mask asm("g2");
register unsigned long *ADDR asm("g1");
@@ -112,7 +112,12 @@ extern __inline__ unsigned long set_bit(unsigned long nr, __SMPVOL void *addr)
return mask;
}
-extern __inline__ unsigned long clear_bit(unsigned long nr, __SMPVOL void *addr)
+extern __inline__ void set_bit(unsigned long nr, __SMPVOL void *addr)
+{
+ (void) test_and_set_bit(nr, addr);
+}
+
+extern __inline__ unsigned long test_and_clear_bit(unsigned long nr, __SMPVOL void *addr)
{
register unsigned long mask asm("g2");
register unsigned long *ADDR asm("g1");
@@ -130,7 +135,12 @@ extern __inline__ unsigned long clear_bit(unsigned long nr, __SMPVOL void *addr)
return mask;
}
-extern __inline__ unsigned long change_bit(unsigned long nr, __SMPVOL void *addr)
+extern __inline__ unsigned long clear_bit(unsigned long nr, __SMPVOL void *addr)
+{
+ (void) test_and_clear_bit(nr, addr);
+}
+
+extern __inline__ unsigned long test_and_change_bit(unsigned long nr, __SMPVOL void *addr)
{
register unsigned long mask asm("g2");
register unsigned long *ADDR asm("g1");
@@ -148,6 +158,11 @@ extern __inline__ unsigned long change_bit(unsigned long nr, __SMPVOL void *addr
return mask;
}
+extern __inline__ unsigned long change_bit(unsigned long nr, __SMPVOL void *addr)
+{
+ (void) test_and_change_bit(nr, addr);
+}
+
#endif /* __KERNEL__ */
/* The following routine need not be atomic. */
@@ -369,8 +384,8 @@ found_middle:
#define ext2_find_next_zero_bit find_next_zero_le_bit
/* Bitmap functions for the minix filesystem. */
-#define minix_set_bit(nr,addr) set_bit(nr,addr)
-#define minix_clear_bit(nr,addr) clear_bit(nr,addr)
+#define minix_set_bit(nr,addr) test_and_set_bit(nr,addr)
+#define minix_clear_bit(nr,addr) test_and_clear_bit(nr,addr)
#define minix_test_bit(nr,addr) test_bit(nr,addr)
#define minix_find_first_zero_bit(addr,size) find_first_zero_bit(addr,size)
diff --git a/include/asm-sparc/cache.h b/include/asm-sparc/cache.h
index f1e694ea6..55475a5a1 100644
--- a/include/asm-sparc/cache.h
+++ b/include/asm-sparc/cache.h
@@ -1,4 +1,4 @@
-/* $Id: cache.h,v 1.6 1996/12/28 19:55:12 davem Exp $
+/* $Id: cache.h,v 1.7 1997/05/06 09:31:46 davem Exp $
* cache.h: Cache specific code for the Sparc. These include flushing
* and direct tag/data line access.
*
@@ -11,6 +11,7 @@
#include <asm/asi.h>
#define L1_CACHE_BYTES 32
+#define L1_CACHE_ALIGN(x) ((((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1)))
/* Direct access to the instruction cache is provided through and
* alternate address space. The IDC bit must be off in the ICCR on
diff --git a/include/asm-sparc/current.h b/include/asm-sparc/current.h
index 254ce5618..66cf661e4 100644
--- a/include/asm-sparc/current.h
+++ b/include/asm-sparc/current.h
@@ -1,12 +1,6 @@
#ifndef _SPARC_CURRENT_H
#define _SPARC_CURRENT_H
-/* Some architectures may want to do something "clever" here since
- * this is the most frequently accessed piece of data in the entire
- * kernel.
- */
-extern struct task_struct *current_set[NR_CPUS];
-
/* Sparc rules... */
register struct task_struct *current asm("g6");
diff --git a/include/asm-sparc/hardirq.h b/include/asm-sparc/hardirq.h
index 2d3f70bc6..8b0f4f9e2 100644
--- a/include/asm-sparc/hardirq.h
+++ b/include/asm-sparc/hardirq.h
@@ -51,7 +51,7 @@ do { if(global_irq_holder == (unsigned char) cpu) { \
__save_flags(flags); \
__cli(); \
if(atomic_add_return(1, &global_irq_count) != 1 || \
- global_irq_lock) { \
+ *(((unsigned char *)(&global_irq_lock)))) { \
atomic_dec(&global_irq_count); \
__restore_flags(flags); \
ret = 0; \
diff --git a/include/asm-sparc/irq.h b/include/asm-sparc/irq.h
index 16c2ca5a1..daac48d56 100644
--- a/include/asm-sparc/irq.h
+++ b/include/asm-sparc/irq.h
@@ -1,4 +1,4 @@
-/* $Id: irq.h,v 1.17 1997/04/18 05:44:52 davem Exp $
+/* $Id: irq.h,v 1.19 1997/05/08 20:57:39 davem Exp $
* irq.h: IRQ registers on the Sparc.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -13,8 +13,17 @@
#define NR_IRQS 15
+/* Get rid of this when lockups have gone away. -DaveM */
+#ifndef DEBUG_IRQLOCK
+#define DEBUG_IRQLOCK
+#endif
+
/* IRQ handler dispatch entry and exit. */
#ifdef __SMP__
+#ifdef DEBUG_IRQLOCK
+extern void irq_enter(int cpu, int irq, void *regs);
+extern void irq_exit(int cpu, int irq);
+#else
extern __inline__ void irq_enter(int cpu, int irq)
{
register int proc asm("g1");
@@ -40,6 +49,7 @@ extern __inline__ void irq_exit(int cpu, int irq)
: "0" (proc)
: "g1", "g2", "g3", "g4", "g5", "memory", "cc");
}
+#endif /* DEBUG_IRQLOCK */
#else
#define irq_enter(cpu, irq) (local_irq_count[cpu]++)
#define irq_exit(cpu, irq) (local_irq_count[cpu]--)
diff --git a/include/asm-sparc/linux_logo.h b/include/asm-sparc/linux_logo.h
index 4c323b49e..a8b8ff1b4 100644
--- a/include/asm-sparc/linux_logo.h
+++ b/include/asm-sparc/linux_logo.h
@@ -1043,1048 +1043,3 @@ unsigned char *linux_serial_image __initdata = "\n"
"'!!!!!!!W..e$$!!!!!!` %s\n"
" \"~^^~ ^~~^\n"
"\n";
-/* $Id: linux_logo.h,v 1.1 1997/04/16 17:51:24 jj Exp $
- * include/asm-sparc/linux_logo.h: This is a linux logo
- * to be displayed on boot.
- *
- * Copyright (C) 1996 Larry Ewing (lewing@isc.tamu.edu)
- * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- *
- * You can put anything here, but:
- * LINUX_LOGO_COLORS has to be less than 224
- * image size has to be 80x80
- * values have to start from 0x20
- * (i.e. RGB(linux_logo_red[0],
- * linux_logo_green[0],
- * linux_logo_blue[0]) is color 0x20)
- * BW image has to be 80x80 as well, with MS bit
- * on the left
- * Serial_console ascii image can be any size,
- * but should contain %s to display the version
- */
-
-#include <linux/init.h>
-#include <linux/version.h>
-
-#define linux_logo_banner "Linux/SPARC version " UTS_RELEASE
-
-#define LINUX_LOGO_COLORS 221
-
-unsigned char linux_logo_red[] __initdata = {
- 0xF3, 0xF6, 0xF8, 0xF7, 0xEF, 0xE7, 0xE5, 0xE3,
- 0xCA, 0xD4, 0xDD, 0xC8, 0xC7, 0xC4, 0xC2, 0xE5,
- 0xF1, 0xED, 0xEE, 0xE6, 0xC6, 0xDA, 0xDD, 0xE5,
- 0xD9, 0xC6, 0xE3, 0xD0, 0xC6, 0xBA, 0xB0, 0xB6,
- 0xBB, 0xBE, 0xB9, 0xB8, 0xB3, 0xB2, 0xB0, 0xAD,
- 0xAC, 0xA9, 0xA8, 0xA6, 0xA4, 0xA1, 0xA0, 0x9D,
- 0xA0, 0x9F, 0x9E, 0x9C, 0x9B, 0x99, 0x9A, 0x99,
- 0x98, 0x95, 0x96, 0x94, 0x93, 0x92, 0x8F, 0x8D,
- 0x8C, 0x8A, 0x87, 0x86, 0x83, 0x81, 0x0D, 0x03,
- 0x66, 0x44, 0x24, 0x08, 0xD6, 0xE6, 0xE9, 0xE6,
- 0xE7, 0xCA, 0xDC, 0xDB, 0xD5, 0xD0, 0xC9, 0xE2,
- 0xD5, 0xC6, 0xC4, 0xB3, 0xB2, 0xB9, 0xA9, 0x9A,
- 0xB2, 0x9D, 0xE8, 0xEC, 0xF5, 0xF5, 0xF4, 0xF4,
- 0xEC, 0xEE, 0xF0, 0xF5, 0xE0, 0xD6, 0xC5, 0xC2,
- 0xD9, 0xD5, 0xD8, 0xD6, 0xF6, 0xF4, 0xED, 0xEC,
- 0xEB, 0xF1, 0xF6, 0xF5, 0xF5, 0xEE, 0xEF, 0xEC,
- 0xE7, 0xE3, 0xE6, 0xD6, 0xDD, 0xC3, 0xD6, 0xD7,
- 0xCD, 0xCA, 0xC3, 0xAC, 0x95, 0x99, 0xB7, 0xA3,
- 0x8B, 0x88, 0x95, 0x8A, 0x94, 0xD2, 0xCC, 0xC4,
- 0xA8, 0x8E, 0x8F, 0xAE, 0xB8, 0xAC, 0xB6, 0xB4,
- 0xAD, 0xA5, 0xA0, 0x9B, 0x8B, 0xA3, 0x94, 0x87,
- 0x85, 0x89, 0x53, 0x80, 0x7D, 0x7C, 0x7A, 0x78,
- 0x76, 0x71, 0x73, 0x6E, 0x6B, 0x67, 0x65, 0x62,
- 0x4B, 0x5B, 0x5F, 0x53, 0x56, 0x52, 0x4F, 0x46,
- 0x42, 0x0F, 0x75, 0x78, 0x7D, 0x72, 0x5F, 0x6E,
- 0x7A, 0x75, 0x6A, 0x58, 0x48, 0x4F, 0x00, 0x2B,
- 0x37, 0x3E, 0x32, 0x33, 0x25, 0x2C, 0x3B, 0x11,
- 0x1D, 0x14, 0x06, 0x02, 0x00
-};
-
-unsigned char linux_logo_green[] __initdata = {
- 0xF3, 0xF6, 0xF8, 0xF7, 0xEF, 0xE7, 0xE5, 0xE3,
- 0xCA, 0xD4, 0xDD, 0xC8, 0xC7, 0xC4, 0xC2, 0xD3,
- 0xDA, 0xD4, 0xD7, 0xCC, 0xC1, 0xCC, 0xCB, 0xC9,
- 0xC5, 0xBC, 0xBC, 0xBB, 0xB7, 0xA5, 0xB0, 0xB6,
- 0xBB, 0xBE, 0xB9, 0xB8, 0xB3, 0xB2, 0xAD, 0xAD,
- 0xAC, 0xA9, 0xA8, 0xA6, 0xA4, 0xA1, 0xA0, 0x95,
- 0xA0, 0x9F, 0x9E, 0x9C, 0x9B, 0x99, 0x9A, 0x99,
- 0x98, 0x95, 0x96, 0x94, 0x93, 0x92, 0x8F, 0x8D,
- 0x8C, 0x8A, 0x87, 0x86, 0x83, 0x81, 0x08, 0x02,
- 0x53, 0x2E, 0x19, 0x06, 0xC6, 0xC8, 0xCF, 0xBD,
- 0xB3, 0xB6, 0xB4, 0xAB, 0xA5, 0xA3, 0x9B, 0xB6,
- 0xA7, 0x99, 0x92, 0xA4, 0x9E, 0x9D, 0x98, 0x8C,
- 0x8A, 0x86, 0xCD, 0xCC, 0xC9, 0xD7, 0xCA, 0xC4,
- 0xCA, 0xC3, 0xC7, 0xC3, 0xC8, 0xB4, 0x91, 0x8E,
- 0x8A, 0x82, 0x87, 0x85, 0xBD, 0xBF, 0xB6, 0xBC,
- 0xAE, 0xB7, 0xBC, 0xB8, 0xBF, 0xB6, 0xBC, 0xB5,
- 0xAB, 0xA6, 0xAD, 0xB2, 0xA5, 0x87, 0x9C, 0x96,
- 0x95, 0x8E, 0x87, 0x8F, 0x86, 0x86, 0x8E, 0x80,
- 0x7A, 0x70, 0x7B, 0x78, 0x78, 0x7F, 0x77, 0x6F,
- 0x70, 0x76, 0x59, 0x77, 0x68, 0x64, 0x7B, 0x7C,
- 0x75, 0x6D, 0x77, 0x69, 0x65, 0x5F, 0x5B, 0x54,
- 0x4F, 0x5B, 0x39, 0x80, 0x7D, 0x7C, 0x7A, 0x78,
- 0x76, 0x71, 0x73, 0x6E, 0x6B, 0x67, 0x65, 0x62,
- 0x4B, 0x5B, 0x5F, 0x53, 0x56, 0x52, 0x4F, 0x46,
- 0x42, 0x0B, 0x69, 0x66, 0x64, 0x57, 0x4A, 0x4E,
- 0x55, 0x4B, 0x46, 0x3B, 0x30, 0x33, 0x00, 0x2B,
- 0x37, 0x3E, 0x32, 0x33, 0x25, 0x2C, 0x29, 0x0D,
- 0x1D, 0x14, 0x06, 0x02, 0x00
-};
-
-unsigned char linux_logo_blue[] __initdata = {
- 0xF3, 0xF6, 0xF8, 0xF7, 0xEF, 0xEE, 0xE5, 0xDE,
- 0xD7, 0xD3, 0xDD, 0xC8, 0xC7, 0xC4, 0xC2, 0xB5,
- 0xB0, 0xA6, 0xAC, 0x9B, 0xB5, 0xB5, 0xAE, 0x84,
- 0x90, 0xA9, 0x81, 0x8D, 0x96, 0x86, 0xB0, 0xB6,
- 0xBB, 0xBE, 0xB9, 0xB8, 0xB3, 0xB2, 0xA7, 0xAD,
- 0xAC, 0xA9, 0xA8, 0xA6, 0xA4, 0xA1, 0xA5, 0x87,
- 0xA0, 0x9F, 0x9E, 0x9C, 0x9B, 0x9A, 0x9A, 0x99,
- 0x98, 0x95, 0x96, 0x94, 0x93, 0x92, 0x8F, 0x8D,
- 0x8C, 0x8A, 0x87, 0x86, 0x83, 0x81, 0xC8, 0xD7,
- 0x9B, 0x8E, 0x8C, 0xB2, 0x77, 0x77, 0x4E, 0x77,
- 0x69, 0x71, 0x78, 0x6B, 0x65, 0x66, 0x64, 0x59,
- 0x5C, 0x5A, 0x48, 0x72, 0x7B, 0x6B, 0x67, 0x6E,
- 0x42, 0x5B, 0x29, 0x36, 0x25, 0x10, 0x17, 0x14,
- 0x19, 0x16, 0x13, 0x0E, 0x08, 0x2E, 0x2E, 0x3D,
- 0x24, 0x24, 0x24, 0x24, 0x13, 0x12, 0x14, 0x14,
- 0x0E, 0x08, 0x0D, 0x0F, 0x08, 0x0D, 0x0E, 0x08,
- 0x08, 0x0C, 0x06, 0x06, 0x07, 0x16, 0x07, 0x0E,
- 0x08, 0x0A, 0x07, 0x0D, 0x2D, 0x3E, 0x09, 0x4E,
- 0x68, 0x52, 0x56, 0x58, 0x4B, 0x22, 0x20, 0x20,
- 0x27, 0x39, 0x28, 0x19, 0x1E, 0x1E, 0x08, 0x06,
- 0x07, 0x09, 0x08, 0x08, 0x05, 0x1D, 0x1F, 0x17,
- 0x18, 0x06, 0x79, 0x80, 0x7D, 0x7C, 0x7A, 0x78,
- 0x76, 0x71, 0x73, 0x6E, 0x6B, 0x68, 0x65, 0x62,
- 0x4B, 0x5B, 0x5F, 0x55, 0x56, 0x52, 0x4F, 0x46,
- 0x42, 0x5A, 0x14, 0x23, 0x3D, 0x2B, 0x21, 0x14,
- 0x06, 0x04, 0x03, 0x07, 0x09, 0x13, 0x2A, 0x3A,
- 0x37, 0x3E, 0x32, 0x33, 0x25, 0x2C, 0x07, 0x09,
- 0x1D, 0x14, 0x06, 0x02, 0x00
-};
-
-unsigned char linux_logo[] __initdata = {
- 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
- 0x57, 0x57, 0x58, 0x57, 0x57, 0x57, 0x57, 0x57,
- 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x58, 0x57,
- 0x58, 0x58, 0x59, 0x5C, 0x5D, 0x5F, 0x60, 0x61,
- 0x62, 0x61, 0x61, 0x62, 0x62, 0x62, 0x63, 0x63,
- 0x61, 0x61, 0x61, 0x61, 0x61, 0x60, 0x5E, 0x5E,
- 0x5E, 0x5D, 0x5D, 0x5C, 0x5D, 0x5B, 0x58, 0x58,
- 0x58, 0x57, 0x58, 0x57, 0x57, 0x57, 0x57, 0x58,
- 0x57, 0x57, 0x58, 0x57, 0x57, 0x58, 0x57, 0x57,
- 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
- 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
- 0x57, 0x57, 0x58, 0x57, 0x57, 0x57, 0x57, 0x57,
- 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x58, 0x57,
- 0x54, 0x56, 0x57, 0x67, 0xFC, 0xFC, 0xFC, 0xFC,
- 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x67, 0x4C,
- 0x4A, 0x49, 0x4A, 0x49, 0x4A, 0x49, 0x49, 0x4A,
- 0x4A, 0x4B, 0x4B, 0x4B, 0x4C, 0x50, 0x51, 0x52,
- 0x54, 0x54, 0x56, 0x57, 0x57, 0x57, 0x57, 0x58,
- 0x57, 0x57, 0x58, 0x57, 0x57, 0x58, 0x57, 0x57,
- 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
- 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
- 0x57, 0x57, 0x58, 0x57, 0x57, 0x57, 0x57, 0x57,
- 0x57, 0x57, 0x57, 0x57, 0x58, 0x56, 0x56, 0x53,
- 0x52, 0x53, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
- 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFB, 0xFB, 0xFB,
- 0x4B, 0x4B, 0x4B, 0x4A, 0x49, 0x4A, 0x4A, 0x49,
- 0x49, 0x49, 0x48, 0x49, 0x49, 0x4A, 0x4A, 0x4B,
- 0x4C, 0x4D, 0x52, 0x54, 0x56, 0x55, 0x57, 0x58,
- 0x57, 0x57, 0x58, 0x57, 0x57, 0x58, 0x57, 0x57,
- 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
- 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
- 0x57, 0x57, 0x58, 0x57, 0x57, 0x57, 0x57, 0x57,
- 0x57, 0x57, 0x55, 0x54, 0x53, 0x52, 0x51, 0x50,
- 0x50, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
- 0xFC, 0xFC, 0xFC, 0xFC, 0xF8, 0xF0, 0xF4, 0xFB,
- 0xFC, 0x67, 0x53, 0x50, 0x4D, 0x4C, 0x4C, 0x4C,
- 0x4B, 0x4A, 0x4A, 0x48, 0x49, 0x48, 0x48, 0x49,
- 0x49, 0x49, 0x4B, 0x4C, 0x50, 0x52, 0x53, 0x56,
- 0x57, 0x57, 0x58, 0x57, 0x57, 0x58, 0x57, 0x57,
- 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
- 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
- 0x57, 0x57, 0x58, 0x57, 0x57, 0x57, 0x57, 0x57,
- 0x55, 0x54, 0x53, 0x51, 0x51, 0x50, 0x4C, 0x4D,
- 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
- 0xFC, 0xFC, 0xFC, 0xFC, 0xF4, 0xD2, 0xD7, 0xF5,
- 0xFC, 0xFC, 0x5D, 0x5D, 0x5C, 0x5C, 0x59, 0x58,
- 0x58, 0x56, 0x52, 0x4C, 0x4B, 0x4A, 0x4A, 0x48,
- 0x48, 0x48, 0x48, 0x48, 0x49, 0x4B, 0x4D, 0x51,
- 0x54, 0x56, 0x58, 0x57, 0x57, 0x58, 0x57, 0x57,
- 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
- 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
- 0x57, 0x57, 0x58, 0x57, 0x57, 0x57, 0x55, 0x54,
- 0x53, 0x52, 0x51, 0x4D, 0x4D, 0x4D, 0x50, 0x50,
- 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
- 0xFC, 0xFC, 0xFC, 0xFC, 0xF4, 0x64, 0xD9, 0xF5,
- 0xF9, 0xFC, 0xFC, 0x64, 0x63, 0x62, 0x61, 0x61,
- 0x61, 0x60, 0x5E, 0x5B, 0x5A, 0x54, 0x52, 0x4C,
- 0x4B, 0x49, 0x49, 0x47, 0x47, 0x48, 0x49, 0x4B,
- 0x4C, 0x51, 0x53, 0x56, 0x57, 0x58, 0x57, 0x57,
- 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
- 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
- 0x57, 0x57, 0x58, 0x57, 0x57, 0x55, 0x53, 0x53,
- 0x51, 0x50, 0x50, 0x50, 0x50, 0x50, 0x53, 0xFC,
- 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
- 0xFC, 0xFC, 0xFC, 0xFC, 0xF4, 0xF5, 0xF9, 0xFC,
- 0xFC, 0xFC, 0xFC, 0x64, 0x64, 0x64, 0x64, 0x64,
- 0x64, 0x64, 0x64, 0x63, 0x61, 0x61, 0x5E, 0x59,
- 0x55, 0x52, 0x4C, 0x4A, 0x49, 0x47, 0x48, 0x48,
- 0x49, 0x4B, 0x4D, 0x51, 0x54, 0x57, 0x57, 0x57,
- 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
- 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
- 0x57, 0x57, 0x58, 0x55, 0x54, 0x54, 0x52, 0x51,
- 0x51, 0x51, 0x51, 0x51, 0x53, 0x54, 0x59, 0xFC,
- 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
- 0xFC, 0xFC, 0xFC, 0xFC, 0xF7, 0xFC, 0xFC, 0xFC,
- 0xFC, 0xFC, 0xFC, 0xFC, 0x60, 0x60, 0x60, 0x61,
- 0x62, 0x63, 0x64, 0x64, 0x65, 0x65, 0x64, 0x63,
- 0x61, 0x5E, 0x59, 0x56, 0x4D, 0x4B, 0x48, 0x48,
- 0x48, 0x48, 0x49, 0x4B, 0x50, 0x53, 0x56, 0x56,
- 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
- 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
- 0x57, 0x57, 0x56, 0x54, 0x53, 0x52, 0x51, 0x51,
- 0x51, 0x52, 0x53, 0x55, 0x59, 0x5D, 0x5E, 0xFC,
- 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
- 0xFC, 0xFC, 0xFC, 0xFB, 0xFB, 0xFB, 0xFC, 0xFC,
- 0xFC, 0xFC, 0xFC, 0xFC, 0x4C, 0x4E, 0x51, 0x52,
- 0x57, 0x5A, 0x5E, 0x60, 0x61, 0x63, 0x65, 0xCB,
- 0x64, 0x64, 0x63, 0x60, 0x5C, 0x57, 0x50, 0x4B,
- 0x48, 0x47, 0x47, 0x47, 0x4A, 0x4C, 0x52, 0x53,
- 0x54, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
- 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
- 0x55, 0x54, 0x53, 0x53, 0x51, 0x52, 0x52, 0x53,
- 0x53, 0x57, 0x5A, 0x5D, 0x5E, 0x5E, 0x60, 0xFC,
- 0xFC, 0xFC, 0xFB, 0xF9, 0xFC, 0xFC, 0xFC, 0xFC,
- 0xFC, 0xFC, 0xFC, 0xFA, 0xF9, 0xF5, 0xFB, 0xFC,
- 0xFC, 0xFC, 0xFC, 0xFC, 0xFB, 0x45, 0x3F, 0x3F,
- 0x45, 0x48, 0x4B, 0x4D, 0x54, 0x5A, 0x5E, 0x61,
- 0x63, 0xCB, 0xCB, 0x65, 0x64, 0x62, 0x5E, 0x57,
- 0x50, 0x4B, 0x48, 0x47, 0x47, 0x48, 0x4B, 0x4D,
- 0x51, 0x56, 0x56, 0x57, 0x57, 0x57, 0x57, 0x57,
- 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x55,
- 0x54, 0x54, 0x53, 0x53, 0x52, 0x53, 0x54, 0x57,
- 0x59, 0x5C, 0x5E, 0x5E, 0x5E, 0x5E, 0x5E, 0xFC,
- 0xFC, 0xFA, 0xFC, 0xFA, 0xE0, 0xFC, 0xFC, 0xFC,
- 0xFB, 0xFB, 0xFB, 0xDF, 0xD8, 0xF9, 0xE0, 0xFC,
- 0xFC, 0xFC, 0xFC, 0xFC, 0xFB, 0x4C, 0x4A, 0x48,
- 0x48, 0x3E, 0x44, 0x43, 0x3F, 0x47, 0x4B, 0x52,
- 0x5A, 0x5E, 0x62, 0x64, 0xCB, 0xCB, 0x64, 0x61,
- 0x5E, 0x57, 0x4D, 0x49, 0x47, 0x47, 0x48, 0x4A,
- 0x4C, 0x52, 0x54, 0x56, 0x57, 0x57, 0x57, 0x57,
- 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x55,
- 0x54, 0x53, 0x53, 0x54, 0x54, 0x55, 0x58, 0x5B,
- 0x5C, 0x5D, 0x5E, 0x5D, 0x5D, 0x5B, 0x58, 0xFC,
- 0xFC, 0xD8, 0x4C, 0x60, 0xFC, 0xF5, 0xFC, 0xFC,
- 0xFC, 0xF7, 0x5F, 0x48, 0x48, 0x2C, 0xF8, 0xF9,
- 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x4B, 0x4A, 0x49,
- 0x49, 0x49, 0x49, 0x47, 0x3E, 0x44, 0x42, 0x3F,
- 0x3E, 0x4B, 0x54, 0x5C, 0x61, 0x64, 0xCB, 0xCB,
- 0x64, 0x61, 0x5D, 0x53, 0x4B, 0x49, 0x47, 0x47,
- 0x49, 0x4B, 0x50, 0x53, 0x56, 0x57, 0x57, 0x57,
- 0x57, 0x57, 0x57, 0x57, 0x57, 0x55, 0x55, 0x54,
- 0x53, 0x53, 0x54, 0x56, 0x58, 0x5A, 0x5B, 0x5D,
- 0x5D, 0x5D, 0x5C, 0x5A, 0x54, 0x52, 0x4C, 0xFC,
- 0xF7, 0x4E, 0x2D, 0x29, 0x4E, 0xFC, 0xFC, 0xFC,
- 0xFB, 0x5F, 0x26, 0x24, 0x20, 0x2E, 0x65, 0xFC,
- 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x45, 0x3F, 0x45,
- 0x3E, 0x47, 0x47, 0x47, 0x47, 0x47, 0x3E, 0x44,
- 0x43, 0x40, 0x44, 0x49, 0x51, 0x5C, 0x62, 0x64,
- 0xCB, 0xCB, 0x63, 0x60, 0x58, 0x50, 0x49, 0x48,
- 0x48, 0x48, 0x4A, 0x4D, 0x53, 0x54, 0x57, 0x57,
- 0x57, 0x57, 0x57, 0x57, 0x55, 0x54, 0x54, 0x54,
- 0x54, 0x54, 0x55, 0x57, 0x59, 0x5B, 0x5C, 0x5D,
- 0x5C, 0x5A, 0x54, 0x51, 0x4C, 0x4C, 0x54, 0xFC,
- 0xF9, 0x23, 0xDB, 0x2D, 0x23, 0xFA, 0xFB, 0xFA,
- 0xF5, 0x27, 0x21, 0xD9, 0xF8, 0x20, 0x21, 0xFB,
- 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x5D, 0x58, 0x55,
- 0x50, 0x48, 0x45, 0x43, 0x44, 0x44, 0x45, 0x45,
- 0x3E, 0x3F, 0x43, 0x41, 0x3F, 0x48, 0x52, 0x5D,
- 0x63, 0x65, 0xCB, 0x65, 0x61, 0x5D, 0x52, 0x4B,
- 0x48, 0x47, 0x47, 0x49, 0x4C, 0x51, 0x54, 0x57,
- 0x57, 0x57, 0x57, 0x57, 0x55, 0x54, 0x54, 0x54,
- 0x54, 0x58, 0x5A, 0x59, 0x5B, 0x5B, 0x5B, 0x5A,
- 0x55, 0x52, 0x4D, 0x4D, 0x55, 0x5B, 0x5D, 0xFC,
- 0xF1, 0xF9, 0xFC, 0xD4, 0x21, 0xCC, 0xF7, 0xF8,
- 0xF2, 0x21, 0xD9, 0xFC, 0xF2, 0xFB, 0x21, 0x45,
- 0xFC, 0xFC, 0xFC, 0xFC, 0xFB, 0xD1, 0xD0, 0xCD,
- 0xCC, 0x63, 0x5E, 0x58, 0x50, 0x47, 0x43, 0x3F,
- 0x3F, 0x3F, 0x3F, 0x3F, 0x40, 0x41, 0x3F, 0x4A,
- 0x56, 0x5E, 0x64, 0xCB, 0x65, 0x63, 0x5E, 0x56,
- 0x4C, 0x48, 0x47, 0x47, 0x49, 0x4C, 0x51, 0x54,
- 0x58, 0x57, 0x57, 0x57, 0x57, 0x55, 0x54, 0x54,
- 0x57, 0x5A, 0x5A, 0x5C, 0x5B, 0x5A, 0x58, 0x54,
- 0x51, 0x4C, 0x55, 0x5D, 0x5D, 0x5B, 0x54, 0xFC,
- 0xF0, 0xF9, 0xFC, 0x65, 0x45, 0xCD, 0xFB, 0xFB,
- 0xF8, 0x26, 0xFB, 0xFC, 0xFC, 0xFC, 0x21, 0x27,
- 0xFB, 0xFC, 0xFC, 0xFC, 0xFB, 0xD7, 0x35, 0x34,
- 0x2F, 0x35, 0x36, 0x2F, 0x2F, 0x36, 0x2F, 0x2F,
- 0x36, 0x36, 0x35, 0x35, 0x43, 0x42, 0x41, 0x2E,
- 0x45, 0x4C, 0x5B, 0x62, 0x65, 0xCC, 0x64, 0x60,
- 0x58, 0x4D, 0x49, 0x47, 0x47, 0x49, 0x4C, 0x51,
- 0x58, 0x57, 0x57, 0x57, 0x57, 0x57, 0x55, 0x57,
- 0x58, 0x5A, 0x5A, 0x5B, 0x5A, 0x55, 0x54, 0x51,
- 0x53, 0x5C, 0x5D, 0x5D, 0x54, 0x4B, 0x4D, 0xFC,
- 0xFC, 0x44, 0xFC, 0xFB, 0x7B, 0xAB, 0xA8, 0xAE,
- 0xAB, 0x7F, 0xFC, 0xFC, 0xFB, 0xFB, 0x22, 0x2A,
- 0xFC, 0xFC, 0xFC, 0xFC, 0x36, 0x2F, 0x30, 0x30,
- 0x32, 0x30, 0x32, 0x30, 0x30, 0x30, 0x30, 0x30,
- 0x30, 0x30, 0x30, 0x30, 0x2F, 0x2F, 0x40, 0x41,
- 0x2E, 0x40, 0x48, 0x56, 0x5F, 0x64, 0xCC, 0x65,
- 0x61, 0x59, 0x50, 0x49, 0x47, 0x47, 0x49, 0x4C,
- 0x5A, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x58,
- 0x5A, 0x5A, 0x5A, 0x58, 0x55, 0x52, 0x51, 0x5A,
- 0x5D, 0x5D, 0x57, 0x4C, 0x51, 0x54, 0x5D, 0xFC,
- 0xFC, 0x2A, 0xFC, 0xC9, 0xAA, 0x8B, 0x8A, 0x8C,
- 0xAB, 0x8C, 0x8C, 0xFB, 0xFB, 0x23, 0x20, 0xF1,
- 0xFC, 0xFC, 0xFC, 0x3B, 0x33, 0x33, 0x32, 0x32,
- 0x31, 0x32, 0x30, 0x32, 0x32, 0x32, 0x32, 0x30,
- 0x31, 0x31, 0x31, 0x32, 0x33, 0x33, 0x3C, 0x41,
- 0x41, 0x2E, 0x2D, 0x45, 0x4D, 0x5D, 0x63, 0xCC,
- 0x65, 0x62, 0x5D, 0x51, 0x49, 0x47, 0x47, 0x4A,
- 0x59, 0x57, 0x57, 0x57, 0x57, 0x58, 0x58, 0x58,
- 0x5A, 0x5A, 0x58, 0x55, 0x53, 0x53, 0x5C, 0x5E,
- 0x59, 0x51, 0x4E, 0x54, 0x59, 0x5E, 0x62, 0xFC,
- 0xFC, 0xDB, 0xAA, 0xA1, 0x95, 0x9C, 0x8C, 0x88,
- 0x82, 0x83, 0x83, 0x8C, 0x88, 0xAE, 0xB9, 0xFB,
- 0xFC, 0xFC, 0xFC, 0x3C, 0x3B, 0x72, 0x38, 0x33,
- 0x33, 0x33, 0x31, 0x33, 0x31, 0x31, 0x31, 0x31,
- 0x33, 0x33, 0x38, 0x33, 0x72, 0x3B, 0x44, 0x2E,
- 0x41, 0x2E, 0x2E, 0x2D, 0x43, 0x4B, 0x5B, 0x63,
- 0xCB, 0xCC, 0x63, 0x5D, 0x51, 0x49, 0x47, 0x49,
- 0x5C, 0x58, 0x57, 0x57, 0x57, 0x57, 0x58, 0x58,
- 0x58, 0x58, 0x57, 0x53, 0x58, 0x5D, 0x5E, 0x55,
- 0x51, 0x53, 0x58, 0x5E, 0x60, 0x63, 0x64, 0xFC,
- 0xFC, 0xC0, 0xA6, 0x9D, 0x8B, 0x9C, 0x8C, 0x8C,
- 0x6E, 0x83, 0x88, 0x8C, 0x8C, 0x8C, 0x83, 0xE8,
- 0xFB, 0xFC, 0xFC, 0xFC, 0x33, 0x70, 0x70, 0x6F,
- 0x6F, 0x6F, 0x6F, 0x3A, 0x6F, 0x6D, 0x6F, 0x6F,
- 0x70, 0x6F, 0x6F, 0x70, 0x6F, 0x32, 0x5A, 0x48,
- 0x41, 0x2D, 0x2D, 0x2D, 0x2C, 0x41, 0x49, 0x5A,
- 0x62, 0xCB, 0xCB, 0x63, 0x5D, 0x50, 0x49, 0x4A,
- 0x5C, 0x58, 0x58, 0x57, 0x55, 0x57, 0x57, 0x57,
- 0x57, 0x55, 0x56, 0x59, 0x5E, 0x5C, 0x52, 0x53,
- 0x55, 0x5B, 0x5E, 0x61, 0x63, 0x64, 0x63, 0xFC,
- 0xE8, 0xBF, 0xA4, 0x99, 0x9C, 0x8C, 0x88, 0x88,
- 0x6E, 0x88, 0x8C, 0x8C, 0x8C, 0xC2, 0xA6, 0xC4,
- 0xFC, 0xFC, 0xFC, 0xFC, 0x36, 0x3A, 0x6F, 0x70,
- 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70,
- 0x70, 0x70, 0x70, 0x70, 0x37, 0x32, 0xCD, 0x5E,
- 0x4C, 0x43, 0x2C, 0x2D, 0x2D, 0x2C, 0x2E, 0x47,
- 0x57, 0x61, 0x65, 0xCC, 0x63, 0x5C, 0x50, 0x4D,
- 0x5C, 0x5A, 0x57, 0x55, 0x55, 0x55, 0x58, 0x58,
- 0x55, 0x54, 0x5B, 0x5E, 0x5D, 0x53, 0x53, 0x55,
- 0x5D, 0x5E, 0x61, 0x61, 0x61, 0x61, 0x5E, 0xFC,
- 0xEA, 0xBE, 0xA4, 0x9B, 0x8B, 0x85, 0x8C, 0x6E,
- 0x8C, 0x8C, 0x8C, 0xA3, 0xAA, 0xA4, 0xA4, 0xE9,
- 0xFB, 0xFC, 0xFC, 0xFC, 0x36, 0x6D, 0x70, 0x73,
- 0x70, 0x70, 0x70, 0x73, 0x73, 0x73, 0x73, 0x70,
- 0x70, 0x70, 0x73, 0x70, 0x37, 0x38, 0xD1, 0xCF,
- 0x61, 0x4D, 0x44, 0x2C, 0x2D, 0x2E, 0x2C, 0x2E,
- 0x3E, 0x56, 0x61, 0xCB, 0xCC, 0x62, 0x5B, 0x57,
- 0x59, 0x58, 0x55, 0x54, 0x54, 0x55, 0x58, 0x58,
- 0x58, 0x5B, 0x5E, 0x5B, 0x53, 0x55, 0x55, 0x5C,
- 0x5E, 0x61, 0x61, 0x60, 0x5D, 0x5A, 0x4E, 0xFC,
- 0xFC, 0xEA, 0xAA, 0x9C, 0x8A, 0x85, 0x82, 0x8C,
- 0x8C, 0xA8, 0xEB, 0xA8, 0xA4, 0xA4, 0xAA, 0xFC,
- 0xFC, 0xFC, 0x64, 0xFB, 0x39, 0x31, 0x72, 0x78,
- 0x73, 0x78, 0x73, 0x74, 0x74, 0x74, 0x74, 0x73,
- 0x78, 0x70, 0x73, 0x73, 0x33, 0xCC, 0xD2, 0xD1,
- 0xCE, 0x62, 0x53, 0x3F, 0x2D, 0x2D, 0x41, 0x2C,
- 0x2E, 0x3E, 0x56, 0x62, 0xCB, 0xCB, 0x61, 0x5D,
- 0x54, 0x54, 0x54, 0x54, 0x56, 0x58, 0x58, 0x58,
- 0x5C, 0x5E, 0x5A, 0x55, 0x58, 0x58, 0x5B, 0x5E,
- 0x61, 0x5E, 0x5D, 0x5A, 0x52, 0x55, 0xCD, 0xFC,
- 0xFC, 0x34, 0xC9, 0xE8, 0xA8, 0xAE, 0xC2, 0xE8,
- 0xC3, 0xA6, 0xA7, 0xA6, 0xAA, 0x78, 0x2E, 0x42,
- 0xFC, 0xFC, 0xD2, 0x64, 0xF8, 0x31, 0x72, 0x73,
- 0x73, 0x73, 0x73, 0x74, 0x75, 0x75, 0x74, 0x73,
- 0x73, 0x73, 0x73, 0x72, 0x33, 0x5C, 0x64, 0xD2,
- 0xD1, 0xCF, 0x63, 0x54, 0x3F, 0x2C, 0x41, 0x41,
- 0x2C, 0x2E, 0x47, 0x58, 0x63, 0xCB, 0xCB, 0x62,
- 0x52, 0x53, 0x53, 0x56, 0x58, 0x58, 0x5A, 0x5B,
- 0x5E, 0x5A, 0x57, 0x58, 0x58, 0x58, 0x60, 0x60,
- 0x5D, 0x5A, 0x55, 0x4E, 0x64, 0xD2, 0xD1, 0xFC,
- 0xFC, 0x41, 0x3E, 0xC1, 0xC0, 0xA3, 0xA6, 0xA7,
- 0xA7, 0xA9, 0xAA, 0xB8, 0x2E, 0x3F, 0x2C, 0x41,
- 0xFC, 0xFC, 0xF7, 0xCE, 0xCD, 0x36, 0x72, 0x73,
- 0x74, 0x75, 0x78, 0x75, 0x75, 0x75, 0x74, 0x74,
- 0x74, 0x74, 0x78, 0x72, 0x6D, 0x49, 0x59, 0xCB,
- 0xD1, 0xD1, 0xD2, 0xCB, 0x56, 0x3F, 0x2C, 0x41,
- 0x40, 0x2D, 0x2E, 0x49, 0x5B, 0x64, 0xCC, 0x64,
- 0x51, 0x53, 0x53, 0x55, 0x58, 0x59, 0x5B, 0x5E,
- 0x59, 0x58, 0x58, 0x58, 0x55, 0x60, 0x60, 0x5C,
- 0x5A, 0x53, 0x5B, 0xD0, 0xD3, 0xD3, 0xD3, 0xFB,
- 0xFC, 0x40, 0x41, 0x45, 0xC4, 0xC0, 0xBE, 0xBE,
- 0xC1, 0xC0, 0x3C, 0x47, 0x2E, 0x21, 0x22, 0x20,
- 0x65, 0xFC, 0xFC, 0xFC, 0xFC, 0x6D, 0x72, 0x75,
- 0x78, 0x76, 0x75, 0x79, 0x76, 0x76, 0x76, 0x76,
- 0x75, 0x75, 0x75, 0x72, 0x6D, 0x2E, 0x48, 0x5D,
- 0xCE, 0xD1, 0xD4, 0xD3, 0xCB, 0x56, 0x43, 0x2C,
- 0x42, 0x43, 0x2E, 0x2E, 0x4A, 0x5D, 0x64, 0x64,
- 0x50, 0x52, 0x56, 0x58, 0x5C, 0x5D, 0x5E, 0x5D,
- 0x5A, 0x58, 0x58, 0x55, 0x61, 0x60, 0x58, 0x58,
- 0x4E, 0x61, 0xD1, 0xD4, 0xD4, 0xD1, 0xEE, 0xFC,
- 0xFC, 0x2B, 0x29, 0x2E, 0x3F, 0xB0, 0xAD, 0x81,
- 0x46, 0x2D, 0x46, 0x2C, 0x24, 0x22, 0x22, 0x23,
- 0x25, 0xFC, 0xFC, 0xFC, 0xFC, 0x6E, 0x73, 0x76,
- 0x76, 0x79, 0x79, 0x79, 0x76, 0x76, 0x79, 0x76,
- 0x79, 0x79, 0x79, 0x74, 0x3F, 0x41, 0x2C, 0x48,
- 0x5F, 0xCF, 0xD5, 0xD7, 0xD6, 0xCD, 0x57, 0x40,
- 0x2E, 0x3F, 0x44, 0x2E, 0x41, 0x4C, 0x60, 0x61,
- 0x51, 0x53, 0x58, 0x5C, 0x5D, 0x5E, 0x5D, 0x5C,
- 0x58, 0x57, 0x54, 0x5F, 0x5E, 0x55, 0x55, 0x52,
- 0x64, 0xD4, 0xD5, 0xD4, 0xD1, 0x5D, 0xFA, 0xFB,
- 0xF4, 0x21, 0x24, 0x41, 0x40, 0x44, 0x2E, 0x2E,
- 0x42, 0x41, 0x2A, 0x24, 0x22, 0x22, 0x22, 0x22,
- 0x23, 0xD9, 0xFC, 0xFC, 0xFC, 0xFC, 0xE5, 0xB8,
- 0x8F, 0x8F, 0x7A, 0x8F, 0x7A, 0x8F, 0x7A, 0x8F,
- 0x8F, 0x8F, 0xB8, 0xE5, 0x3F, 0x3E, 0x43, 0x2C,
- 0x48, 0x61, 0xD1, 0xD7, 0xD9, 0xD7, 0xD0, 0x57,
- 0x41, 0x2E, 0x3E, 0x44, 0x2D, 0x40, 0x52, 0x5D,
- 0x53, 0x55, 0x59, 0x5D, 0x5E, 0x5E, 0x5D, 0x5A,
- 0x57, 0x53, 0x5E, 0x5E, 0x54, 0x53, 0x54, 0x65,
- 0xD5, 0xD6, 0xD4, 0xCE, 0x53, 0xFB, 0xF9, 0xFC,
- 0x24, 0x22, 0x23, 0x23, 0x41, 0x42, 0x2E, 0x40,
- 0x2B, 0x21, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
- 0x23, 0x23, 0xFC, 0xFC, 0xFC, 0xFC, 0xE7, 0xBD,
- 0xB5, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
- 0x93, 0xB5, 0xC6, 0xEB, 0x2D, 0x47, 0x4A, 0x47,
- 0x2C, 0x3E, 0x61, 0xD4, 0xDC, 0xDC, 0xDA, 0xCF,
- 0x54, 0x41, 0x41, 0x3E, 0x45, 0x2C, 0x3F, 0x4A,
- 0x58, 0x5A, 0x5C, 0x5F, 0x60, 0x5E, 0x5D, 0x57,
- 0x51, 0x5D, 0x5D, 0x51, 0x53, 0x53, 0xCB, 0xD5,
- 0xD6, 0xD5, 0x63, 0x55, 0xFC, 0xFC, 0xFC, 0x2C,
- 0x23, 0x22, 0x23, 0x22, 0x20, 0x2D, 0x2C, 0x26,
- 0x21, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
- 0x22, 0x21, 0xF0, 0xFC, 0xFC, 0xFC, 0xE2, 0xC6,
- 0xB5, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
- 0x93, 0x93, 0xC7, 0xE3, 0x3E, 0x2E, 0x49, 0x52,
- 0x4C, 0x41, 0x44, 0x62, 0xD6, 0xDE, 0xDE, 0xD9,
- 0xD0, 0x51, 0x2E, 0x40, 0x47, 0x44, 0x2C, 0x42,
- 0x5D, 0x5D, 0x5F, 0x60, 0x60, 0x5D, 0x57, 0x51,
- 0x58, 0x5D, 0x4E, 0x52, 0x55, 0x64, 0xD5, 0xD6,
- 0xD4, 0x61, 0x59, 0x6B, 0xFC, 0xFC, 0xFC, 0x21,
- 0x23, 0x22, 0x23, 0x22, 0x23, 0x21, 0x23, 0x22,
- 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
- 0x22, 0x21, 0x24, 0xFC, 0xFC, 0xFC, 0xE2, 0xC7,
- 0xB5, 0x90, 0x93, 0x93, 0x93, 0x90, 0x93, 0x93,
- 0x90, 0xB5, 0xC8, 0xE4, 0x5F, 0x45, 0x2E, 0x4D,
- 0x57, 0x57, 0x44, 0x43, 0x63, 0xDA, 0xDF, 0xDF,
- 0xD9, 0xCE, 0x4C, 0x2C, 0x3F, 0x3E, 0x40, 0x40,
- 0x60, 0x5E, 0x61, 0x61, 0x5E, 0x5B, 0x53, 0x52,
- 0x5C, 0x52, 0x52, 0x55, 0x61, 0xD4, 0xD5, 0xD1,
- 0x5E, 0x5B, 0x5C, 0xFB, 0xFC, 0xFC, 0x2A, 0x21,
- 0x23, 0x22, 0x23, 0x22, 0x22, 0x22, 0x23, 0x22,
- 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
- 0x22, 0x22, 0x22, 0xFB, 0xFC, 0xFC, 0xB3, 0xC8,
- 0xB5, 0x90, 0x92, 0xB5, 0x93, 0x93, 0xB5, 0x93,
- 0x92, 0xB5, 0xC8, 0xB9, 0xD0, 0x5E, 0x44, 0x40,
- 0x52, 0x58, 0x57, 0x48, 0x40, 0x63, 0xD9, 0xE0,
- 0xE0, 0xD9, 0xCB, 0x49, 0x2D, 0x3F, 0x45, 0x3F,
- 0x63, 0x61, 0x62, 0x60, 0x5E, 0x55, 0x4D, 0x59,
- 0x53, 0x4E, 0x54, 0x5D, 0xD2, 0xD4, 0xD2, 0x5E,
- 0x5C, 0x5D, 0xFC, 0xFC, 0xFC, 0xF8, 0x29, 0x23,
- 0x23, 0x23, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
- 0x23, 0x22, 0x22, 0x23, 0x23, 0x23, 0x22, 0x22,
- 0x22, 0x22, 0x22, 0xF0, 0xFC, 0xFC, 0xB3, 0xC7,
- 0xB5, 0x93, 0xB5, 0x93, 0x93, 0x91, 0x93, 0x93,
- 0x91, 0xB5, 0xC7, 0xAD, 0xD6, 0xD2, 0x5E, 0x3F,
- 0x3F, 0x57, 0x57, 0x58, 0x4A, 0x41, 0x64, 0xDC,
- 0xF1, 0xDF, 0xDA, 0x61, 0x45, 0x2E, 0x43, 0x47,
- 0xCB, 0x63, 0x62, 0x5F, 0x58, 0x51, 0x53, 0x54,
- 0x4C, 0x52, 0x5C, 0xCD, 0xD3, 0xD2, 0x60, 0x5D,
- 0x5D, 0xFB, 0xFC, 0xFC, 0xFC, 0xDB, 0x49, 0x24,
- 0x21, 0x23, 0x23, 0x22, 0x26, 0x26, 0x2A, 0x24,
- 0x22, 0x23, 0x22, 0x21, 0x24, 0x26, 0x26, 0x2A,
- 0x29, 0x2B, 0x24, 0x25, 0xFC, 0xFC, 0xB3, 0xC5,
- 0x91, 0x91, 0x92, 0x91, 0x92, 0x92, 0x93, 0x93,
- 0x91, 0x93, 0xC6, 0xAD, 0xDC, 0xD9, 0xD4, 0x60,
- 0x43, 0x45, 0x58, 0x58, 0x57, 0x4B, 0x43, 0xCC,
- 0xDD, 0xF1, 0xD8, 0xD5, 0x5D, 0x43, 0x41, 0x47,
- 0xCD, 0x63, 0x62, 0x5D, 0x54, 0x4C, 0x55, 0x4B,
- 0x51, 0x58, 0x62, 0xD0, 0xD0, 0x62, 0x5D, 0x5D,
- 0x67, 0xFC, 0xFC, 0xFC, 0xFC, 0x58, 0x4E, 0x28,
- 0x2A, 0x20, 0x23, 0x22, 0x23, 0x2A, 0x23, 0x22,
- 0x22, 0x22, 0x23, 0x23, 0x25, 0x2A, 0x2E, 0x2D,
- 0x2E, 0x2E, 0x2E, 0x23, 0xFA, 0xFC, 0xB2, 0xBD,
- 0xB5, 0x90, 0x91, 0x93, 0x92, 0x90, 0x91, 0x93,
- 0x92, 0x91, 0xBD, 0xAD, 0xDE, 0xE0, 0xD8, 0xD7,
- 0x61, 0x40, 0x48, 0x58, 0x58, 0x58, 0x48, 0x44,
- 0xCF, 0xDE, 0xE0, 0xDD, 0xD0, 0x52, 0x41, 0x45,
- 0xCD, 0x63, 0x61, 0x58, 0x4D, 0x51, 0x4C, 0x4B,
- 0x54, 0x5D, 0xCC, 0xCE, 0x63, 0x61, 0x5D, 0x5D,
- 0xFB, 0xFC, 0xFC, 0xFC, 0xFC, 0x4B, 0x27, 0x21,
- 0x22, 0x22, 0x23, 0x22, 0x22, 0x24, 0x23, 0x22,
- 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x20,
- 0x27, 0x2B, 0x41, 0x2B, 0x23, 0xFC, 0xB2, 0xB6,
- 0x93, 0x90, 0x92, 0xB5, 0x92, 0x90, 0xB5, 0x90,
- 0x92, 0x93, 0xBC, 0xAD, 0xDC, 0xF1, 0xF3, 0xF0,
- 0xD9, 0x61, 0x41, 0x4A, 0x58, 0x57, 0x57, 0x44,
- 0x49, 0xD2, 0xDD, 0xD8, 0xDA, 0x63, 0x4A, 0x45,
- 0xCC, 0x63, 0x5E, 0x52, 0x4B, 0x4C, 0x49, 0x51,
- 0x5C, 0x61, 0xCD, 0x65, 0x63, 0x5E, 0x4E, 0xCF,
- 0xFB, 0xFB, 0xF0, 0xFC, 0xD2, 0x2A, 0x22, 0x23,
- 0x22, 0x22, 0x23, 0x22, 0x22, 0x21, 0x22, 0x22,
- 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
- 0x23, 0x22, 0x26, 0x41, 0x27, 0xF9, 0x81, 0xB7,
- 0xB5, 0x91, 0x92, 0xB5, 0x91, 0xB5, 0x93, 0xB5,
- 0x93, 0xB6, 0xB7, 0xB9, 0xCB, 0xD8, 0xF3, 0xF2,
- 0xF2, 0xDB, 0x61, 0x2D, 0x51, 0x58, 0x57, 0x58,
- 0x41, 0x51, 0xD4, 0xDB, 0xDC, 0xD1, 0x5B, 0x4C,
- 0xCB, 0x62, 0x59, 0x4C, 0x4A, 0x49, 0x4B, 0x55,
- 0x60, 0x64, 0xCC, 0x64, 0x5E, 0x55, 0x60, 0xE1,
- 0xFB, 0xF8, 0xFC, 0xFC, 0x21, 0x22, 0x22, 0x23,
- 0x22, 0x22, 0x23, 0x22, 0x22, 0x21, 0x22, 0x22,
- 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
- 0x23, 0x22, 0x21, 0x24, 0x2D, 0x21, 0xB4, 0xBB,
- 0xB6, 0xB5, 0xB6, 0xB7, 0xB7, 0xB7, 0xB7, 0xB6,
- 0xB6, 0xB6, 0xBB, 0xB9, 0x45, 0xCB, 0xDF, 0xF3,
- 0xF3, 0xF3, 0xDB, 0x5E, 0x2C, 0x51, 0x58, 0x58,
- 0x52, 0x2D, 0x5C, 0xD4, 0xD9, 0xD5, 0x63, 0x58,
- 0x64, 0x60, 0x53, 0x49, 0x4A, 0x49, 0x52, 0x5C,
- 0x63, 0xCD, 0xCD, 0x63, 0x5C, 0x4E, 0x65, 0xFC,
- 0xFC, 0xF5, 0xFC, 0xD2, 0x23, 0x22, 0x22, 0x23,
- 0x22, 0x22, 0x23, 0x22, 0x22, 0x21, 0x22, 0x22,
- 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
- 0x23, 0x22, 0x21, 0x22, 0x25, 0x29, 0xB3, 0xC7,
- 0xB5, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6,
- 0xB6, 0xB5, 0xC7, 0xAD, 0x57, 0x3F, 0xCB, 0xF0,
- 0xF3, 0xF3, 0xF2, 0xD9, 0x58, 0x41, 0x4C, 0x58,
- 0x57, 0x47, 0x42, 0x62, 0xD4, 0xD4, 0xCC, 0x60,
- 0x63, 0x5D, 0x50, 0x47, 0x48, 0x4B, 0x58, 0x60,
- 0xCC, 0xCE, 0xCD, 0x60, 0x53, 0x5C, 0x62, 0xFB,
- 0xF9, 0xFC, 0xFC, 0x21, 0x23, 0x22, 0x22, 0x23,
- 0x22, 0x22, 0x23, 0x23, 0x23, 0x21, 0x22, 0x22,
- 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
- 0x23, 0x22, 0x23, 0x23, 0x22, 0x23, 0x81, 0xC7,
- 0xB7, 0xB7, 0xBC, 0xB7, 0xBC, 0xBC, 0xBC, 0xB7,
- 0xB7, 0xB7, 0xC8, 0x80, 0x58, 0x57, 0x40, 0xCE,
- 0xF3, 0xF2, 0xF2, 0xF0, 0xD5, 0x4C, 0x3F, 0x4B,
- 0x52, 0x50, 0x2D, 0x4B, 0x64, 0xD2, 0xCC, 0x61,
- 0x60, 0x58, 0x4A, 0x47, 0x47, 0x4C, 0x59, 0x64,
- 0xD0, 0xD0, 0x64, 0x59, 0x49, 0x5D, 0xFB, 0xFC,
- 0xD9, 0xFC, 0xD6, 0x23, 0x22, 0x22, 0x22, 0x23,
- 0x22, 0x22, 0x23, 0x23, 0x21, 0x21, 0x22, 0x22,
- 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
- 0x23, 0x22, 0x23, 0x23, 0x22, 0x23, 0xB4, 0xC8,
- 0xBD, 0xB7, 0xBD, 0xBC, 0xBD, 0xC5, 0xBC, 0xC5,
- 0xBC, 0xBD, 0xC7, 0xAC, 0x58, 0x57, 0x58, 0x2C,
- 0xD1, 0xF0, 0xF3, 0xF3, 0xE0, 0xCD, 0x45, 0x3E,
- 0x48, 0x4B, 0x3F, 0x41, 0x56, 0x64, 0x65, 0x62,
- 0x5D, 0x52, 0x47, 0x48, 0x48, 0x53, 0x60, 0xCC,
- 0xD2, 0xD0, 0x63, 0x52, 0x4E, 0x53, 0xFB, 0xFB,
- 0xFC, 0xFC, 0x23, 0x23, 0x22, 0x23, 0x22, 0x23,
- 0x22, 0x22, 0x23, 0x23, 0x20, 0x21, 0x22, 0x22,
- 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
- 0x23, 0x22, 0x23, 0x22, 0x23, 0x22, 0xB4, 0xC7,
- 0xC5, 0xBC, 0xC5, 0xBD, 0xC5, 0xC5, 0xBD, 0xC5,
- 0xBC, 0xC6, 0xC7, 0xB9, 0x58, 0x57, 0x58, 0x57,
- 0x2D, 0xD4, 0xF1, 0xF2, 0xF0, 0xD9, 0x5D, 0x47,
- 0x48, 0x3F, 0x42, 0x2C, 0x48, 0x5C, 0x5F, 0x60,
- 0x58, 0x50, 0x47, 0x4A, 0x49, 0x55, 0x63, 0xD0,
- 0xD2, 0xCD, 0x5D, 0x49, 0x4E, 0xE1, 0xFC, 0xF0,
- 0xFC, 0xF8, 0x22, 0x22, 0x22, 0x23, 0x22, 0x23,
- 0x22, 0x22, 0x23, 0x20, 0x21, 0x21, 0x22, 0x22,
- 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x23, 0x22,
- 0x23, 0x22, 0x23, 0x23, 0x23, 0x22, 0xC4, 0xC8,
- 0xBD, 0xBD, 0xC6, 0xBD, 0xC6, 0xC6, 0xC5, 0xC6,
- 0xBD, 0xC6, 0xC7, 0xE4, 0x54, 0x57, 0x58, 0x57,
- 0x57, 0x43, 0xD7, 0xE0, 0xF1, 0xD8, 0xCD, 0x4B,
- 0x4A, 0x47, 0x42, 0x2C, 0x3F, 0x4D, 0x58, 0x5C,
- 0x52, 0x4B, 0x48, 0x4B, 0x4A, 0x58, 0xCB, 0xD3,
- 0xD2, 0xCD, 0x58, 0x47, 0x4A, 0xFC, 0xFC, 0xFB,
- 0xFC, 0x2B, 0x22, 0x22, 0x22, 0x23, 0x22, 0x23,
- 0x22, 0x22, 0x23, 0x26, 0x21, 0x21, 0x23, 0x22,
- 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x23,
- 0x22, 0x23, 0x22, 0x23, 0x22, 0x23, 0xE5, 0xC8,
- 0xBA, 0xC5, 0xC6, 0xC6, 0xC6, 0xC7, 0xC6, 0xC7,
- 0xC5, 0xC6, 0xC8, 0xE5, 0x2E, 0x54, 0x58, 0x57,
- 0x57, 0x4C, 0x4D, 0xDA, 0xD8, 0xD8, 0xD4, 0x5C,
- 0x4B, 0x4B, 0x3F, 0x42, 0x44, 0x4A, 0x51, 0x58,
- 0x4B, 0x48, 0x4B, 0x51, 0x4D, 0x5F, 0xD0, 0xD1,
- 0xD0, 0x64, 0x51, 0x44, 0x6B, 0xFC, 0xFB, 0xFC,
- 0xFC, 0x21, 0x23, 0x22, 0x22, 0x23, 0x22, 0x23,
- 0x22, 0x22, 0x23, 0x26, 0x21, 0x23, 0x23, 0x22,
- 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x23,
- 0x22, 0x23, 0x22, 0x23, 0x23, 0x23, 0xE5, 0xED,
- 0xE7, 0xBA, 0xC8, 0xC6, 0xC6, 0xC6, 0xC6, 0xC7,
- 0xC7, 0xE5, 0xED, 0xE6, 0x61, 0x41, 0x52, 0x58,
- 0x58, 0x57, 0x45, 0x5E, 0xD7, 0xDD, 0xD5, 0x60,
- 0x4B, 0x4C, 0x48, 0x4D, 0x4D, 0x50, 0x4D, 0x56,
- 0x4A, 0x3E, 0x53, 0x53, 0x52, 0x63, 0xD3, 0xD0,
- 0xCE, 0x60, 0x4A, 0x45, 0xFC, 0xFC, 0xF7, 0xFC,
- 0xFC, 0x21, 0x23, 0x23, 0x22, 0x23, 0x22, 0x23,
- 0x22, 0x23, 0x21, 0x2A, 0x20, 0x23, 0x23, 0x22,
- 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
- 0x23, 0x22, 0x23, 0x22, 0x21, 0x23, 0xEB, 0xF6,
- 0xF6, 0xED, 0xED, 0xED, 0xED, 0xED, 0xED, 0xED,
- 0xF6, 0xF6, 0xF6, 0xE6, 0xDB, 0x58, 0x45, 0x4B,
- 0x58, 0x57, 0x4D, 0x4B, 0x64, 0xD4, 0xD0, 0x5C,
- 0x48, 0x51, 0x4C, 0x5D, 0x5E, 0x5C, 0x56, 0x59,
- 0x3E, 0x4A, 0x58, 0x54, 0x52, 0x65, 0xD3, 0xD0,
- 0xCF, 0x5D, 0x48, 0xFC, 0xFC, 0xFC, 0xFA, 0xFC,
- 0xFC, 0x21, 0x22, 0x23, 0x22, 0x23, 0x22, 0x23,
- 0x22, 0x23, 0x21, 0x2A, 0x21, 0x23, 0x23, 0x22,
- 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
- 0x23, 0x22, 0x23, 0x22, 0x21, 0x4F, 0xE6, 0xC6,
- 0xC6, 0xBD, 0xC6, 0xBD, 0xBD, 0xBD, 0xBD, 0xC6,
- 0xC5, 0xBA, 0xC7, 0xE6, 0xF2, 0xD4, 0x49, 0x4B,
- 0x3E, 0x4D, 0x52, 0x3E, 0x52, 0x63, 0x64, 0x56,
- 0x48, 0x54, 0x4D, 0x61, 0xCC, 0xCC, 0x60, 0x60,
- 0x47, 0x4D, 0x5C, 0x53, 0x58, 0xCF, 0xD1, 0xCF,
- 0xD0, 0x59, 0x45, 0xFC, 0xFC, 0xFC, 0xEF, 0xF9,
- 0xFC, 0x21, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22,
- 0x23, 0x22, 0x23, 0x2A, 0x21, 0x23, 0x23, 0x22,
- 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
- 0x23, 0x22, 0x23, 0x22, 0x23, 0x4F, 0xE4, 0xB9,
- 0xAF, 0x80, 0x80, 0x8E, 0x8E, 0x8E, 0x8E, 0x8F,
- 0x80, 0xB4, 0xB9, 0xE4, 0x7F, 0xDE, 0x61, 0x52,
- 0x54, 0x48, 0x3F, 0x43, 0x4D, 0x56, 0x59, 0x4B,
- 0x3E, 0x58, 0x53, 0x61, 0xD3, 0xD4, 0xCF, 0xCD,
- 0x4C, 0x58, 0x5F, 0x53, 0x5E, 0xD3, 0xD0, 0xCE,
- 0xCE, 0x52, 0x3F, 0xFC, 0xFC, 0xFC, 0xF7, 0x65,
- 0xFA, 0x22, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22,
- 0x23, 0x22, 0x21, 0x2A, 0x23, 0x23, 0x23, 0x22,
- 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
- 0x23, 0x22, 0x23, 0x22, 0x21, 0xB1, 0xE4, 0xE6,
- 0x7C, 0xB1, 0x7C, 0xB1, 0xB2, 0xB2, 0xB3, 0x3D,
- 0xB3, 0x3C, 0xE5, 0xB3, 0xB0, 0xF1, 0xD0, 0x58,
- 0x5D, 0x4D, 0x40, 0x41, 0x48, 0x51, 0x4C, 0x3F,
- 0x3F, 0x4D, 0x5A, 0x5A, 0xD5, 0xD9, 0xD7, 0xD4,
- 0x57, 0x5E, 0x61, 0x4C, 0x63, 0xD4, 0xCF, 0xCE,
- 0xCB, 0x4D, 0x4A, 0xFC, 0xFC, 0xFC, 0xFC, 0xF0,
- 0xFB, 0x22, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22,
- 0x23, 0x22, 0x23, 0x2A, 0x21, 0x23, 0x23, 0x22,
- 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
- 0x22, 0x23, 0x22, 0x23, 0x23, 0xB1, 0x81, 0x7D,
- 0x39, 0x35, 0x35, 0x36, 0x36, 0x36, 0x36, 0x36,
- 0x36, 0x36, 0x7C, 0xB2, 0xB0, 0xDF, 0xD2, 0x57,
- 0x60, 0x59, 0x5B, 0x59, 0x52, 0x4C, 0x4A, 0x40,
- 0x42, 0x4A, 0x53, 0x4D, 0xD2, 0xDE, 0xDE, 0xD9,
- 0x5E, 0x5E, 0x60, 0x4A, 0xCD, 0xD1, 0xCF, 0xCE,
- 0x63, 0x49, 0x5C, 0xFB, 0xE8, 0x89, 0x9F, 0xFC,
- 0xD6, 0x21, 0x21, 0x23, 0x22, 0x22, 0x23, 0x22,
- 0x23, 0x22, 0x21, 0x2A, 0x22, 0x23, 0x23, 0x22,
- 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
- 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x7F, 0xB9,
- 0x71, 0x6C, 0x38, 0x38, 0x33, 0x33, 0x33, 0x38,
- 0x38, 0x71, 0xAD, 0xE4, 0xD3, 0xDA, 0xCC, 0x52,
- 0x63, 0x60, 0xCE, 0xD4, 0xCF, 0x60, 0x4C, 0x40,
- 0x3F, 0x45, 0x4B, 0x5A, 0xCB, 0xD8, 0xDE, 0xDC,
- 0x5E, 0x5E, 0x5F, 0x4C, 0xD2, 0xD2, 0xCF, 0xCF,
- 0x61, 0x45, 0x5E, 0xA7, 0x9D, 0x95, 0x8B, 0x99,
- 0xFC, 0x41, 0x21, 0x23, 0x23, 0x22, 0x23, 0x22,
- 0x23, 0x22, 0x23, 0x2A, 0x23, 0x23, 0x23, 0x22,
- 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
- 0x22, 0x22, 0x23, 0x22, 0x23, 0x77, 0x77, 0xF6,
- 0xFC, 0x7D, 0x7D, 0x7E, 0x7E, 0x7E, 0x7E, 0x7D,
- 0x7D, 0xFC, 0x47, 0x64, 0xD0, 0xD0, 0x5D, 0x4B,
- 0x62, 0xCC, 0xD1, 0xDE, 0xDE, 0xD4, 0x5E, 0x43,
- 0x3F, 0x3E, 0x48, 0x53, 0x58, 0xDB, 0xD8, 0xDC,
- 0x5E, 0x5E, 0x5E, 0x53, 0xD4, 0xD2, 0xD0, 0xD0,
- 0x5E, 0x49, 0xA7, 0xA6, 0x89, 0x95, 0x8B, 0x9C,
- 0x9C, 0xFB, 0xD4, 0x22, 0x22, 0x22, 0x22, 0x23,
- 0x22, 0x23, 0x23, 0x2A, 0x22, 0x23, 0x23, 0x22,
- 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x23,
- 0x23, 0x22, 0x23, 0x23, 0x98, 0x8C, 0x8C, 0x88,
- 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xF8,
- 0xE9, 0x9C, 0x48, 0x5C, 0xD0, 0xCB, 0x48, 0x49,
- 0x5B, 0xCB, 0xCD, 0xE0, 0xF1, 0xDD, 0xD0, 0x4A,
- 0x41, 0x47, 0x45, 0x4C, 0x48, 0xD7, 0xDE, 0xDC,
- 0x5E, 0x5E, 0x5A, 0x58, 0xD1, 0xD0, 0xD0, 0xD2,
- 0x5C, 0x55, 0xA7, 0xA6, 0x87, 0x86, 0x89, 0x94,
- 0x9C, 0xA9, 0xFC, 0xF4, 0x22, 0x23, 0x22, 0x23,
- 0x22, 0x23, 0x22, 0x2A, 0x21, 0x23, 0x23, 0x22,
- 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x23,
- 0x22, 0x23, 0x22, 0x23, 0xA4, 0x89, 0x8C, 0xAA,
- 0xFB, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xF7,
- 0x85, 0x88, 0x8D, 0x59, 0x64, 0x63, 0x47, 0x3E,
- 0x4C, 0x60, 0x61, 0xE0, 0xF0, 0xDF, 0xD9, 0x5D,
- 0x2E, 0x3E, 0x3E, 0x47, 0x4D, 0xCD, 0xDE, 0xDC,
- 0x5D, 0x5C, 0x51, 0x5D, 0xD1, 0xD2, 0xD2, 0xD4,
- 0x5A, 0xBE, 0xA7, 0x98, 0x8A, 0x8A, 0xA0, 0x8B,
- 0x86, 0x86, 0xF7, 0xFC, 0xF7, 0x26, 0x23, 0x23,
- 0x22, 0x22, 0x22, 0x22, 0x21, 0x22, 0x23, 0x22,
- 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x23,
- 0x22, 0x21, 0x21, 0x21, 0xA1, 0x98, 0x9F, 0xBF,
- 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xA7,
- 0x8C, 0x86, 0x8D, 0x59, 0x5E, 0x5D, 0x3F, 0x3E,
- 0x47, 0x53, 0x63, 0xD9, 0xF0, 0xF1, 0xDE, 0xD0,
- 0x43, 0x3E, 0x47, 0x45, 0x4A, 0x5B, 0xDC, 0xDA,
- 0x5D, 0x59, 0x49, 0x5F, 0xD1, 0xD2, 0xD3, 0xB9,
- 0xA5, 0xA7, 0x98, 0x9B, 0x96, 0x9D, 0x89, 0x89,
- 0x8B, 0x9C, 0x9D, 0xFC, 0xFC, 0xFC, 0x26, 0x22,
- 0x23, 0x23, 0x22, 0x22, 0x21, 0x22, 0x23, 0x22,
- 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x23,
- 0x22, 0x22, 0x29, 0x2D, 0x99, 0x99, 0xA2, 0xAA,
- 0xC4, 0xFB, 0xFC, 0xFC, 0xFC, 0xF6, 0xBF, 0xA2,
- 0x9C, 0x9C, 0x8E, 0xDC, 0xCD, 0x51, 0x41, 0x3E,
- 0x45, 0x49, 0x58, 0xCD, 0xE0, 0xE0, 0xD8, 0xDA,
- 0x4C, 0x4A, 0x45, 0x45, 0x48, 0x47, 0xDA, 0xDA,
- 0x5C, 0x58, 0x44, 0x69, 0xA9, 0x98, 0xA4, 0xA6,
- 0xA1, 0xA4, 0x99, 0x9E, 0x9D, 0x8B, 0x8A, 0x97,
- 0x87, 0x9A, 0x8A, 0xC2, 0xFC, 0xFC, 0xFC, 0x4D,
- 0x21, 0x21, 0x23, 0x22, 0x21, 0x22, 0x23, 0x22,
- 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x23, 0x22,
- 0x21, 0x22, 0x2D, 0x34, 0xA4, 0xA2, 0xA2, 0xA9,
- 0xBF, 0xC0, 0xC3, 0xC1, 0xC0, 0xBE, 0xA6, 0x9D,
- 0x99, 0x87, 0xA2, 0xF1, 0xDC, 0x64, 0x42, 0x45,
- 0x47, 0x3E, 0x49, 0x4C, 0xDD, 0xDF, 0xD8, 0xDB,
- 0x5E, 0x4C, 0x48, 0x45, 0x45, 0x41, 0xD1, 0xD6,
- 0x5A, 0x55, 0x3F, 0xA7, 0xA1, 0x98, 0x9F, 0x99,
- 0x9F, 0x9D, 0x9A, 0x95, 0x8B, 0x97, 0x89, 0x8A,
- 0x88, 0x94, 0x9C, 0x8C, 0xFC, 0xFC, 0xFC, 0xFC,
- 0xF4, 0x21, 0x23, 0x22, 0x21, 0x22, 0x23, 0x22,
- 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x23,
- 0x23, 0x23, 0x2C, 0x2C, 0xA8, 0xA2, 0xA4, 0xA4,
- 0xA9, 0xAA, 0xAA, 0xAA, 0xA9, 0xA6, 0x98, 0x9C,
- 0x8B, 0x88, 0x98, 0x8D, 0xD8, 0xD6, 0x4E, 0x47,
- 0x47, 0x49, 0x47, 0x3F, 0xDA, 0xDD, 0xDE, 0xDD,
- 0xCC, 0x4A, 0x4B, 0x3E, 0x45, 0x43, 0x61, 0xD4,
- 0x56, 0x51, 0x44, 0xA4, 0x9B, 0x8B, 0x9C, 0x9A,
- 0xA0, 0xA2, 0x98, 0x98, 0x8B, 0x8B, 0x98, 0x98,
- 0x84, 0x8B, 0x94, 0x8A, 0xA4, 0xFC, 0xFC, 0xFC,
- 0xFC, 0xF2, 0x21, 0x22, 0x21, 0x22, 0x23, 0x22,
- 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x23, 0x23,
- 0x23, 0x22, 0x2C, 0x2D, 0xC0, 0xA4, 0xA2, 0xA4,
- 0xA4, 0xA6, 0xA6, 0xA6, 0xA4, 0xA2, 0x9F, 0x89,
- 0x8B, 0x9C, 0x9C, 0x8B, 0x68, 0xDB, 0x5F, 0x4B,
- 0x3E, 0x49, 0x4B, 0x3E, 0xCC, 0xDA, 0xDC, 0xDD,
- 0xD3, 0x49, 0x52, 0x48, 0x45, 0x45, 0x53, 0xD0,
- 0x51, 0x4A, 0x44, 0xA4, 0x9B, 0x8B, 0x9C, 0xA0,
- 0x9B, 0x86, 0x89, 0x98, 0x89, 0x8A, 0x96, 0x8A,
- 0x9C, 0x89, 0x89, 0x9C, 0x8C, 0xF6, 0xFC, 0xFC,
- 0xFC, 0xFC, 0x21, 0x22, 0x21, 0x22, 0x23, 0x22,
- 0x22, 0x22, 0x22, 0x23, 0x22, 0x21, 0x22, 0x23,
- 0x22, 0x21, 0x2B, 0x34, 0xC0, 0xA8, 0xA4, 0xA2,
- 0xA2, 0x98, 0xA1, 0xA0, 0x98, 0x9F, 0x95, 0x8A,
- 0x94, 0xA1, 0x8A, 0x84, 0x9B, 0x68, 0xCC, 0x49,
- 0x4A, 0x47, 0x4C, 0x4B, 0x51, 0xD3, 0xDA, 0xDC,
- 0xD5, 0x56, 0x56, 0x4A, 0x3E, 0x45, 0x48, 0x63,
- 0x4A, 0x47, 0x3E, 0xA7, 0x98, 0x9D, 0x9E, 0x8B,
- 0x95, 0x9B, 0x89, 0x86, 0x9B, 0x8B, 0x89, 0x84,
- 0x9A, 0xA1, 0x95, 0x9A, 0x8C, 0xA4, 0xFC, 0xFC,
- 0xFC, 0xFA, 0x23, 0x22, 0x21, 0x22, 0x23, 0x22,
- 0x22, 0x22, 0x22, 0x23, 0x22, 0x21, 0x22, 0x23,
- 0x21, 0x23, 0x2C, 0xF6, 0xBF, 0xA9, 0xA2, 0x99,
- 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9B, 0x87, 0x8B,
- 0x9C, 0x86, 0x9C, 0x8A, 0x87, 0x87, 0x89, 0x51,
- 0x54, 0x47, 0x4B, 0x50, 0x4B, 0xCF, 0xD6, 0xDC,
- 0xD5, 0x60, 0x54, 0x52, 0x48, 0x45, 0x40, 0x5A,
- 0x45, 0x43, 0x47, 0xA7, 0x98, 0x9B, 0x95, 0x95,
- 0x9A, 0x87, 0x98, 0x98, 0x8A, 0x86, 0x87, 0x9E,
- 0x9B, 0x95, 0x9D, 0x9D, 0x99, 0x85, 0xA6, 0xFA,
- 0xF2, 0x21, 0x23, 0x22, 0x21, 0x22, 0x23, 0x22,
- 0x22, 0x22, 0x22, 0x23, 0x22, 0x21, 0x22, 0x22,
- 0x21, 0x24, 0xFB, 0xF7, 0xBF, 0xA6, 0xA2, 0x99,
- 0x97, 0x89, 0x86, 0x89, 0x9C, 0x96, 0x9E, 0x94,
- 0x89, 0x99, 0x98, 0x89, 0x9E, 0x9B, 0x89, 0x8B,
- 0x58, 0x4B, 0x4A, 0x52, 0x48, 0xCC, 0xD3, 0xDA,
- 0xD3, 0x65, 0x4C, 0x58, 0x49, 0x3E, 0x2E, 0x4D,
- 0x40, 0x41, 0x45, 0xA9, 0xA1, 0x9B, 0x9E, 0x9C,
- 0x95, 0x8A, 0x94, 0x89, 0x96, 0x87, 0x9C, 0x9A,
- 0x84, 0x9D, 0x9C, 0x9E, 0x9A, 0x9C, 0x9D, 0xBB,
- 0x23, 0x23, 0x22, 0x22, 0x21, 0x22, 0x23, 0x22,
- 0x22, 0x22, 0x22, 0x23, 0x22, 0x21, 0x23, 0x23,
- 0x24, 0xFC, 0xFC, 0xF6, 0xBF, 0xA6, 0x9F, 0x99,
- 0x89, 0x95, 0x87, 0x94, 0x9D, 0x9E, 0x97, 0x9E,
- 0x95, 0x9B, 0x89, 0x95, 0x95, 0x9B, 0x89, 0x87,
- 0x5D, 0x56, 0x3E, 0x51, 0x3E, 0x60, 0xCF, 0xD3,
- 0xD2, 0xCD, 0x5C, 0x49, 0x4B, 0x3E, 0x2C, 0x48,
- 0x3E, 0x43, 0x3E, 0xA9, 0xA1, 0x9B, 0x97, 0x94,
- 0x95, 0x9A, 0x9C, 0x87, 0x87, 0x9B, 0x9C, 0x95,
- 0x9D, 0x89, 0x9A, 0x89, 0x9E, 0x9E, 0x8C, 0xA6,
- 0x20, 0x23, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22,
- 0x22, 0x22, 0x22, 0x22, 0x21, 0x21, 0x20, 0x40,
- 0xFC, 0xFC, 0xFC, 0xEC, 0xBE, 0xA4, 0x9F, 0x99,
- 0x95, 0x9F, 0xA0, 0x88, 0x9D, 0x8B, 0x97, 0x95,
- 0x87, 0x95, 0x96, 0x95, 0x97, 0x94, 0x94, 0x98,
- 0xD3, 0x4C, 0x47, 0x4D, 0x42, 0x4C, 0x60, 0xCC,
- 0xCE, 0xD0, 0x65, 0x4B, 0x47, 0x44, 0x2B, 0x45,
- 0x4B, 0x47, 0x49, 0xA7, 0xA1, 0x9A, 0x97, 0x89,
- 0x95, 0x97, 0x97, 0x9E, 0x89, 0x95, 0x89, 0x9C,
- 0x87, 0x95, 0x97, 0x99, 0x95, 0x99, 0x9F, 0xA4,
- 0xC4, 0x21, 0x21, 0x23, 0x21, 0x23, 0x23, 0x23,
- 0x23, 0x23, 0x23, 0x23, 0x21, 0x20, 0xFC, 0xFC,
- 0xFC, 0xFC, 0xFC, 0xEA, 0xAA, 0xA6, 0xA2, 0x99,
- 0x8B, 0x9A, 0x95, 0x9E, 0x9E, 0x9A, 0x94, 0x87,
- 0x94, 0x94, 0x89, 0x94, 0x9B, 0x9B, 0xA7, 0xDC,
- 0xDB, 0x65, 0x2E, 0x3E, 0x43, 0x44, 0x49, 0x58,
- 0x63, 0xD3, 0xD3, 0x5E, 0x42, 0x42, 0x2D, 0x40,
- 0x54, 0x4C, 0x4A, 0xA7, 0xA0, 0x99, 0x9B, 0x94,
- 0xA0, 0x8A, 0x9B, 0x9D, 0x87, 0x95, 0x94, 0x8B,
- 0x8A, 0x98, 0x9C, 0x8A, 0x9B, 0x99, 0xA2, 0xA6,
- 0xBF, 0xEC, 0x2A, 0x20, 0x21, 0x23, 0x21, 0x20,
- 0x20, 0x20, 0x20, 0x4C, 0xF9, 0xFC, 0xFC, 0xFC,
- 0xFC, 0xFC, 0xFC, 0xEB, 0xAA, 0xA4, 0x9F, 0x9C,
- 0x8B, 0x9B, 0x88, 0x84, 0x9E, 0x9D, 0x96, 0x94,
- 0x94, 0x9A, 0x9B, 0x9B, 0xA4, 0xD5, 0xCD, 0xDE,
- 0xF1, 0xDA, 0x4C, 0x2D, 0x41, 0x2B, 0x42, 0x4C,
- 0x5E, 0xD4, 0xD7, 0xCD, 0x49, 0x2E, 0x2E, 0x41,
- 0x5E, 0x57, 0xA7, 0xA6, 0xA7, 0xA4, 0xA2, 0x98,
- 0x9D, 0x9C, 0xA1, 0x99, 0x9D, 0x88, 0x8B, 0x9C,
- 0x8A, 0x9C, 0x9C, 0x94, 0x9C, 0x89, 0xA0, 0xA6,
- 0xAA, 0xEB, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
- 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
- 0xFC, 0xFC, 0xFB, 0xE9, 0xAA, 0xA6, 0xA2, 0x8B,
- 0x8B, 0x8A, 0x86, 0x9B, 0x9C, 0x98, 0xA0, 0x9B,
- 0x9B, 0x84, 0xA7, 0xB4, 0x61, 0xD1, 0xD2, 0xE0,
- 0xF1, 0xDC, 0x61, 0x2D, 0x2E, 0x3F, 0x56, 0x62,
- 0x5D, 0xD4, 0xD9, 0xD3, 0x54, 0x41, 0x41, 0x44,
- 0xCB, 0x60, 0x52, 0xA9, 0xA9, 0xA9, 0xA7, 0xA6,
- 0xA6, 0xA4, 0xA4, 0xA2, 0xA2, 0x9D, 0x95, 0x89,
- 0x9C, 0x8A, 0x9E, 0x9C, 0x8A, 0x9E, 0xA0, 0xA8,
- 0xC0, 0xE9, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
- 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
- 0xFC, 0xFC, 0xFC, 0xE9, 0xAA, 0xA6, 0xA0, 0x99,
- 0x9C, 0x8B, 0x9A, 0x84, 0x9B, 0x9B, 0x98, 0x98,
- 0xA9, 0xB9, 0x49, 0x57, 0xCB, 0xD4, 0xD3, 0xF1,
- 0xD8, 0xDA, 0xCE, 0x3F, 0x41, 0x4B, 0x5D, 0xCB,
- 0x5E, 0xD6, 0xDB, 0xD6, 0x5D, 0x43, 0x3F, 0x49,
- 0xD1, 0xCC, 0x4F, 0xDD, 0xC3, 0xBB, 0xBF, 0xAA,
- 0xAA, 0xA9, 0xAA, 0xA8, 0xA8, 0xA6, 0xA6, 0xA2,
- 0x9C, 0x9F, 0x9B, 0x9A, 0x9D, 0xA2, 0xA8, 0xAA,
- 0xC1, 0xEA, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
- 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
- 0xFC, 0xFC, 0xFC, 0xEA, 0xC0, 0xAA, 0xA6, 0xA2,
- 0xA2, 0x99, 0xA0, 0xA0, 0xA4, 0xA7, 0xA9, 0xC0,
- 0x67, 0x49, 0x54, 0x60, 0xD0, 0xD4, 0xCC, 0xDF,
- 0xD9, 0xD5, 0xD2, 0x3E, 0x47, 0x56, 0x60, 0xCD,
- 0x5D, 0xD9, 0xD9, 0xD6, 0x61, 0x3F, 0x47, 0x52,
- 0xD6, 0xD3, 0x62, 0x4D, 0x40, 0x4A, 0x57, 0xCA,
- 0xC3, 0xC1, 0xC1, 0xC0, 0xBF, 0xBF, 0xAA, 0xAA,
- 0xA6, 0xA4, 0xA4, 0xA4, 0xA6, 0xA8, 0xBE, 0xC1,
- 0xC9, 0xEB, 0xFB, 0xFB, 0xFC, 0xFC, 0xFC, 0xFC,
- 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
- 0xFC, 0xFC, 0xFC, 0xEB, 0xC3, 0xC0, 0xAA, 0xA8,
- 0xA6, 0xA6, 0xA6, 0xA9, 0xAA, 0xC0, 0xE8, 0xD0,
- 0xD2, 0x4C, 0x5E, 0x64, 0xD0, 0xD1, 0x5F, 0xD9,
- 0xD5, 0xD1, 0xD0, 0x48, 0x52, 0x5C, 0x64, 0xCD,
- 0x5C, 0xDC, 0xD7, 0xD5, 0x62, 0x3F, 0x4C, 0x53,
- 0xDA, 0xD7, 0xCE, 0x56, 0x40, 0x4B, 0x52, 0x56,
- 0xCE, 0xDF, 0x6A, 0xEB, 0xE9, 0xC9, 0xC3, 0xC0,
- 0xC0, 0xBF, 0xBE, 0xAA, 0xBF, 0xC0, 0xC3, 0xC9,
- 0xEA, 0xF6, 0xEE, 0x58, 0x57, 0x5E, 0xD6, 0xD0,
- 0xD2, 0x61, 0xCB, 0xD6, 0xD6, 0xD4, 0xDF, 0xF3,
- 0xF2, 0xDD, 0xD7, 0xEB, 0xC9, 0xC1, 0xC0, 0xBF,
- 0xAA, 0xAA, 0xAA, 0xBE, 0xC3, 0xF0, 0xD2, 0xD2,
- 0xD2, 0x51, 0x62, 0xCC, 0xD0, 0xCC, 0x61, 0xD3,
- 0xCF, 0xCE, 0xD2, 0x48, 0x5A, 0x61, 0xCC, 0xCE,
- 0x5F, 0xD9, 0xD5, 0xD1, 0x63, 0x44, 0x56, 0x56,
- 0xDC, 0xD9, 0xD4, 0x5E, 0x42, 0x4A, 0x4C, 0x57,
- 0x5D, 0xD8, 0xE0, 0xD8, 0xDC, 0xCB, 0x66, 0xEC,
- 0xE8, 0xC3, 0xC3, 0xC3, 0xC3, 0xC9, 0xE8, 0xEA,
- 0xF6, 0x50, 0x3E, 0x58, 0x57, 0x5A, 0xD6, 0xD4,
- 0xCC, 0x4B, 0x53, 0x5C, 0x64, 0xD1, 0xDF, 0xF3,
- 0xF1, 0xDE, 0xD9, 0xF6, 0xEB, 0xC9, 0xC1, 0xC1,
- 0xC0, 0xC0, 0xC1, 0xC9, 0xF0, 0xD6, 0xCD, 0xD6,
- 0xD3, 0x53, 0xCB, 0xCF, 0xCD, 0x5F, 0x5F, 0xCE,
- 0xCF, 0xCD, 0xD0, 0x47, 0x5F, 0xCB, 0xCE, 0xCD,
- 0x63, 0xD6, 0xD3, 0xD1, 0x63, 0x3F, 0x58, 0x58,
- 0xDB, 0xDC, 0xDA, 0x65, 0x3E, 0x49, 0x49, 0x4D,
- 0x49, 0xDC, 0xDF, 0xE0, 0xDE, 0xD5, 0x47, 0x47,
- 0x46, 0x6B, 0xEB, 0xEA, 0xE9, 0xEA, 0xEB, 0xF6,
- 0xD0, 0x57, 0x57, 0x47, 0x47, 0x5B, 0xD4, 0xD4,
- 0xCD, 0x44, 0x3E, 0x4B, 0x50, 0x4B, 0x51, 0xD5,
- 0xDB, 0xD8, 0xDE, 0x4B, 0xF6, 0xF6, 0xEA, 0xE9,
- 0xE8, 0xEA, 0xEB, 0x67, 0x5E, 0xCC, 0xD6, 0xDC,
- 0xD5, 0x58, 0xCE, 0xCE, 0x62, 0x50, 0xCC, 0xD3,
- 0xD2, 0xCD, 0xCD, 0x4B, 0x64, 0xCE, 0xCE, 0x64,
- 0xCC, 0xD3, 0xD2, 0xD2, 0x61, 0x47, 0x5D, 0x5C,
- 0xDD, 0xDD, 0xD9, 0xD1, 0x4C, 0x47, 0x49, 0x4A,
- 0x4B, 0xD1, 0xD8, 0xE0, 0xDF, 0xDD, 0x5D, 0x4A,
- 0x48, 0x52, 0x51, 0x3F, 0xF6, 0xEC, 0xE0, 0xE0,
- 0xD3, 0x5E, 0x5F, 0x50, 0x4B, 0x50, 0xCB, 0xCE,
- 0x64, 0x45, 0x4C, 0x57, 0x57, 0x58, 0x52, 0xD6,
- 0xD3, 0xDE, 0xDF, 0xD1, 0x3E, 0x4B, 0xF6, 0xF6,
- 0xEC, 0x66, 0x53, 0x43, 0x56, 0xD1, 0xD9, 0xDE,
- 0xD4, 0x5E, 0xCE, 0xCC, 0x5B, 0x2C, 0xD4, 0xD5,
- 0xD2, 0xD0, 0x63, 0x5D, 0xCD, 0xD0, 0xCD, 0x5E,
- 0xD0, 0xCF, 0xCE, 0xD2, 0x5E, 0x50, 0x60, 0x5D,
- 0xDE, 0xDD, 0xDC, 0xD7, 0x5D, 0x45, 0x47, 0x3E,
- 0x4B, 0x5E, 0xDE, 0xDF, 0xE0, 0xD8, 0xCF, 0x3E,
- 0x45, 0x51, 0x58, 0x42, 0xCB, 0xDA, 0xDE, 0xD8,
- 0xD2, 0x61, 0xCC, 0xCF, 0xD6, 0xDA, 0xDA, 0xD5,
- 0xD0, 0x50, 0x44, 0x57, 0x57, 0x58, 0x45, 0xD1,
- 0xD1, 0xD7, 0xDF, 0xDF, 0xD7, 0xCF, 0x64, 0x60,
- 0xCE, 0xCE, 0xCE, 0x63, 0xCF, 0xDA, 0xDE, 0xD9,
- 0xCF, 0x63, 0xCD, 0x63, 0x4D, 0x4B, 0xD6, 0xD5,
- 0xCE, 0xD3, 0x60, 0xCB, 0xD0, 0xD0, 0x65, 0x47,
- 0xD0, 0xCC, 0xCC, 0xD1, 0x59, 0x5D, 0x63, 0x5E,
- 0xDD, 0xDD, 0xDE, 0xDC, 0xCB, 0x40, 0x48, 0x45,
- 0x3E, 0x3E, 0xD9, 0xDF, 0xE0, 0xDF, 0xDA, 0x51,
- 0x4C, 0x48, 0x56, 0x4C, 0x5B, 0xD2, 0xDA, 0xDB,
- 0xCB, 0x5F, 0xD0, 0xCC, 0xDC, 0xF0, 0xF3, 0xE0,
- 0xDD, 0xCC, 0x41, 0x50, 0x57, 0x57, 0x4B, 0x5D,
- 0xD3, 0xD1, 0xDE, 0xDF, 0xDE, 0xD7, 0xD0, 0xD0,
- 0xD5, 0xD6, 0xD6, 0xCE, 0xD7, 0xDC, 0xDA, 0xD5,
- 0x60, 0x63, 0x64, 0x5E, 0x47, 0x61, 0xD5, 0xD2,
- 0xCF, 0xD0, 0x59, 0xCD, 0xD1, 0xCF, 0x61, 0x4D,
- 0xCC, 0xCE, 0xCD, 0xD0, 0x52, 0x61, 0x64, 0x60,
- 0xDA, 0xDE, 0xDE, 0xDD, 0xD1, 0x4B, 0x4A, 0x45,
- 0x3E, 0x41, 0xCD, 0xDE, 0xE0, 0xF1, 0xDE, 0x63,
- 0x4A, 0x4A, 0x4A, 0x4B, 0x50, 0xCB, 0xD4, 0xD7,
- 0x5E, 0x54, 0x62, 0xD3, 0xD4, 0xF0, 0xF3, 0xF3,
- 0xF2, 0xDE, 0x61, 0x40, 0x49, 0x56, 0x4D, 0x3E,
- 0x4B, 0xCE, 0xD9, 0xD8, 0xD9, 0xD5, 0xCF, 0xD2,
- 0xD6, 0xD6, 0xD1, 0xD1, 0xD7, 0xD5, 0xCF, 0xD0,
- 0x54, 0x64, 0x63, 0x56, 0x2C, 0xCB, 0xD1, 0xCC,
- 0xD3, 0xCD, 0x54, 0xCF, 0xD1, 0xCE, 0x5E, 0x5C,
- 0xCE, 0xCE, 0xCE, 0xCB, 0x4B, 0x63, 0xCC, 0x61,
- 0xD4, 0xDC, 0xDE, 0xDE, 0xDA, 0x5D, 0x45, 0x45,
- 0x48, 0x3F, 0x52, 0xD9, 0xD8, 0xDF, 0xDF, 0xD2,
- 0x52, 0x4B, 0x3E, 0x2E, 0x47, 0x60, 0xCF, 0xD3,
- 0x59, 0x48, 0x50, 0x5E, 0xCC, 0xDE, 0xF2, 0xF2,
- 0xF3, 0xF3, 0xDD, 0x5D, 0x3E, 0x48, 0x47, 0x47,
- 0x58, 0xD1, 0xDA, 0xDA, 0xD5, 0xD1, 0xCD, 0xD2,
- 0xD3, 0xCF, 0xD3, 0xD1, 0xCD, 0xD3, 0xD2, 0x5E,
- 0x52, 0x64, 0x60, 0x4B, 0x45, 0x61, 0xCD, 0xD3,
- 0xD3, 0x64, 0x61, 0xD0, 0xD0, 0x64, 0x45, 0x63,
- 0xD0, 0xCE, 0xD0, 0x60, 0x56, 0xCB, 0xCC, 0x62,
- 0xCE, 0xDA, 0xDE, 0xD8, 0xDD, 0xCC, 0x45, 0x49,
- 0x3E, 0x47, 0x42, 0xD1, 0xDC, 0xD8, 0xD8, 0xD3,
- 0x5D, 0x4C, 0x49, 0x3F, 0x47, 0x59, 0xCD, 0xCF,
- 0x59, 0x2E, 0x48, 0x47, 0x52, 0x63, 0xF0, 0xF2,
- 0xF3, 0xF3, 0xF2, 0xDA, 0x52, 0x4B, 0x52, 0x58,
- 0x5E, 0x63, 0xD0, 0xD0, 0xD0, 0xCF, 0xCE, 0xCE,
- 0xCF, 0x65, 0x61, 0xD6, 0xD6, 0xD6, 0xCB, 0x4B,
- 0x61, 0x62, 0x5D, 0x43, 0x4B, 0x61, 0xD0, 0xD4,
- 0xD1, 0x61, 0xCE, 0xD2, 0xCD, 0x5E, 0x4A, 0xCE,
- 0xD0, 0xCC, 0xD0, 0x59, 0x61, 0xCC, 0xCC, 0x62,
- 0xD1, 0xD5, 0xDE, 0xD8, 0xDD, 0xCF, 0x4B, 0x4A,
- 0x45, 0x3E, 0x2D, 0xCB, 0xDC, 0xDE, 0xD8, 0xD5,
- 0x60, 0x54, 0x51, 0x4C, 0x4D, 0x5C, 0xCC, 0xCE,
- 0x5A, 0x2C, 0x50, 0x53, 0x3E, 0x59, 0xD8, 0xF3,
- 0xF2, 0xF3, 0xF3, 0xE0, 0x5E, 0x4A, 0x4C, 0x53,
- 0x5E, 0x63, 0xCC, 0xCC, 0xCC, 0xCD, 0xCF, 0xD3,
- 0x62, 0x53, 0xD6, 0xD6, 0xD6, 0xD6, 0x5B, 0x48,
- 0x64, 0x63, 0x59, 0x44, 0x57, 0x63, 0xD2, 0xD3,
- 0xD0, 0x5E, 0xD0, 0xD1, 0xCB, 0x58, 0x4C, 0xCF,
- 0xCF, 0xCE, 0xCE, 0x57, 0x63, 0xCC, 0xCD, 0x57,
-};
-
-unsigned char linux_logo_bw[] __initdata = {
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x3F,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F,
- 0xFE, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFE, 0x3F, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFE, 0x7F, 0xFF, 0xC7, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xC3,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF,
- 0xFB, 0xE3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFD, 0xFF, 0xFF, 0xE1, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xF9, 0xFF, 0xFF, 0xF1, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0xFF, 0xFF, 0xF1,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0xFF,
- 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xF9, 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xF9, 0xCF, 0xC3, 0xF8, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0x87, 0x81, 0xF9,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0xA7,
- 0x99, 0xF9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xF9, 0xF3, 0xBC, 0xF9, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xF9, 0xE3, 0xBC, 0xF9, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0xB0, 0x3C, 0xF9,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0xB0,
- 0x19, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xF9, 0xC0, 0x03, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xF9, 0x80, 0x01, 0xF8, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0x80, 0x01, 0xF8,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0x80,
- 0x01, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xF9, 0xC0, 0x21, 0xD8, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xF9, 0xB1, 0x80, 0xEC, 0xC0, 0x1F,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xF1, 0x90, 0x00, 0xE4,
- 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xF1, 0x8C,
- 0xC0, 0x7C, 0x04, 0x81, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xE3, 0x80, 0x00, 0x7C, 0x40, 0x11, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xE3, 0x80, 0x00, 0x7F, 0xD2, 0x29,
- 0xFF, 0xFF, 0xFF, 0xFF, 0x87, 0x00, 0x00, 0x3F,
- 0x80, 0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0x0E, 0x00,
- 0x00, 0x3F, 0x80, 0x19, 0xFF, 0xFF, 0xFF, 0xFF,
- 0x1E, 0x00, 0x00, 0x1F, 0x80, 0x19, 0xFF, 0xFF,
- 0xFF, 0xFE, 0x1C, 0x00, 0x00, 0x1E, 0x80, 0x19,
- 0xFF, 0xFF, 0xFF, 0xFE, 0x3C, 0x00, 0x00, 0x1E,
- 0x80, 0x11, 0xFF, 0xFF, 0xFF, 0xFC, 0x7C, 0x00,
- 0x00, 0x0F, 0x80, 0x11, 0xFF, 0xFF, 0xFF, 0xFC,
- 0xF8, 0x00, 0x00, 0x0E, 0x80, 0x11, 0xFF, 0xFF,
- 0xFF, 0xFC, 0xF8, 0x00, 0x00, 0x06, 0x00, 0x11,
- 0xFF, 0xFF, 0xFF, 0xF8, 0xF8, 0x00, 0x00, 0x06,
- 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xF9, 0xF0, 0x00,
- 0x00, 0x02, 0x00, 0x09, 0xFF, 0xFF, 0xFF, 0xF1,
- 0xF0, 0x00, 0x00, 0x02, 0x80, 0x10, 0xFF, 0xFF,
- 0xFF, 0xF1, 0xE0, 0x00, 0x00, 0x00, 0x97, 0x10,
- 0xFF, 0xFF, 0xFF, 0xE3, 0xE0, 0x00, 0x00, 0x00,
- 0xDF, 0xF0, 0xFF, 0xFF, 0xFF, 0xE3, 0xC0, 0x00,
- 0x00, 0x00, 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0xC7,
- 0xC0, 0x00, 0x00, 0x01, 0xFF, 0xF8, 0xFF, 0xFF,
- 0xFF, 0xC7, 0x80, 0x00, 0x00, 0x01, 0xFF, 0xF8,
- 0xFF, 0xFF, 0xFF, 0x8F, 0x80, 0x00, 0x00, 0x01,
- 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0x8F, 0x80, 0x00,
- 0x00, 0x01, 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0x9F,
- 0x80, 0x00, 0x00, 0x01, 0xFF, 0xF8, 0xFF, 0xFF,
- 0xFF, 0x9F, 0x80, 0x00, 0x00, 0x01, 0x80, 0x18,
- 0xFF, 0xFF, 0xFF, 0x9E, 0x80, 0x00, 0x00, 0x03,
- 0xA8, 0x11, 0xFF, 0xFF, 0xFF, 0x9F, 0x80, 0x00,
- 0x00, 0x02, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x99,
- 0x80, 0x00, 0x00, 0x00, 0x00, 0x09, 0xFF, 0xFF,
- 0xFF, 0x00, 0x80, 0x00, 0x00, 0x01, 0xC0, 0x01,
- 0xFF, 0xFF, 0xFE, 0x20, 0x60, 0x00, 0x00, 0x00,
- 0xFF, 0xC3, 0xFF, 0xFF, 0xF8, 0x00, 0x30, 0x00,
- 0x00, 0x00, 0xFF, 0x0F, 0xFF, 0xFF, 0xC0, 0x40,
- 0x38, 0x00, 0x00, 0x00, 0xFE, 0x47, 0xFF, 0xFF,
- 0x81, 0x00, 0x1C, 0x00, 0x00, 0x00, 0xFC, 0x23,
- 0xFF, 0xFF, 0x90, 0x00, 0x1E, 0x00, 0x00, 0x00,
- 0x78, 0x11, 0xFF, 0xFF, 0x80, 0x00, 0x0F, 0x80,
- 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00,
- 0x07, 0xC0, 0x00, 0x00, 0x00, 0x08, 0xFF, 0xFF,
- 0xC0, 0x00, 0x07, 0xC0, 0x00, 0x00, 0x00, 0x04,
- 0x7F, 0xFF, 0x80, 0x00, 0x03, 0xC0, 0x00, 0x10,
- 0x00, 0x00, 0x1F, 0xFF, 0x80, 0x00, 0x01, 0x80,
- 0x00, 0x30, 0x00, 0x00, 0x0F, 0xFF, 0x80, 0x00,
- 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, 0x4F, 0xFF,
- 0x80, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00,
- 0x0F, 0xFF, 0xC0, 0x00, 0x00, 0x80, 0x03, 0xF0,
- 0x00, 0x00, 0x8F, 0xFF, 0x80, 0x00, 0x00, 0x40,
- 0x0F, 0xF0, 0x00, 0x04, 0x1F, 0xFF, 0x80, 0x00,
- 0x00, 0x7F, 0xFF, 0xF0, 0x00, 0x10, 0x1F, 0xFF,
- 0xC0, 0x00, 0x00, 0x7F, 0xFF, 0xF0, 0x00, 0x40,
- 0xFF, 0xFF, 0x98, 0x00, 0x00, 0xFF, 0xFF, 0xF0,
- 0x00, 0x83, 0xFF, 0xFF, 0x81, 0xE0, 0x01, 0xFF,
- 0xFF, 0xF8, 0x02, 0x07, 0xFF, 0xFF, 0x80, 0x3F,
- 0x07, 0xE0, 0x00, 0x1C, 0x0C, 0x1F, 0xFF, 0xFF,
- 0xF8, 0x03, 0xFF, 0x80, 0x00, 0x1F, 0x78, 0x1F,
- 0xFF, 0xFF, 0xFF, 0x80, 0x7F, 0x00, 0x07, 0x0F,
- 0xF0, 0x7F, 0xFF, 0xFF, 0xFF, 0xFE, 0x0C, 0x07,
- 0xFF, 0x83, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0x00, 0x1F, 0xFF, 0xC0, 0x03, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x07, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-};
-
-/* Painted by Johnny Stenback <jst@uwasa.fi> */
-
-unsigned char *linux_serial_image __initdata = "\n"
-" .u$e.\n"
-" .$$$$$:S\n"
-" $\"*$/\"*$$\n"
-" $.`$ . ^F\n"
-" 4k+#+T.$F\n"
-" 4P+++\"$\"$\n"
-" :R\"+ t$$B\n"
-" ___# $$$\n"
-" | | R$$k\n"
-" dd. | Linux $!$\n"
-" ddd | Sparc $9$F\n"
-" '!!!!!$ !!#!`\n"
-" !!!!!* .!!!!!`\n"
-"'!!!!!!!W..e$$!!!!!!` %s\n"
-" \"~^^~ ^~~^\n"
-"\n";
diff --git a/include/asm-sparc/processor.h b/include/asm-sparc/processor.h
index a6efa8c2c..6ee971dc2 100644
--- a/include/asm-sparc/processor.h
+++ b/include/asm-sparc/processor.h
@@ -1,4 +1,4 @@
-/* $Id: processor.h,v 1.57 1997/03/04 16:27:22 jj Exp $
+/* $Id: processor.h,v 1.59 1997/05/01 01:42:03 davem Exp $
* include/asm-sparc/processor.h
*
* Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu)
@@ -83,7 +83,7 @@ struct thread_struct {
#define SPARC_FLAG_UNALIGNED 0x2 /* is allowed to do unaligned accesses */
#define INIT_MMAP { &init_mm, (0), (0), \
- __pgprot(0x0) , VM_READ | VM_WRITE | VM_EXEC }
+ __pgprot(0x0) , VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap }
#define INIT_TSS { \
/* uwinmask, kregs, sig_address, sig_desc, ksp, kpc, kpsr, kwim */ \
@@ -144,11 +144,14 @@ extern __inline__ void start_thread(struct pt_regs * regs, unsigned long pc,
#define release_thread(tsk) do { } while(0)
#ifdef __KERNEL__
+
/* Allocation and freeing of basic task resources. */
-extern unsigned long (*alloc_kernel_stack)(struct task_struct *tsk);
-extern void (*free_kernel_stack)(unsigned long stack);
extern struct task_struct *(*alloc_task_struct)(void);
extern void (*free_task_struct)(struct task_struct *tsk);
+
+#define init_task (init_task_union.task)
+#define init_stack (init_task_union.stack)
+
#endif
/*
diff --git a/include/asm-sparc/semaphore.h b/include/asm-sparc/semaphore.h
index 48da860e4..eac2160e7 100644
--- a/include/asm-sparc/semaphore.h
+++ b/include/asm-sparc/semaphore.h
@@ -28,20 +28,18 @@ extern void __up(struct semaphore * sem);
* XXX spinlock can allow this to be done without grabbing the IRQ
* XXX global lock.
*/
-static inline int waking_non_zero(struct semaphore *sem)
-{
- unsigned long flags;
- int ret = 0;
-
- save_flags(flags);
- cli();
- if (atomic_read(&sem->waking) > 0) {
- atomic_dec(&sem->waking);
- ret = 1;
- }
- restore_flags(flags);
- return ret;
-}
+#define waking_non_zero(sem) \
+({ unsigned long flags; \
+ int ret = 0; \
+ save_flags(flags); \
+ cli(); \
+ if (atomic_read(&sem->waking) > 0) { \
+ atomic_dec(&sem->waking); \
+ ret = 1; \
+ } \
+ restore_flags(flags); \
+ ret; \
+})
/* This isn't quite as clever as the x86 side, I'll be fixing this
* soon enough.
diff --git a/include/asm-sparc/smp.h b/include/asm-sparc/smp.h
index 7d4106b03..106fa4e1b 100644
--- a/include/asm-sparc/smp.h
+++ b/include/asm-sparc/smp.h
@@ -85,7 +85,7 @@ extern __volatile__ int cpu_number_map[NR_CPUS];
extern __volatile__ int cpu_logical_map[NR_CPUS];
extern unsigned long smp_proc_in_lock[NR_CPUS];
-extern __inline__ int smp_processor_id(void)
+extern __inline__ int hard_smp_processor_id(void)
{
int cpuid;
@@ -96,6 +96,8 @@ extern __inline__ int smp_processor_id(void)
return cpuid;
}
+#define smp_processor_id() hard_smp_processor_id()
+
#endif /* !(__ASSEMBLY__) */
/* Sparc specific messages. */
diff --git a/include/asm-sparc/spinlock.h b/include/asm-sparc/spinlock.h
index 877b7416a..eb612dca4 100644
--- a/include/asm-sparc/spinlock.h
+++ b/include/asm-sparc/spinlock.h
@@ -55,6 +55,82 @@ typedef struct { } rwlock_t;
#include <asm/psr.h>
+/* Define this to use the verbose/debugging versions in arch/sparc/lib/debuglocks.c */
+#define SPIN_LOCK_DEBUG
+
+#ifdef SPIN_LOCK_DEBUG
+struct _spinlock_debug {
+ unsigned char lock;
+ unsigned long owner_pc;
+};
+typedef struct _spinlock_debug spinlock_t;
+
+#define SPIN_LOCK_UNLOCKED { 0, 0 }
+#define spin_lock_init(lp) do { (lp)->owner_pc = 0; (lp)->lock = 0; } while(0)
+#define spin_unlock_wait(lp) do { barrier(); } while((lp)->lock)
+
+extern void _spin_lock(spinlock_t *lock);
+extern int _spin_trylock(spinlock_t *lock);
+extern void _spin_unlock(spinlock_t *lock);
+extern void _spin_lock_irq(spinlock_t *lock);
+extern void _spin_unlock_irq(spinlock_t *lock);
+extern void _spin_lock_irqsave(spinlock_t *lock);
+extern void _spin_unlock_irqrestore(spinlock_t *lock);
+
+#define spin_lock(lp) _spin_lock(lp)
+#define spin_trylock(lp) _spin_trylock(lp)
+#define spin_unlock(lp) _spin_unlock(lp)
+#define spin_lock_irq(lp) _spin_lock_irq(lp)
+#define spin_unlock_irq(lp) _spin_unlock_irq(lp)
+#define spin_lock_irqsave(lp, flags) do { __save_and_cli(flags); \
+ _spin_lock_irqsave(lp); } while (0)
+#define spin_unlock_irqrestore(lp, flags) do { _spin_unlock_irqrestore(lp); \
+ __restore_flags(flags); } while(0)
+
+struct _rwlock_debug {
+ volatile unsigned int lock;
+ unsigned long owner_pc;
+};
+typedef struct _rwlock_debug rwlock_t;
+
+#define RW_LOCK_UNLOCKED { 0, 0 }
+
+extern void _read_lock(rwlock_t *rw);
+extern void _read_unlock(rwlock_t *rw);
+extern void _write_lock(rwlock_t *rw);
+extern void _write_unlock(rwlock_t *rw);
+extern void _read_lock_irq(rwlock_t *rw);
+extern void _read_unlock_irq(rwlock_t *rw);
+extern void _write_lock_irq(rwlock_t *rw);
+extern void _write_unlock_irq(rwlock_t *rw);
+extern void _read_lock_irqsave(rwlock_t *rw);
+extern void _read_unlock_irqrestore(rwlock_t *rw);
+extern void _write_lock_irqsave(rwlock_t *rw);
+extern void _write_unlock_irqrestore(rwlock_t *rw);
+
+#define read_lock(rw) _read_lock(rw)
+#define read_unlock(rw) _read_unlock(rw)
+#define write_lock(rw) _write_lock(rw)
+#define write_unlock(rw) _write_unlock(rw)
+#define read_lock_irq(rw) _read_lock_irq(rw)
+#define read_unlock_irq(rw) _read_unlock_irq(rw)
+#define write_lock_irq(rw) _write_lock_irq(rw)
+#define write_unlock_irq(rw) _write_unlock_irq(rw)
+
+#define read_lock_irqsave(rw, flags) \
+do { __save_and_cli(flags); _read_lock_irqsave(rw); } while (0)
+
+#define read_unlock_irqrestore(rw, flags) do { _read_unlock_irqrestore(rw); \
+ __restore_flags(flags); } while(0)
+
+#define write_lock_irqsave(rw, flags) \
+do { __save_and_cli(flags); _write_lock_irqsave(rw); } while(0)
+
+#define write_unlock_irqrestore(rw, flags) do { _write_unlock_irqrestore(rw); \
+ __restore_flags(flags); } while(0)
+
+#else /* !SPIN_LOCK_DEBUG */
+
typedef unsigned char spinlock_t;
#define SPIN_LOCK_UNLOCKED 0
@@ -151,7 +227,7 @@ do { \
"b,a 1b\n\t" \
".previous\n" \
: "=r" (flags) \
- : "i" (PSR_PIL), "r" (lock) \
+ : "i" (PSR_PIL), "r" (lp) \
: "g2", "memory", "cc"); \
} while(0)
@@ -198,7 +274,7 @@ typedef struct { volatile unsigned int lock; } rwlock_t;
*
* Unfortunately this scheme limits us to ~65,000 cpus.
*/
-extern __inline__ void read_lock(rwlock_t *rw)
+extern __inline__ void _read_lock(rwlock_t *rw)
{
register rwlock_t *lp asm("g1");
lp = rw;
@@ -211,7 +287,14 @@ extern __inline__ void read_lock(rwlock_t *rw)
: "g2", "g4", "g7", "memory", "cc");
}
-extern __inline__ void read_unlock(rwlock_t *rw)
+#define read_lock(lock) \
+do { unsigned long flags; \
+ __save_and_cli(flags); \
+ _read_lock(lock); \
+ __restore_flags(flags); \
+} while(0)
+
+extern __inline__ void _read_unlock(rwlock_t *rw)
{
register rwlock_t *lp asm("g1");
lp = rw;
@@ -224,6 +307,13 @@ extern __inline__ void read_unlock(rwlock_t *rw)
: "g2", "g4", "g7", "memory", "cc");
}
+#define read_unlock(lock) \
+do { unsigned long flags; \
+ __save_and_cli(flags); \
+ _read_unlock(lock); \
+ __restore_flags(flags); \
+} while(0)
+
extern __inline__ void write_lock(rwlock_t *rw)
{
register rwlock_t *lp asm("g1");
@@ -238,20 +328,22 @@ extern __inline__ void write_lock(rwlock_t *rw)
}
#define write_unlock(rw) do { (rw)->lock = 0; } while(0)
-#define read_lock_irq(lock) do { __cli(); read_lock(lock); } while (0)
-#define read_unlock_irq(lock) do { read_unlock(lock); __sti(); } while (0)
+#define read_lock_irq(lock) do { __cli(); _read_lock(lock); } while (0)
+#define read_unlock_irq(lock) do { _read_unlock(lock); __sti(); } while (0)
#define write_lock_irq(lock) do { __cli(); write_lock(lock); } while (0)
#define write_unlock_irq(lock) do { write_unlock(lock); __sti(); } while (0)
#define read_lock_irqsave(lock, flags) \
- do { __save_and_cli(flags); read_lock(lock); } while (0)
+ do { __save_and_cli(flags); _read_lock(lock); } while (0)
#define read_unlock_irqrestore(lock, flags) \
- do { read_unlock(lock); __restore_flags(flags); } while (0)
+ do { _read_unlock(lock); __restore_flags(flags); } while (0)
#define write_lock_irqsave(lock, flags) \
do { __save_and_cli(flags); write_lock(lock); } while (0)
#define write_unlock_irqrestore(lock, flags) \
do { write_unlock(lock); __restore_flags(flags); } while (0)
+#endif /* SPIN_LOCK_DEBUG */
+
#endif /* __SMP__ */
#endif /* !(__ASSEMBLY__) */
diff --git a/include/asm-sparc/string.h b/include/asm-sparc/string.h
index ca5dc4003..d4ed14b26 100644
--- a/include/asm-sparc/string.h
+++ b/include/asm-sparc/string.h
@@ -1,4 +1,4 @@
-/* $Id: string.h,v 1.30 1997/03/03 17:11:12 jj Exp $
+/* $Id: string.h,v 1.31 1997/05/03 02:02:12 davem Exp $
* string.h: External definitions for optimized assembly string
* routines for the Linux Kernel.
*
@@ -34,7 +34,7 @@ extern __kernel_size_t __memset(void *,int,__kernel_size_t);
extern inline void *__constant_memcpy(void *to, const void *from, __kernel_size_t n)
{
- extern void __copy_1page(void *, const void *);
+ extern void (*__copy_1page)(void *, const void *);
if(n <= 32) {
__builtin_memcpy(to, from, n);
@@ -67,7 +67,7 @@ extern inline void *__nonconstant_memcpy(void *to, const void *from, __kernel_si
extern inline void *__constant_c_and_count_memset(void *s, char c, __kernel_size_t count)
{
- extern void *bzero_1page(void *);
+ extern void (*bzero_1page)(void *);
extern __kernel_size_t __bzero(void *, __kernel_size_t);
if(!c) {
diff --git a/include/asm-sparc/system.h b/include/asm-sparc/system.h
index e1d33e436..69d7cfe16 100644
--- a/include/asm-sparc/system.h
+++ b/include/asm-sparc/system.h
@@ -1,4 +1,4 @@
-/* $Id: system.h,v 1.58 1997/04/18 05:44:54 davem Exp $ */
+/* $Id: system.h,v 1.65 1997/05/14 20:47:59 davem Exp $ */
#ifndef __SPARC_SYSTEM_H
#define __SPARC_SYSTEM_H
@@ -75,6 +75,7 @@ extern void fpsave(unsigned long *fpregs, unsigned long *fsr,
#define switch_to(prev, next) do { \
__label__ here; \
register unsigned long task_pc asm("o7"); \
+ extern struct task_struct *current_set[NR_CPUS]; \
SWITCH_ENTER \
SWITCH_DO_LAZY_FPU \
__asm__ __volatile__( \
@@ -86,6 +87,7 @@ extern void fpsave(unsigned long *fpregs, unsigned long *fsr,
if(!(next->tss.flags & SPARC_FLAG_KTHREAD) && \
!(next->flags & PF_EXITING)) \
switch_to_context(next); \
+ next->mm->cpu_vm_mask |= (1 << smp_processor_id()); \
task_pc = ((unsigned long) &&here) - 0x8; \
__asm__ __volatile__( \
"rd %%psr, %%g4\n\t" \
@@ -108,7 +110,7 @@ extern void fpsave(unsigned long *fpregs, unsigned long *fsr,
"nop\n\t" \
"nop\n\t" \
"jmpl %%o7 + 0x8, %%g0\n\t" \
- " nop\n\t" : : "r" (&(current_set[smp_processor_id()])), "r" (next), \
+ " nop\n\t" : : "r" (&(current_set[hard_smp_processor_id()])), "r" (next), \
"i" ((const unsigned long)(&((struct task_struct *)0)->tss.kpsr)), \
"i" ((const unsigned long)(&((struct task_struct *)0)->tss.ksp)), \
"r" (task_pc) \
@@ -136,6 +138,7 @@ extern __inline__ void __cli(void)
__asm__ __volatile__("
rd %%psr, %0
+ nop; nop; nop;
or %0, %1, %0
wr %0, 0x0, %%psr
nop; nop; nop
@@ -149,7 +152,8 @@ extern __inline__ void __sti(void)
unsigned long tmp;
__asm__ __volatile__("
- rd %%psr, %0
+ rd %%psr, %0
+ nop; nop; nop;
andn %0, %1, %0
wr %0, 0x0, %%psr
nop; nop; nop
@@ -168,23 +172,22 @@ extern __inline__ unsigned long getipl(void)
extern __inline__ unsigned long swap_pil(unsigned long __new_psr)
{
- unsigned long retval, tmp1, tmp2;
+ unsigned long retval;
__asm__ __volatile__("
rd %%psr, %0
- and %0, %4, %1
- and %3, %4, %2
- xorcc %1, %2, %%g0
+ nop; nop; nop;
+ and %0, %2, %%g1
+ and %1, %2, %%g2
+ xorcc %%g1, %%g2, %%g0
be 1f
nop
- wr %0, %4, %%psr
- nop
- nop
- nop
+ wr %0, %2, %%psr
+ nop; nop; nop;
1:
-" : "=r" (retval), "=r" (tmp1), "=r" (tmp2)
+" : "=r" (retval)
: "r" (__new_psr), "i" (PSR_PIL)
- : "memory", "cc");
+ : "g1", "g2", "memory", "cc");
return retval;
}
@@ -195,6 +198,7 @@ extern __inline__ unsigned long read_psr_and_cli(void)
__asm__ __volatile__("
rd %%psr, %0
+ nop; nop; nop;
or %0, %1, %%g1
wr %%g1, 0x0, %%psr
nop; nop; nop
@@ -211,6 +215,28 @@ extern __inline__ unsigned long read_psr_and_cli(void)
#ifdef __SMP__
+/* This goes away after lockups have been found... */
+#ifndef DEBUG_IRQLOCK
+#define DEBUG_IRQLOCK
+#endif
+
+extern unsigned char global_irq_holder;
+
+#define save_flags(x) \
+do { ((x) = ((global_irq_holder == (unsigned char) smp_processor_id()) ? 1 : \
+ ((getipl() & PSR_PIL) ? 2 : 0))); } while(0)
+
+#define save_and_cli(flags) do { save_flags(flags); cli(); } while(0)
+
+#ifdef DEBUG_IRQLOCK
+extern void __global_cli(void);
+extern void __global_sti(void);
+extern void __global_restore_flags(unsigned long flags);
+#define cli() __global_cli()
+#define sti() __global_sti()
+#define restore_flags(flags) __global_restore_flags(flags)
+#else
+
/* Visit arch/sparc/lib/irqlock.S for all the fun details... */
#define cli() __asm__ __volatile__("mov %%o7, %%g4\n\t" \
"call ___global_cli\n\t" \
@@ -230,16 +256,6 @@ do { register unsigned long bits asm("g7"); \
"memory", "cc"); \
} while(0)
-extern unsigned char global_irq_holder;
-
-#define save_flags(x) \
-do { int cpuid; \
- __asm__ __volatile__("rd %%tbr, %0; srl %0, 12, %0; and %0, 3, %0" \
- : "=r" (cpuid)); \
- ((x) = ((global_irq_holder == (unsigned char) cpuid) ? 1 : \
- ((getipl() & PSR_PIL) ? 2 : 0))); \
-} while(0)
-
#define restore_flags(flags) \
do { register unsigned long bits asm("g7"); \
bits = flags; \
@@ -252,7 +268,7 @@ do { register unsigned long bits asm("g7"); \
"memory", "cc"); \
} while(0)
-#define save_and_cli(flags) do { save_flags(flags); cli(); } while(0)
+#endif /* DEBUG_IRQLOCK */
#else
@@ -271,6 +287,12 @@ do { register unsigned long bits asm("g7"); \
extern __inline__ unsigned long xchg_u32(__volatile__ unsigned long *m, unsigned long val)
{
+#ifdef __SMP__
+ __asm__ __volatile__("swap [%2], %0"
+ : "=&r" (val)
+ : "0" (val), "r" (m));
+ return val;
+#else
register unsigned long *ptr asm("g1");
register unsigned long ret asm("g2");
@@ -286,6 +308,7 @@ extern __inline__ unsigned long xchg_u32(__volatile__ unsigned long *m, unsigned
: "g3", "g4", "g7", "memory", "cc");
return ret;
+#endif
}
#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
diff --git a/include/asm-sparc/termbits.h b/include/asm-sparc/termbits.h
index 7a6958340..1e4ed5e50 100644
--- a/include/asm-sparc/termbits.h
+++ b/include/asm-sparc/termbits.h
@@ -146,7 +146,13 @@ struct termios {
#define HUPCL 0x00000400
#define CLOCAL 0x00000800
#define CBAUDEX 0x00001000
-#define B76800 0x00001001
+/* We'll never see these speeds with the Zilogs, but for completeness... */
+#define B57600 0x00001001
+#define B115200 0x00001002
+#define B230400 0x00001003
+#define B460800 0x00001004
+/* This is what we can do with the Zilogs. */
+#define B76800 0x00001005
#define CIBAUD 0x100f0000 /* input baud rate (not used) */
#define CMSPAR 0x40000000 /* mark or space (stick) parity */
#define CRTSCTS 0x80000000 /* flow control */
diff --git a/include/asm-sparc/winmacro.h b/include/asm-sparc/winmacro.h
index 8ba88ec61..cb2f4e73b 100644
--- a/include/asm-sparc/winmacro.h
+++ b/include/asm-sparc/winmacro.h
@@ -1,4 +1,4 @@
-/* $Id: winmacro.h,v 1.18 1997/03/04 16:27:27 jj Exp $
+/* $Id: winmacro.h,v 1.19 1997/05/01 01:42:05 davem Exp $
* winmacro.h: Window loading-unloading macros.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -114,12 +114,11 @@
#ifdef __SMP__
#define LOAD_CURRENT(dest_reg, idreg) \
rd %tbr, %idreg; \
- srl %idreg, 10, %idreg; \
- and %idreg, 0xc, %idreg; \
sethi %hi(C_LABEL(current_set)), %dest_reg; \
+ srl %idreg, 10, %idreg; \
or %dest_reg, %lo(C_LABEL(current_set)), %dest_reg; \
- add %dest_reg, %idreg, %idreg; \
- ld [%idreg], %dest_reg;
+ and %idreg, 0xc, %idreg; \
+ ld [%idreg + %dest_reg], %dest_reg;
#else
#define LOAD_CURRENT(dest_reg, idreg) \
sethi %hi(C_LABEL(current_set)), %idreg; \
diff --git a/include/asm-sparc64/a.out.h b/include/asm-sparc64/a.out.h
index 9b17dc36d..1a16d0a74 100644
--- a/include/asm-sparc64/a.out.h
+++ b/include/asm-sparc64/a.out.h
@@ -1,4 +1,4 @@
-/* $Id: a.out.h,v 1.3 1997/04/07 18:57:14 jj Exp $ */
+/* $Id: a.out.h,v 1.4 1997/05/04 07:21:19 davem Exp $ */
#ifndef __SPARC64_A_OUT_H__
#define __SPARC64_A_OUT_H__
@@ -95,7 +95,7 @@ struct relocation_info /* used when header.a_machtype == M_SPARC */
#ifdef __KERNEL__
-#define STACK_TOP TASK_SIZE
+#define STACK_TOP (current->tss.flags & SPARC_FLAG_32BIT ? 0xf0000000 : TASK_SIZE)
#endif
diff --git a/include/asm-sparc64/asm_offsets.h b/include/asm-sparc64/asm_offsets.h
index a232d9e80..ac7449777 100644
--- a/include/asm-sparc64/asm_offsets.h
+++ b/include/asm-sparc64/asm_offsets.h
@@ -30,123 +30,125 @@
#define ASIZ_task_next_run 0x00000008
#define AOFF_task_prev_run 0x000000a0
#define ASIZ_task_prev_run 0x00000008
-#define AOFF_task_saved_kernel_stack 0x000000a8
-#define ASIZ_task_saved_kernel_stack 0x00000008
-#define AOFF_task_kernel_stack_page 0x000000b0
-#define ASIZ_task_kernel_stack_page 0x00000008
-#define AOFF_task_exit_code 0x000000b8
+#define AOFF_task_exit_code 0x000000a8
#define ASIZ_task_exit_code 0x00000004
-#define AOFF_task_exit_signal 0x000000bc
+#define AOFF_task_exit_signal 0x000000ac
#define ASIZ_task_exit_signal 0x00000004
-#define AOFF_task_personality 0x000000c0
+#define AOFF_task_personality 0x000000b0
#define ASIZ_task_personality 0x00000008
-#define AOFF_task_pid 0x000000cc
+#define AOFF_task_pid 0x000000bc
#define ASIZ_task_pid 0x00000004
-#define AOFF_task_pgrp 0x000000d0
+#define AOFF_task_pgrp 0x000000c0
#define ASIZ_task_pgrp 0x00000004
-#define AOFF_task_tty_old_pgrp 0x000000d4
+#define AOFF_task_tty_old_pgrp 0x000000c4
#define ASIZ_task_tty_old_pgrp 0x00000004
-#define AOFF_task_session 0x000000d8
+#define AOFF_task_session 0x000000c8
#define ASIZ_task_session 0x00000004
-#define AOFF_task_leader 0x000000dc
+#define AOFF_task_leader 0x000000cc
#define ASIZ_task_leader 0x00000004
-#define AOFF_task_ngroups 0x000000e0
+#define AOFF_task_ngroups 0x000000d0
#define ASIZ_task_ngroups 0x00000004
-#define AOFF_task_groups 0x000000e4
+#define AOFF_task_groups 0x000000d4
#define ASIZ_task_groups 0x00000080
-#define AOFF_task_p_opptr 0x00000168
+#define AOFF_task_p_opptr 0x00000158
#define ASIZ_task_p_opptr 0x00000008
-#define AOFF_task_p_pptr 0x00000170
+#define AOFF_task_p_pptr 0x00000160
#define ASIZ_task_p_pptr 0x00000008
-#define AOFF_task_p_cptr 0x00000178
+#define AOFF_task_p_cptr 0x00000168
#define ASIZ_task_p_cptr 0x00000008
-#define AOFF_task_p_ysptr 0x00000180
+#define AOFF_task_p_ysptr 0x00000170
#define ASIZ_task_p_ysptr 0x00000008
-#define AOFF_task_p_osptr 0x00000188
+#define AOFF_task_p_osptr 0x00000178
#define ASIZ_task_p_osptr 0x00000008
-#define AOFF_task_wait_chldexit 0x00000190
+#define AOFF_task_pidhash_next 0x00000180
+#define ASIZ_task_pidhash_next 0x00000008
+#define AOFF_task_pidhash_pprev 0x00000188
+#define ASIZ_task_pidhash_pprev 0x00000008
+#define AOFF_task_tarray_ptr 0x00000190
+#define ASIZ_task_tarray_ptr 0x00000008
+#define AOFF_task_wait_chldexit 0x00000198
#define ASIZ_task_wait_chldexit 0x00000008
-#define AOFF_task_uid 0x00000198
+#define AOFF_task_uid 0x000001a0
#define ASIZ_task_uid 0x00000002
-#define AOFF_task_euid 0x0000019a
+#define AOFF_task_euid 0x000001a2
#define ASIZ_task_euid 0x00000002
-#define AOFF_task_suid 0x0000019c
+#define AOFF_task_suid 0x000001a4
#define ASIZ_task_suid 0x00000002
-#define AOFF_task_fsuid 0x0000019e
+#define AOFF_task_fsuid 0x000001a6
#define ASIZ_task_fsuid 0x00000002
-#define AOFF_task_gid 0x000001a0
+#define AOFF_task_gid 0x000001a8
#define ASIZ_task_gid 0x00000002
-#define AOFF_task_egid 0x000001a2
+#define AOFF_task_egid 0x000001aa
#define ASIZ_task_egid 0x00000002
-#define AOFF_task_sgid 0x000001a4
+#define AOFF_task_sgid 0x000001ac
#define ASIZ_task_sgid 0x00000002
-#define AOFF_task_fsgid 0x000001a6
+#define AOFF_task_fsgid 0x000001ae
#define ASIZ_task_fsgid 0x00000002
-#define AOFF_task_timeout 0x000001a8
+#define AOFF_task_timeout 0x000001b0
#define ASIZ_task_timeout 0x00000008
-#define AOFF_task_policy 0x000001b0
+#define AOFF_task_policy 0x000001b8
#define ASIZ_task_policy 0x00000008
-#define AOFF_task_rt_priority 0x000001b8
+#define AOFF_task_rt_priority 0x000001c0
#define ASIZ_task_rt_priority 0x00000008
-#define AOFF_task_it_real_value 0x000001c0
+#define AOFF_task_it_real_value 0x000001c8
#define ASIZ_task_it_real_value 0x00000008
-#define AOFF_task_it_prof_value 0x000001c8
+#define AOFF_task_it_prof_value 0x000001d0
#define ASIZ_task_it_prof_value 0x00000008
-#define AOFF_task_it_virt_value 0x000001d0
+#define AOFF_task_it_virt_value 0x000001d8
#define ASIZ_task_it_virt_value 0x00000008
-#define AOFF_task_it_real_incr 0x000001d8
+#define AOFF_task_it_real_incr 0x000001e0
#define ASIZ_task_it_real_incr 0x00000008
-#define AOFF_task_it_prof_incr 0x000001e0
+#define AOFF_task_it_prof_incr 0x000001e8
#define ASIZ_task_it_prof_incr 0x00000008
-#define AOFF_task_it_virt_incr 0x000001e8
+#define AOFF_task_it_virt_incr 0x000001f0
#define ASIZ_task_it_virt_incr 0x00000008
-#define AOFF_task_real_timer 0x000001f0
+#define AOFF_task_real_timer 0x000001f8
#define ASIZ_task_real_timer 0x00000028
-#define AOFF_task_utime 0x00000218
+#define AOFF_task_utime 0x00000220
#define ASIZ_task_utime 0x00000008
-#define AOFF_task_stime 0x00000220
+#define AOFF_task_stime 0x00000228
#define ASIZ_task_stime 0x00000008
-#define AOFF_task_cutime 0x00000228
+#define AOFF_task_cutime 0x00000230
#define ASIZ_task_cutime 0x00000008
-#define AOFF_task_cstime 0x00000230
+#define AOFF_task_cstime 0x00000238
#define ASIZ_task_cstime 0x00000008
-#define AOFF_task_start_time 0x00000238
+#define AOFF_task_start_time 0x00000240
#define ASIZ_task_start_time 0x00000008
-#define AOFF_task_min_flt 0x00000240
+#define AOFF_task_min_flt 0x00000248
#define ASIZ_task_min_flt 0x00000008
-#define AOFF_task_maj_flt 0x00000248
+#define AOFF_task_maj_flt 0x00000250
#define ASIZ_task_maj_flt 0x00000008
-#define AOFF_task_nswap 0x00000250
+#define AOFF_task_nswap 0x00000258
#define ASIZ_task_nswap 0x00000008
-#define AOFF_task_cmin_flt 0x00000258
+#define AOFF_task_cmin_flt 0x00000260
#define ASIZ_task_cmin_flt 0x00000008
-#define AOFF_task_cmaj_flt 0x00000260
+#define AOFF_task_cmaj_flt 0x00000268
#define ASIZ_task_cmaj_flt 0x00000008
-#define AOFF_task_cnswap 0x00000268
+#define AOFF_task_cnswap 0x00000270
#define ASIZ_task_cnswap 0x00000008
-#define AOFF_task_swap_address 0x00000278
+#define AOFF_task_swap_address 0x00000280
#define ASIZ_task_swap_address 0x00000008
-#define AOFF_task_old_maj_flt 0x00000280
+#define AOFF_task_old_maj_flt 0x00000288
#define ASIZ_task_old_maj_flt 0x00000008
-#define AOFF_task_dec_flt 0x00000288
+#define AOFF_task_dec_flt 0x00000290
#define ASIZ_task_dec_flt 0x00000008
-#define AOFF_task_swap_cnt 0x00000290
+#define AOFF_task_swap_cnt 0x00000298
#define ASIZ_task_swap_cnt 0x00000008
-#define AOFF_task_rlim 0x00000298
+#define AOFF_task_rlim 0x000002a0
#define ASIZ_task_rlim 0x000000a0
-#define AOFF_task_used_math 0x00000338
+#define AOFF_task_used_math 0x00000340
#define ASIZ_task_used_math 0x00000002
-#define AOFF_task_comm 0x0000033a
+#define AOFF_task_comm 0x00000342
#define ASIZ_task_comm 0x00000010
-#define AOFF_task_link_count 0x0000034c
+#define AOFF_task_link_count 0x00000354
#define ASIZ_task_link_count 0x00000004
-#define AOFF_task_tty 0x00000350
+#define AOFF_task_tty 0x00000358
#define ASIZ_task_tty 0x00000008
-#define AOFF_task_semundo 0x00000358
+#define AOFF_task_semundo 0x00000360
#define ASIZ_task_semundo 0x00000008
-#define AOFF_task_semsleeping 0x00000360
+#define AOFF_task_semsleeping 0x00000368
#define ASIZ_task_semsleeping 0x00000008
-#define AOFF_task_ldt 0x00000368
+#define AOFF_task_ldt 0x00000370
#define ASIZ_task_ldt 0x00000008
#define AOFF_task_tss 0x00000380
#define ASIZ_task_tss 0x00000600
@@ -158,56 +160,62 @@
#define ASIZ_task_mm 0x00000008
#define AOFF_task_sig 0x00000998
#define ASIZ_task_sig 0x00000008
-#define AOFF_task_processor 0x000009a0
+#define AOFF_task_has_cpu 0x000009a0
+#define ASIZ_task_has_cpu 0x00000004
+#define AOFF_task_processor 0x000009a4
#define ASIZ_task_processor 0x00000004
-#define AOFF_task_last_processor 0x000009a4
+#define AOFF_task_last_processor 0x000009a8
#define ASIZ_task_last_processor 0x00000004
-#define AOFF_task_lock_depth 0x000009a8
+#define AOFF_task_lock_depth 0x000009ac
#define ASIZ_task_lock_depth 0x00000004
-#define AOFF_mm_count 0x00000000
-#define ASIZ_mm_count 0x00000004
-#define AOFF_mm_pgd 0x00000008
+#define AOFF_task_sigmask_lock 0x000009b0
+#define ASIZ_task_sigmask_lock 0x00000000
+#define AOFF_mm_mmap 0x00000000
+#define ASIZ_mm_mmap 0x00000008
+#define AOFF_mm_mmap_cache 0x00000008
+#define ASIZ_mm_mmap_cache 0x00000008
+#define AOFF_mm_pgd 0x00000010
#define ASIZ_mm_pgd 0x00000008
-#define AOFF_mm_context 0x00000010
+#define AOFF_mm_count 0x00000018
+#define ASIZ_mm_count 0x00000004
+#define AOFF_mm_mmap_sem 0x00000020
+#define ASIZ_mm_mmap_sem 0x00000010
+#define AOFF_mm_context 0x00000030
#define ASIZ_mm_context 0x00000008
-#define AOFF_mm_start_code 0x00000018
+#define AOFF_mm_start_code 0x00000038
#define ASIZ_mm_start_code 0x00000008
-#define AOFF_mm_end_code 0x00000020
+#define AOFF_mm_end_code 0x00000040
#define ASIZ_mm_end_code 0x00000008
-#define AOFF_mm_start_data 0x00000028
+#define AOFF_mm_start_data 0x00000048
#define ASIZ_mm_start_data 0x00000008
-#define AOFF_mm_end_data 0x00000030
+#define AOFF_mm_end_data 0x00000050
#define ASIZ_mm_end_data 0x00000008
-#define AOFF_mm_start_brk 0x00000038
+#define AOFF_mm_start_brk 0x00000058
#define ASIZ_mm_start_brk 0x00000008
-#define AOFF_mm_brk 0x00000040
+#define AOFF_mm_brk 0x00000060
#define ASIZ_mm_brk 0x00000008
-#define AOFF_mm_start_stack 0x00000048
+#define AOFF_mm_start_stack 0x00000068
#define ASIZ_mm_start_stack 0x00000008
-#define AOFF_mm_start_mmap 0x00000050
+#define AOFF_mm_start_mmap 0x00000070
#define ASIZ_mm_start_mmap 0x00000008
-#define AOFF_mm_arg_start 0x00000058
+#define AOFF_mm_arg_start 0x00000078
#define ASIZ_mm_arg_start 0x00000008
-#define AOFF_mm_arg_end 0x00000060
+#define AOFF_mm_arg_end 0x00000080
#define ASIZ_mm_arg_end 0x00000008
-#define AOFF_mm_env_start 0x00000068
+#define AOFF_mm_env_start 0x00000088
#define ASIZ_mm_env_start 0x00000008
-#define AOFF_mm_env_end 0x00000070
+#define AOFF_mm_env_end 0x00000090
#define ASIZ_mm_env_end 0x00000008
-#define AOFF_mm_rss 0x00000078
+#define AOFF_mm_rss 0x00000098
#define ASIZ_mm_rss 0x00000008
-#define AOFF_mm_total_vm 0x00000080
+#define AOFF_mm_total_vm 0x000000a0
#define ASIZ_mm_total_vm 0x00000008
-#define AOFF_mm_locked_vm 0x00000088
+#define AOFF_mm_locked_vm 0x000000a8
#define ASIZ_mm_locked_vm 0x00000008
-#define AOFF_mm_def_flags 0x00000090
+#define AOFF_mm_def_flags 0x000000b0
#define ASIZ_mm_def_flags 0x00000008
-#define AOFF_mm_mmap 0x00000098
-#define ASIZ_mm_mmap 0x00000008
-#define AOFF_mm_mmap_avl 0x000000a0
-#define ASIZ_mm_mmap_avl 0x00000008
-#define AOFF_mm_mmap_sem 0x000000a8
-#define ASIZ_mm_mmap_sem 0x00000010
+#define AOFF_mm_cpu_vm_mask 0x000000b8
+#define ASIZ_mm_cpu_vm_mask 0x00000008
#define AOFF_thread_float_regs 0x00000000
#define ASIZ_thread_float_regs 0x00000100
#define AOFF_thread_fsr 0x00000100
diff --git a/include/asm-sparc64/bitops.h b/include/asm-sparc64/bitops.h
index 39a16948d..8e7a9a472 100644
--- a/include/asm-sparc64/bitops.h
+++ b/include/asm-sparc64/bitops.h
@@ -1,4 +1,4 @@
-/* $Id: bitops.h,v 1.11 1997/04/10 23:32:42 davem Exp $
+/* $Id: bitops.h,v 1.12 1997/05/14 20:48:04 davem Exp $
* bitops.h: Bit string operations on the V9.
*
* Copyright 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -19,7 +19,7 @@
* all bit-ops return 0 if bit was previously clear and != 0 otherwise.
*/
-extern __inline__ unsigned long set_bit(unsigned long nr, void *addr)
+extern __inline__ unsigned long test_and_set_bit(unsigned long nr, void *addr)
{
unsigned long oldbit;
unsigned long temp0, temp1;
@@ -42,7 +42,12 @@ extern __inline__ unsigned long set_bit(unsigned long nr, void *addr)
return oldbit != 0;
}
-extern __inline__ unsigned long clear_bit(unsigned long nr, void *addr)
+extern __inline__ void set_bit(unsigned long nr, void *addr)
+{
+ (void) test_and_set_bit(nr, addr);
+}
+
+extern __inline__ unsigned long test_and_clear_bit(unsigned long nr, void *addr)
{
unsigned long oldbit;
unsigned long temp0, temp1;
@@ -65,7 +70,12 @@ extern __inline__ unsigned long clear_bit(unsigned long nr, void *addr)
return oldbit != 0;
}
-extern __inline__ unsigned long change_bit(unsigned long nr, void *addr)
+extern __inline__ void clear_bit(unsigned long nr, void *addr)
+{
+ (void) test_and_clear_bit(nr, addr);
+}
+
+extern __inline__ unsigned long test_and_change_bit(unsigned long nr, void *addr)
{
unsigned long oldbit;
unsigned long temp0, temp1;
@@ -86,6 +96,11 @@ extern __inline__ unsigned long change_bit(unsigned long nr, void *addr)
return oldbit != 0;
}
+extern __inline__ void change_bit(unsigned long nr, void *addr)
+{
+ (void) test_and_change_bit(nr, addr);
+}
+
extern __inline__ unsigned long test_bit(int nr, __const__ void *addr)
{
return 1UL & (((__const__ int *) addr)[nr >> 5] >> (nr & 31));
@@ -266,8 +281,8 @@ found_middle:
#define ext2_find_next_zero_bit find_next_zero_le_bit
/* Bitmap functions for the minix filesystem. */
-#define minix_set_bit(nr,addr) set_bit(nr,addr)
-#define minix_clear_bit(nr,addr) clear_bit(nr,addr)
+#define minix_set_bit(nr,addr) test_and_set_bit(nr,addr)
+#define minix_clear_bit(nr,addr) test_and_clear_bit(nr,addr)
#define minix_test_bit(nr,addr) test_bit(nr,addr)
#define minix_find_first_zero_bit(addr,size) find_first_zero_bit(addr,size)
diff --git a/include/asm-sparc64/checksum.h b/include/asm-sparc64/checksum.h
index 543e5a627..63dbfec3d 100644
--- a/include/asm-sparc64/checksum.h
+++ b/include/asm-sparc64/checksum.h
@@ -1,4 +1,4 @@
-/* $Id: checksum.h,v 1.6 1997/04/10 23:32:43 davem Exp $ */
+/* $Id: checksum.h,v 1.7 1997/05/14 07:02:44 davem Exp $ */
#ifndef __SPARC64_CHECKSUM_H
#define __SPARC64_CHECKSUM_H
@@ -54,6 +54,7 @@ csum_partial_copy_nocheck (const char *src, char *dst, int len,
__asm__ __volatile__ ("
call __csum_partial_copy_sparc_generic
mov %4, %%g7
+ srl %%o0, 0, %%o0
" : "=r" (ret) : "0" (ret), "r" (d), "r" (l), "r" (sum) :
"o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3", "g5", "g7");
return (unsigned int)ret;
@@ -81,6 +82,7 @@ csum_partial_copy_from_user(const char *src, char *dst, int len,
1:
call __csum_partial_copy_sparc_generic
stx %5, [%%sp + 0x7ff + 128]
+ srl %%o0, 0, %%o0
" : "=r" (ret) : "0" (ret), "r" (d), "r" (l), "r" (s), "r" (err) :
"o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3", "g5", "g7");
return (unsigned int)ret;
@@ -108,6 +110,7 @@ csum_partial_copy_to_user(const char *src, char *dst, int len,
1:
call __csum_partial_copy_sparc_generic
stx %5, [%%sp + 0x7ff + 128]
+ srl %%o0, 0, %%o0
" : "=r" (ret) : "0" (ret), "r" (d), "r" (l), "r" (s), "r" (err) :
"o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3", "g5", "g7");
return (unsigned int)ret;
@@ -151,6 +154,7 @@ extern __inline__ unsigned short ip_fast_csum(__const__ unsigned char *iph,
srl %%g2, 16, %0
addc %0, %%g0, %0
xnor %%g0, %0, %0
+ srl %0, 0, %0
" : "=r" (sum), "=&r" (iph)
: "r" (ihl), "1" (iph)
: "g2", "g3", "g7", "cc");
@@ -179,11 +183,11 @@ extern __inline__ unsigned short csum_tcpudp_magic(unsigned long saddr,
" : "=r" (sum), "=r" (saddr)
: "r" (daddr), "r" ((proto<<16)+len), "0" (sum), "1" (saddr)
: "cc");
- return sum;
+ return (sum & 0xffff);
}
/* Fold a partial checksum without adding pseudo headers. */
-extern __inline__ unsigned int csum_fold(unsigned int sum)
+extern __inline__ unsigned short csum_fold(unsigned int sum)
{
unsigned int tmp;
@@ -195,7 +199,7 @@ extern __inline__ unsigned int csum_fold(unsigned int sum)
" : "=&r" (sum), "=r" (tmp)
: "0" (sum), "1" (sum<<16)
: "cc");
- return sum;
+ return (sum & 0xffff);
}
#define _HAVE_ARCH_IPV6_CSUM
diff --git a/include/asm-sparc64/current.h b/include/asm-sparc64/current.h
index 8cdfc6109..80652fb35 100644
--- a/include/asm-sparc64/current.h
+++ b/include/asm-sparc64/current.h
@@ -1,12 +1,6 @@
#ifndef _SPARC64_CURRENT_H
#define _SPARC64_CURRENT_H
-/* Some architectures may want to do something "clever" here since
- * this is the most frequently accessed piece of data in the entire
- * kernel.
- */
-extern struct task_struct *current_set[NR_CPUS];
-
/* Sparc rules... */
register struct task_struct *current asm("g6");
diff --git a/include/asm-sparc64/elf.h b/include/asm-sparc64/elf.h
index d5e29751c..9a43b6c3f 100644
--- a/include/asm-sparc64/elf.h
+++ b/include/asm-sparc64/elf.h
@@ -1,4 +1,4 @@
-/* $Id: elf.h,v 1.3 1997/04/04 00:50:12 davem Exp $ */
+/* $Id: elf.h,v 1.6 1997/05/17 11:51:27 davem Exp $ */
#ifndef __ASM_SPARC64_ELF_H
#define __ASM_SPARC64_ELF_H
@@ -7,6 +7,7 @@
*/
#include <asm/ptrace.h>
+#include <asm/processor.h>
typedef unsigned long elf_greg_t;
@@ -16,21 +17,24 @@ typedef elf_greg_t elf_gregset_t[ELF_NGREG];
typedef unsigned long elf_fpregset_t;
/*
- * This is used to ensure we don't load something for the wrong architecture.
- */
-#define elf_check_arch(x) ((x) == EM_SPARC)
-
-/*
* These are used to set parameters in the core dumps.
*/
#ifndef ELF_ARCH
-#define ELF_ARCH EM_SPARC64
-#define ELF_CLASS ELFCLASS64
-#define ELF_DATA ELFDATA2MSB;
+#define ELF_ARCH EM_SPARC64
+#define ELF_CLASS ELFCLASS64
+#define ELF_DATA ELFDATA2MSB;
#endif
-#define USE_ELF_CORE_DUMP
-#define ELF_EXEC_PAGESIZE 4096
+#ifndef ELF_FLAGS_INIT
+#define ELF_FLAGS_INIT current->tss.flags &= ~SPARC_FLAG_32BIT
+#endif
+/*
+ * This is used to ensure we don't load something for the wrong architecture.
+ */
+#define elf_check_arch(x) ((x) == ELF_ARCH) /* Might be EM_SPARC64 or EM_SPARC */
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE 8192
#endif /* !(__ASM_SPARC64_ELF_H) */
diff --git a/include/asm-sparc64/fs_mount.h b/include/asm-sparc64/fs_mount.h
new file mode 100644
index 000000000..3ad7ad698
--- /dev/null
+++ b/include/asm-sparc64/fs_mount.h
@@ -0,0 +1,44 @@
+/* $Id: fs_mount.h,v 1.2 1997/04/18 14:34:46 jj Exp $
+ * fs_mount.h: Definitions for mount structure conversions.
+ *
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+#ifndef __ASM_FS_MOUNT_H
+#define __ASM_FS_MOUNT_H
+
+#if defined(CONFIG_SPARC32_COMPAT) || defined(CONFIG_SPARC32_COMPAT_MODULE)
+
+#include <linux/sched.h>
+
+/* We need this to convert 32bit mount structures to 64bit */
+
+extern void *do_ncp_super_data_conv(void *raw_data);
+extern void *do_smb_super_data_conv(void *raw_data);
+
+extern __inline__ void *ncp_super_data_conv(void *raw_data)
+{
+ if (current->tss.flags & SPARC_FLAG_32BIT)
+ return do_ncp_super_data_conv(raw_data);
+ else
+ return raw_data;
+}
+
+extern __inline__ void *smb_super_data_conv(void *raw_data)
+{
+ if (current->tss.flags & SPARC_FLAG_32BIT)
+ return do_smb_super_data_conv(raw_data);
+ else
+ return raw_data;
+}
+
+#else /* CONFIG_SPARC32_COMPAT* */
+
+#define ncp_super_data_conv(__x) __x
+#define smb_super_data_conv(__x) __x
+
+#endif /* CONFIG_SPARC32_COMPAT* */
+
+#define nfs_super_data_conv(__x) __x
+
+#endif /* __ASM_FS_MOUNT_H */
diff --git a/include/asm-sparc64/head.h b/include/asm-sparc64/head.h
index 60ed4ca66..e3d03bf0f 100644
--- a/include/asm-sparc64/head.h
+++ b/include/asm-sparc64/head.h
@@ -1,4 +1,4 @@
-/* $Id: head.h,v 1.16 1997/04/08 11:03:13 davem Exp $ */
+/* $Id: head.h,v 1.19 1997/05/18 08:42:18 davem Exp $ */
#ifndef _SPARC64_HEAD_H
#define _SPARC64_HEAD_H
@@ -113,7 +113,7 @@
#define INDIRECT_SOLARIS_SYSCALL(tlvl) TRAP_ARG(indirect_syscall, tlvl)
#define TRAP_IRQ(routine, level) \
- rdpr %pil, %g4; \
+ rdpr %pil, %g2; \
wrpr %g0, 15, %pil; \
ba,pt %xcc, etrap_irq; \
rd %pc, %g7; \
@@ -147,6 +147,9 @@
flushw; \
done; nop; nop; nop; nop; nop; nop;
+/* Before touching these macros, you owe it to yourself to go and
+ * see how arch/sparc64/kernel/winfixup.S works... -DaveM
+ */
/* Normal kernel spill */
#define SPILL_0_NORMAL \
@@ -189,23 +192,25 @@
stxa %i6, [%sp + STACK_BIAS + 0x70] %asi; \
stxa %i7, [%sp + STACK_BIAS + 0x78] %asi; \
saved; retry; nop; nop; nop; nop; nop; nop; \
- nop; nop; nop; nop; nop; nop; nop;
+ nop; nop; nop; nop; nop; nop; \
+ b,a,pt %xcc, spill_fixup;
/* Normal 32bit spill */
#define SPILL_2_GENERIC(xxx) \
wr %g0, xxx, %asi; \
srl %sp, 0, %sp; \
stda %l0, [%sp + 0x00] %asi; \
- stda %l2, [%sp + 0x10] %asi; \
- stda %l4, [%sp + 0x20] %asi; \
- stda %l6, [%sp + 0x30] %asi; \
- stda %i0, [%sp + 0x40] %asi; \
- stda %i2, [%sp + 0x50] %asi; \
- stda %i4, [%sp + 0x60] %asi; \
- stda %i6, [%sp + 0x70] %asi; \
+ stda %l2, [%sp + 0x08] %asi; \
+ stda %l4, [%sp + 0x10] %asi; \
+ stda %l6, [%sp + 0x18] %asi; \
+ stda %i0, [%sp + 0x20] %asi; \
+ stda %i2, [%sp + 0x28] %asi; \
+ stda %i4, [%sp + 0x30] %asi; \
+ stda %i6, [%sp + 0x38] %asi; \
saved; retry; nop; nop; nop; nop; \
nop; nop; nop; nop; nop; nop; nop; nop; \
- nop; nop; nop; nop; nop; nop; nop; nop;
+ nop; nop; nop; nop; nop; nop; nop; \
+ b,a,pt %xcc, spill_fixup;
#define SPILL_1_NORMAL SPILL_1_GENERIC(ASI_AIUP)
#define SPILL_2_NORMAL SPILL_2_GENERIC(ASI_AIUP)
@@ -265,23 +270,25 @@
ldxa [%sp + STACK_BIAS + 0x70] %asi, %i6; \
ldxa [%sp + STACK_BIAS + 0x78] %asi, %i7; \
restored; retry; nop; nop; nop; nop; nop; nop; \
- nop; nop; nop; nop; nop; nop; nop;
+ nop; nop; nop; nop; nop; nop; \
+ b,a,pt %xcc, fill_fixup;
/* Normal 32bit fill */
#define FILL_2_GENERIC(xxx) \
wr %g0, xxx, %asi; \
srl %sp, 0, %sp; \
ldda [%sp + 0x00] %asi, %l0; \
- ldda [%sp + 0x10] %asi, %l2; \
- ldda [%sp + 0x20] %asi, %l4; \
- ldda [%sp + 0x30] %asi, %l6; \
- ldda [%sp + 0x40] %asi, %i0; \
- ldda [%sp + 0x50] %asi, %i2; \
- ldda [%sp + 0x60] %asi, %i4; \
- ldda [%sp + 0x70] %asi, %i6; \
+ ldda [%sp + 0x08] %asi, %l2; \
+ ldda [%sp + 0x10] %asi, %l4; \
+ ldda [%sp + 0x18] %asi, %l6; \
+ ldda [%sp + 0x20] %asi, %i0; \
+ ldda [%sp + 0x28] %asi, %i2; \
+ ldda [%sp + 0x30] %asi, %i4; \
+ ldda [%sp + 0x38] %asi, %i6; \
restored; retry; nop; nop; nop; nop; \
nop; nop; nop; nop; nop; nop; nop; nop; \
- nop; nop; nop; nop; nop; nop; nop; nop;
+ nop; nop; nop; nop; nop; nop; nop; \
+ b,a,pt %xcc, fill_fixup;
#define FILL_1_NORMAL FILL_1_GENERIC(ASI_AIUP)
#define FILL_2_NORMAL FILL_2_GENERIC(ASI_AIUP)
diff --git a/include/asm-sparc64/linux_logo.h b/include/asm-sparc64/linux_logo.h
index 7787fb059..35254c6a3 100644
--- a/include/asm-sparc64/linux_logo.h
+++ b/include/asm-sparc64/linux_logo.h
@@ -1040,1045 +1040,3 @@ unsigned char *linux_serial_image __initdata = "\n"
"'!!!!!!!W..e$$!!!!!!` %s\n"
" \"~^^~ ^~~^\n"
"\n";
-/* $Id: linux_logo.h,v 1.1 1997/04/16 17:51:37 jj Exp $
- * include/asm-sparc64/linux_logo.h: This is a linux logo
- * to be displayed on boot.
- *
- * Copyright (C) 1996 Larry Ewing (lewing@isc.tamu.edu)
- * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- *
- * You can put anything here, but:
- * LINUX_LOGO_COLORS has to be less than 224
- * image size has to be 80x80
- * values have to start from 0x20
- * (i.e. RGB(linux_logo_red[0],
- * linux_logo_green[0],
- * linux_logo_blue[0]) is color 0x20)
- * BW image has to be 80x80 as well, with MS bit
- * on the left
- * Serial_console ascii image can be any size,
- * but should contain %s to display the version
- */
-
-#include <linux/init.h>
-#include <linux/version.h>
-
-#define linux_logo_banner "Linux/UltraSPARC version " UTS_RELEASE
-
-#define LINUX_LOGO_COLORS 215
-
-unsigned char linux_logo_red[] __initdata = {
- 0x99, 0x95, 0x92, 0x8E, 0x8A, 0x86, 0x02, 0x00,
- 0xA5, 0xA9, 0xA2, 0x9E, 0xAD, 0x1B, 0x3B, 0x25,
- 0x71, 0x65, 0x2C, 0x82, 0x5B, 0x33, 0x13, 0xB0,
- 0x0C, 0xB1, 0xD4, 0xCE, 0x04, 0x06, 0x16, 0xB6,
- 0xCD, 0xB2, 0x42, 0x46, 0x4B, 0xA8, 0xF3, 0xCA,
- 0xC5, 0x1C, 0xDC, 0xA0, 0xD4, 0xE6, 0xED, 0xF3,
- 0xC2, 0x8E, 0xCC, 0xA5, 0x7E, 0x52, 0xF7, 0xE3,
- 0x56, 0x79, 0x68, 0x8D, 0xAF, 0xFC, 0x8E, 0x3E,
- 0x6B, 0x11, 0x37, 0x79, 0x5C, 0x3C, 0x3F, 0x3C,
- 0x48, 0x47, 0x3D, 0xB9, 0x62, 0xE1, 0x4D, 0x57,
- 0x84, 0x78, 0xA6, 0x58, 0x99, 0xCD, 0xB7, 0xE3,
- 0x6D, 0x5A, 0xAF, 0x79, 0x79, 0xF2, 0x42, 0x46,
- 0xDD, 0x89, 0xC3, 0xF2, 0xF0, 0xE0, 0xD1, 0x90,
- 0x76, 0x6B, 0x4A, 0xBE, 0xBD, 0xE3, 0xF6, 0xE9,
- 0xEC, 0xE8, 0xEC, 0xC0, 0x66, 0x63, 0xCB, 0xAB,
- 0x49, 0x5C, 0xAD, 0xD6, 0xEE, 0xF5, 0xF5, 0xE9,
- 0x6E, 0x00, 0x69, 0x6A, 0xA1, 0x7A, 0xB4, 0xDE,
- 0xF1, 0xF6, 0xDD, 0x00, 0x73, 0xDB, 0x4C, 0x53,
- 0x6A, 0xF5, 0xF5, 0xD6, 0xC3, 0x6A, 0x4B, 0x4B,
- 0x60, 0xF8, 0x9B, 0xD7, 0xD7, 0x71, 0xB3, 0xA4,
- 0xCA, 0xAB, 0xB4, 0xB2, 0x76, 0xBA, 0x8B, 0xA0,
- 0xA5, 0xEE, 0xE7, 0x67, 0x5F, 0x08, 0x94, 0xDB,
- 0xE5, 0x4F, 0x00, 0x34, 0xEE, 0xEC, 0xE2, 0x48,
- 0xF3, 0xEB, 0xF4, 0xF4, 0xEF, 0xD6, 0xB6, 0xE6,
- 0xE6, 0xED, 0xE7, 0xE6, 0x3D, 0xE7, 0xCD, 0x44,
- 0xEF, 0xEC, 0xF5, 0x66, 0xF3, 0xA9, 0x77, 0x58,
- 0x75, 0x6C, 0x53, 0x24, 0xAC, 0x0D, 0x3C
-};
-
-unsigned char linux_logo_green[] __initdata = {
- 0x99, 0x95, 0x92, 0x8E, 0x8A, 0x86, 0x02, 0x00,
- 0xA5, 0xA9, 0xA2, 0x9E, 0xAD, 0x1B, 0x3B, 0x25,
- 0x71, 0x65, 0x2C, 0x82, 0x5B, 0x33, 0x13, 0xAD,
- 0x0C, 0xB1, 0x92, 0xAB, 0x03, 0x06, 0x16, 0xB6,
- 0xCD, 0x88, 0x42, 0x46, 0x4B, 0x94, 0xBB, 0xCA,
- 0xC5, 0x1C, 0xAB, 0xA0, 0xD4, 0xE6, 0xED, 0xF3,
- 0xC2, 0x73, 0xCA, 0x91, 0x7E, 0x52, 0xF7, 0xE3,
- 0x56, 0x5A, 0x49, 0x56, 0x6E, 0xFC, 0x6B, 0x3E,
- 0x6B, 0x0D, 0x37, 0x79, 0x51, 0x44, 0x3F, 0x43,
- 0x38, 0x3D, 0x48, 0xB9, 0x62, 0xA5, 0x47, 0x48,
- 0x49, 0x4A, 0x97, 0x48, 0x81, 0x95, 0x8E, 0xE3,
- 0x6D, 0x57, 0x51, 0x51, 0x47, 0xB2, 0x42, 0x46,
- 0xDD, 0x5B, 0x87, 0xBE, 0xC7, 0xC8, 0x56, 0x75,
- 0x5D, 0x4B, 0x4D, 0xBE, 0x85, 0xA6, 0xBC, 0xC7,
- 0xCA, 0xCD, 0xCC, 0xA4, 0x53, 0x4D, 0x9F, 0x55,
- 0x52, 0x5E, 0x75, 0x9C, 0xB6, 0xC3, 0xD7, 0xCC,
- 0x55, 0x00, 0x6A, 0x59, 0x7D, 0x55, 0x7C, 0xA3,
- 0xB7, 0xBF, 0xA5, 0x00, 0x67, 0xC6, 0x47, 0x54,
- 0x46, 0xB8, 0xBE, 0xB2, 0x87, 0x52, 0x4B, 0x43,
- 0x41, 0xF8, 0x69, 0x96, 0x9B, 0x66, 0xB0, 0x6C,
- 0x8E, 0x81, 0xB4, 0x76, 0x76, 0xB9, 0x65, 0x77,
- 0x6D, 0xED, 0xE7, 0x67, 0x5F, 0x06, 0x54, 0x6C,
- 0xCB, 0x4F, 0x00, 0x2F, 0xC2, 0xB5, 0xB6, 0x30,
- 0xC3, 0xAE, 0xC4, 0xCA, 0xC6, 0xB4, 0x7B, 0xAD,
- 0xAD, 0xB6, 0xB6, 0xAD, 0x29, 0xAB, 0x93, 0x2E,
- 0xBC, 0xBC, 0xC9, 0x53, 0xBF, 0x77, 0x54, 0x3B,
- 0x4B, 0x3F, 0x39, 0x19, 0x76, 0x08, 0x2C
-};
-
-unsigned char linux_logo_blue[] __initdata = {
- 0x99, 0x95, 0x92, 0x8E, 0x8A, 0x86, 0xD6, 0x00,
- 0xA5, 0xA9, 0xA2, 0x9E, 0xAD, 0x1B, 0x39, 0x25,
- 0x71, 0x65, 0x2C, 0x82, 0x5B, 0x33, 0x13, 0xA7,
- 0x0C, 0xB1, 0x58, 0x8A, 0x03, 0x07, 0x16, 0xB6,
- 0xCD, 0x5A, 0x42, 0x46, 0x4F, 0x6F, 0x77, 0xCA,
- 0xC5, 0x1C, 0x6F, 0xA5, 0xD4, 0xE6, 0xF5, 0xF3,
- 0xC2, 0x4D, 0xD1, 0x64, 0x7E, 0x52, 0xF7, 0xE3,
- 0x56, 0x49, 0x3C, 0x47, 0x45, 0xFE, 0x3B, 0x41,
- 0x6B, 0x09, 0x37, 0x79, 0x39, 0x39, 0x3F, 0x42,
- 0x3A, 0x42, 0x5F, 0xB9, 0x62, 0x4C, 0x39, 0x44,
- 0x3B, 0x3A, 0xA0, 0x3D, 0x08, 0x08, 0x09, 0xDE,
- 0x6D, 0x48, 0x3B, 0x3F, 0x42, 0xF3, 0x36, 0x3C,
- 0xDD, 0x06, 0x16, 0x08, 0x13, 0x0A, 0x4B, 0x71,
- 0x5D, 0x44, 0x47, 0xBE, 0x08, 0x0C, 0x0D, 0x0C,
- 0x19, 0x29, 0x36, 0x06, 0x43, 0x44, 0xBA, 0x45,
- 0x50, 0x58, 0x07, 0x07, 0x0D, 0x0E, 0x10, 0x50,
- 0x06, 0x42, 0x40, 0x44, 0x79, 0x06, 0x06, 0x0C,
- 0x08, 0x08, 0x07, 0x36, 0x4C, 0xE5, 0x42, 0x55,
- 0x03, 0x0F, 0x12, 0x06, 0x07, 0x3C, 0x4B, 0x3D,
- 0x01, 0xF8, 0x08, 0x0E, 0x0A, 0x69, 0xAC, 0x0C,
- 0x0A, 0x27, 0xBB, 0x36, 0x76, 0xC0, 0x04, 0x08,
- 0x08, 0xED, 0xEE, 0x68, 0x5F, 0xB2, 0x3B, 0x52,
- 0xAC, 0x4F, 0x6F, 0x2D, 0x16, 0x08, 0x59, 0x04,
- 0x13, 0x0E, 0x14, 0x17, 0x16, 0x2E, 0x08, 0x0D,
- 0x11, 0x14, 0x0D, 0x06, 0x04, 0x08, 0x25, 0x8E,
- 0x0E, 0x14, 0x25, 0x9B, 0x1C, 0x16, 0x78, 0x06,
- 0x04, 0x03, 0x79, 0x8C, 0x0B, 0xC8, 0x48
-};
-
-unsigned char linux_logo[] __initdata = {
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x21, 0x21, 0x22, 0x23, 0x24, 0x24,
- 0x25, 0x24, 0x24, 0x25, 0x25, 0x25, 0x25, 0x25,
- 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x23, 0x23,
- 0x23, 0x22, 0x22, 0x22, 0x22, 0x21, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x26, 0x27, 0x27, 0x27, 0x27,
- 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x26, 0x28,
- 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
- 0x29, 0x28, 0x28, 0x28, 0x2A, 0x2A, 0x2B, 0x2B,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x2B, 0x2B, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27,
- 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27,
- 0x28, 0x28, 0x28, 0x29, 0x29, 0x29, 0x29, 0x29,
- 0x29, 0x29, 0x29, 0x2C, 0x29, 0x29, 0x29, 0x28,
- 0x28, 0x2A, 0x2B, 0x2B, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x2B, 0x2B, 0x2A, 0x2A,
- 0x2A, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27,
- 0x27, 0x27, 0x27, 0x27, 0x2D, 0x2E, 0x2F, 0x27,
- 0x27, 0x26, 0x2B, 0x2A, 0x2A, 0x2A, 0x2A, 0x28,
- 0x28, 0x29, 0x29, 0x29, 0x29, 0x2C, 0x2C, 0x29,
- 0x29, 0x29, 0x28, 0x28, 0x2A, 0x2B, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x2B, 0x2B, 0x2B, 0x2A, 0x2A, 0x2A,
- 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27,
- 0x27, 0x27, 0x27, 0x27, 0x2F, 0x30, 0x31, 0x32,
- 0x27, 0x27, 0x22, 0x22, 0x22, 0x22, 0x21, 0x20,
- 0x20, 0x20, 0x2B, 0x2A, 0x28, 0x29, 0x29, 0x29,
- 0x2C, 0x2C, 0x2C, 0x29, 0x29, 0x28, 0x2A, 0x2B,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x2B, 0x2B, 0x2A, 0x2A, 0x2A, 0x2A, 0x2B,
- 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27,
- 0x27, 0x27, 0x27, 0x27, 0x32, 0x33, 0x34, 0x35,
- 0x36, 0x27, 0x27, 0x33, 0x25, 0x25, 0x24, 0x24,
- 0x24, 0x24, 0x23, 0x21, 0x20, 0x20, 0x2B, 0x2A,
- 0x28, 0x29, 0x29, 0x37, 0x2C, 0x2C, 0x29, 0x28,
- 0x2A, 0x2B, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2B, 0x2B,
- 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2A, 0x2B, 0x27,
- 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27,
- 0x27, 0x27, 0x27, 0x27, 0x2F, 0x32, 0x36, 0x27,
- 0x27, 0x27, 0x27, 0x33, 0x33, 0x33, 0x33, 0x33,
- 0x33, 0x33, 0x33, 0x25, 0x25, 0x24, 0x23, 0x21,
- 0x20, 0x2B, 0x2A, 0x29, 0x29, 0x2C, 0x2C, 0x2C,
- 0x29, 0x28, 0x2A, 0x2B, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2B, 0x2B,
- 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x20, 0x21, 0x27,
- 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27,
- 0x27, 0x27, 0x27, 0x27, 0x38, 0x27, 0x27, 0x27,
- 0x27, 0x27, 0x27, 0x27, 0x23, 0x23, 0x24, 0x24,
- 0x25, 0x25, 0x33, 0x33, 0x33, 0x33, 0x33, 0x25,
- 0x24, 0x22, 0x20, 0x20, 0x2A, 0x28, 0x29, 0x2C,
- 0x2C, 0x2C, 0x29, 0x28, 0x2A, 0x2B, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x2B, 0x2B, 0x2B, 0x2B,
- 0x2B, 0x2B, 0x2B, 0x20, 0x21, 0x22, 0x23, 0x27,
- 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27,
- 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27,
- 0x27, 0x27, 0x27, 0x27, 0x2A, 0x2A, 0x2B, 0x2B,
- 0x20, 0x21, 0x22, 0x24, 0x20, 0x39, 0x39, 0x39,
- 0x39, 0x39, 0x3A, 0x3B, 0x22, 0x20, 0x2A, 0x28,
- 0x29, 0x2C, 0x2C, 0x2C, 0x29, 0x28, 0x2B, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B,
- 0x2B, 0x20, 0x21, 0x22, 0x22, 0x23, 0x24, 0x27,
- 0x27, 0x27, 0x3C, 0x36, 0x3C, 0x27, 0x27, 0x27,
- 0x27, 0x27, 0x27, 0x3D, 0x3E, 0x32, 0x27, 0x27,
- 0x27, 0x27, 0x27, 0x27, 0x3D, 0x39, 0x3F, 0x3F,
- 0x39, 0x2C, 0x20, 0x20, 0x39, 0x39, 0x39, 0x39,
- 0x39, 0x39, 0x39, 0x40, 0x40, 0x41, 0x22, 0x20,
- 0x2A, 0x28, 0x2C, 0x2C, 0x2C, 0x29, 0x29, 0x2A,
- 0x2B, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x2B, 0x2B, 0x2B, 0x2B, 0x20, 0x20,
- 0x21, 0x22, 0x22, 0x22, 0x23, 0x23, 0x22, 0x27,
- 0x27, 0x3C, 0x3C, 0x3D, 0x42, 0x3C, 0x27, 0x27,
- 0x3C, 0x27, 0x3C, 0x43, 0x44, 0x36, 0x42, 0x27,
- 0x27, 0x27, 0x27, 0x27, 0x3D, 0x28, 0x29, 0x2C,
- 0x2C, 0x45, 0x20, 0x39, 0x39, 0x39, 0x39, 0x39,
- 0x39, 0x46, 0x40, 0x47, 0x40, 0x47, 0x3A, 0x40,
- 0x22, 0x20, 0x2A, 0x29, 0x2C, 0x2C, 0x2C, 0x29,
- 0x28, 0x2B, 0x2B, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x2B, 0x2B, 0x2B, 0x2B, 0x20, 0x20, 0x22,
- 0x22, 0x22, 0x23, 0x22, 0x22, 0x21, 0x20, 0x27,
- 0x27, 0x44, 0x28, 0x24, 0x27, 0x2F, 0x3C, 0x27,
- 0x27, 0x38, 0x24, 0x2C, 0x2C, 0x48, 0x49, 0x36,
- 0x27, 0x27, 0x27, 0x27, 0x27, 0x28, 0x29, 0x29,
- 0x4A, 0x20, 0x3A, 0x40, 0x47, 0x40, 0x47, 0x40,
- 0x40, 0x47, 0x40, 0x40, 0x39, 0x39, 0x39, 0x4A,
- 0x25, 0x24, 0x22, 0x2B, 0x28, 0x29, 0x2C, 0x2C,
- 0x29, 0x28, 0x2A, 0x2B, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x2B, 0x2B, 0x20, 0x20, 0x20, 0x21, 0x22, 0x22,
- 0x22, 0x22, 0x22, 0x21, 0x20, 0x2B, 0x2A, 0x27,
- 0x3D, 0x4B, 0x48, 0x4C, 0x2B, 0x3C, 0x27, 0x3C,
- 0x3C, 0x23, 0x4D, 0x4E, 0x4F, 0x50, 0x33, 0x27,
- 0x27, 0x27, 0x27, 0x27, 0x27, 0x39, 0x3F, 0x39,
- 0x51, 0x20, 0x39, 0x39, 0x47, 0x40, 0x4D, 0x4D,
- 0x40, 0x52, 0x4D, 0x40, 0x47, 0x40, 0x39, 0x39,
- 0x53, 0x54, 0x25, 0x24, 0x20, 0x2A, 0x29, 0x2C,
- 0x2C, 0x2C, 0x29, 0x2A, 0x2B, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x22, 0x22,
- 0x22, 0x21, 0x20, 0x2B, 0x28, 0x2A, 0x20, 0x27,
- 0x36, 0x4F, 0x55, 0x48, 0x56, 0x3D, 0x3C, 0x3C,
- 0x32, 0x57, 0x56, 0x58, 0x49, 0x56, 0x56, 0x27,
- 0x27, 0x27, 0x27, 0x27, 0x27, 0x22, 0x20, 0x20,
- 0x41, 0x39, 0x39, 0x3A, 0x59, 0x5A, 0x59, 0x5B,
- 0x5C, 0x3A, 0x4D, 0x5D, 0x57, 0x39, 0x39, 0x4A,
- 0x5E, 0x33, 0x54, 0x33, 0x24, 0x22, 0x2B, 0x28,
- 0x2C, 0x2C, 0x2C, 0x29, 0x28, 0x2B, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x21, 0x21, 0x21, 0x22, 0x22, 0x21,
- 0x20, 0x2B, 0x2A, 0x2A, 0x20, 0x22, 0x22, 0x27,
- 0x5F, 0x2D, 0x3C, 0x60, 0x56, 0x54, 0x61, 0x49,
- 0x35, 0x56, 0x34, 0x27, 0x62, 0x27, 0x56, 0x39,
- 0x27, 0x27, 0x27, 0x27, 0x27, 0x30, 0x63, 0x54,
- 0x40, 0x64, 0x65, 0x66, 0x67, 0x67, 0x68, 0x5F,
- 0x2E, 0x69, 0x6A, 0x67, 0x5F, 0x3A, 0x39, 0x2C,
- 0x53, 0x23, 0x25, 0x54, 0x33, 0x25, 0x23, 0x20,
- 0x2A, 0x29, 0x2C, 0x2C, 0x29, 0x28, 0x2B, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, 0x20,
- 0x2B, 0x2A, 0x20, 0x22, 0x22, 0x21, 0x2B, 0x27,
- 0x62, 0x36, 0x27, 0x33, 0x6B, 0x54, 0x3D, 0x3C,
- 0x49, 0x57, 0x27, 0x27, 0x27, 0x27, 0x56, 0x57,
- 0x27, 0x27, 0x27, 0x27, 0x27, 0x6C, 0x31, 0x6D,
- 0x64, 0x51, 0x6E, 0x2E, 0x2E, 0x6F, 0x5A, 0x70,
- 0x70, 0x71, 0x72, 0x67, 0x67, 0x69, 0x73, 0x46,
- 0x4A, 0x2A, 0x21, 0x25, 0x33, 0x54, 0x33, 0x24,
- 0x20, 0x2A, 0x29, 0x2C, 0x2C, 0x29, 0x28, 0x2B,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x21, 0x21, 0x21, 0x21, 0x20, 0x20, 0x2B,
- 0x2B, 0x22, 0x22, 0x22, 0x2B, 0x28, 0x2A, 0x27,
- 0x27, 0x39, 0x3C, 0x3D, 0x45, 0x74, 0x75, 0x76,
- 0x76, 0x45, 0x27, 0x27, 0x27, 0x27, 0x56, 0x77,
- 0x27, 0x27, 0x27, 0x27, 0x27, 0x78, 0x78, 0x5E,
- 0x79, 0x7A, 0x7B, 0x6E, 0x5A, 0x5A, 0x70, 0x7C,
- 0x70, 0x5B, 0x7D, 0x5A, 0x66, 0x7E, 0x7F, 0x79,
- 0x48, 0x6B, 0x2C, 0x20, 0x24, 0x33, 0x54, 0x33,
- 0x24, 0x21, 0x2A, 0x29, 0x2C, 0x2C, 0x29, 0x28,
- 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x21, 0x21, 0x21, 0x20, 0x20, 0x2B, 0x2B, 0x21,
- 0x22, 0x22, 0x20, 0x28, 0x2B, 0x20, 0x22, 0x27,
- 0x27, 0x80, 0x27, 0x81, 0x82, 0x83, 0x84, 0x85,
- 0x74, 0x85, 0x84, 0x27, 0x3C, 0x4F, 0x4F, 0x66,
- 0x27, 0x27, 0x27, 0x27, 0x27, 0x22, 0x23, 0x5E,
- 0x64, 0x86, 0x79, 0x73, 0x87, 0x88, 0x7C, 0x5A,
- 0x5A, 0x71, 0x7D, 0x71, 0x89, 0x79, 0x8A, 0x8A,
- 0x51, 0x8B, 0x48, 0x39, 0x2A, 0x22, 0x33, 0x54,
- 0x33, 0x25, 0x22, 0x2B, 0x29, 0x2C, 0x2C, 0x29,
- 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x21, 0x21, 0x20, 0x20, 0x2B, 0x2B, 0x22, 0x23,
- 0x21, 0x2A, 0x2A, 0x20, 0x21, 0x23, 0x25, 0x27,
- 0x27, 0x55, 0x8C, 0x8D, 0x8E, 0x83, 0x8F, 0x90,
- 0x91, 0x92, 0x92, 0x85, 0x85, 0x93, 0x51, 0x27,
- 0x27, 0x27, 0x27, 0x27, 0x27, 0x2A, 0x29, 0x51,
- 0x79, 0x79, 0x94, 0x89, 0x89, 0x89, 0x5A, 0x95,
- 0x64, 0x88, 0x96, 0x97, 0x7A, 0x73, 0x98, 0x98,
- 0x99, 0x50, 0x50, 0x48, 0x6B, 0x28, 0x21, 0x25,
- 0x54, 0x54, 0x25, 0x22, 0x2B, 0x29, 0x2C, 0x29,
- 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x2B, 0x20, 0x22, 0x22, 0x20,
- 0x2B, 0x2B, 0x20, 0x22, 0x24, 0x25, 0x33, 0x27,
- 0x27, 0x9A, 0x9B, 0x9C, 0x9D, 0x83, 0x9E, 0x85,
- 0x9F, 0x92, 0x85, 0x85, 0x85, 0x85, 0x92, 0xA0,
- 0x27, 0x27, 0x27, 0x27, 0x27, 0xA1, 0x47, 0xA2,
- 0xA2, 0x94, 0xA3, 0x94, 0x95, 0x95, 0x73, 0x73,
- 0x95, 0x87, 0xA4, 0x5B, 0x97, 0x7B, 0x88, 0x98,
- 0xA2, 0x50, 0x48, 0x48, 0x48, 0x8B, 0x29, 0x20,
- 0x25, 0x54, 0x54, 0x25, 0x22, 0x2B, 0x29, 0x29,
- 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x21, 0x22, 0x22, 0x2B, 0x2B,
- 0x20, 0x21, 0x23, 0x24, 0x25, 0x25, 0x33, 0x27,
- 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0x8F, 0x90, 0x90,
- 0x9F, 0x90, 0x85, 0x90, 0x85, 0x74, 0xAA, 0x81,
- 0x27, 0x27, 0x27, 0x27, 0x27, 0xAB, 0x40, 0xAC,
- 0x79, 0xA3, 0x89, 0xAD, 0x95, 0x6F, 0xAE, 0xAE,
- 0xAE, 0x5B, 0x59, 0x88, 0x7B, 0x89, 0x79, 0xAF,
- 0xA2, 0x6B, 0x48, 0x48, 0x48, 0x48, 0x50, 0x2C,
- 0x20, 0x24, 0x33, 0x54, 0x25, 0x22, 0x2A, 0x2A,
- 0x21, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x21, 0x23, 0x22, 0x2B, 0x20, 0x20,
- 0x22, 0x23, 0x24, 0x25, 0x24, 0x24, 0x22, 0x27,
- 0xB0, 0x8C, 0xAA, 0xB1, 0xB2, 0x84, 0x85, 0x9F,
- 0x85, 0x85, 0x85, 0xB3, 0xB4, 0xAA, 0xAA, 0xA0,
- 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x2A, 0xB5,
- 0xA3, 0xA3, 0xAC, 0x5D, 0xB6, 0xAE, 0xB7, 0x69,
- 0x73, 0x5B, 0x88, 0x89, 0x95, 0x73, 0x99, 0x99,
- 0x59, 0x2A, 0x39, 0x48, 0x48, 0x50, 0x48, 0x50,
- 0x2C, 0x20, 0x24, 0x33, 0x54, 0x25, 0x21, 0x20,
- 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x21, 0x23, 0x21, 0x2B, 0x20, 0x20, 0x22,
- 0x22, 0x24, 0x24, 0x23, 0x22, 0x20, 0x2A, 0x27,
- 0x27, 0xB0, 0x8C, 0xA9, 0xB2, 0x9E, 0x91, 0x85,
- 0x85, 0x93, 0xB8, 0x75, 0xAA, 0xA7, 0x8C, 0x27,
- 0x27, 0x27, 0x33, 0x3C, 0x27, 0x27, 0x2C, 0x7B,
- 0x55, 0x79, 0xA3, 0x5D, 0xB9, 0x43, 0x7F, 0x7E,
- 0x5F, 0x5A, 0x5A, 0x95, 0x64, 0x73, 0x58, 0x64,
- 0x5C, 0x25, 0x2B, 0x3F, 0x48, 0x48, 0x8B, 0x48,
- 0x48, 0x2C, 0x20, 0x25, 0x54, 0x33, 0x24, 0x22,
- 0x2B, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x21, 0x23, 0x21, 0x20, 0x20, 0x20, 0x21, 0x22,
- 0x24, 0x23, 0x22, 0x21, 0x2B, 0x20, 0x54, 0x27,
- 0x27, 0x8B, 0x81, 0xA5, 0x93, 0x93, 0x74, 0xA5,
- 0xBA, 0x75, 0xBB, 0xBC, 0xB4, 0x6D, 0x50, 0x6B,
- 0x27, 0x27, 0x30, 0x33, 0x49, 0x27, 0x27, 0x5E,
- 0x6F, 0x73, 0x94, 0xBD, 0x4E, 0x5D, 0x7F, 0x7F,
- 0xB7, 0x68, 0x73, 0x6E, 0xB7, 0x7F, 0x95, 0x97,
- 0x47, 0x63, 0x25, 0x20, 0x3F, 0x48, 0x8B, 0x8B,
- 0x48, 0x48, 0x2C, 0x20, 0x25, 0x54, 0x33, 0x25,
- 0x2B, 0x2B, 0x2B, 0x20, 0x20, 0x20, 0x21, 0x21,
- 0x23, 0x21, 0x20, 0x20, 0x20, 0x20, 0x24, 0x24,
- 0x22, 0x21, 0x20, 0x2A, 0x33, 0x30, 0x30, 0x27,
- 0x27, 0x50, 0xBE, 0xBF, 0x9A, 0xB3, 0x9B, 0xBB,
- 0xBB, 0xC0, 0x8C, 0xC1, 0x8B, 0xC2, 0x47, 0x8B,
- 0x27, 0x27, 0x38, 0x63, 0x63, 0x27, 0x27, 0xC3,
- 0xB5, 0x95, 0x72, 0x95, 0x6F, 0x69, 0x7E, 0x66,
- 0x7E, 0x7F, 0x6E, 0x7E, 0x95, 0x95, 0x73, 0x70,
- 0x30, 0x30, 0x30, 0x33, 0x20, 0x3F, 0x48, 0x8B,
- 0x6B, 0x48, 0x50, 0x29, 0x21, 0x33, 0x54, 0x33,
- 0x2A, 0x2B, 0x2B, 0x20, 0x20, 0x21, 0x21, 0x23,
- 0x21, 0x20, 0x20, 0x20, 0x20, 0x24, 0x24, 0x22,
- 0x20, 0x2B, 0x21, 0xC4, 0x30, 0x60, 0x30, 0x27,
- 0x27, 0xC5, 0x8B, 0x39, 0xC6, 0xC7, 0xA6, 0xA6,
- 0xC8, 0x9A, 0x3B, 0x39, 0x50, 0x56, 0x56, 0x4F,
- 0x33, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x48,
- 0x59, 0x94, 0x73, 0xAE, 0xB7, 0xB7, 0x7E, 0x7E,
- 0x7E, 0x7E, 0x7E, 0x5A, 0x70, 0x7C, 0x71, 0xC3,
- 0x63, 0x30, 0x60, 0x78, 0x54, 0x20, 0x6B, 0x48,
- 0x6B, 0x6B, 0x50, 0x50, 0x29, 0x22, 0x33, 0x33,
- 0x2A, 0x2B, 0x20, 0x20, 0x21, 0x22, 0x22, 0x22,
- 0x21, 0x20, 0x20, 0x20, 0x24, 0x24, 0x20, 0x20,
- 0x2B, 0x24, 0x30, 0x60, 0x60, 0x30, 0xAB, 0x27,
- 0x27, 0x40, 0x4C, 0x50, 0x39, 0x87, 0xC3, 0x53,
- 0x37, 0x48, 0x37, 0x48, 0xC9, 0x56, 0xB9, 0x56,
- 0xCA, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x3C,
- 0x51, 0x5A, 0x6E, 0xB7, 0xB7, 0x7E, 0x7E, 0x7E,
- 0x7E, 0x7E, 0x7F, 0xB7, 0x5A, 0x7C, 0x5B, 0x37,
- 0x23, 0x63, 0x31, 0x6C, 0xCB, 0x63, 0x20, 0x6B,
- 0x50, 0x3F, 0x39, 0x50, 0x8B, 0x28, 0x24, 0x24,
- 0x2B, 0x2B, 0x20, 0x21, 0x22, 0x22, 0x22, 0x21,
- 0x20, 0x20, 0x20, 0x23, 0x23, 0x20, 0x20, 0x2B,
- 0x33, 0x78, 0xCB, 0x60, 0x30, 0x22, 0x3D, 0x27,
- 0x2F, 0x56, 0x4E, 0x8B, 0x6B, 0x39, 0x48, 0x8B,
- 0x6B, 0x8B, 0x80, 0xC9, 0xB9, 0xB9, 0x56, 0xB9,
- 0x56, 0x34, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27,
- 0x48, 0xB5, 0xB7, 0xB7, 0x7E, 0x7E, 0x2E, 0x7E,
- 0x7E, 0x7E, 0x7F, 0x7C, 0x65, 0x71, 0x3A, 0x48,
- 0x2C, 0x24, 0x30, 0x6C, 0x34, 0x6C, 0xC4, 0x20,
- 0x8B, 0x50, 0x39, 0x39, 0x48, 0x6B, 0x2B, 0x22,
- 0x2B, 0x20, 0x21, 0x22, 0x23, 0x23, 0x22, 0x21,
- 0x20, 0x2B, 0x23, 0x22, 0x20, 0x2B, 0x2B, 0x54,
- 0x60, 0x31, 0xCB, 0x54, 0x20, 0x3D, 0x36, 0x27,
- 0x4E, 0xB9, 0x56, 0x56, 0x8B, 0x6B, 0x50, 0x6B,
- 0x40, 0x56, 0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0xB9,
- 0x56, 0x56, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27,
- 0x27, 0x7B, 0x6E, 0xB7, 0xB7, 0xB7, 0x7E, 0x7F,
- 0xB7, 0xB7, 0x7F, 0x7E, 0x6F, 0x5B, 0x29, 0x2C,
- 0x48, 0x39, 0x24, 0x60, 0x58, 0xAF, 0xCC, 0x63,
- 0x20, 0x8B, 0x8B, 0x39, 0x39, 0x48, 0x3F, 0x28,
- 0x20, 0x20, 0x22, 0x23, 0x23, 0x23, 0x22, 0x20,
- 0x2B, 0x22, 0x22, 0x2B, 0x2B, 0x20, 0x54, 0xCB,
- 0x31, 0xCB, 0x25, 0x20, 0x27, 0x27, 0x27, 0x48,
- 0xB9, 0x56, 0xB9, 0x56, 0x4F, 0x48, 0x47, 0x57,
- 0x56, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0x56,
- 0xB9, 0x56, 0x62, 0x27, 0x27, 0x27, 0x27, 0x27,
- 0x27, 0x48, 0x6F, 0x69, 0xB7, 0xB7, 0xB7, 0x7F,
- 0xB7, 0xB7, 0xB7, 0x73, 0x59, 0x50, 0x29, 0x2B,
- 0x28, 0x8B, 0x39, 0x25, 0x31, 0x55, 0xB6, 0x34,
- 0x63, 0x2B, 0x48, 0x6B, 0x2C, 0x39, 0x47, 0x6B,
- 0x22, 0x22, 0x23, 0x24, 0x23, 0x22, 0x20, 0x2B,
- 0x20, 0x22, 0x2A, 0x2B, 0x20, 0x33, 0xCB, 0x31,
- 0x78, 0x24, 0x21, 0xCD, 0x27, 0x27, 0x27, 0x56,
- 0x56, 0xB9, 0x56, 0xB9, 0x56, 0x56, 0x56, 0xB9,
- 0x56, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0x56,
- 0xB9, 0x56, 0xC9, 0x27, 0x27, 0x27, 0x27, 0x27,
- 0x27, 0x27, 0x41, 0x64, 0xB7, 0xB7, 0xB7, 0x7F,
- 0x68, 0xB7, 0xAE, 0xA3, 0x23, 0x39, 0x8B, 0x2A,
- 0x20, 0x20, 0x39, 0x6B, 0x25, 0xCC, 0x43, 0x43,
- 0x34, 0x63, 0x2A, 0x48, 0x3F, 0x39, 0x6B, 0x6B,
- 0x24, 0x23, 0x24, 0x24, 0x23, 0x21, 0x2B, 0x2B,
- 0x22, 0x2B, 0x2B, 0x20, 0x24, 0x78, 0x31, 0x30,
- 0x23, 0x21, 0x21, 0x27, 0x27, 0x27, 0x80, 0x56,
- 0x56, 0xB9, 0x56, 0xB9, 0x56, 0xB9, 0x56, 0xB9,
- 0x56, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9,
- 0x56, 0xB9, 0x56, 0x3C, 0x27, 0x27, 0x27, 0x27,
- 0x27, 0x27, 0x27, 0xCE, 0x8A, 0xAE, 0x6F, 0xB7,
- 0x6F, 0x89, 0x71, 0x78, 0x63, 0x23, 0x39, 0x6B,
- 0x2B, 0x20, 0x20, 0x2C, 0x6B, 0x25, 0x34, 0x42,
- 0x42, 0x34, 0x54, 0x29, 0x48, 0x3F, 0x39, 0x3F,
- 0x25, 0x24, 0x25, 0x24, 0x22, 0x20, 0x2A, 0x21,
- 0x2B, 0x2A, 0x20, 0x22, 0x30, 0x60, 0x30, 0x22,
- 0x21, 0x22, 0x27, 0x27, 0x27, 0x2D, 0x4C, 0x56,
- 0x56, 0xB9, 0xB9, 0x56, 0xB9, 0xB9, 0x56, 0x56,
- 0xB9, 0xB9, 0xB9, 0x56, 0x56, 0x56, 0xB9, 0xB9,
- 0xB9, 0xB9, 0x56, 0x2E, 0x27, 0x27, 0x27, 0x27,
- 0x27, 0x27, 0x27, 0x40, 0x97, 0x95, 0x5A, 0x71,
- 0x7C, 0xCE, 0x40, 0x60, 0x31, 0x30, 0x23, 0x3F,
- 0x3F, 0x20, 0x20, 0x20, 0x29, 0x8B, 0x33, 0x58,
- 0x66, 0x43, 0xCC, 0x25, 0x39, 0x50, 0x6B, 0x2C,
- 0x33, 0x25, 0x25, 0x23, 0x20, 0x2A, 0x2B, 0x20,
- 0x2A, 0x2B, 0x22, 0x54, 0x30, 0x30, 0x24, 0x22,
- 0x21, 0x27, 0x27, 0x27, 0x27, 0xAF, 0x29, 0x4E,
- 0x4F, 0xB9, 0x56, 0xB9, 0x4D, 0x4D, 0x77, 0xC9,
- 0xB9, 0xB9, 0xB9, 0x56, 0xC9, 0x4D, 0x4D, 0x80,
- 0x4C, 0x40, 0xC9, 0x4D, 0x27, 0x27, 0x27, 0x27,
- 0x27, 0x27, 0x27, 0x27, 0xCF, 0x97, 0x97, 0xCE,
- 0x86, 0xD0, 0x54, 0x6C, 0x58, 0x34, 0x60, 0x23,
- 0x6B, 0x39, 0x20, 0x20, 0x20, 0x28, 0x6B, 0x54,
- 0xD1, 0x66, 0xB6, 0x60, 0x22, 0x6B, 0x8B, 0x2C,
- 0x54, 0x33, 0x24, 0x22, 0x2B, 0x28, 0x20, 0x28,
- 0x2B, 0x20, 0x25, 0xC4, 0x30, 0x25, 0x22, 0x21,
- 0x26, 0x27, 0x27, 0x27, 0x27, 0x20, 0x4B, 0x52,
- 0x80, 0x4F, 0xB9, 0x56, 0xB9, 0x80, 0x56, 0xB9,
- 0xB9, 0xB9, 0xB9, 0xB9, 0x4D, 0x80, 0x50, 0x48,
- 0x50, 0x50, 0x50, 0x56, 0x3D, 0x27, 0x36, 0x27,
- 0x27, 0x27, 0x27, 0x3C, 0x46, 0xC3, 0x86, 0x86,
- 0xD0, 0x39, 0x24, 0x6C, 0xD1, 0x43, 0x43, 0x6C,
- 0x24, 0x6B, 0x2C, 0x20, 0x20, 0x20, 0x29, 0x39,
- 0x63, 0xD1, 0x42, 0x55, 0xC4, 0x2B, 0x8B, 0x39,
- 0x54, 0x25, 0x24, 0x20, 0x2A, 0x2A, 0x28, 0x28,
- 0x20, 0x22, 0x54, 0x63, 0x25, 0x24, 0x22, 0x22,
- 0x27, 0x27, 0x27, 0x27, 0x27, 0x28, 0x77, 0x56,
- 0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0xC9, 0x56, 0xB9,
- 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0x4F,
- 0x77, 0x47, 0x8B, 0x40, 0x56, 0x27, 0x27, 0x49,
- 0x2D, 0x27, 0x27, 0x27, 0x39, 0x40, 0x39, 0x39,
- 0x28, 0x3F, 0x39, 0x33, 0x58, 0x66, 0x35, 0x2E,
- 0x58, 0x24, 0x8B, 0x29, 0x20, 0x20, 0x20, 0x39,
- 0x29, 0x30, 0x55, 0xB6, 0xCC, 0x25, 0x29, 0x39,
- 0x54, 0x25, 0x22, 0x2B, 0x29, 0x2A, 0x29, 0x2B,
- 0x22, 0x24, 0x54, 0x33, 0x25, 0x22, 0x2B, 0x54,
- 0x27, 0x27, 0x62, 0x27, 0x30, 0x80, 0xB9, 0x56,
- 0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0x56, 0xB9, 0xB9,
- 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0x56,
- 0xB9, 0x56, 0x4D, 0x8B, 0x77, 0x36, 0x27, 0x27,
- 0x3C, 0x2F, 0x27, 0x27, 0x39, 0x39, 0x39, 0x47,
- 0x20, 0x2B, 0x2C, 0x39, 0x33, 0xB6, 0x35, 0x35,
- 0x35, 0xAF, 0x24, 0x48, 0x2A, 0x20, 0x20, 0x20,
- 0x8B, 0x2B, 0x78, 0xAF, 0x58, 0x30, 0x21, 0x28,
- 0x33, 0x25, 0x21, 0x28, 0x29, 0x29, 0x28, 0x20,
- 0x24, 0x33, 0x54, 0x33, 0x23, 0x20, 0x24, 0xD2,
- 0x27, 0x49, 0x27, 0x27, 0x56, 0xB9, 0xB9, 0x56,
- 0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0x56, 0xB9, 0xB9,
- 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0x56,
- 0xB9, 0xB9, 0x56, 0xC9, 0x50, 0x56, 0x27, 0x27,
- 0x3D, 0x38, 0x3D, 0x27, 0x27, 0x47, 0x39, 0x39,
- 0x28, 0x20, 0x20, 0x2A, 0x39, 0x54, 0x43, 0x35,
- 0x35, 0x35, 0xAF, 0x23, 0x48, 0x2B, 0x20, 0x20,
- 0x2B, 0x48, 0x22, 0x60, 0x34, 0xCB, 0x25, 0x21,
- 0x33, 0x24, 0x2B, 0x29, 0x29, 0x29, 0x2B, 0x22,
- 0x25, 0x54, 0x54, 0x25, 0x22, 0x2B, 0x33, 0x27,
- 0x27, 0x32, 0x27, 0x30, 0x56, 0xB9, 0xB9, 0x56,
- 0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0x56, 0xB9, 0xB9,
- 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0x56,
- 0xB9, 0xB9, 0x56, 0x56, 0xC9, 0x4C, 0x36, 0x3C,
- 0x62, 0x2F, 0x2E, 0x27, 0x27, 0x54, 0x47, 0x47,
- 0x8B, 0x2B, 0x20, 0x20, 0x20, 0x3F, 0x54, 0x2E,
- 0x35, 0x35, 0x35, 0x34, 0x21, 0x8B, 0x2A, 0x20,
- 0x20, 0x2C, 0x6B, 0x25, 0x60, 0x60, 0x54, 0x23,
- 0x25, 0x22, 0x2A, 0x2C, 0x29, 0x28, 0x20, 0x24,
- 0x54, 0x63, 0x54, 0x24, 0x2B, 0x22, 0x24, 0x27,
- 0x36, 0x27, 0x27, 0x56, 0x56, 0xB9, 0xB9, 0x56,
- 0xB9, 0xB9, 0xB9, 0x56, 0x56, 0x56, 0xB9, 0xB9,
- 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0x56,
- 0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0x56, 0x4C, 0x36,
- 0x66, 0xD3, 0x27, 0x2F, 0x27, 0x54, 0x54, 0x27,
- 0x26, 0x6B, 0x20, 0x20, 0x20, 0x20, 0x6B, 0x63,
- 0x35, 0x35, 0x35, 0x62, 0xCB, 0x2A, 0x3F, 0x28,
- 0x2B, 0x2A, 0x50, 0x29, 0x33, 0x30, 0x54, 0x25,
- 0x24, 0x20, 0x29, 0x2C, 0x2C, 0x2A, 0x21, 0x33,
- 0xC4, 0xC4, 0x33, 0x21, 0x29, 0x22, 0x27, 0x27,
- 0x99, 0x27, 0x31, 0xB9, 0xB9, 0xB9, 0xB9, 0x56,
- 0xB9, 0xB9, 0xB9, 0x56, 0x56, 0x56, 0xB9, 0xB9,
- 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0x56,
- 0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0x56, 0x56, 0x3D,
- 0x3D, 0x3C, 0x3C, 0x55, 0x54, 0x54, 0x54, 0x20,
- 0x27, 0x2C, 0x39, 0x20, 0x20, 0x20, 0x20, 0x48,
- 0x30, 0x62, 0x35, 0x35, 0x42, 0x54, 0x39, 0x39,
- 0x2C, 0x28, 0x3F, 0x8B, 0x20, 0x33, 0x54, 0x24,
- 0x22, 0x2B, 0x2C, 0x2C, 0x2C, 0x2B, 0x24, 0x54,
- 0x30, 0xC4, 0x25, 0x2B, 0x28, 0x2B, 0x27, 0x3D,
- 0x27, 0x27, 0x56, 0xB9, 0xB9, 0xB9, 0xB9, 0x56,
- 0xB9, 0xB9, 0x56, 0x56, 0x4F, 0x56, 0xB9, 0xB9,
- 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0x56,
- 0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0x56, 0x56, 0x27,
- 0x20, 0x20, 0x20, 0x54, 0x54, 0x54, 0x54, 0x20,
- 0x20, 0x2D, 0x2D, 0x29, 0x20, 0x20, 0x20, 0x20,
- 0x48, 0x60, 0x66, 0x35, 0x62, 0x34, 0x22, 0x2C,
- 0x2C, 0x3F, 0x6B, 0x48, 0x2C, 0x22, 0x23, 0x23,
- 0x20, 0x2A, 0x2C, 0x29, 0x29, 0x20, 0x25, 0xC4,
- 0x30, 0x54, 0x22, 0x29, 0x28, 0xD2, 0x27, 0x35,
- 0x27, 0x49, 0x56, 0xB9, 0xB9, 0xB9, 0xB9, 0x56,
- 0xB9, 0xB9, 0x56, 0x4F, 0x56, 0x56, 0xB9, 0xB9,
- 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0x56,
- 0xB9, 0xB9, 0xB9, 0x56, 0x56, 0x56, 0x40, 0x20,
- 0x20, 0x54, 0x54, 0x54, 0x20, 0x20, 0x20, 0x20,
- 0x2D, 0x2D, 0x2D, 0x49, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x6B, 0x6C, 0x42, 0x2E, 0xB6, 0x54, 0x28,
- 0x29, 0x2C, 0x6B, 0x48, 0x3F, 0x2A, 0x20, 0x22,
- 0x2B, 0x28, 0x2C, 0x28, 0x29, 0x20, 0x33, 0x30,
- 0x30, 0x54, 0x20, 0x2C, 0x29, 0x27, 0x27, 0x3D,
- 0x27, 0x40, 0x56, 0xB9, 0x56, 0x56, 0xB9, 0x56,
- 0xB9, 0x56, 0x56, 0x4D, 0x56, 0x56, 0xB9, 0xB9,
- 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0x56,
- 0xB9, 0xB9, 0x56, 0x56, 0x63, 0x56, 0x54, 0x54,
- 0x54, 0x54, 0x20, 0xD3, 0x45, 0x51, 0x51, 0x49,
- 0x7C, 0x2D, 0x2D, 0x49, 0x49, 0x20, 0x20, 0x20,
- 0x20, 0x2A, 0x2A, 0xCC, 0xB6, 0x8A, 0x60, 0x22,
- 0x28, 0x29, 0x3F, 0x6B, 0x39, 0x29, 0x2B, 0x20,
- 0x28, 0x2C, 0x28, 0x2A, 0x2A, 0x24, 0xC4, 0x30,
- 0xC4, 0x33, 0x2B, 0x39, 0xCD, 0x27, 0x3C, 0x27,
- 0x27, 0x56, 0xB9, 0x56, 0xB9, 0x56, 0xB9, 0x56,
- 0xB9, 0x56, 0x56, 0x4D, 0x56, 0x56, 0xB9, 0xB9,
- 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0x56,
- 0xB9, 0xB9, 0x56, 0x63, 0x63, 0x49, 0x2D, 0x20,
- 0x20, 0x2D, 0xD3, 0x49, 0x66, 0x2D, 0x49, 0x49,
- 0x49, 0x49, 0x49, 0x49, 0x49, 0x8B, 0x2B, 0x20,
- 0x20, 0x20, 0x39, 0x23, 0x6C, 0xAF, 0xCB, 0x23,
- 0x28, 0x28, 0x29, 0x2A, 0x2A, 0x2A, 0x2A, 0x20,
- 0x29, 0x39, 0x2B, 0x2B, 0x2B, 0x25, 0x78, 0xC4,
- 0x63, 0x23, 0x29, 0x39, 0x27, 0x27, 0x3D, 0x27,
- 0x27, 0x56, 0xB9, 0x56, 0xB9, 0x56, 0xB9, 0x56,
- 0xB9, 0x56, 0x56, 0x80, 0x4F, 0x56, 0xB9, 0xB9,
- 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0x56,
- 0xB9, 0xB9, 0xB9, 0xB9, 0x2D, 0x49, 0x2D, 0x49,
- 0x49, 0x2D, 0x49, 0x2D, 0x49, 0x2D, 0x2D, 0x2D,
- 0x49, 0x49, 0x35, 0x49, 0x2D, 0x2D, 0x39, 0x28,
- 0x20, 0x20, 0x2A, 0x28, 0x33, 0x60, 0xC4, 0x22,
- 0x2C, 0x2A, 0x2A, 0x22, 0x23, 0x22, 0x20, 0x21,
- 0x2C, 0x29, 0x20, 0x2B, 0x2B, 0x54, 0x30, 0xC4,
- 0x63, 0x22, 0x2C, 0x27, 0x27, 0x27, 0x3D, 0x27,
- 0x27, 0x56, 0x56, 0xB9, 0xB9, 0x56, 0xB9, 0x56,
- 0xB9, 0x56, 0x56, 0x80, 0x56, 0x56, 0xB9, 0xB9,
- 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0x56,
- 0xB9, 0xB9, 0xB9, 0xB9, 0x2D, 0x49, 0x2D, 0x49,
- 0x61, 0x49, 0x2D, 0x49, 0x49, 0x2D, 0x2D, 0x49,
- 0x49, 0x49, 0x2F, 0x49, 0x2D, 0x78, 0x29, 0x28,
- 0x2C, 0x2A, 0x2B, 0x39, 0x2B, 0x25, 0x33, 0x20,
- 0x2C, 0x20, 0x2A, 0x24, 0x54, 0x54, 0x23, 0x23,
- 0x2C, 0x2A, 0x22, 0x2B, 0x20, 0x63, 0x30, 0x63,
- 0xC4, 0x21, 0x39, 0x27, 0x27, 0x27, 0x35, 0x36,
- 0x27, 0x56, 0x56, 0xB9, 0xB9, 0x56, 0xB9, 0x56,
- 0xB9, 0xB9, 0x56, 0x80, 0x56, 0x56, 0xB9, 0xB9,
- 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0x56,
- 0xB9, 0xB9, 0xB9, 0x56, 0x2D, 0x49, 0x49, 0x49,
- 0x49, 0x27, 0x27, 0x2D, 0x38, 0x27, 0x36, 0x36,
- 0x49, 0x27, 0x49, 0x2D, 0x2D, 0x44, 0x24, 0x2B,
- 0x20, 0x2C, 0x3F, 0x6B, 0x2A, 0x20, 0x21, 0x28,
- 0x2C, 0x20, 0x2B, 0x24, 0x30, 0xCB, 0x63, 0x54,
- 0x28, 0x20, 0x24, 0x2B, 0x23, 0x78, 0xC4, 0x63,
- 0x63, 0x2B, 0x3F, 0x27, 0x27, 0x27, 0x38, 0x33,
- 0x3D, 0xB9, 0x56, 0xB9, 0xB9, 0x56, 0xB9, 0x56,
- 0xB9, 0xB9, 0x56, 0x80, 0x56, 0x56, 0xB9, 0xB9,
- 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0x56,
- 0xB9, 0xB9, 0xB9, 0x56, 0x63, 0x49, 0x49, 0x49,
- 0x49, 0x49, 0x3D, 0x3D, 0x27, 0x27, 0x27, 0x2D,
- 0x49, 0x49, 0x49, 0x2D, 0x62, 0x5F, 0xC4, 0x20,
- 0x22, 0x2A, 0x6B, 0x8B, 0x2C, 0x2B, 0x2A, 0x3F,
- 0x3F, 0x2A, 0x21, 0x21, 0xCB, 0x58, 0x6C, 0x60,
- 0x20, 0x23, 0x24, 0x2A, 0x25, 0x78, 0x63, 0x63,
- 0x54, 0x2A, 0x28, 0x27, 0x27, 0x27, 0x27, 0x62,
- 0x3C, 0xB9, 0x56, 0x56, 0xB9, 0x56, 0xB9, 0x56,
- 0xB9, 0x56, 0x56, 0x80, 0x56, 0x56, 0xB9, 0xB9,
- 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0x56,
- 0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0x49, 0x2D, 0x2D,
- 0x2D, 0x3D, 0x2F, 0x3C, 0x2D, 0x3C, 0x27, 0x38,
- 0x2D, 0x49, 0x2D, 0x2D, 0xD1, 0x43, 0x30, 0x20,
- 0x24, 0x21, 0x21, 0x21, 0x2B, 0x2A, 0x29, 0x8B,
- 0x6B, 0x29, 0x2B, 0x2A, 0x30, 0x55, 0x55, 0x34,
- 0x22, 0x23, 0x24, 0x29, 0x54, 0x30, 0x63, 0x63,
- 0x25, 0x29, 0x22, 0x3C, 0xA5, 0xD4, 0xD5, 0x27,
- 0x31, 0x56, 0x56, 0x56, 0xB9, 0x56, 0xB9, 0x56,
- 0xB9, 0x56, 0x56, 0x80, 0xB9, 0x56, 0xB9, 0xB9,
- 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0x56,
- 0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0x56, 0x2D, 0x2E,
- 0x3E, 0x27, 0x27, 0x27, 0x27, 0x27, 0x36, 0x44,
- 0x3C, 0x27, 0x2D, 0xC4, 0x78, 0xCC, 0x54, 0x2B,
- 0x25, 0x24, 0x63, 0x60, 0x63, 0x24, 0x2A, 0x6B,
- 0x3F, 0x39, 0x28, 0x21, 0x33, 0xB6, 0x44, 0x58,
- 0x22, 0x23, 0x24, 0x2A, 0x30, 0x30, 0x63, 0x63,
- 0x24, 0x39, 0x22, 0xBB, 0x9C, 0xB2, 0x9D, 0xA8,
- 0x27, 0x8B, 0x56, 0x56, 0xB9, 0x56, 0xB9, 0xB9,
- 0x56, 0xB9, 0x56, 0x80, 0xB9, 0x56, 0xB9, 0xB9,
- 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0x56,
- 0xB9, 0xB9, 0xB9, 0x56, 0x56, 0xD6, 0xD6, 0xD7,
- 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x32,
- 0x3D, 0x27, 0x39, 0x33, 0xC4, 0xC4, 0x22, 0x28,
- 0x25, 0x54, 0x30, 0xD1, 0xD1, 0x60, 0x23, 0x6B,
- 0x3F, 0x39, 0x2C, 0x2B, 0x20, 0x58, 0x8A, 0x58,
- 0x22, 0x23, 0x23, 0x2B, 0x78, 0x30, 0xC4, 0xC4,
- 0x23, 0x29, 0xBB, 0xBB, 0xD8, 0xB2, 0x9D, 0xA9,
- 0xA9, 0x3C, 0x60, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9,
- 0x56, 0xB9, 0x56, 0x80, 0xB9, 0x56, 0xB9, 0xB9,
- 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0x56,
- 0xB9, 0xB9, 0xB9, 0x56, 0xD9, 0x85, 0x85, 0x85,
- 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x2D,
- 0xA0, 0x83, 0x2C, 0x21, 0x30, 0x33, 0x29, 0x29,
- 0x21, 0x33, 0x54, 0x42, 0x66, 0x55, 0xC4, 0x29,
- 0x8B, 0x2C, 0x39, 0x28, 0x29, 0x31, 0x44, 0x58,
- 0x23, 0x23, 0x21, 0x20, 0x30, 0xC4, 0xC4, 0x30,
- 0x21, 0x20, 0xBB, 0xBC, 0xDA, 0xDB, 0xDC, 0xB2,
- 0x83, 0xB4, 0x3C, 0x2F, 0xB9, 0x56, 0x56, 0xB9,
- 0x56, 0xB9, 0x56, 0x80, 0x56, 0x56, 0xB9, 0xB9,
- 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0x56,
- 0xB9, 0x56, 0x56, 0x56, 0xA7, 0xD4, 0x85, 0x82,
- 0x3C, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x61,
- 0x9E, 0x90, 0xDD, 0x21, 0x33, 0x25, 0x2C, 0x39,
- 0x2A, 0x24, 0x24, 0x42, 0x62, 0x43, 0x34, 0x22,
- 0x50, 0x39, 0x2C, 0x2C, 0x2A, 0x54, 0xD1, 0x58,
- 0x22, 0x22, 0x2B, 0x22, 0x30, 0xC4, 0x30, 0x60,
- 0x20, 0xDE, 0xBB, 0xD9, 0x84, 0x84, 0xDF, 0xA9,
- 0xDB, 0xDB, 0x61, 0x27, 0x38, 0x4D, 0x56, 0x56,
- 0x56, 0xB9, 0x56, 0xB9, 0x56, 0x56, 0xB9, 0xB9,
- 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0x56,
- 0xB9, 0x56, 0x56, 0x56, 0x8D, 0xD9, 0xD5, 0xA6,
- 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0xBB,
- 0x85, 0xDB, 0xDD, 0x21, 0x22, 0x22, 0x3F, 0x39,
- 0x2C, 0x2B, 0x25, 0x34, 0x62, 0x66, 0xD1, 0xC4,
- 0x6B, 0x39, 0x2C, 0x39, 0x29, 0x21, 0x58, 0xCC,
- 0x22, 0x21, 0x29, 0x23, 0x30, 0x30, 0x30, 0x5E,
- 0x82, 0xBB, 0xE0, 0xB1, 0xE1, 0x9C, 0xD4, 0xDC,
- 0x9D, 0xA9, 0xE2, 0x27, 0x27, 0x27, 0x4D, 0x56,
- 0x56, 0xB9, 0x56, 0xB9, 0x56, 0x56, 0xB9, 0xB9,
- 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0x56,
- 0xB9, 0x56, 0x4C, 0x48, 0xA8, 0xA8, 0xE3, 0x8C,
- 0xC6, 0x3C, 0x27, 0x27, 0x27, 0xE4, 0xA6, 0xE5,
- 0x83, 0xA9, 0xE6, 0xAF, 0x54, 0x2B, 0x8B, 0x39,
- 0x39, 0x29, 0x20, 0x54, 0x42, 0x42, 0xB6, 0xCC,
- 0x2A, 0x29, 0x39, 0x39, 0x2C, 0x2C, 0xCC, 0xCC,
- 0x22, 0x20, 0x39, 0xE7, 0xC0, 0xD9, 0xA7, 0xBC,
- 0x8D, 0xAA, 0x9C, 0xE8, 0x9C, 0x9D, 0xD4, 0xD4,
- 0xD8, 0xA9, 0x84, 0xC7, 0x27, 0x27, 0x27, 0x2A,
- 0x56, 0x56, 0x56, 0xB9, 0x56, 0x56, 0xB9, 0xB9,
- 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0x56,
- 0x56, 0x56, 0x48, 0x50, 0xAA, 0xE3, 0xE3, 0xC0,
- 0xA6, 0x9A, 0xBA, 0xC8, 0x9A, 0xDE, 0x9B, 0xD5,
- 0xE8, 0xD8, 0xD5, 0x2E, 0x58, 0x33, 0x6B, 0x39,
- 0x2C, 0x39, 0x29, 0x28, 0xD1, 0x43, 0xB6, 0xAF,
- 0x23, 0x28, 0x2C, 0x39, 0x39, 0x8B, 0x30, 0x31,
- 0x21, 0x20, 0x3F, 0xBB, 0xDF, 0xDF, 0xD5, 0xA8,
- 0xD5, 0x9C, 0x8E, 0xB2, 0x9D, 0xE9, 0xD4, 0xD8,
- 0x90, 0xB2, 0xA9, 0x8F, 0x27, 0x27, 0x27, 0x27,
- 0x2F, 0x56, 0x56, 0xB9, 0x56, 0x56, 0xB9, 0xB9,
- 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0x56,
- 0x56, 0xB9, 0x48, 0x48, 0x75, 0xE3, 0xAA, 0xAA,
- 0xC0, 0xB4, 0xB4, 0xB4, 0x75, 0x9B, 0xD9, 0x83,
- 0x9D, 0x90, 0xDF, 0xDD, 0x8A, 0x31, 0x4B, 0x2C,
- 0x2C, 0x29, 0x2C, 0x3F, 0x6C, 0x55, 0xD1, 0x55,
- 0x54, 0x29, 0x28, 0x39, 0x39, 0x6B, 0x24, 0x60,
- 0x20, 0x2B, 0x3F, 0xA7, 0xB1, 0x9D, 0xA9, 0x8E,
- 0xE5, 0xE5, 0xDF, 0xE0, 0xA9, 0x9D, 0xDF, 0xDF,
- 0xEA, 0x9D, 0xB2, 0x84, 0xAA, 0x27, 0x27, 0x27,
- 0x27, 0x35, 0x56, 0x56, 0x56, 0x56, 0xB9, 0xB9,
- 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0x56,
- 0xB9, 0xB9, 0x48, 0x48, 0xA6, 0x9B, 0xE3, 0xAA,
- 0xAA, 0x9B, 0x9B, 0x9B, 0xAA, 0xE3, 0xD5, 0xD4,
- 0x9D, 0xA9, 0xA9, 0x9D, 0xEB, 0xAF, 0x23, 0x28,
- 0x2C, 0x29, 0x28, 0x39, 0x54, 0xCC, 0xAF, 0x55,
- 0x30, 0x29, 0x2B, 0x2C, 0x39, 0x39, 0x2B, 0xC4,
- 0x2B, 0x29, 0x39, 0xA7, 0x8E, 0x9D, 0x83, 0xE5,
- 0xB1, 0xDB, 0xDC, 0xE0, 0xDC, 0x84, 0xE9, 0x84,
- 0x83, 0xD4, 0xEC, 0x83, 0x8F, 0xE4, 0x27, 0x27,
- 0x27, 0x27, 0x56, 0x56, 0x56, 0x56, 0xB9, 0xB9,
- 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0x56,
- 0xB9, 0x56, 0x40, 0x50, 0x9A, 0x75, 0xE3, 0xE3,
- 0xE3, 0xD9, 0x8D, 0xAA, 0xD9, 0xA8, 0xB2, 0xDC,
- 0xB2, 0x8D, 0x84, 0xEA, 0xB1, 0xEB, 0x54, 0x29,
- 0x28, 0x2C, 0x2A, 0x28, 0x2B, 0x78, 0xCC, 0x58,
- 0xCB, 0x20, 0x20, 0x29, 0x39, 0x39, 0x2C, 0x25,
- 0x29, 0x2C, 0x39, 0xBB, 0xD9, 0xD9, 0x9D, 0x9D,
- 0xB2, 0xB1, 0xD4, 0xDB, 0xB1, 0x9D, 0xD4, 0xEA,
- 0xB1, 0x8D, 0xD8, 0x8E, 0x8F, 0xAA, 0x27, 0x27,
- 0x27, 0x3D, 0x56, 0xB9, 0x56, 0xB9, 0xB9, 0xB9,
- 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0x56,
- 0x56, 0x56, 0x47, 0xE4, 0xA6, 0x75, 0xAA, 0xA8,
- 0x9C, 0x9C, 0xE1, 0x9C, 0x9C, 0x8E, 0xD8, 0x9D,
- 0xA9, 0xDB, 0xA9, 0xDC, 0xD8, 0xDA, 0xD4, 0x2B,
- 0x20, 0x2C, 0x28, 0x2A, 0x28, 0x63, 0x31, 0x58,
- 0xCB, 0x24, 0x20, 0x2B, 0x2C, 0x39, 0x6B, 0x21,
- 0x39, 0x6B, 0x2C, 0xC0, 0xE0, 0xB1, 0xB2, 0x9D,
- 0x8E, 0xD8, 0xE0, 0xD9, 0x84, 0xDB, 0xD8, 0xB1,
- 0x8E, 0xB2, 0xE2, 0x9C, 0x83, 0x9E, 0xBC, 0x3D,
- 0xD3, 0x56, 0x56, 0xB9, 0x56, 0xB9, 0xB9, 0xB9,
- 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0xB9,
- 0x56, 0x4F, 0x27, 0x61, 0xA6, 0x9B, 0xE3, 0xA9,
- 0xE9, 0xD4, 0xDA, 0xDB, 0x8E, 0xE1, 0xE9, 0x8E,
- 0xD4, 0xA8, 0xE0, 0x84, 0xE8, 0xB1, 0xDC, 0x9D,
- 0x20, 0x29, 0x29, 0x2B, 0x2C, 0x54, 0x78, 0xCC,
- 0x78, 0x33, 0x2A, 0x20, 0x29, 0x39, 0x50, 0x2A,
- 0x6B, 0x8B, 0x39, 0xC0, 0x8D, 0xB1, 0xE9, 0xA9,
- 0xB2, 0xDC, 0x8E, 0xDC, 0xE1, 0xDA, 0xA9, 0x8E,
- 0xEA, 0xE2, 0x83, 0xE8, 0x8E, 0x83, 0xE2, 0xED,
- 0xB9, 0xB9, 0x56, 0xB9, 0x56, 0xB9, 0xB9, 0xB9,
- 0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0x56, 0x56, 0xB9,
- 0xC9, 0x27, 0x27, 0xE4, 0xA6, 0x9B, 0xD5, 0xA8,
- 0xD4, 0xB2, 0xD8, 0xDA, 0xD9, 0xE8, 0xE9, 0xE8,
- 0xD8, 0xB1, 0xDA, 0xB2, 0xE9, 0x8E, 0xEC, 0xDA,
- 0x22, 0x20, 0x39, 0x2B, 0x39, 0x24, 0xC4, 0x30,
- 0x30, 0x54, 0x22, 0x29, 0x29, 0x39, 0x48, 0x2C,
- 0x39, 0x6B, 0x39, 0xC0, 0x8D, 0xB1, 0xE9, 0xB2,
- 0xB2, 0x8E, 0xA9, 0xD8, 0xDA, 0xB1, 0xA9, 0xDA,
- 0x9C, 0xDC, 0x8E, 0xD4, 0xE8, 0xE8, 0x8F, 0x9B,
- 0x4F, 0xB9, 0x56, 0xB9, 0x56, 0xB9, 0xB9, 0xB9,
- 0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0x56, 0x4F, 0x6B,
- 0x27, 0x27, 0x27, 0xD7, 0xDE, 0xAA, 0xE3, 0xA8,
- 0xB2, 0xD5, 0xE5, 0x90, 0xE2, 0xA9, 0xE9, 0xB2,
- 0xDA, 0xB2, 0xE1, 0xB2, 0xE9, 0x8E, 0xDA, 0xDF,
- 0x78, 0x2A, 0x2C, 0x2A, 0x6B, 0x28, 0x23, 0x54,
- 0x63, 0xC4, 0x33, 0x28, 0x2C, 0x39, 0x47, 0x39,
- 0x28, 0x2C, 0x29, 0xBB, 0x8D, 0x83, 0xE9, 0xD4,
- 0xB2, 0xE9, 0xE9, 0xE8, 0xD4, 0xD8, 0xD4, 0xA9,
- 0xDA, 0xB2, 0xE9, 0xA8, 0xB2, 0xA8, 0xD5, 0xAA,
- 0xC6, 0x56, 0x56, 0x56, 0x56, 0x56, 0xB9, 0x56,
- 0x56, 0x56, 0x56, 0x56, 0x56, 0xC9, 0x27, 0x27,
- 0x27, 0x27, 0x27, 0xB8, 0xB4, 0x9B, 0xE3, 0x8E,
- 0x9D, 0x8E, 0xB2, 0xE8, 0xE8, 0x8E, 0xB2, 0xDA,
- 0xB2, 0x8E, 0xEC, 0xB2, 0x8E, 0xB2, 0xBB, 0x58,
- 0xAF, 0x33, 0x50, 0x39, 0x6B, 0x39, 0x29, 0x20,
- 0x33, 0x30, 0x78, 0x23, 0x6B, 0x6B, 0x48, 0x6B,
- 0x2B, 0x2A, 0x29, 0xBB, 0xE5, 0x9C, 0xB1, 0xB2,
- 0xE5, 0x84, 0x8E, 0x9C, 0x84, 0xB2, 0xB2, 0x9D,
- 0x84, 0xDF, 0xA9, 0x84, 0x8E, 0xA8, 0xE3, 0x9B,
- 0xA6, 0xD7, 0x80, 0x4F, 0x56, 0x56, 0x56, 0x4F,
- 0x4F, 0x4F, 0x4F, 0x2A, 0x2D, 0x27, 0x27, 0x27,
- 0x27, 0x27, 0x27, 0xB8, 0xB4, 0xAA, 0xD5, 0xA9,
- 0x9D, 0xB2, 0x90, 0xEA, 0xE9, 0xE2, 0xE1, 0x8E,
- 0xB2, 0x9D, 0x8E, 0xB1, 0xA7, 0xEE, 0x63, 0xD1,
- 0x2E, 0xCC, 0x28, 0x48, 0x8B, 0x47, 0x6B, 0x28,
- 0x23, 0x78, 0x6C, 0x54, 0x29, 0x50, 0x50, 0x6B,
- 0x23, 0x20, 0xBB, 0xBC, 0xBB, 0x8D, 0xE3, 0xDF,
- 0x9C, 0xA9, 0x8D, 0xA8, 0xD9, 0x90, 0x9D, 0xA9,
- 0xDC, 0xA9, 0x83, 0xB2, 0xA9, 0xD4, 0xE3, 0x9B,
- 0x8C, 0xEF, 0x27, 0x27, 0x27, 0x3C, 0x27, 0x27,
- 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27,
- 0x27, 0x27, 0x27, 0xF0, 0xB4, 0x9B, 0xE3, 0x84,
- 0x9D, 0x84, 0x90, 0xB1, 0xA9, 0x9C, 0xD9, 0xB1,
- 0xB2, 0xEA, 0xBB, 0x51, 0x24, 0x30, 0x30, 0x42,
- 0x66, 0x58, 0x24, 0x48, 0x50, 0x3F, 0x20, 0x25,
- 0x22, 0x60, 0x34, 0x30, 0x20, 0x8B, 0x8B, 0x39,
- 0x54, 0x24, 0x2B, 0xC0, 0xC0, 0xC0, 0xBB, 0x9B,
- 0xBC, 0xAA, 0xAA, 0xE3, 0xE3, 0x9C, 0xB2, 0xD4,
- 0x83, 0xD8, 0xE8, 0x83, 0x84, 0xE8, 0xE5, 0x75,
- 0x9A, 0xF0, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27,
- 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27,
- 0x27, 0x27, 0x27, 0xF0, 0xB4, 0x9B, 0xE3, 0xA8,
- 0xA9, 0xD8, 0x8E, 0xEA, 0xA8, 0x9C, 0xD9, 0xE0,
- 0xC0, 0x5E, 0x2C, 0x20, 0x54, 0x60, 0x30, 0x66,
- 0xB6, 0xCC, 0x63, 0x3F, 0x8B, 0x28, 0x22, 0x33,
- 0x23, 0x31, 0xAF, 0x31, 0x22, 0x6B, 0x6B, 0x29,
- 0x30, 0x54, 0x22, 0x89, 0xBA, 0xED, 0xA6, 0x8C,
- 0xB4, 0xC0, 0xB4, 0x75, 0x75, 0x9B, 0x9B, 0xE5,
- 0xA9, 0xD5, 0x8E, 0x8E, 0x9C, 0xE3, 0x75, 0x8C,
- 0xC8, 0xF1, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27,
- 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27,
- 0x27, 0x27, 0x27, 0xF1, 0x9A, 0xB4, 0x9B, 0xE3,
- 0xE3, 0xA8, 0xE3, 0xE5, 0xAA, 0xBC, 0xC0, 0x9A,
- 0x26, 0x29, 0x20, 0x24, 0x63, 0x60, 0x54, 0x43,
- 0x34, 0xCB, 0x30, 0x39, 0x2C, 0x20, 0x24, 0x54,
- 0x22, 0x34, 0x34, 0x31, 0x24, 0x3F, 0x2C, 0x2B,
- 0x31, 0x30, 0x25, 0x2A, 0x6B, 0x29, 0x20, 0xF2,
- 0xBA, 0xBF, 0xC8, 0x9A, 0xA6, 0xA6, 0x8C, 0xB4,
- 0x9B, 0xAA, 0xAA, 0xAA, 0x9B, 0x75, 0xDE, 0xBF,
- 0x81, 0xEF, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27,
- 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27,
- 0x27, 0x27, 0x27, 0xEF, 0xBA, 0x9A, 0xB4, 0x75,
- 0x9B, 0x9B, 0x9B, 0xC0, 0xB4, 0x9A, 0xA5, 0xC4,
- 0x30, 0x28, 0x22, 0x33, 0x30, 0x30, 0x23, 0x34,
- 0x31, 0x30, 0xC4, 0x2C, 0x2B, 0x22, 0x33, 0x63,
- 0x21, 0x58, 0x6C, 0x60, 0x25, 0x39, 0x28, 0x2B,
- 0xCC, 0x6C, 0x63, 0x20, 0x6B, 0x28, 0x2B, 0x20,
- 0x63, 0x43, 0xF3, 0xEF, 0xF0, 0x81, 0xBA, 0xF4,
- 0xF4, 0xA6, 0xDE, 0x8C, 0xA6, 0x9A, 0xBA, 0x81,
- 0xB0, 0xE4, 0xA1, 0x20, 0x20, 0x23, 0x31, 0xC4,
- 0x30, 0x24, 0x33, 0x31, 0x31, 0x60, 0x43, 0x35,
- 0x35, 0x55, 0x6C, 0xEF, 0x81, 0xC8, 0x9A, 0xA6,
- 0xB4, 0xB4, 0x8C, 0xA6, 0xBA, 0x68, 0x30, 0x30,
- 0x30, 0x2B, 0x25, 0x54, 0xC4, 0x54, 0x24, 0x78,
- 0x63, 0x63, 0x30, 0x29, 0x21, 0x24, 0x54, 0x63,
- 0x23, 0x34, 0xCB, 0x30, 0x25, 0x39, 0x20, 0x20,
- 0x58, 0x34, 0x60, 0x23, 0x6B, 0x29, 0x28, 0x20,
- 0x22, 0xB6, 0x42, 0xB6, 0x58, 0x54, 0xF5, 0xD7,
- 0xA5, 0xBA, 0xBA, 0xBA, 0xBA, 0x81, 0xA5, 0xF1,
- 0xE4, 0x2A, 0x39, 0x20, 0x20, 0x20, 0x31, 0x60,
- 0x54, 0x28, 0x2B, 0x22, 0x33, 0x30, 0x43, 0x35,
- 0x66, 0xD1, 0x34, 0xE4, 0xEF, 0x81, 0xC8, 0x9A,
- 0x9A, 0xC8, 0xC8, 0x81, 0xF6, 0x31, 0x63, 0x31,
- 0x78, 0x2B, 0x54, 0x63, 0x54, 0x24, 0x23, 0x54,
- 0x63, 0x54, 0x63, 0x2C, 0x23, 0x33, 0x63, 0x54,
- 0x25, 0x31, 0x78, 0x30, 0x25, 0x3F, 0x20, 0x20,
- 0xAF, 0x58, 0xCC, 0x33, 0x39, 0x29, 0x29, 0x2A,
- 0x29, 0x58, 0x43, 0x42, 0xD1, 0xCB, 0x2C, 0x2C,
- 0x37, 0xCD, 0xEF, 0xB0, 0xF0, 0xB0, 0xEF, 0xE4,
- 0x63, 0x20, 0x20, 0x2C, 0x2C, 0x21, 0xCB, 0x78,
- 0x54, 0x39, 0x39, 0x28, 0x2B, 0x28, 0x2B, 0xCB,
- 0x55, 0xB6, 0xD1, 0x28, 0xE4, 0xD7, 0xB8, 0xF0,
- 0xA5, 0xB0, 0xEF, 0x26, 0x23, 0x54, 0x31, 0x58,
- 0xCB, 0x20, 0x63, 0x63, 0x25, 0x2B, 0x54, 0x78,
- 0x30, 0x63, 0x54, 0x28, 0x33, 0x63, 0x63, 0x33,
- 0x54, 0x78, 0xC4, 0x30, 0x24, 0x2C, 0x22, 0x22,
- 0x55, 0x55, 0x34, 0x30, 0x28, 0x2C, 0x29, 0x29,
- 0x28, 0x30, 0xB6, 0x42, 0x43, 0x55, 0x22, 0x29,
- 0x2C, 0x2B, 0x2B, 0x3F, 0xE4, 0xE4, 0x43, 0x66,
- 0x30, 0x23, 0x24, 0x2A, 0x28, 0x2B, 0x54, 0x63,
- 0x33, 0x39, 0x28, 0x20, 0x20, 0x20, 0x2B, 0x31,
- 0x30, 0xD1, 0x43, 0x30, 0x39, 0x28, 0xE4, 0xE4,
- 0xD7, 0xF5, 0x2B, 0x6B, 0x20, 0x30, 0x34, 0xD1,
- 0x60, 0x23, 0x63, 0x54, 0x22, 0x47, 0x60, 0xCB,
- 0xC4, 0xC4, 0x25, 0x22, 0x54, 0xC4, 0x63, 0x23,
- 0xC4, 0xC4, 0x63, 0xC4, 0x23, 0x2A, 0x24, 0x22,
- 0x55, 0x55, 0xAF, 0x6C, 0x22, 0x39, 0x2C, 0x39,
- 0x28, 0x23, 0xD1, 0x43, 0x42, 0x8A, 0x63, 0x39,
- 0x39, 0x2A, 0x20, 0x6B, 0x33, 0xCC, 0xD1, 0xB6,
- 0x30, 0x24, 0x54, 0x63, 0x31, 0xCC, 0xCC, 0xCB,
- 0xC4, 0x2A, 0x39, 0x20, 0x20, 0x20, 0x39, 0x30,
- 0x30, 0x6C, 0x43, 0x43, 0x6C, 0x63, 0x25, 0x24,
- 0x63, 0x63, 0x63, 0x25, 0x63, 0xCC, 0xD1, 0x34,
- 0x63, 0x25, 0x54, 0x25, 0x2A, 0x28, 0x31, 0xCB,
- 0x63, 0x78, 0x24, 0x33, 0xC4, 0xC4, 0x33, 0x2C,
- 0xC4, 0x54, 0x54, 0x30, 0x21, 0x22, 0x25, 0x23,
- 0x55, 0x55, 0xD1, 0x58, 0x33, 0x6B, 0x2C, 0x39,
- 0x39, 0x39, 0x34, 0x43, 0x42, 0x43, 0xCC, 0x2B,
- 0x28, 0x29, 0x20, 0x28, 0x21, 0x30, 0xCC, 0xAF,
- 0x54, 0x23, 0xC4, 0x54, 0x58, 0x2E, 0x35, 0x42,
- 0x55, 0x54, 0x8B, 0x2A, 0x20, 0x20, 0x28, 0x22,
- 0x78, 0x30, 0xD1, 0x43, 0x44, 0x6C, 0xC4, 0xC4,
- 0x60, 0x31, 0x31, 0x63, 0x6C, 0xAF, 0xCC, 0xCB,
- 0x24, 0x25, 0x33, 0x23, 0x2C, 0x24, 0x31, 0x30,
- 0x63, 0xC4, 0x21, 0x54, 0x30, 0x63, 0x24, 0x2A,
- 0x54, 0x63, 0x54, 0xC4, 0x2B, 0x24, 0x33, 0x24,
- 0x34, 0x55, 0xD1, 0x55, 0x30, 0x28, 0x29, 0x39,
- 0x39, 0x8B, 0x63, 0x55, 0x42, 0x66, 0xB6, 0x25,
- 0x29, 0x29, 0x29, 0x28, 0x2A, 0x54, 0x78, 0x6C,
- 0x23, 0x20, 0x25, 0x30, 0xCB, 0x62, 0x35, 0x35,
- 0x35, 0x44, 0x24, 0x6B, 0x29, 0x20, 0x2A, 0x39,
- 0x28, 0x63, 0x34, 0xB6, 0x34, 0xCB, 0x63, 0x30,
- 0x31, 0x31, 0x30, 0x30, 0xCC, 0x60, 0x63, 0xC4,
- 0x20, 0x33, 0x25, 0x20, 0x48, 0x33, 0x30, 0x54,
- 0x78, 0x54, 0x2B, 0x63, 0x30, 0x63, 0x23, 0x22,
- 0x63, 0x63, 0x63, 0x33, 0x28, 0x25, 0x54, 0x24,
- 0x78, 0xAF, 0xD1, 0xD1, 0xCC, 0x22, 0x39, 0x39,
- 0x2C, 0x3F, 0x2B, 0x34, 0xB6, 0x43, 0x43, 0xC4,
- 0x2B, 0x28, 0x39, 0x50, 0x2C, 0x24, 0x63, 0x78,
- 0x21, 0x2C, 0x2A, 0x23, 0x54, 0xD1, 0x35, 0x35,
- 0x35, 0x35, 0x55, 0x22, 0x39, 0x2C, 0x2C, 0x2C,
- 0x20, 0x30, 0xCC, 0x6C, 0xCB, 0x30, 0x54, 0x30,
- 0x78, 0x63, 0x78, 0x30, 0x54, 0x78, 0x30, 0x23,
- 0x2B, 0x33, 0x24, 0x28, 0x39, 0x24, 0x54, 0x30,
- 0x78, 0x33, 0x25, 0xC4, 0xC4, 0x33, 0x39, 0x25,
- 0xC4, 0x63, 0xC4, 0x24, 0x20, 0x54, 0x54, 0x25,
- 0x63, 0xCC, 0xD1, 0xB6, 0x55, 0x54, 0x39, 0x29,
- 0x39, 0x2C, 0x6B, 0x30, 0xAF, 0xB6, 0xB6, 0x60,
- 0x22, 0x2A, 0x2C, 0x39, 0x2C, 0x21, 0x54, 0x63,
- 0x21, 0x50, 0x2C, 0x2C, 0x2B, 0x25, 0x62, 0x35,
- 0x35, 0x35, 0x35, 0xCC, 0x2B, 0x29, 0x2B, 0x20,
- 0x23, 0x25, 0xC4, 0x30, 0xC4, 0x63, 0x63, 0x63,
- 0x63, 0x33, 0x24, 0x31, 0x31, 0x31, 0x54, 0x28,
- 0x24, 0x25, 0x22, 0x6B, 0x28, 0x24, 0xC4, 0x78,
- 0x30, 0x24, 0x63, 0xC4, 0x54, 0x23, 0x29, 0x63,
- 0xC4, 0x54, 0xC4, 0x21, 0x24, 0x54, 0x54, 0x25,
- 0x30, 0xCB, 0xD1, 0xB6, 0x55, 0x63, 0x28, 0x29,
- 0x39, 0x39, 0x48, 0x33, 0x58, 0x44, 0xB6, 0x60,
- 0x24, 0x20, 0x2B, 0x28, 0x2A, 0x22, 0x54, 0x63,
- 0x21, 0x48, 0x2A, 0x2B, 0x39, 0x21, 0xB6, 0x35,
- 0x35, 0x35, 0x35, 0x42, 0x23, 0x29, 0x2A, 0x2B,
- 0x23, 0x25, 0x54, 0x54, 0x54, 0x63, 0x63, 0x30,
- 0x25, 0x2B, 0x31, 0x31, 0x31, 0x31, 0x21, 0x2C,
- 0x33, 0x25, 0x21, 0x39, 0x20, 0x25, 0x30, 0x78,
- 0xC4, 0x23, 0xC4, 0x30, 0x54, 0x20, 0x28, 0x63,
- 0x63, 0x63, 0x63, 0x20, 0x25, 0x54, 0x54, 0x20,
-};
-
-unsigned char linux_logo_bw[] __initdata = {
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x3F,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F,
- 0xFE, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFE, 0x3F, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFE, 0x7F, 0xFF, 0xC7, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xC3,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF,
- 0xFB, 0xE3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFD, 0xFF, 0xFF, 0xE1, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xF9, 0xFF, 0xFF, 0xF1, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0xFF, 0xFF, 0xF1,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0xFF,
- 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xF9, 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xF9, 0xCF, 0xC3, 0xF8, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0x87, 0x81, 0xF9,
- 0xF8, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0xA7,
- 0x99, 0xF9, 0xC2, 0x40, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xF9, 0xF3, 0xBC, 0xF9, 0x90, 0x00, 0x1F, 0xFF,
- 0xFF, 0xFF, 0xF9, 0xE3, 0xBC, 0xF9, 0xA0, 0x00,
- 0x8F, 0xFF, 0xFF, 0xFF, 0xF9, 0xB0, 0x3C, 0xF9,
- 0x83, 0xE0, 0x2F, 0xFF, 0xFF, 0xFF, 0xF9, 0xB0,
- 0x19, 0xF0, 0x1F, 0xFE, 0x0F, 0xFF, 0xFF, 0xFF,
- 0xF9, 0xC0, 0x03, 0xF0, 0x3F, 0xF7, 0x8F, 0xFF,
- 0xFF, 0xFF, 0xF9, 0x80, 0x01, 0xF8, 0x7F, 0xF7,
- 0xC7, 0xFF, 0xFF, 0xFF, 0xF9, 0x80, 0x01, 0xF8,
- 0x6F, 0xF7, 0xE7, 0xFF, 0xFF, 0xFF, 0xF9, 0x80,
- 0x01, 0xF8, 0x7F, 0xF7, 0xE7, 0xFF, 0xFF, 0xFF,
- 0xF9, 0xC0, 0x21, 0xD8, 0x7F, 0xE7, 0xEF, 0xFF,
- 0xFF, 0xFF, 0xF9, 0xB1, 0x80, 0xEC, 0x7B, 0xFF,
- 0xEF, 0xFF, 0xFF, 0xFF, 0xF1, 0x90, 0x00, 0xE4,
- 0x7B, 0xFF, 0xEF, 0xFF, 0xFF, 0xFF, 0xF1, 0x8C,
- 0xC0, 0x7C, 0x79, 0xFF, 0xEF, 0xFF, 0xFF, 0xFF,
- 0xE3, 0x80, 0x00, 0x7C, 0x7C, 0xFF, 0xCF, 0xFF,
- 0xFF, 0xFF, 0xE3, 0x80, 0x00, 0x7F, 0x77, 0xFF,
- 0xDF, 0xFF, 0xFF, 0xFF, 0x87, 0x00, 0x00, 0x3F,
- 0x3F, 0xFF, 0xDF, 0xFF, 0xFF, 0xFF, 0x0E, 0x00,
- 0x00, 0x3F, 0xBF, 0xFF, 0x9F, 0xFF, 0xFF, 0xFF,
- 0x1E, 0x00, 0x00, 0x1F, 0x9F, 0xFF, 0x3F, 0xFF,
- 0xFF, 0xFE, 0x1C, 0x00, 0x00, 0x1F, 0x9F, 0xFF,
- 0x7F, 0xFF, 0xFF, 0xFE, 0x3C, 0x00, 0x00, 0x1F,
- 0x8F, 0xFE, 0x7F, 0xFF, 0xFF, 0xFC, 0x7C, 0x00,
- 0x00, 0x0F, 0xC7, 0xFC, 0xFF, 0xFF, 0xFF, 0xFC,
- 0xF8, 0x00, 0x00, 0x0F, 0xF7, 0xF9, 0xFF, 0xFF,
- 0xFF, 0xFC, 0xF8, 0x00, 0x00, 0x07, 0xFB, 0xF3,
- 0xFF, 0xFF, 0xFF, 0xF8, 0xF8, 0x00, 0x00, 0x07,
- 0xFD, 0xE7, 0xFF, 0xFF, 0xFF, 0xF9, 0xF0, 0x00,
- 0x00, 0x03, 0xFE, 0x8F, 0xFF, 0xFF, 0xFF, 0xF1,
- 0xF0, 0x00, 0x00, 0x03, 0xFE, 0x1F, 0xFF, 0xFF,
- 0xFF, 0xF1, 0xE0, 0x00, 0x00, 0x00, 0xFF, 0xBF,
- 0xFF, 0xFF, 0xFF, 0xE3, 0xE0, 0x00, 0x00, 0x00,
- 0xFE, 0xBF, 0xFF, 0xFF, 0xFF, 0xE3, 0xC0, 0x00,
- 0x00, 0x00, 0xFE, 0x3F, 0xFF, 0xFF, 0xFF, 0xC7,
- 0xC0, 0x00, 0x00, 0x01, 0xFE, 0xBF, 0xFF, 0xFF,
- 0xFF, 0xC7, 0x80, 0x00, 0x00, 0x01, 0xFE, 0x9F,
- 0xFF, 0xFF, 0xFF, 0x8F, 0x80, 0x00, 0x00, 0x01,
- 0xFE, 0x07, 0xFF, 0xFF, 0xFF, 0x8F, 0x80, 0x00,
- 0x00, 0x01, 0xFE, 0x87, 0xFF, 0xFF, 0xFF, 0x9F,
- 0x80, 0x00, 0x00, 0x01, 0xFD, 0x33, 0xFF, 0xFF,
- 0xFF, 0x9F, 0x80, 0x00, 0x00, 0x01, 0x80, 0xF3,
- 0xFF, 0xFF, 0xFF, 0x9E, 0x80, 0x00, 0x00, 0x03,
- 0x8B, 0xF9, 0xFF, 0xFF, 0xFF, 0x9F, 0x80, 0x00,
- 0x00, 0x02, 0x27, 0xF8, 0xFF, 0xFF, 0xFF, 0x99,
- 0x80, 0x00, 0x00, 0x00, 0x07, 0xF8, 0xFF, 0xFF,
- 0xFF, 0x00, 0x80, 0x00, 0x00, 0x01, 0x8F, 0xF8,
- 0xFF, 0xFF, 0xFE, 0x20, 0x60, 0x00, 0x00, 0x00,
- 0xE3, 0xF8, 0xFF, 0xFF, 0xF8, 0x00, 0x30, 0x00,
- 0x00, 0x00, 0xF8, 0x78, 0xFF, 0xFF, 0xC0, 0x40,
- 0x38, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x7F, 0xFF,
- 0x81, 0x00, 0x1C, 0x00, 0x00, 0x00, 0xFC, 0x20,
- 0x7F, 0xFF, 0x90, 0x00, 0x1E, 0x00, 0x00, 0x00,
- 0x78, 0x10, 0xFF, 0xFF, 0x80, 0x00, 0x0F, 0x80,
- 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x00,
- 0x07, 0xC0, 0x00, 0x00, 0x00, 0x08, 0xFF, 0xFF,
- 0xC0, 0x00, 0x07, 0xC0, 0x00, 0x00, 0x00, 0x04,
- 0x7F, 0xFF, 0x80, 0x00, 0x03, 0xC0, 0x00, 0x10,
- 0x00, 0x00, 0x1F, 0xFF, 0x80, 0x00, 0x01, 0x80,
- 0x00, 0x30, 0x00, 0x00, 0x0F, 0xFF, 0x80, 0x00,
- 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, 0x4F, 0xFF,
- 0x80, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00,
- 0x0F, 0xFF, 0xC0, 0x00, 0x00, 0x80, 0x03, 0xF0,
- 0x00, 0x00, 0x8F, 0xFF, 0x80, 0x00, 0x00, 0x40,
- 0x0F, 0xF0, 0x00, 0x04, 0x1F, 0xFF, 0x80, 0x00,
- 0x00, 0x7F, 0xFF, 0xF0, 0x00, 0x10, 0x1F, 0xFF,
- 0xC0, 0x00, 0x00, 0x7F, 0xFF, 0xF0, 0x00, 0x40,
- 0xFF, 0xFF, 0x98, 0x00, 0x00, 0xFF, 0xFF, 0xF0,
- 0x00, 0x83, 0xFF, 0xFF, 0x81, 0xE0, 0x01, 0xFF,
- 0xFF, 0xF8, 0x02, 0x07, 0xFF, 0xFF, 0x80, 0x3F,
- 0x07, 0xE0, 0x00, 0x1C, 0x0C, 0x1F, 0xFF, 0xFF,
- 0xF8, 0x03, 0xFF, 0x80, 0x00, 0x1F, 0x78, 0x1F,
- 0xFF, 0xFF, 0xFF, 0x80, 0x7F, 0x00, 0x07, 0x0F,
- 0xF0, 0x7F, 0xFF, 0xFF, 0xFF, 0xFE, 0x0C, 0x07,
- 0xFF, 0x83, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0x00, 0x1F, 0xFF, 0xC0, 0x03, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x07, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-};
-
-/* Painted by Johnny Stenback <jst@uwasa.fi> */
-
-unsigned char *linux_serial_image __initdata = "\n"
-" .u$e.\n"
-" .$$$$$:S\n"
-" $\"*$/\"*$$\n"
-" $.`$ . ^F\n"
-" 4k+#+T.$F\n"
-" 4P+++\"$\"$\n"
-" :R\"+ t$$B\n"
-" ___# $$$\n"
-" | | R$$k\n"
-" dd. | Linux $!$\n"
-" ddd | Sparc $9$F\n"
-" '!!!!!$ !!#!`\n"
-" !!!!!* .!!!!!`\n"
-"'!!!!!!!W..e$$!!!!!!` %s\n"
-" \"~^^~ ^~~^\n"
-"\n";
diff --git a/include/asm-sparc64/mmu_context.h b/include/asm-sparc64/mmu_context.h
index 76aacba13..0e8168bb5 100644
--- a/include/asm-sparc64/mmu_context.h
+++ b/include/asm-sparc64/mmu_context.h
@@ -1,4 +1,4 @@
-/* $Id: mmu_context.h,v 1.7 1997/04/04 00:50:23 davem Exp $ */
+/* $Id: mmu_context.h,v 1.8 1997/05/18 20:44:23 davem Exp $ */
#ifndef __SPARC64_MMU_CONTEXT_H
#define __SPARC64_MMU_CONTEXT_H
@@ -63,11 +63,21 @@ extern __inline__ void get_mmu_context(struct task_struct *tsk)
!(tsk->tss.flags & SPARC_FLAG_KTHREAD) &&
!(tsk->flags & PF_EXITING)) {
unsigned long ctx = tlb_context_cache;
+ register unsigned long paddr asm("o5");
flushw_user();
if((mm->context ^ ctx) & CTX_VERSION_MASK)
get_new_mmu_context(mm, ctx);
spitfire_set_secondary_context(mm->context);
+ paddr = __pa(mm->pgd);
+ __asm__ __volatile__("
+ rdpr %%pstate, %%o4
+ wrpr %%o4, %1, %%pstate
+ mov %0, %%g7
+ wrpr %%o4, 0x0, %%pstate
+ " : /* no outputs */
+ : "r" (paddr), "i" (PSTATE_MG|PSTATE_IE)
+ : "o4");
}
}
diff --git a/include/asm-sparc64/pgtable.h b/include/asm-sparc64/pgtable.h
index 600ac1632..ca35d567f 100644
--- a/include/asm-sparc64/pgtable.h
+++ b/include/asm-sparc64/pgtable.h
@@ -1,7 +1,7 @@
-/* $Id: pgtable.h,v 1.28 1997/04/14 17:05:19 jj Exp $
+/* $Id: pgtable.h,v 1.31 1997/05/18 21:11:42 davem Exp $
* pgtable.h: SpitFire page table operations.
*
- * Copyright 1996 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright 1996,1997 David S. Miller (davem@caip.rutgers.edu)
*/
#ifndef _SPARC64_PGTABLE_H
@@ -204,13 +204,8 @@ extern __inline__ void flush_cache_all(void)
unsigned long addr;
flushw_all();
- for(addr = 0; addr < (PAGE_SIZE << 1); addr += 32) {
+ for(addr = 0; addr < (PAGE_SIZE << 1); addr += 32)
spitfire_put_icache_tag(addr, 0x0UL);
- membar("#Sync");
- }
-
- /* Kill the pipeline. */
- flushi(PAGE_OFFSET);
}
extern __inline__ void flush_cache_mm(struct mm_struct *mm)
@@ -219,13 +214,8 @@ extern __inline__ void flush_cache_mm(struct mm_struct *mm)
unsigned long addr;
flushw_user();
- for(addr = 0; addr < (PAGE_SIZE << 1); addr += 32) {
+ for(addr = 0; addr < (PAGE_SIZE << 1); addr += 32)
spitfire_put_icache_tag(addr, 0x0UL);
- membar("#Sync");
- }
-
- /* Kill the pipeline. */
- flushi(PAGE_OFFSET);
}
}
@@ -236,13 +226,8 @@ extern __inline__ void flush_cache_range(struct mm_struct *mm, unsigned long sta
unsigned long addr;
flushw_user();
- for(addr = 0; addr < (PAGE_SIZE << 1); addr += 32) {
+ for(addr = 0; addr < (PAGE_SIZE << 1); addr += 32)
spitfire_put_icache_tag(addr, 0x0UL);
- membar("#Sync");
- }
-
- /* Kill the pipeline. */
- flushi(PAGE_OFFSET);
}
}
@@ -254,13 +239,8 @@ extern __inline__ void flush_cache_page(struct vm_area_struct *vma, unsigned lon
unsigned long addr;
flushw_user();
- for(addr = 0; addr < (PAGE_SIZE << 1); addr += 32) {
+ for(addr = 0; addr < (PAGE_SIZE << 1); addr += 32)
spitfire_put_icache_tag(addr, 0x0UL);
- membar("#Sync");
- }
-
- /* Kill the pipeline. */
- flushi(PAGE_OFFSET);
}
}
@@ -290,15 +270,28 @@ extern __inline__ void flush_tlb_all(void)
extern __inline__ void flush_tlb_mm(struct mm_struct *mm)
{
if(mm->context != NO_CONTEXT) {
- unsigned long orig_ctx = spitfire_get_secondary_context();
- unsigned long flags;
-
- save_and_cli(flags);
- spitfire_set_secondary_context(mm->context);
- spitfire_flush_dtlb_secondary_context();
- spitfire_flush_itlb_secondary_context();
- spitfire_set_secondary_context(orig_ctx);
- restore_flags(flags);
+ __asm__ __volatile__("
+ /* flush_tlb_mm() */
+ rdpr %%pil, %%g1
+ mov %1, %%g7
+ wrpr %%g0, 15, %%pil
+ ldxa [%%g7] %2, %%g2
+ cmp %%g2, %0
+ be,pt %%icc, 1f
+ mov 0x50, %%g3
+ stxa %0, [%%g7] %2
+1:
+ stxa %%g0, [%%g3] %3
+ stxa %%g0, [%%g3] %4
+ bne,a,pn %%icc, 1f
+ stxa %%g2, [%%g7] %2
+1:
+ flush %%g4
+ wrpr %%g1, 0x0, %%pil
+" : /* no outputs */
+ : "r" (mm->context), "i" (SECONDARY_CONTEXT), "i" (ASI_DMMU),
+ "i" (ASI_DMMU_DEMAP), "i" (ASI_IMMU_DEMAP)
+ : "g1", "g2", "g3", "g7", "cc");
}
}
@@ -307,17 +300,21 @@ extern __inline__ void flush_tlb_range(struct mm_struct *mm, unsigned long start
{
if(mm->context != NO_CONTEXT) {
unsigned long old_ctx = spitfire_get_secondary_context();
+ unsigned long new_ctx = mm->context;
unsigned long flags;
start &= PAGE_MASK;
save_and_cli(flags);
- spitfire_set_secondary_context(mm->context);
+ if(new_ctx != old_ctx)
+ spitfire_set_secondary_context(mm->context);
while(start < end) {
spitfire_flush_dtlb_secondary_page(start);
spitfire_flush_itlb_secondary_page(start);
start += PAGE_SIZE;
}
- spitfire_set_secondary_context(old_ctx);
+ if(new_ctx != old_ctx)
+ spitfire_set_secondary_context(old_ctx);
+ __asm__ __volatile__("flush %g4");
restore_flags(flags);
}
}
@@ -327,17 +324,31 @@ extern __inline__ void flush_tlb_page(struct vm_area_struct *vma, unsigned long
struct mm_struct *mm = vma->vm_mm;
if(mm->context != NO_CONTEXT) {
- unsigned long old_ctx = spitfire_get_secondary_context();
- unsigned long flags;
-
- page &= PAGE_MASK;
- save_and_cli(flags);
- spitfire_set_secondary_context(mm->context);
- if(vma->vm_flags & VM_EXEC)
- spitfire_flush_itlb_secondary_page(page);
- spitfire_flush_dtlb_secondary_page(page);
- spitfire_set_secondary_context(old_ctx);
- restore_flags(flags);
+ __asm__ __volatile__("
+ /* flush_tlb_page() */
+ rdpr %%pil, %%g1
+ mov %1, %%g7
+ wrpr %%g0, 15, %%pil
+ ldxa [%%g7] %2, %%g2
+ cmp %%g2, %0
+ be,pt %%icc, 1f
+ or %5, 0x10, %5
+ stxa %0, [%%g7] %2
+1:
+ stxa %%g0, [%5] %3
+ brnz,a %6, 1f
+ stxa %%g0, [%5] %4
+1:
+ bne,a,pn %%icc, 1f
+ stxa %%g2, [%%g7] %2
+1:
+ flush %%g4
+ wrpr %%g1, 0x0, %%pil
+" : /* no outputs */
+ : "r" (mm->context), "i" (SECONDARY_CONTEXT), "i" (ASI_DMMU),
+ "i" (ASI_DMMU_DEMAP), "i" (ASI_IMMU_DEMAP), "r" (page & PAGE_MASK),
+ "r" (vma->vm_flags & VM_EXEC)
+ : "g1", "g2", "g3", "g7", "cc");
}
}
@@ -649,7 +660,7 @@ extern inline void update_mmu_cache(struct vm_area_struct * vma,
start += PAGE_SIZE;
}
}
- } while((vmaring = vmaring->vm_next_share) != inode->i_mmap);
+ } while((vmaring = vmaring->vm_next_share) != NULL);
if(alias_found && (pte_val(pte) & _PAGE_CV)) {
pgdp = pgd_offset(vma->vm_mm, address);
diff --git a/include/asm-sparc64/processor.h b/include/asm-sparc64/processor.h
index 25c907ddb..8b2380a2e 100644
--- a/include/asm-sparc64/processor.h
+++ b/include/asm-sparc64/processor.h
@@ -1,4 +1,4 @@
-/* $Id: processor.h,v 1.21 1997/04/14 17:05:18 jj Exp $
+/* $Id: processor.h,v 1.26 1997/05/17 05:59:10 davem Exp $
* include/asm-sparc64/processor.h
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -71,7 +71,7 @@ struct thread_struct {
#define SPARC_FLAG_32BIT 0x8 /* task is older 32-bit binary */
#define INIT_MMAP { &init_mm, 0xfffff80000000000, 0xfffff80001000000, \
- PAGE_SHARED , VM_READ | VM_WRITE | VM_EXEC }
+ PAGE_SHARED , VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap }
#define INIT_TSS { \
/* FPU regs */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
@@ -115,6 +115,7 @@ do { \
regs->tpc = ((pc & (~3)) - 4); \
regs->tnpc = regs->tpc + 4; \
regs->y = 0; \
+ current->tss.flags &= ~SPARC_FLAG_32BIT; \
__asm__ __volatile__( \
"stx %%g0, [%0 + %2 + 0x00]\n\t" \
"stx %%g0, [%0 + %2 + 0x08]\n\t" \
@@ -132,7 +133,7 @@ do { \
"stx %%g0, [%0 + %2 + 0x68]\n\t" \
"stx %1, [%0 + %2 + 0x70]\n\t" \
"stx %%g0, [%0 + %2 + 0x78]\n\t" \
- "wrpr %%g0, 1, %%wstate\n\t" \
+ "wrpr %%g0, (1 << 3), %%wstate\n\t" \
: \
: "r" (regs), "r" (sp - REGWIN_SZ), \
"i" ((const unsigned long)(&((struct pt_regs *)0)->u_regs[0]))); \
@@ -168,7 +169,7 @@ do { \
"stx %%g0, [%0 + %2 + 0x68]\n\t" \
"stx %1, [%0 + %2 + 0x70]\n\t" \
"stx %%g0, [%0 + %2 + 0x78]\n\t" \
- "wrpr %%g0, 2, %%wstate\n\t" \
+ "wrpr %%g0, (2 << 3), %%wstate\n\t" \
: \
: "r" (regs), "r" (sp - REGWIN32_SZ), \
"i" ((const unsigned long)(&((struct pt_regs *)0)->u_regs[0])), \
@@ -179,16 +180,13 @@ do { \
#define release_thread(tsk) do { } while(0)
#ifdef __KERNEL__
-/* Allocation and freeing of basic task resources. */
+/* Allocation and freeing of task_struct and kernel stack. */
+#define alloc_task_struct() ((struct task_struct *)__get_free_pages(GFP_KERNEL, 1, 0))
+#define free_task_struct(tsk) free_pages((unsigned long)(tsk),1)
+
+#define init_task (init_task_union.task)
+#define init_stack (init_task_union.stack)
-/* XXX FIXME For task_struct must use SLAB or something other than
- * XXX kmalloc() as FPU registers in TSS require that entire structure
- * XXX be 64-byte aligned as well.
- */
-#define alloc_kernel_stack(tsk) __get_free_page(GFP_KERNEL)
-#define free_kernel_stack(stack) free_page(stack)
-#define alloc_task_struct() kmalloc(sizeof(struct task_struct), GFP_KERNEL)
-#define free_task_struct(tsk) kfree(tsk)
#endif /* __KERNEL__ */
#endif /* !(__ASSEMBLY__) */
diff --git a/include/asm-sparc64/spitfire.h b/include/asm-sparc64/spitfire.h
index 10918dc82..76232c227 100644
--- a/include/asm-sparc64/spitfire.h
+++ b/include/asm-sparc64/spitfire.h
@@ -1,4 +1,4 @@
-/* $Id: spitfire.h,v 1.7 1997/04/04 00:50:29 davem Exp $
+/* $Id: spitfire.h,v 1.8 1997/05/18 04:16:56 davem Exp $
* spitfire.h: SpitFire/BlackBird/Cheetah inline MMU operations.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -209,28 +209,28 @@ extern __inline__ void spitfire_flush_dtlb_secondary_context(void)
{
__asm__ __volatile__("stxa %%g0, [%0] %1"
: /* No outputs */
- : "r" (0x41), "i" (ASI_DMMU_DEMAP));
+ : "r" (0x50), "i" (ASI_DMMU_DEMAP));
}
extern __inline__ void spitfire_flush_itlb_secondary_context(void)
{
__asm__ __volatile__("stxa %%g0, [%0] %1"
: /* No outputs */
- : "r" (0x41), "i" (ASI_IMMU_DEMAP));
+ : "r" (0x50), "i" (ASI_IMMU_DEMAP));
}
extern __inline__ void spitfire_flush_dtlb_nucleus_context(void)
{
__asm__ __volatile__("stxa %%g0, [%0] %1"
: /* No outputs */
- : "r" (0x42), "i" (ASI_DMMU_DEMAP));
+ : "r" (0x60), "i" (ASI_DMMU_DEMAP));
}
extern __inline__ void spitfire_flush_itlb_nucleus_context(void)
{
__asm__ __volatile__("stxa %%g0, [%0] %1"
: /* No outputs */
- : "r" (0x42), "i" (ASI_IMMU_DEMAP));
+ : "r" (0x60), "i" (ASI_IMMU_DEMAP));
}
/* Page level flushes. */
diff --git a/include/asm-sparc64/string.h b/include/asm-sparc64/string.h
index 1470bcfef..b420d80bb 100644
--- a/include/asm-sparc64/string.h
+++ b/include/asm-sparc64/string.h
@@ -1,4 +1,4 @@
-/* $Id: string.h,v 1.4 1997/04/01 09:34:41 davem Exp $
+/* $Id: string.h,v 1.5 1997/05/18 04:16:57 davem Exp $
* string.h: External definitions for optimized assembly string
* routines for the Linux Kernel.
*
@@ -41,14 +41,18 @@ extern inline void *__constant_memcpy(void *to, const void *from, __kernel_size_
if(n <= 32) {
__builtin_memcpy(to, from, n);
} else {
+#if 0
switch(n) {
case 8192:
__copy_1page(to, from);
break;
default:
+#endif
__memcpy(to, from, n);
+#if 0
break;
}
+#endif
}
}
return to;
@@ -74,9 +78,11 @@ extern inline void *__constant_c_and_count_memset(void *s, char c, __kernel_size
extern __kernel_size_t __bzero(void *, __kernel_size_t);
if(!c) {
+#if 0
if(count == 8192)
bzero_1page(s);
else
+#endif
__bzero(s, count);
} else {
__memset(s, c, count);
diff --git a/include/asm-sparc64/system.h b/include/asm-sparc64/system.h
index 8bc44e1c8..786cfd2af 100644
--- a/include/asm-sparc64/system.h
+++ b/include/asm-sparc64/system.h
@@ -1,4 +1,4 @@
-/* $Id: system.h,v 1.15 1997/04/10 23:32:49 davem Exp $ */
+/* $Id: system.h,v 1.19 1997/05/18 22:52:32 davem Exp $ */
#ifndef __SPARC64_SYSTEM_H
#define __SPARC64_SYSTEM_H
@@ -89,18 +89,24 @@ extern unsigned long empty_zero_page;
#ifndef __ASSEMBLY__
+extern void synchronize_user_stack(void);
+
extern __inline__ void flushw_user(void)
{
__asm__ __volatile__("
rdpr %%otherwin, %%g1
+ brz,pt %%g1, 2f
+ clr %%g2
1:
- rdpr %%otherwin, %%g2
- brnz,pn %%g2, 1b
- save %%sp, %0, %%sp
+ save %%sp, %0, %%sp
+ rdpr %%otherwin, %%g1
+ brnz,pt %%g1, 1b
+ add %%g2, 1, %%g2
1:
- subcc %%g1, 1, %%g1
- bne,pn %%xcc, 1b
+ subcc %%g2, 1, %%g2
+ bne,pt %%xcc, 1b
restore %%g0, %%g0, %%g0
+2:
" : : "i" (-REGWIN_SZ)
: "g1", "g2", "cc");
}
@@ -122,9 +128,9 @@ extern __inline__ void flushw_user(void)
/* See what happens when you design the chip correctly?
* NOTE NOTE NOTE this is extremely non-trivial what I
- * am doing here. GCC needs only two registers to stuff
- * things into ('next' and &current_set[cpu]) So I "claim"
- * that I do not clobber them, when in fact I do. Please,
+ * am doing here. GCC needs only one register to stuff
+ * things into ('next' in particular) So I "claim" that
+ * I do not clobber it, when in fact I do. Please,
* when modifying this code inspect output of sched.s very
* carefully to make sure things still work. -DaveM
*/
@@ -141,14 +147,12 @@ do { \
"stx %%o6, [%%g6 + %3]\n\t" \
"rdpr %%wstate, %%o5\n\t" \
"stx %%o7, [%%g6 + %4]\n\t" \
- "mov %6, %%o4\n\t" \
"stx %%o5, [%%g6 + %2]\n\t" \
- "st %%o4, [%%g6 + %7]\n\t" \
"rdpr %%cwp, %%o5\n\t" \
- "stx %%o5, [%%g6 + %8]\n\t" \
- "mov %1, %%g6\n\t" \
- "stx %%g6, [%0]\n\t" \
- "ldx [%%g6 + %8], %%g1\n\t" \
+ "stx %%o5, [%%g6 + %5]\n\t" \
+ "mov %0, %%g6\n\t" \
+ "wr %0, 0x0, %%pic\n\t" \
+ "ldx [%%g6 + %5], %%g1\n\t" \
"wrpr %%g1, %%cwp\n\t" \
"ldx [%%g6 + %2], %%o5\n\t" \
"ldx [%%g6 + %3], %%o6\n\t" \
@@ -158,15 +162,13 @@ do { \
"jmpl %%o7 + 0x8, %%g0\n\t" \
" ldx [%%sp + 2047 + 0x78], %%i7\n\t" \
: /* No outputs */ \
- : "r" (&(current_set[smp_processor_id()])), "r" (next), \
+ : "r" (next), "r" (task_pc), \
"i" ((const unsigned long)(&((struct task_struct *)0)->tss.wstate)), \
"i" ((const unsigned long)(&((struct task_struct *)0)->tss.ksp)), \
"i" ((const unsigned long)(&((struct task_struct *)0)->tss.kpc)), \
- "r" (task_pc), "i" (255), \
- "i" ((const unsigned long)(&((struct task_struct *)0)->processor)), \
"i" ((const unsigned long)(&((struct task_struct *)0)->tss.cwp)) \
: "cc", "g1", "g2", "g3", "g5", "g7", \
- "l2", "l3", "l4", "l5", "l6", "l7", \
+ "l1", "l2", "l3", "l4", "l5", "l6", "l7", \
"i0", "i1", "i2", "i3", "i4", "i5", \
"o0", "o1", "o2", "o3", "o4", "o5"); \
switch_continue: } while(0)
diff --git a/include/asm-sparc64/termbits.h b/include/asm-sparc64/termbits.h
index fae8ac1cc..01e8364c6 100644
--- a/include/asm-sparc64/termbits.h
+++ b/include/asm-sparc64/termbits.h
@@ -148,7 +148,13 @@ struct termios {
#define HUPCL 0x00000400
#define CLOCAL 0x00000800
#define CBAUDEX 0x00001000
+/* We'll never see these speeds with the Zilogs, but for completeness... */
#define B57600 0x00001001
+#define B115200 0x00001002
+#define B230400 0x00001003
+#define B460800 0x00001004
+/* This is what we can do with the Zilogs. */
+#define B76800 0x00001005
#define CIBAUD 0x100f0000 /* input baud rate (not used) */
#define CMSPAR 0x40000000 /* mark or space (stick) parity */
#define CRTSCTS 0x80000000 /* flow control */
diff --git a/include/linux/affs_fs.h b/include/linux/affs_fs.h
index 0067552fc..fc7c46dc8 100644
--- a/include/linux/affs_fs.h
+++ b/include/linux/affs_fs.h
@@ -22,9 +22,9 @@
struct DateStamp
{
- __u32 ds_Days;
- __u32 ds_Minute;
- __u32 ds_Tick;
+ u32 ds_Days;
+ u32 ds_Minute;
+ u32 ds_Tick;
};
@@ -32,66 +32,58 @@ struct DateStamp
/* amigaffs.c */
-extern int affs_get_key_entry(int bsize, void *data, int entry_pos);
-extern int affs_find_next_hash_entry(int bsize, void *dir_data, int *hash_pos);
-extern int affs_get_file_name(int bsize, void *fh_data, char **name);
-extern unsigned int affs_checksum_block(int bsize, void *data, int *ptype, int *stype);
-extern void affs_fix_checksum(int bsize, void *data, int cspos);
-extern void secs_to_datestamp(int secs, struct DateStamp *ds);
-extern int prot_to_mode(unsigned int prot);
-extern unsigned int mode_to_prot(int mode);
-extern int affs_fix_hash_pred(struct inode *startino, int startoffset,
- int key, int newkey);
-extern int affs_fix_link_pred(struct inode *startino, int key, int newkey);
+extern int affs_get_key_entry(int bsize, void *data, int entry_pos);
+extern int affs_get_file_name(int bsize, void *fh_data, char **name);
+extern u32 affs_checksum_block(int bsize, void *data, s32 *ptype, s32 *stype);
+extern void affs_fix_checksum(int bsize, void *data, int cspos);
+extern void secs_to_datestamp(time_t secs, struct DateStamp *ds);
+extern int prot_to_mode(unsigned int prot);
+extern u32 mode_to_prot(int mode);
+extern int affs_fix_hash_pred(struct inode *startino, int startoffset,
+ s32 key, s32 newkey);
+extern int affs_fix_link_pred(struct inode *startino, s32 key, s32 newkey);
+extern void affs_error(struct super_block *sb, const char *function, const char *fmt, ...);
+extern void affs_warning(struct super_block *sb, const char *function, const char *fmt, ...);
/* bitmap. c */
-extern int affs_count_free_blocks(struct super_block *s);
-extern int affs_count_free_bits(int blocksize, const char *data);
-extern void affs_free_block(struct super_block *sb, int block);
-extern int affs_new_header(struct inode *inode);
-extern int affs_new_data(struct inode *inode);
-extern void affs_make_zones(struct super_block *sb);
+extern int affs_count_free_blocks(struct super_block *s);
+extern int affs_count_free_bits(int blocksize, const char *data);
+extern void affs_free_block(struct super_block *sb, s32 block);
+extern s32 affs_new_header(struct inode *inode);
+extern s32 affs_new_data(struct inode *inode);
+extern void affs_make_zones(struct super_block *sb);
/* namei.c */
-extern int affs_hash_name(const char *name, int len, int intl, int hashsize);
-extern int affs_lookup(struct inode *dir,const char *name, int len,
- struct inode **result);
-extern int affs_unlink(struct inode *dir, const char *name, int len);
-extern int affs_create(struct inode *dir, const char *name, int len, int mode,
- struct inode **result);
-extern int affs_mkdir(struct inode *dir, const char *name, int len, int mode);
-extern int affs_rmdir(struct inode *dir, const char *name, int len);
-extern int affs_link(struct inode *oldinode, struct inode *dir,
- const char *name, int len);
-extern int affs_symlink(struct inode *dir, const char *name, int len,
- const char *symname);
-extern int affs_fixup(struct buffer_head *bh, struct inode *inode);
-extern int affs_rename(struct inode *old_dir, const char *old_name, int old_len,
- struct inode *new_dir, const char *new_name, int new_len,
- int must_be_dir);
+extern int affs_hash_name(const char *name, int len, int intl, int hashsize);
+extern int affs_lookup(struct inode *dir,const char *name, int len,
+ struct inode **result);
+extern int affs_unlink(struct inode *dir, const char *name, int len);
+extern int affs_create(struct inode *dir, const char *name, int len, int mode,
+ struct inode **result);
+extern int affs_mkdir(struct inode *dir, const char *name, int len, int mode);
+extern int affs_rmdir(struct inode *dir, const char *name, int len);
+extern int affs_link(struct inode *oldinode, struct inode *dir,
+ const char *name, int len);
+extern int affs_symlink(struct inode *dir, const char *name, int len,
+ const char *symname);
+extern int affs_rename(struct inode *old_dir, const char *old_name, int old_len,
+ struct inode *new_dir, const char *new_name, int new_len,
+ int must_be_dir);
/* inode.c */
extern struct buffer_head *affs_bread(kdev_t dev, int block, int size);
extern void affs_brelse(struct buffer_head *buf);
-extern void affs_put_super(struct super_block *);
-extern int affs_parent_ino(struct inode *dir);
-extern struct super_block *affs_read_super(struct super_block *,void *, int);
-extern void affs_statfs(struct super_block *, struct statfs *, int bufsiz);
-extern void affs_read_inode(struct inode *);
-extern void affs_write_inode(struct inode *);
-extern int affs_notify_change(struct inode *inode, struct iattr *attr);
-extern void affs_put_inode(struct inode *);
+extern unsigned long affs_parent_ino(struct inode *dir);
extern struct inode *affs_new_inode(const struct inode *dir);
-extern int affs_add_entry(struct inode *dir, struct inode *link, struct inode *inode,
- const char *name, int len, int type);
+extern int affs_add_entry(struct inode *dir, struct inode *link,
+ struct inode *inode, const char *name,
+ int len, s32 type);
/* file.c */
-extern int affs_bmap(struct inode *inode, int block);
-extern struct buffer_head *affs_getblock(struct inode *inode, int block);
extern void affs_truncate(struct inode *);
extern void affs_truncate_ofs(struct inode *);
diff --git a/include/linux/affs_fs_i.h b/include/linux/affs_fs_i.h
index 40b823909..beeabb0de 100644
--- a/include/linux/affs_fs_i.h
+++ b/include/linux/affs_fs_i.h
@@ -9,19 +9,19 @@
struct key_cache {
struct timeval kc_lru_time; /* Last time this cache was used */
- int kc_first; /* First cached key */
- int kc_last; /* Last cached key */
- int kc_this_key; /* Key of extension block this data block keys are from */
+ s32 kc_first; /* First cached key */
+ s32 kc_last; /* Last cached key */
+ s32 kc_this_key; /* Key of extension block this data block keys are from */
int kc_this_seq; /* Sequence number of this extension block */
- int kc_next_key; /* Key of next extension block */
- int kc_keys[AFFS_KCSIZE]; /* Key cache */
+ s32 kc_next_key; /* Key of next extension block */
+ s32 kc_keys[AFFS_KCSIZE]; /* Key cache */
};
#define EC_SIZE (PAGE_SIZE - 4 * sizeof(struct key_cache) - 4) / 4
struct ext_cache {
struct key_cache kc[4]; /* The 4 key caches */
- __s32 ec[EC_SIZE]; /* Keys of assorted extension blocks */
+ s32 ec[EC_SIZE]; /* Keys of assorted extension blocks */
int max_ext; /* Index of last known extension block */
};
@@ -29,18 +29,18 @@ struct ext_cache {
* affs fs inode data in memory
*/
struct affs_inode_info {
- __u32 i_protect; /* unused attribute bits */
- __s32 i_parent; /* parent ino */
- __s32 i_original; /* if != 0, this is the key of the original */
- __s32 i_data[AFFS_MAX_PREALLOC]; /* preallocated blocks */
- struct ext_cache *i_ec; /* Cache gets allocated dynamically */
- int i_cache_users; /* Cache cannot be freed while > 0 */
- int i_lastblock; /* last allocated block */
- short i_pa_cnt; /* number of preallocated blocks */
- short i_pa_next; /* Index of next block in i_data[] */
- short i_pa_last; /* Index of next free slot in i_data[] */
- short i_zone; /* write zone */
- unsigned char i_hlink; /* This is a fake */
+ u32 i_protect; /* unused attribute bits */
+ s32 i_parent; /* parent ino */
+ s32 i_original; /* if != 0, this is the key of the original */
+ s32 i_data[AFFS_MAX_PREALLOC]; /* preallocated blocks */
+ struct ext_cache *i_ec; /* Cache gets allocated dynamically */
+ int i_cache_users; /* Cache cannot be freed while > 0 */
+ int i_lastblock; /* last allocated block */
+ short i_pa_cnt; /* number of preallocated blocks */
+ short i_pa_next; /* Index of next block in i_data[] */
+ short i_pa_last; /* Index of next free slot in i_data[] */
+ short i_zone; /* write zone */
+ unsigned char i_hlink; /* This is a fake */
unsigned char i_pad;
};
diff --git a/include/linux/affs_fs_sb.h b/include/linux/affs_fs_sb.h
index 0ff862d13..75af71dba 100644
--- a/include/linux/affs_fs_sb.h
+++ b/include/linux/affs_fs_sb.h
@@ -15,8 +15,8 @@
struct affs_bm_info {
struct buffer_head *bm_bh; /* Buffer head if loaded (bm_count > 0) */
- int bm_firstblk; /* Block number of first bit in this map */
- int bm_key; /* Disk block number */
+ s32 bm_firstblk; /* Block number of first bit in this map */
+ s32 bm_key; /* Disk block number */
int bm_count; /* Usage counter */
};
@@ -37,11 +37,11 @@ struct affs_zone {
struct affs_sb_info {
int s_partition_size; /* Partition size in blocks. */
- int s_root_block; /* FFS root block number. */
+ s32 s_root_block; /* FFS root block number. */
int s_hashsize; /* Size of hash table. */
unsigned long s_flags; /* See below. */
- short s_uid; /* uid to override */
- short s_gid; /* gid to override */
+ s16 s_uid; /* uid to override */
+ s16 s_gid; /* gid to override */
umode_t s_mode; /* mode to override */
int s_reserved; /* Number of reserved blocks. */
struct buffer_head *s_root_bh; /* Cached root block. */
diff --git a/include/linux/affs_hardblocks.h b/include/linux/affs_hardblocks.h
index 33315488d..ae893e022 100644
--- a/include/linux/affs_hardblocks.h
+++ b/include/linux/affs_hardblocks.h
@@ -4,59 +4,59 @@
/* Just the needed definitions for the RDB of an Amiga HD. */
struct RigidDiskBlock {
- __u32 rdb_ID;
- __u32 rdb_SummedLongs;
- __s32 rdb_ChkSum;
- __u32 rdb_HostID;
- __u32 rdb_BlockBytes;
- __u32 rdb_Flags;
- __u32 rdb_BadBlockList;
- __u32 rdb_PartitionList;
- __u32 rdb_FileSysHeaderList;
- __u32 rdb_DriveInit;
- __u32 rdb_Reserved1[6];
- __u32 rdb_Cylinders;
- __u32 rdb_Sectors;
- __u32 rdb_Heads;
- __u32 rdb_Interleave;
- __u32 rdb_Park;
- __u32 rdb_Reserved2[3];
- __u32 rdb_WritePreComp;
- __u32 rdb_ReducedWrite;
- __u32 rdb_StepRate;
- __u32 rdb_Reserved3[5];
- __u32 rdb_RDBBlocksLo;
- __u32 rdb_RDBBlocksHi;
- __u32 rdb_LoCylinder;
- __u32 rdb_HiCylinder;
- __u32 rdb_CylBlocks;
- __u32 rdb_AutoParkSeconds;
- __u32 rdb_HighRDSKBlock;
- __u32 rdb_Reserved4;
+ u32 rdb_ID;
+ u32 rdb_SummedLongs;
+ s32 rdb_ChkSum;
+ u32 rdb_HostID;
+ u32 rdb_BlockBytes;
+ u32 rdb_Flags;
+ u32 rdb_BadBlockList;
+ u32 rdb_PartitionList;
+ u32 rdb_FileSysHeaderList;
+ u32 rdb_DriveInit;
+ u32 rdb_Reserved1[6];
+ u32 rdb_Cylinders;
+ u32 rdb_Sectors;
+ u32 rdb_Heads;
+ u32 rdb_Interleave;
+ u32 rdb_Park;
+ u32 rdb_Reserved2[3];
+ u32 rdb_WritePreComp;
+ u32 rdb_ReducedWrite;
+ u32 rdb_StepRate;
+ u32 rdb_Reserved3[5];
+ u32 rdb_RDBBlocksLo;
+ u32 rdb_RDBBlocksHi;
+ u32 rdb_LoCylinder;
+ u32 rdb_HiCylinder;
+ u32 rdb_CylBlocks;
+ u32 rdb_AutoParkSeconds;
+ u32 rdb_HighRDSKBlock;
+ u32 rdb_Reserved4;
char rdb_DiskVendor[8];
char rdb_DiskProduct[16];
char rdb_DiskRevision[4];
char rdb_ControllerVendor[8];
char rdb_ControllerProduct[16];
char rdb_ControllerRevision[4];
- __u32 rdb_Reserved5[10];
+ u32 rdb_Reserved5[10];
};
#define IDNAME_RIGIDDISK 0x5244534B /* "RDSK" */
struct PartitionBlock {
- __u32 pb_ID;
- __u32 pb_SummedLongs;
- __s32 pb_ChkSum;
- __u32 pb_HostID;
- __u32 pb_Next;
- __u32 pb_Flags;
- __u32 pb_Reserved1[2];
- __u32 pb_DevFlags;
- __u8 pb_DriveName[32];
- __u32 pb_Reserved2[15];
- __u32 pb_Environment[17];
- __u32 pb_EReserved[15];
+ u32 pb_ID;
+ u32 pb_SummedLongs;
+ s32 pb_ChkSum;
+ u32 pb_HostID;
+ u32 pb_Next;
+ u32 pb_Flags;
+ u32 pb_Reserved1[2];
+ u32 pb_DevFlags;
+ u8 pb_DriveName[32];
+ u32 pb_Reserved2[15];
+ u32 pb_Environment[17];
+ u32 pb_EReserved[15];
};
#define IDNAME_PARTITION 0x50415254 /* "PART" */
diff --git a/include/linux/amigaffs.h b/include/linux/amigaffs.h
index 679f333e5..8e39a6fe2 100644
--- a/include/linux/amigaffs.h
+++ b/include/linux/amigaffs.h
@@ -56,131 +56,131 @@
struct root_front
{
- __s32 primary_type;
- __s32 spare1[2];
- __s32 hash_size;
- __s32 spare2;
- __u32 checksum;
- __s32 hashtable[0];
+ s32 primary_type;
+ s32 spare1[2];
+ s32 hash_size;
+ s32 spare2;
+ u32 checksum;
+ s32 hashtable[0];
};
struct root_end
{
- __s32 bm_flag;
- __s32 bm_keys[25];
- __s32 bm_extend;
+ s32 bm_flag;
+ s32 bm_keys[25];
+ s32 bm_extend;
struct DateStamp dir_altered;
- __u8 disk_name[40];
+ u8 disk_name[40];
struct DateStamp disk_altered;
struct DateStamp disk_made;
- __s32 spare1[3];
- __s32 secondary_type;
+ s32 spare1[3];
+ s32 secondary_type;
};
struct dir_front
{
- __s32 primary_type;
- __s32 own_key;
- __s32 spare1[3];
- __u32 checksum;
- __s32 hashtable[0];
+ s32 primary_type;
+ s32 own_key;
+ s32 spare1[3];
+ u32 checksum;
+ s32 hashtable[0];
};
struct dir_end
{
- __s32 spare1;
- __s16 owner_uid;
- __s16 owner_gid;
- __u32 protect;
- __s32 spare2;
- __u8 comment[92];
+ s32 spare1;
+ s16 owner_uid;
+ s16 owner_gid;
+ u32 protect;
+ s32 spare2;
+ u8 comment[92];
struct DateStamp created;
- __u8 dir_name[32];
- __s32 spare3[2];
- __s32 link_chain;
- __s32 spare4[5];
- __s32 hash_chain;
- __s32 parent;
- __s32 spare5;
- __s32 secondary_type;
+ u8 dir_name[32];
+ s32 spare3[2];
+ s32 link_chain;
+ s32 spare4[5];
+ s32 hash_chain;
+ s32 parent;
+ s32 spare5;
+ s32 secondary_type;
};
struct file_front
{
- __s32 primary_type;
- __s32 own_key;
- __s32 block_count;
- __s32 unknown1;
- __s32 first_data;
- __u32 checksum;
- __s32 blocks[0];
+ s32 primary_type;
+ s32 own_key;
+ s32 block_count;
+ s32 unknown1;
+ s32 first_data;
+ u32 checksum;
+ s32 blocks[0];
};
struct file_end
{
- __s32 spare1;
- __s16 owner_uid;
- __s16 owner_gid;
- __u32 protect;
- __s32 byte_size;
- __u8 comment[92];
+ s32 spare1;
+ s16 owner_uid;
+ s16 owner_gid;
+ u32 protect;
+ s32 byte_size;
+ u8 comment[92];
struct DateStamp created;
- __u8 file_name[32];
- __s32 spare2;
- __s32 original; /* not really in file_end */
- __s32 link_chain;
- __s32 spare3[5];
- __s32 hash_chain;
- __s32 parent;
- __s32 extension;
- __s32 secondary_type;
+ u8 file_name[32];
+ s32 spare2;
+ s32 original; /* not really in file_end */
+ s32 link_chain;
+ s32 spare3[5];
+ s32 hash_chain;
+ s32 parent;
+ s32 extension;
+ s32 secondary_type;
};
struct hlink_front
{
- __s32 primary_type;
- __s32 own_key;
- __s32 spare1[3];
- __u32 checksum;
+ s32 primary_type;
+ s32 own_key;
+ s32 spare1[3];
+ u32 checksum;
};
struct hlink_end
{
- __s32 spare1;
- __s16 owner_uid;
- __s16 owner_gid;
- __u32 protect;
- __u8 comment[92];
+ s32 spare1;
+ s16 owner_uid;
+ s16 owner_gid;
+ u32 protect;
+ u8 comment[92];
struct DateStamp created;
- __u8 link_name[32];
- __s32 spare2;
- __s32 original;
- __s32 link_chain;
- __s32 spare3[5];
- __s32 hash_chain;
- __s32 parent;
- __s32 spare4;
- __s32 secondary_type;
+ u8 link_name[32];
+ s32 spare2;
+ s32 original;
+ s32 link_chain;
+ s32 spare3[5];
+ s32 hash_chain;
+ s32 parent;
+ s32 spare4;
+ s32 secondary_type;
};
struct slink_front
{
- __s32 primary_type;
- __s32 own_key;
- __s32 spare1[3];
- __s32 checksum;
- __u8 symname[288]; /* depends on block size */
+ s32 primary_type;
+ s32 own_key;
+ s32 spare1[3];
+ s32 checksum;
+ u8 symname[288]; /* depends on block size */
};
struct data_front
{
- __s32 primary_type;
- __s32 header_key;
- __s32 sequence_number;
- __s32 data_size;
- __s32 next_data;
- __s32 checksum;
- __u8 data[488]; /* depends on block size */
+ s32 primary_type;
+ s32 header_key;
+ s32 sequence_number;
+ s32 data_size;
+ s32 next_data;
+ s32 checksum;
+ u8 data[488]; /* depends on block size */
};
/* Permission bits */
diff --git a/include/linux/auto_fs.h b/include/linux/auto_fs.h
index d32a6a253..2b25d2902 100644
--- a/include/linux/auto_fs.h
+++ b/include/linux/auto_fs.h
@@ -1,14 +1,14 @@
-/* -*- linux-c -*- --------------------------------------------------------- *
- *
+/* -*- linux-c -*- ------------------------------------------------------- *
+ *
* linux/include/linux/auto_fs.h
*
- * Copyright 1997 Transmeta Corporation -- All Rights Reserved
+ * Copyright 1997 Transmeta Corporation - All Rights Reserved
*
* This file is part of the Linux kernel and is made available under
* the terms of the GNU General Public License, version 2, or at your
* option, any later version, incorporated herein by reference.
*
- * ------------------------------------------------------------------------- */
+ * ----------------------------------------------------------------------- */
#ifndef _LINUX_AUTO_FS_H
@@ -20,11 +20,11 @@
#include <linux/ioctl.h>
#include <asm/types.h>
-#define AUTOFS_PROTO_VERSION 2
+#define AUTOFS_PROTO_VERSION 3
enum autofs_packet_type {
- autofs_ptype_missing, /* Missing entry (create wait queue) */
- /* ...need more in the future... */
+ autofs_ptype_missing, /* Missing entry (mount request) */
+ autofs_ptype_expire, /* Expire entry (umount request) */
};
struct autofs_packet_hdr {
@@ -39,139 +39,24 @@ struct autofs_packet_missing {
char name[NAME_MAX+1];
};
-#define AUTOFS_IOC_READY _IO(0x93,0x60)
-#define AUTOFS_IOC_FAIL _IO(0x93,0x61)
-#define AUTOFS_IOC_CATATONIC _IO(0x93,0x62)
-
-#ifdef __KERNEL__
-
-#include <linux/wait.h>
-#include <linux/sched.h>
-
-#if LINUX_VERSION_CODE < 0x20100
-
-#include <asm/segment.h>
-#define copy_to_user memcpy_tofs
-#define copy_from_user memcpy_fromfs
-
-#else
-
-#include <asm/uaccess.h>
-#define register_symtab(x) do { } while (0)
-
-#endif
-
-#ifndef DPRINTK
-#ifdef DEBUG
-#define DPRINTK(D) printk D;
-#else
-#define DPRINTK(D)
-#endif
-#endif
-
-#define AUTOFS_SUPER_MAGIC 0x0187
-
-/* Structures associated with the root directory hash */
-
-#define AUTOFS_HASH_SIZE 67
-
-typedef u32 autofs_hash_t; /* Type returned by autofs_hash() */
-
-struct autofs_dir_ent {
- autofs_hash_t hash;
- struct autofs_dir_ent *next;
- struct autofs_dir_ent **back;
- char *name;
- int len;
- ino_t ino;
- time_t expiry; /* Reserved for use in failed-lookup cache */
-};
-
-struct autofs_dirhash {
- struct autofs_dir_ent *h[AUTOFS_HASH_SIZE];
-};
-
-struct autofs_wait_queue {
- unsigned long wait_queue_token;
- struct wait_queue *queue;
- struct autofs_wait_queue *next;
- /* We use the following to see what we are waiting for */
- autofs_hash_t hash;
- int len;
- char *name;
- /* This is for status reporting upon return */
- int status;
- int wait_ctr;
-};
-
-struct autofs_symlink {
+struct autofs_packet_expire {
+ struct autofs_packet_hdr hdr;
int len;
- char *data;
- time_t mtime;
+ char name[NAME_MAX+1];
};
-#define AUTOFS_MAX_SYMLINKS 256
-
-#define AUTOFS_ROOT_INO 1
-#define AUTOFS_FIRST_SYMLINK 2
-#define AUTOFS_FIRST_DIR_INO (AUTOFS_FIRST_SYMLINK+AUTOFS_MAX_SYMLINKS)
+#define AUTOFS_IOC_READY _IO(0x93,0x60)
+#define AUTOFS_IOC_FAIL _IO(0x93,0x61)
+#define AUTOFS_IOC_CATATONIC _IO(0x93,0x62)
+#define AUTOFS_IOC_PROTOVER _IOR(0x93,0x63,int)
+#define AUTOFS_IOC_SETTIMEOUT _IOWR(0x93,0x64,unsigned long)
+#define AUTOFS_IOC_EXPIRE _IOR(0x93,0x65,struct autofs_packet_expire)
-#define AUTOFS_SYMLINK_BITMAP_LEN ((AUTOFS_MAX_SYMLINKS+31)/32)
-
-#ifndef END_OF_TIME
-#define END_OF_TIME ((time_t)((unsigned long)((time_t)(~0UL)) >> 1))
-#endif
-
-struct autofs_sb_info {
- struct file *pipe;
- pid_t oz_pgrp;
- int catatonic;
- ino_t next_dir_ino;
- struct autofs_wait_queue *queues; /* Wait queue pointer */
- struct autofs_dirhash dirhash; /* Root directory hash */
- struct autofs_symlink symlink[AUTOFS_MAX_SYMLINKS];
- u32 symlink_bitmap[AUTOFS_SYMLINK_BITMAP_LEN];
-};
-
-/* autofs_oz_mode(): do we see the man behind the curtain? */
-static inline int autofs_oz_mode(struct autofs_sb_info *sbi) {
- return sbi->catatonic || current->pgrp == sbi->oz_pgrp;
-}
+#ifdef __KERNEL__
/* Init function */
int init_autofs_fs(void);
-/* Hash operations */
-
-autofs_hash_t autofs_hash(const char *,int);
-void autofs_initialize_hash(struct autofs_dirhash *);
-struct autofs_dir_ent *autofs_hash_lookup(const struct autofs_dirhash *,autofs_hash_t,const char *,int);
-void autofs_hash_insert(struct autofs_dirhash *,struct autofs_dir_ent *);
-void autofs_hash_delete(struct autofs_dir_ent *);
-struct autofs_dir_ent *autofs_hash_enum(const struct autofs_dirhash *,off_t *);
-void autofs_hash_nuke(struct autofs_dirhash *);
-
-/* Operations structures */
-
-extern struct inode_operations autofs_root_inode_operations;
-extern struct inode_operations autofs_symlink_inode_operations;
-extern struct inode_operations autofs_dir_inode_operations;
-
-/* Initializing function */
-
-struct super_block *autofs_read_super(struct super_block *, void *,int);
-
-/* Queue management functions */
-
-int autofs_wait(struct autofs_sb_info *,autofs_hash_t,const char *,int);
-int autofs_wait_release(struct autofs_sb_info *,unsigned long,int);
-void autofs_catatonic_mode(struct autofs_sb_info *);
-
-#ifdef DEBUG
-void autofs_say(const char *name, int len);
-#else
-#define autofs_say(n,l)
-#endif
-
#endif /* __KERNEL__ */
+
#endif /* _LINUX_AUTO_FS_H */
diff --git a/include/linux/console.h b/include/linux/console.h
index 7589ce794..16f1754ec 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -27,19 +27,20 @@ struct vc_data;
/* DPC: 1994-04-13 !!! con_putcs is new entry !!! */
struct consw {
- unsigned long (*con_startup)(unsigned long, char **);
- void (*con_init)(struct vc_data *);
- int (*con_deinit)(struct vc_data *);
- int (*con_clear)(struct vc_data *, int, int, int, int);
- int (*con_putc)(struct vc_data *, int, int, int);
- int (*con_putcs)(struct vc_data *, const char *, int, int, int);
- int (*con_cursor)(struct vc_data *, int);
- int (*con_scroll)(struct vc_data *, int, int, int, int);
- int (*con_bmove)(struct vc_data *, int, int, int, int, int, int);
- int (*con_switch)(struct vc_data *);
- int (*con_blank)(int);
- int (*con_get_font)(struct vc_data *, int *, int *, char *);
- int (*con_set_font)(struct vc_data *, int, int, char *);
+ unsigned long (*con_startup)(unsigned long, const char **);
+ void (*con_init)(struct vc_data *);
+ int (*con_deinit)(struct vc_data *);
+ int (*con_clear)(struct vc_data *, int, int, int, int);
+ int (*con_putc)(struct vc_data *, int, int, int);
+ int (*con_putcs)(struct vc_data *, const char *, int, int, int);
+ int (*con_cursor)(struct vc_data *, int);
+ int (*con_scroll)(struct vc_data *, int, int, int, int);
+ int (*con_bmove)(struct vc_data *, int, int, int, int, int, int);
+ int (*con_switch)(struct vc_data *);
+ int (*con_blank)(int);
+ int (*con_get_font)(struct vc_data *, int *, int *, char *);
+ int (*con_set_font)(struct vc_data *, int, int, char *);
+ int (*con_set_palette)(struct vc_data *, unsigned char *);
};
extern struct consw *conswitchp;
diff --git a/include/linux/cyclades.h b/include/linux/cyclades.h
index efed32b4d..9386c17f0 100644
--- a/include/linux/cyclades.h
+++ b/include/linux/cyclades.h
@@ -1,4 +1,4 @@
-/*
+/* $Revision: 1.7 $$Date: 1997/03/26 10:30:00 $
* linux/include/linux/cyclades.h
*
* This file is maintained by Marcio Saito <marcio@cyclades.com> and
@@ -6,9 +6,18 @@
*
* This file contains the general definitions for the cyclades.c driver
*$Log: cyclades.h,v $
- * Revision 1.5 1995/11/13 21:13:31 bentson
- * changes suggested by Michael Chastain <mec@duracef.shout.net>
- * to support use of this file in non-kernel applications
+ *Revision 1.7 1997/03/26 10:30:00 daniel
+ *new entries at the end of cyclades_port struct to reallocate
+ *variables illegally allocated within card memory.
+ *
+ *Revision 1.6 1996/09/09 18:35:30 bentson
+ *fold in changes for Cyclom-Z -- including structures for
+ *communicating with board as well modest changes to original
+ *structures to support new features.
+ *
+ *Revision 1.5 1995/11/13 21:13:31 bentson
+ *changes suggested by Michael Chastain <mec@duracef.shout.net>
+ *to support use of this file in non-kernel applications
*
*
*/
@@ -35,14 +44,359 @@ struct cyclades_monitor {
#define CYGETDEFTIMEOUT 0x435908
#define CYSETDEFTIMEOUT 0x435909
+/*************** CYCLOM-Z ADDITIONS ***************/
+
+#define CZIOC ('M' << 8)
+#define CZ_NBOARDS (CZIOC|0xfa)
+#define CZ_BOOT_START (CZIOC|0xfb)
+#define CZ_BOOT_DATA (CZIOC|0xfc)
+#define CZ_BOOT_END (CZIOC|0xfd)
+#define CZ_TEST (CZIOC|0xfe)
+
+#define MAX_BOARD 4 /* Max number of boards */
+#define MAX_PORT 128 /* Max number of ports per board */
+#define MAX_DEV 256 /* Max number of ports total */
+
+#define CYZ_BOOT_NWORDS 0x100
+struct CYZ_BOOT_CTRL {
+ unsigned short nboard;
+ int status[MAX_BOARD];
+ int nchannel[MAX_BOARD];
+ int fw_rev[MAX_BOARD];
+ unsigned long offset;
+ unsigned long data[CYZ_BOOT_NWORDS];
+};
+
+
+#ifndef DP_WINDOW_SIZE
+/* #include "cyclomz.h" */
+/****************** ****************** *******************/
+/*
+ * The data types defined below are used in all ZFIRM interface
+ * data structures. They accomodate differences between HW
+ * architectures and compilers.
+ */
+
+typedef unsigned long uclong; /* 32 bits, unsigned */
+typedef unsigned short ucshort; /* 16 bits, unsigned */
+typedef unsigned char ucchar; /* 8 bits, unsigned */
+
+/*
+ * Memory Window Sizes
+ */
+
+#define DP_WINDOW_SIZE (0x00080000) /* window size 512 Kb */
+#define CTRL_WINDOW_SIZE (0x00000100) /* runtime regs 256 bytes */
+
+/*
+ * CUSTOM_REG - Cyclom-Z/PCI Custom Registers Set. The driver
+ * normally will access only interested on the fpga_id, fpga_version,
+ * start_cpu and stop_cpu.
+ */
+
+struct CUSTOM_REG {
+ uclong fpga_id; /* FPGA Identification Register */
+ uclong fpga_version; /* FPGA Version Number Register */
+ uclong cpu_start; /* CPU start Register (write) */
+ uclong cpu_stop; /* CPU stop Register (write) */
+ uclong misc_reg; /* Miscelaneous Register */
+ uclong idt_mode; /* IDT mode Register */
+ uclong uart_irq_status; /* UART IRQ status Register */
+ uclong clear_timer0_irq; /* Clear timer interrupt Register */
+ uclong clear_timer1_irq; /* Clear timer interrupt Register */
+ uclong clear_timer2_irq; /* Clear timer interrupt Register */
+ uclong test_register; /* Test Register */
+ uclong test_count; /* Test Count Register */
+ uclong timer_select; /* Timer select register */
+ uclong pr_uart_irq_status; /* Prioritized UART IRQ stat Reg */
+ uclong ram_wait_state; /* RAM wait-state Register */
+ uclong uart_wait_state; /* UART wait-state Register */
+ uclong timer_wait_state; /* timer wait-state Register */
+ uclong ack_wait_state; /* ACK wait State Register */
+};
+
+/*
+ * RUNTIME_9060 - PLX PCI9060ES local configuration and shared runtime
+ * registers. This structure can be used to access the 9060 registers
+ * (memory mapped).
+ */
+
+struct RUNTIME_9060 {
+ uclong loc_addr_range; /* 00h - Local Address Range */
+ uclong loc_addr_base; /* 04h - Local Address Base */
+ uclong loc_arbitr; /* 08h - Local Arbitration */
+ uclong endian_descr; /* 0Ch - Big/Little Endian Descriptor */
+ uclong loc_rom_range; /* 10h - Local ROM Range */
+ uclong loc_rom_base; /* 14h - Local ROM Base */
+ uclong loc_bus_descr; /* 18h - Local Bus descriptor */
+ uclong loc_range_mst; /* 1Ch - Local Range for Master to PCI */
+ uclong loc_base_mst; /* 20h - Local Base for Master PCI */
+ uclong loc_range_io; /* 24h - Local Range for Master IO */
+ uclong pci_base_mst; /* 28h - PCI Base for Master PCI */
+ uclong pci_conf_io; /* 2Ch - PCI configuration for Master IO */
+ uclong filler1; /* 30h */
+ uclong filler2; /* 34h */
+ uclong filler3; /* 38h */
+ uclong filler4; /* 3Ch */
+ uclong mail_box_0; /* 40h - Mail Box 0 */
+ uclong mail_box_1; /* 44h - Mail Box 1 */
+ uclong mail_box_2; /* 48h - Mail Box 2 */
+ uclong mail_box_3; /* 4Ch - Mail Box 3 */
+ uclong filler5; /* 50h */
+ uclong filler6; /* 54h */
+ uclong filler7; /* 58h */
+ uclong filler8; /* 5Ch */
+ uclong pci_doorbell; /* 60h - PCI to Local Doorbell */
+ uclong loc_doorbell; /* 64h - Local to PCI Doorbell */
+ uclong intr_ctrl_stat; /* 68h - Interrupt Control/Status */
+ uclong init_ctrl; /* 6Ch - EEPROM control, Init Control, etc */
+};
+
+/* Values for the Local Base Address re-map register */
+
+#define WIN_RAM 0x00000001L /* set the sliding window to RAM */
+#define WIN_CREG 0x14000001L /* set the window to custom Registers */
+
+/* Values timer select registers */
+
+#define TIMER_BY_1M 0x00 /* clock divided by 1M */
+#define TIMER_BY_256K 0x01 /* clock divided by 256k */
+#define TIMER_BY_128K 0x02 /* clock divided by 128k */
+#define TIMER_BY_32K 0x03 /* clock divided by 32k */
+
+/****************** ****************** *******************/
+#endif
+
+#ifndef ZFIRM_ID
+/* #include "zfwint.h" */
+/****************** ****************** *******************/
+/*
+ * This file contains the definitions for interfacing with the
+ * Cyclom-Z ZFIRM Firmware.
+ */
+
+/* General Constant definitions */
+
+#define MAX_CHAN 64 /* max number of channels per board */
+
+/* firmware id structure (set after boot) */
+
+#define ID_ADDRESS 0x00000180L /* signature/pointer address */
+#define ZFIRM_ID 0x5557465AL /* ZFIRM/U signature */
+struct FIRM_ID {
+ uclong signature; /* ZFIRM/U signature */
+ uclong zfwctrl_addr; /* pointer to ZFW_CTRL structure */
+};
+
+/* Op. System id */
+
+#define C_OS_LINUX 0x00000030 /* generic Linux system */
+
+/* channel op_mode */
+
+#define C_CH_DISABLE 0x00000000 /* channel is disabled */
+#define C_CH_TXENABLE 0x00000001 /* channel Tx enabled */
+#define C_CH_RXENABLE 0x00000002 /* channel Rx enabled */
+#define C_CH_ENABLE 0x00000003 /* channel Tx/Rx enabled */
+#define C_CH_LOOPBACK 0x00000004 /* Loopback mode */
+
+/* comm_parity - parity */
+
+#define C_PR_NONE 0x00000000 /* None */
+#define C_PR_ODD 0x00000001 /* Odd */
+#define C_PR_EVEN 0x00000002 /* Even */
+#define C_PR_MARK 0x00000004 /* Mark */
+#define C_PR_SPACE 0x00000008 /* Space */
+#define C_PR_PARITY 0x000000ff
+
+#define C_PR_DISCARD 0x00000100 /* discard char with frame/par error */
+#define C_PR_IGNORE 0x00000200 /* ignore frame/par error */
+
+/* comm_data_l - data length and stop bits */
+
+#define C_DL_CS5 0x00000001
+#define C_DL_CS6 0x00000002
+#define C_DL_CS7 0x00000004
+#define C_DL_CS8 0x00000008
+#define C_DL_CS 0x0000000f
+#define C_DL_1STOP 0x00000010
+#define C_DL_15STOP 0x00000020
+#define C_DL_2STOP 0x00000040
+#define C_DL_STOP 0x000000f0
+
+/* interrupt enabling/status */
+
+#define C_IN_DISABLE 0x00000000 /* zero, disable interrupts */
+#define C_IN_TXBEMPTY 0x00000001 /* tx buffer empty */
+#define C_IN_TXLOWWM 0x00000002 /* tx buffer below LWM */
+#define C_IN_RXHIWM 0x00000010 /* rx buffer above HWM */
+#define C_IN_RXNNDT 0x00000020 /* rx no new data timeout */
+#define C_IN_MDCD 0x00000100 /* modem DCD change */
+#define C_IN_MDSR 0x00000200 /* modem DSR change */
+#define C_IN_MRI 0x00000400 /* modem RI change */
+#define C_IN_MCTS 0x00000800 /* modem CTS change */
+#define C_IN_RXBRK 0x00001000 /* Break received */
+#define C_IN_PR_ERROR 0x00002000 /* parity error */
+#define C_IN_FR_ERROR 0x00004000 /* frame error */
+
+/* flow control */
+
+#define C_FL_OXX 0x00000001 /* output Xon/Xoff flow control */
+#define C_FL_IXX 0x00000002 /* output Xon/Xoff flow control */
+#define C_FL_OIXANY 0x00000004 /* output Xon/Xoff (any xon) */
+#define C_FL_SWFLOW 0x0000000f
+
+/* flow status */
+
+#define C_FS_TXIDLE 0x00000000 /* no Tx data in the buffer or UART */
+#define C_FS_SENDING 0x00000001 /* UART is sending data */
+#define C_FS_SWFLOW 0x00000002 /* Tx is stopped by received Xoff */
+
+/* rs_control/rs_status RS-232 signals */
+
+#define C_RS_DCD 0x00000100 /* CD */
+#define C_RS_DSR 0x00000200 /* DSR */
+#define C_RS_RI 0x00000400 /* RI */
+#define C_RS_CTS 0x00000800 /* CTS */
+#define C_RS_RTS 0x00000001 /* RTS */
+#define C_RS_DTR 0x00000004 /* DTR */
+
+/* commands Host <-> Board */
+
+#define C_CM_RESET 0x01 /* reset/flush buffers */
+#define C_CM_IOCTL 0x02 /* re-read CH_CTRL */
+#define C_CM_IOCTLW 0x03 /* re-read CH_CTRL, intr when done */
+#define C_CM_IOCTLM 0x04 /* RS-232 outputs change */
+#define C_CM_SENDXOFF 0x10 /* send Xoff */
+#define C_CM_SENDXON 0x11 /* send Xon */
+#define C_CM_CLFLOW 0x12 /* Clear flow control (resume) */
+#define C_CM_SENDBRK 0x41 /* send break */
+#define C_CM_INTBACK 0x42 /* Interrupt back */
+#define C_CM_SET_BREAK 0x43 /* Tx break on */
+#define C_CM_CLR_BREAK 0x44 /* Tx break off */
+#define C_CM_CMD_DONE 0x45 /* Previous command done */
+#define C_CM_TINACT 0x51 /* set inactivity detection */
+#define C_CM_IRQ_ENBL 0x52 /* enable generation of interrupts */
+#define C_CM_IRQ_DSBL 0x53 /* disable generation of interrupts */
+#define C_CM_ACK_ENBL 0x54 /* enable acknolowdged interrupt mode */
+#define C_CM_ACK_DSBL 0x55 /* disable acknolowdged intr mode */
+#define C_CM_FLUSH_RX 0x56 /* flushes Rx buffer */
+#define C_CM_FLUSH_TX 0x57 /* flushes Tx buffer */
+
+#define C_CM_TXBEMPTY 0x60 /* Tx buffer is empty */
+#define C_CM_TXLOWWM 0x61 /* Tx buffer low water mark */
+#define C_CM_RXHIWM 0x62 /* Rx buffer high water mark */
+#define C_CM_RXNNDT 0x63 /* rx no new data timeout */
+#define C_CM_MDCD 0x70 /* modem DCD change */
+#define C_CM_MDSR 0x71 /* modem DSR change */
+#define C_CM_MRI 0x72 /* modem RI change */
+#define C_CM_MCTS 0x73 /* modem CTS change */
+#define C_CM_RXBRK 0x84 /* Break received */
+#define C_CM_PR_ERROR 0x85 /* Parity error */
+#define C_CM_FR_ERROR 0x86 /* Frame error */
+#define C_CM_CMDERROR 0x90 /* command error */
+#define C_CM_FATAL 0x91 /* fatal error */
+#define C_CM_HW_RESET 0x92 /* reset board */
+
+/*
+ * CH_CTRL - This per port structure contains all parameters
+ * that control an specific port. It can be seen as the
+ * configuration registers of a "super-serial-controller".
+ */
+
+struct CH_CTRL {
+ uclong op_mode; /* operation mode */
+ uclong intr_enable; /* interrupt masking */
+ uclong sw_flow; /* SW flow control */
+ uclong flow_status; /* output flow status */
+ uclong comm_baud; /* baud rate - numerically specified */
+ uclong comm_parity; /* parity */
+ uclong comm_data_l; /* data length/stop */
+ uclong comm_flags; /* other flags */
+ uclong hw_flow; /* HW flow control */
+ uclong rs_control; /* RS-232 outputs */
+ uclong rs_status; /* RS-232 inputs */
+ uclong flow_xon; /* xon char */
+ uclong flow_xoff; /* xoff char */
+ uclong filler[3]; /* filler to align structures */
+};
+
+
+/*
+ * BUF_CTRL - This per channel structure contains
+ * all Tx and Rx buffer control for a given channel.
+ */
+
+struct BUF_CTRL {
+ uclong flag_dma; /* buffers are in Host memory */
+ uclong tx_bufaddr; /* address of the tx buffer */
+ uclong tx_bufsize; /* tx buffer size */
+ uclong tx_threshold; /* tx low water mark */
+ uclong tx_get; /* tail index tx buf */
+ uclong tx_put; /* head index tx buf */
+ uclong rx_bufaddr; /* address of the rx buffer */
+ uclong rx_bufsize; /* rx buffer size */
+ uclong rx_threshold; /* rx high water mark */
+ uclong rx_get; /* tail index rx buf */
+ uclong rx_put; /* head index rx buf */
+ uclong filler[5]; /* filler to align structures */
+};
+
+/*
+ * BOARD_CTRL - This per board structure contains all global
+ * control fields related to the board.
+ */
+
+struct BOARD_CTRL {
+
+ /* static info provided by the on-board CPU */
+ uclong n_channel; /* number of channels */
+ uclong fw_version; /* firmware version */
+
+ /* static info provided by the driver */
+ uclong op_system; /* op_system id */
+ uclong dr_version; /* driver version */
+
+ /* board control area */
+ uclong inactivity; /* inactivity control */
+
+ /* host to FW commands */
+ uclong hcmd_channel; /* channel number */
+ uclong *hcmd_param; /* pointer to parameters */
+
+ /* FW to Host commands */
+ uclong fwcmd_channel; /* channel number */
+ uclong *fwcmd_param; /* pointer to parameters */
+
+ /* filler so the structures are aligned */
+ uclong filler[7];
+};
+
+/*
+ * ZFW_CTRL - This is the data structure that includes all other
+ * data structures used by the Firmware.
+ */
+
+struct ZFW_CTRL {
+ struct BOARD_CTRL board_ctrl;
+ struct CH_CTRL ch_ctrl[MAX_CHAN];
+ struct BUF_CTRL buf_ctrl[MAX_CHAN];
+};
+
+/****************** ****************** *******************/
+#endif
+
+
+
#ifdef __KERNEL__
/* Per card data structure */
struct cyclades_card {
- int base_addr;
+ long base_addr;
+ long ctl_addr;
int irq;
- int num_chips; /* 0 if card is absent */
+ int num_chips; /* 0 if card absent, 1 if Z/PCI, else Y */
int first_line; /* minor number of first channel on card */
int bus_index; /* address shift - 0 for ISA, 1 for PCI */
};
@@ -72,6 +426,7 @@ struct cyclades_port {
int xmit_fifo_size;
int cor1,cor2,cor3,cor4,cor5;
int tbpr,tco,rbpr,rco;
+ int baud;
int ignore_status_mask;
int close_delay;
int IER; /* Interrupt Enable Register */
@@ -95,6 +450,8 @@ struct cyclades_port {
struct wait_queue *open_wait;
struct wait_queue *close_wait;
struct cyclades_monitor mon;
+ unsigned long jiffies[3];
+ unsigned long rflush_count;
};
/*
@@ -111,6 +468,10 @@ struct cyclades_port {
#define CyMaxChipsPerCard 8
+#define CyPCI_Ywin 0x4000
+#define CyPCI_Zctl 0x100
+#define CyPCI_Zwin 0x80000
+
/**** CD1400 registers ****/
#define CyRegSize 0x0400
@@ -282,3 +643,4 @@ struct cyclades_port {
#endif /* __KERNEL__ */
#endif /* _LINUX_CYCLADES_H */
+
diff --git a/include/linux/digi1.h b/include/linux/digi1.h
new file mode 100644
index 000000000..184378d23
--- /dev/null
+++ b/include/linux/digi1.h
@@ -0,0 +1,100 @@
+/* Definitions for DigiBoard ditty(1) command. */
+
+#if !defined(TIOCMODG)
+#define TIOCMODG ('d'<<8) | 250 /* get modem ctrl state */
+#define TIOCMODS ('d'<<8) | 251 /* set modem ctrl state */
+#endif
+
+#if !defined(TIOCMSET)
+#define TIOCMSET ('d'<<8) | 252 /* set modem ctrl state */
+#define TIOCMGET ('d'<<8) | 253 /* set modem ctrl state */
+#endif
+
+#if !defined(TIOCMBIC)
+#define TIOCMBIC ('d'<<8) | 254 /* set modem ctrl state */
+#define TIOCMBIS ('d'<<8) | 255 /* set modem ctrl state */
+#endif
+
+#if !defined(TIOCSDTR)
+#define TIOCSDTR ('e'<<8) | 0 /* set DTR */
+#define TIOCCDTR ('e'<<8) | 1 /* clear DTR */
+#endif
+
+/************************************************************************
+ * Ioctl command arguments for DIGI parameters.
+ ************************************************************************/
+#define DIGI_GETA ('e'<<8) | 94 /* Read params */
+
+#define DIGI_SETA ('e'<<8) | 95 /* Set params */
+#define DIGI_SETAW ('e'<<8) | 96 /* Drain & set params */
+#define DIGI_SETAF ('e'<<8) | 97 /* Drain, flush & set params */
+
+#define DIGI_GETFLOW ('e'<<8) | 99 /* Get startc/stopc flow */
+ /* control characters */
+#define DIGI_SETFLOW ('e'<<8) | 100 /* Set startc/stopc flow */
+ /* control characters */
+#define DIGI_GETAFLOW ('e'<<8) | 101 /* Get Aux. startc/stopc */
+ /* flow control chars */
+#define DIGI_SETAFLOW ('e'<<8) | 102 /* Set Aux. startc/stopc */
+ /* flow control chars */
+
+#define DIGI_GETINFO ('e'<<8) | 103 /* Fill in digi_info */
+#define DIGI_POLLER ('e'<<8) | 104 /* Turn on/off poller */
+#define DIGI_INIT ('e'<<8) | 105 /* Allow things to run. */
+
+struct digiflow_struct
+{
+ unsigned char startc; /* flow cntl start char */
+ unsigned char stopc; /* flow cntl stop char */
+};
+
+typedef struct digiflow_struct digiflow_t;
+
+
+/************************************************************************
+ * Values for digi_flags
+ ************************************************************************/
+#define DIGI_IXON 0x0001 /* Handle IXON in the FEP */
+#define DIGI_FAST 0x0002 /* Fast baud rates */
+#define RTSPACE 0x0004 /* RTS input flow control */
+#define CTSPACE 0x0008 /* CTS output flow control */
+#define DSRPACE 0x0010 /* DSR output flow control */
+#define DCDPACE 0x0020 /* DCD output flow control */
+#define DTRPACE 0x0040 /* DTR input flow control */
+#define DIGI_FORCEDCD 0x0100 /* Force carrier */
+#define DIGI_ALTPIN 0x0200 /* Alternate RJ-45 pin config */
+#define DIGI_AIXON 0x0400 /* Aux flow control in fep */
+
+
+/************************************************************************
+ * Values for digiDload
+ ************************************************************************/
+#define NORMAL 0
+#define PCI_CTL 1
+
+#define SIZE8 0
+#define SIZE16 1
+#define SIZE32 2
+
+/************************************************************************
+ * Structure used with ioctl commands for DIGI parameters.
+ ************************************************************************/
+struct digi_struct
+{
+ unsigned short digi_flags; /* Flags (see above) */
+};
+
+typedef struct digi_struct digi_t;
+
+struct digi_info
+{
+ unsigned long board; /* Which board is this ? */
+ unsigned char status; /* Alive or dead */
+ unsigned char type; /* see epca.h */
+ unsigned char subtype; /* For future XEM, XR, etc ... */
+ unsigned short numports; /* Number of ports configured */
+ unsigned char *port; /* I/O Address */
+ unsigned char *membase; /* DPR Address */
+ unsigned char *version; /* For future ... */
+ unsigned short windowData; /* For future ... */
+} ;
diff --git a/include/linux/digiFep1.h b/include/linux/digiFep1.h
new file mode 100644
index 000000000..c47d7fcb8
--- /dev/null
+++ b/include/linux/digiFep1.h
@@ -0,0 +1,136 @@
+
+#define CSTART 0x400L
+#define CMAX 0x800L
+#define ISTART 0x800L
+#define IMAX 0xC00L
+#define CIN 0xD10L
+#define GLOBAL 0xD10L
+#define EIN 0xD18L
+#define FEPSTAT 0xD20L
+#define CHANSTRUCT 0x1000L
+#define RXTXBUF 0x4000L
+
+
+struct global_data
+{
+ volatile ushort cin;
+ volatile ushort cout;
+ volatile ushort cstart;
+ volatile ushort cmax;
+ volatile ushort ein;
+ volatile ushort eout;
+ volatile ushort istart;
+ volatile ushort imax;
+};
+
+
+struct board_chan
+{
+ int filler1;
+ int filler2;
+ volatile ushort tseg;
+ volatile ushort tin;
+ volatile ushort tout;
+ volatile ushort tmax;
+
+ volatile ushort rseg;
+ volatile ushort rin;
+ volatile ushort rout;
+ volatile ushort rmax;
+
+ volatile ushort tlow;
+ volatile ushort rlow;
+ volatile ushort rhigh;
+ volatile ushort incr;
+
+ volatile ushort etime;
+ volatile ushort edelay;
+ volatile unchar *dev;
+
+ volatile ushort iflag;
+ volatile ushort oflag;
+ volatile ushort cflag;
+ volatile ushort gmask;
+
+ volatile ushort col;
+ volatile ushort delay;
+ volatile ushort imask;
+ volatile ushort tflush;
+
+ int filler3;
+ int filler4;
+ int filler5;
+ int filler6;
+
+ volatile unchar num;
+ volatile unchar ract;
+ volatile unchar bstat;
+ volatile unchar tbusy;
+ volatile unchar iempty;
+ volatile unchar ilow;
+ volatile unchar idata;
+ volatile unchar eflag;
+
+ volatile unchar tflag;
+ volatile unchar rflag;
+ volatile unchar xmask;
+ volatile unchar xval;
+ volatile unchar mstat;
+ volatile unchar mchange;
+ volatile unchar mint;
+ volatile unchar lstat;
+
+ volatile unchar mtran;
+ volatile unchar orun;
+ volatile unchar startca;
+ volatile unchar stopca;
+ volatile unchar startc;
+ volatile unchar stopc;
+ volatile unchar vnext;
+ volatile unchar hflow;
+
+ volatile unchar fillc;
+ volatile unchar ochar;
+ volatile unchar omask;
+
+ unchar filler7;
+ unchar filler8[28];
+};
+
+
+#define SRXLWATER 0xE0
+#define SRXHWATER 0xE1
+#define STOUT 0xE2
+#define PAUSETX 0xE3
+#define RESUMETX 0xE4
+#define SAUXONOFFC 0xE6
+#define SENDBREAK 0xE8
+#define SETMODEM 0xE9
+#define SETIFLAGS 0xEA
+#define SONOFFC 0xEB
+#define STXLWATER 0xEC
+#define PAUSERX 0xEE
+#define RESUMERX 0xEF
+#define SETBUFFER 0xF2
+#define SETCOOKED 0xF3
+#define SETHFLOW 0xF4
+#define SETCTRLFLAGS 0xF5
+#define SETVNEXT 0xF6
+
+
+
+#define BREAK_IND 0x01
+#define LOWTX_IND 0x02
+#define EMPTYTX_IND 0x04
+#define DATA_IND 0x08
+#define MODEMCHG_IND 0x20
+
+#define FEP_HUPCL 0002000
+#if 0
+#define RTS 0x02
+#define CD 0x08
+#define DSR 0x10
+#define CTS 0x20
+#define RI 0x40
+#define DTR 0x80
+#endif
diff --git a/include/linux/digiPCI.h b/include/linux/digiPCI.h
new file mode 100644
index 000000000..6ca7819e5
--- /dev/null
+++ b/include/linux/digiPCI.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ * Defines and structure definitions for PCI BIOS Interface
+ *************************************************************************/
+#define PCIMAX 32 /* maximum number of PCI boards */
+
+
+#define PCI_VENDOR_DIGI 0x114F
+#define PCI_DEVICE_EPC 0x0002
+#define PCI_DEVICE_RIGHTSWITCH 0x0003 /* For testing */
+#define PCI_DEVICE_XEM 0x0004
+#define PCI_DEVICE_XR 0x0005
+#define PCI_DEVICE_CX 0x0006
+#define PCI_DEVICE_XRJ 0x0009 /* Jupiter boards with */
+#define PCI_DEVICE_EPCJ 0x000a /* PLX 9060 chip for PCI */
+
+
+/*
+ * On the PCI boards, there is no IO space allocated
+ * The I/O registers will be in the first 3 bytes of the
+ * upper 2MB of the 4MB memory space. The board memory
+ * will be mapped into the low 2MB of the 4MB memory space
+ */
+
+/* Potential location of PCI Bios from E0000 to FFFFF*/
+#define PCI_BIOS_SIZE 0x00020000
+
+/* Size of Memory and I/O for PCI (4MB) */
+#define PCI_RAM_SIZE 0x00400000
+
+/* Size of Memory (2MB) */
+#define PCI_MEM_SIZE 0x00200000
+
+/* Offset of I/0 in Memory (2MB) */
+#define PCI_IO_OFFSET 0x00200000
+
+#define MEMOUTB(basemem, pnum, setmemval) *(caddr_t)((basemem) + ( PCI_IO_OFFSET | pnum << 4 | pnum )) = (setmemval)
+#define MEMINB(basemem, pnum) *(caddr_t)((basemem) + (PCI_IO_OFFSET | pnum << 4 | pnum )) /* for PCI I/O */
+
+
+
+
+
diff --git a/include/linux/elf.h b/include/linux/elf.h
index 17258a19b..5ca3653f1 100644
--- a/include/linux/elf.h
+++ b/include/linux/elf.h
@@ -3,11 +3,20 @@
#include <asm/elf.h>
-typedef unsigned long Elf32_Addr;
-typedef unsigned short Elf32_Half;
-typedef unsigned long Elf32_Off;
-typedef long Elf32_Sword;
-typedef unsigned long Elf32_Word;
+/* 32-bit ELF base types. */
+typedef __u32 Elf32_Addr;
+typedef __u16 Elf32_Half;
+typedef __u32 Elf32_Off;
+typedef __s32 Elf32_Sword;
+typedef __u32 Elf32_Word;
+
+/* 64-bit ELF base types. */
+typedef __u64 Elf64_Addr;
+typedef __u16 Elf64_Half;
+typedef __s16 Elf64_SHalf;
+typedef __u64 Elf64_Off;
+typedef __s64 Elf64_Sword;
+typedef __u64 Elf64_Word;
/* These constants are for the segment types stored in the image headers */
#define PT_NULL 0
@@ -152,10 +161,10 @@ typedef struct dynamic{
} Elf32_Dyn;
typedef struct {
- unsigned long long d_tag; /* entry tag value */
+ Elf64_Word d_tag; /* entry tag value */
union {
- unsigned long long d_val;
- unsigned long long d_ptr;
+ Elf64_Word d_val;
+ Elf64_Word d_ptr;
} d_un;
} Elf64_Dyn;
@@ -299,8 +308,8 @@ typedef struct elf32_rel {
} Elf32_Rel;
typedef struct elf64_rel {
- unsigned long long r_offset; /* Location at which to apply the action */
- unsigned long long r_info; /* index and type of relocation */
+ Elf64_Addr r_offset; /* Location at which to apply the action */
+ Elf64_Word r_info; /* index and type of relocation */
} Elf64_Rel;
typedef struct elf32_rela{
@@ -310,9 +319,9 @@ typedef struct elf32_rela{
} Elf32_Rela;
typedef struct elf64_rela {
- unsigned long long r_offset; /* Location at which to apply the action */
- unsigned long long r_info; /* index and type of relocation */
- unsigned long long r_addend; /* Constant addend used to compute value */
+ Elf64_Addr r_offset; /* Location at which to apply the action */
+ Elf64_Word r_info; /* index and type of relocation */
+ Elf64_Word r_addend; /* Constant addend used to compute value */
} Elf64_Rela;
typedef struct elf32_sym{
@@ -325,12 +334,12 @@ typedef struct elf32_sym{
} Elf32_Sym;
typedef struct elf64_sym {
- unsigned int st_name; /* Symbol name, index in string tbl */
- unsigned char st_info; /* Type and binding attributes */
- unsigned char st_other; /* No defined meaning, 0 */
- unsigned short st_shndx; /* Associated section index */
- unsigned long long st_value; /* Value of the symbol */
- unsigned long long st_size; /* Associated symbol size */
+ Elf32_Word st_name; /* Symbol name, index in string tbl (yes, Elf32) */
+ unsigned char st_info; /* Type and binding attributes */
+ unsigned char st_other; /* No defined meaning, 0 */
+ Elf64_Half st_shndx; /* Associated section index */
+ Elf64_Addr st_value; /* Value of the symbol */
+ Elf64_Word st_size; /* Associated symbol size */
} Elf64_Sym;
@@ -355,19 +364,19 @@ typedef struct elf32_hdr{
typedef struct elf64_hdr {
unsigned char e_ident[16]; /* ELF "magic number" */
- short int e_type;
- short unsigned int e_machine;
- int e_version;
- unsigned long long e_entry; /* Entry point virtual address */
- unsigned long long e_phoff; /* Program header table file offset */
- unsigned long long e_shoff; /* Section header table file offset */
- int e_flags;
- short int e_ehsize;
- short int e_phentsize;
- short int e_phnum;
- short int e_shentsize;
- short int e_shnum;
- short int e_shstrndx;
+ Elf64_SHalf e_type;
+ Elf64_Half e_machine;
+ __s32 e_version;
+ Elf64_Addr e_entry; /* Entry point virtual address */
+ Elf64_Off e_phoff; /* Program header table file offset */
+ Elf64_Off e_shoff; /* Section header table file offset */
+ __s32 e_flags;
+ Elf64_SHalf e_ehsize;
+ Elf64_SHalf e_phentsize;
+ Elf64_SHalf e_phnum;
+ Elf64_SHalf e_shentsize;
+ Elf64_SHalf e_shnum;
+ Elf64_SHalf e_shstrndx;
} Elf64_Ehdr;
/* These constants define the permissions on sections in the program
@@ -388,14 +397,14 @@ typedef struct elf32_phdr{
} Elf32_Phdr;
typedef struct elf64_phdr {
- int p_type;
- int p_flags;
- unsigned long long p_offset; /* Segment file offset */
- unsigned long long p_vaddr; /* Segment virtual address */
- unsigned long long p_paddr; /* Segment physical address */
- unsigned long long p_filesz; /* Segment size in file */
- unsigned long long p_memsz; /* Segment size in memory */
- unsigned long long p_align; /* Segment alignment, file & memory */
+ __s32 p_type;
+ __s32 p_flags;
+ Elf64_Off p_offset; /* Segment file offset */
+ Elf64_Addr p_vaddr; /* Segment virtual address */
+ Elf64_Addr p_paddr; /* Segment physical address */
+ Elf64_Word p_filesz; /* Segment size in file */
+ Elf64_Word p_memsz; /* Segment size in memory */
+ Elf64_Word p_align; /* Segment alignment, file & memory */
} Elf64_Phdr;
/* sh_type */
@@ -452,16 +461,16 @@ typedef struct {
} Elf32_Shdr;
typedef struct elf64_shdr {
- unsigned int sh_name; /* Section name, index in string tbl */
- unsigned int sh_type; /* Type of section */
- unsigned long long sh_flags; /* Miscellaneous section attributes */
- unsigned long long sh_addr; /* Section virtual addr at execution */
- unsigned long long sh_offset; /* Section file offset */
- unsigned long long sh_size; /* Size of section in bytes */
- unsigned int sh_link; /* Index of another section */
- unsigned int sh_info; /* Additional section information */
- unsigned long long sh_addralign; /* Section alignment */
- unsigned long long sh_entsize; /* Entry size if section holds table */
+ Elf32_Word sh_name; /* Section name, index in string tbl (yes Elf32) */
+ Elf32_Word sh_type; /* Type of section (yes Elf32) */
+ Elf64_Word sh_flags; /* Miscellaneous section attributes */
+ Elf64_Addr sh_addr; /* Section virtual addr at execution */
+ Elf64_Off sh_offset; /* Section file offset */
+ Elf64_Word sh_size; /* Size of section in bytes */
+ Elf32_Word sh_link; /* Index of another section (yes Elf32) */
+ Elf32_Word sh_info; /* Additional section information (yes Elf32) */
+ Elf64_Word sh_addralign; /* Section alignment */
+ Elf64_Word sh_entsize; /* Entry size if section holds table */
} Elf64_Shdr;
#define EI_MAG0 0 /* e_ident[] indexes */
@@ -513,9 +522,9 @@ typedef struct elf32_note {
* is only 32 bits.
*/
typedef struct elf64_note {
- unsigned int n_namesz; /* Name size */
- unsigned int n_descsz; /* Content size */
- unsigned int n_type; /* Content type */
+ Elf32_Word n_namesz; /* Name size */
+ Elf32_Word n_descsz; /* Content size */
+ Elf32_Word n_type; /* Content type */
} Elf64_Nhdr;
#define ELF_START_MMAP 0x80000000
diff --git a/include/linux/epca.h b/include/linux/epca.h
new file mode 100644
index 000000000..504948149
--- /dev/null
+++ b/include/linux/epca.h
@@ -0,0 +1,170 @@
+#define XEMPORTS 0xC02
+#define XEPORTS 0xC22
+
+#define MAX_ALLOC 0x100
+
+#define MAXBOARDS 12
+#define FEPCODESEG 0x0200L
+#define FEPCODE 0x2000L
+#define BIOSCODE 0xf800L
+
+#define MISCGLOBAL 0x0C00L
+#define NPORT 0x0C22L
+#define MBOX 0x0C40L
+#define PORTBASE 0x0C90L
+
+/* Begin code defines used for epca_setup */
+
+#define INVALID_BOARD_TYPE 0x1
+#define INVALID_NUM_PORTS 0x2
+#define INVALID_MEM_BASE 0x4
+#define INVALID_PORT_BASE 0x8
+#define INVALID_BOARD_STATUS 0x10
+#define INVALID_ALTPIN 0x20
+
+/* End code defines used for epca_setup */
+
+
+#define FEPCLR 0x00
+#define FEPMEM 0x02
+#define FEPRST 0x04
+#define FEPINT 0x08
+#define FEPMASK 0x0e
+#define FEPWIN 0x80
+
+#define PCXE 0
+#define PCXEVE 1
+#define PCXEM 2
+#define EISAXEM 3
+#define PC64XE 4
+#define PCXI 5
+#define PCIXEM 7
+#define PCICX 8
+#define PCIXR 9
+#define PCIXRJ 10
+#define EPCA_NUM_TYPES 6
+
+
+static char *board_desc[] =
+{
+ "PC/Xe",
+ "PC/Xeve",
+ "PC/Xem",
+ "EISA/Xem",
+ "PC/64Xe",
+ "PC/Xi",
+ "unknown",
+ "PCI/Xem",
+ "PCI/CX",
+ "PCI/Xr",
+ "PCI/Xrj",
+};
+
+#define STARTC 021
+#define STOPC 023
+#define IAIXON 0x2000
+
+
+#define TXSTOPPED 0x1
+#define LOWWAIT 0x2
+#define EMPTYWAIT 0x4
+#define RXSTOPPED 0x8
+#define TXBUSY 0x10
+
+#define DISABLED 0
+#define ENABLED 1
+#define OFF 0
+#define ON 1
+
+#define FEPTIMEOUT 200000
+#define SERIAL_TYPE_NORMAL 1
+#define SERIAL_TYPE_CALLOUT 2
+#define SERIAL_TYPE_INFO 3
+#define EPCA_EVENT_HANGUP 1
+#define EPCA_MAGIC 0x5c6df104L
+
+struct channel
+{
+ long magic;
+ unchar boardnum;
+ unchar channelnum;
+ unchar omodem; /* FEP output modem status */
+ unchar imodem; /* FEP input modem status */
+ unchar modemfake; /* Modem values to be forced */
+ unchar modem; /* Force values */
+ unchar hflow;
+ unchar dsr;
+ unchar dcd;
+ unchar m_rts ; /* The bits used in whatever FEP */
+ unchar m_dcd ; /* is indiginous to this board to */
+ unchar m_dsr ; /* represent each of the physical */
+ unchar m_cts ; /* handshake lines */
+ unchar m_ri ;
+ unchar m_dtr ;
+ unchar stopc;
+ unchar startc;
+ unchar stopca;
+ unchar startca;
+ unchar fepstopc;
+ unchar fepstartc;
+ unchar fepstopca;
+ unchar fepstartca;
+ unchar txwin;
+ unchar rxwin;
+ ushort fepiflag;
+ ushort fepcflag;
+ ushort fepoflag;
+ ushort txbufhead;
+ ushort txbufsize;
+ ushort rxbufhead;
+ ushort rxbufsize;
+ int close_delay;
+ int count;
+ int blocked_open;
+ int event;
+ int asyncflags;
+ uint dev;
+ long session;
+ long pgrp;
+ ulong statusflags;
+ ulong c_iflag;
+ ulong c_cflag;
+ ulong c_lflag;
+ ulong c_oflag;
+ unchar *txptr;
+ unchar *rxptr;
+ unchar *tmp_buf;
+ struct board_info *board;
+ volatile struct board_chan *brdchan;
+ struct digi_struct digiext;
+ struct tty_struct *tty;
+ struct termios normal_termios;
+ struct termios callout_termios;
+ struct wait_queue *open_wait;
+ struct wait_queue *close_wait;
+ struct tq_struct tqueue;
+ volatile struct global_data *mailbox;
+};
+
+struct board_info
+{
+ unchar status;
+ unchar type;
+ unchar altpin;
+ ushort numports;
+ unchar *port;
+ unchar *membase;
+ unchar *re_map_port;
+ unchar *re_map_membase;
+ ulong memory_seg;
+ void ( * memwinon ) (struct board_info *, unsigned int) ;
+ void ( * memwinoff ) (struct board_info *, unsigned int) ;
+ void ( * globalwinon ) (struct channel *) ;
+ void ( * txwinon ) (struct channel *) ;
+ void ( * rxwinon ) (struct channel *) ;
+ void ( * memoff ) (struct channel *) ;
+ void ( * assertgwinon ) (struct channel *) ;
+ void ( * assertmemoff ) (struct channel *) ;
+ unchar poller_inhibited ;
+};
+
diff --git a/include/linux/epcaconfig.h b/include/linux/epcaconfig.h
new file mode 100644
index 000000000..c840c6735
--- /dev/null
+++ b/include/linux/epcaconfig.h
@@ -0,0 +1,8 @@
+#define NUMCARDS 1
+#define NBDEVS 2
+
+struct board_info static_boards[NUMCARDS]={
+ { ENABLED, 0, OFF, 2, (unchar*) 0x320, (unchar*) 0xd0000 },
+};
+
+/* DO NOT HAND EDIT THIS FILE! */
diff --git a/include/linux/ext2_fs.h b/include/linux/ext2_fs.h
index bd87ebcf5..b5f2b5f15 100644
--- a/include/linux/ext2_fs.h
+++ b/include/linux/ext2_fs.h
@@ -189,6 +189,7 @@ struct ext2_group_desc
#define EXT2_IMMUTABLE_FL 0x00000010 /* Immutable file */
#define EXT2_APPEND_FL 0x00000020 /* writes to file may only append */
#define EXT2_NODUMP_FL 0x00000040 /* do not dump file */
+#define EXT2_NOATIME_FL 0x00000080 /* do not update atime */
#define EXT2_RESERVED_FL 0x80000000 /* reserved for ext2 lib */
/*
@@ -363,7 +364,10 @@ struct ext2_super_block {
__u32 s_feature_compat; /* compatible feature set */
__u32 s_feature_incompat; /* incompatible feature set */
__u32 s_feature_ro_compat; /* readonly-compatible feature set */
- __u32 s_reserved[230]; /* Padding to the end of the block */
+ __u8 s_uuid[16]; /* 128-bit uuid for volume */
+ char s_volume_name[16]; /* volume name */
+ char s_last_mounted[64]; /* directory where last mounted */
+ __u32 s_reserved[206]; /* Padding to the end of the block */
};
/*
@@ -387,6 +391,16 @@ struct ext2_super_block {
#define EXT2_GOOD_OLD_INODE_SIZE 128
/*
+ * Feature set definitions
+ */
+
+#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001
+
+#define EXT2_FEATURE_COMPAT_SUPP 0
+#define EXT2_FEATURE_INCOMPAT_SUPP 0
+#define EXT2_FEATURE_RO_COMPAT_SUPP EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER
+
+/*
* Default values for user and/or group using reserved blocks
*/
#define EXT2_DEF_RESUID 0
@@ -414,13 +428,6 @@ struct ext2_dir_entry {
#define EXT2_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT2_DIR_ROUND) & \
~EXT2_DIR_ROUND)
-/*
- * Feature set definitions --- none are defined as of now
- */
-#define EXT2_FEATURE_COMPAT_SUPP 0
-#define EXT2_FEATURE_INCOMPAT_SUPP 0
-#define EXT2_FEATURE_RO_COMPAT_SUPP 0
-
#ifdef __KERNEL__
/*
* Function prototypes
diff --git a/include/linux/ext2_fs_sb.h b/include/linux/ext2_fs_sb.h
index dd064b86a..9ce758116 100644
--- a/include/linux/ext2_fs_sb.h
+++ b/include/linux/ext2_fs_sb.h
@@ -60,6 +60,9 @@ struct ext2_sb_info {
int s_desc_per_block_bits;
int s_inode_size;
int s_first_ino;
+ int s_feature_compat;
+ int s_feature_incompat;
+ int s_feature_ro_compat;
};
#endif /* _LINUX_EXT2_FS_SB */
diff --git a/include/linux/fb.h b/include/linux/fb.h
index f97a313c6..9ed7546d5 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -59,6 +59,7 @@ struct fb_bitfield {
#define FB_ACCEL_ATARIBLITT 1 /* Atari Blitter */
#define FB_ACCEL_AMIGABLITT 2 /* Amiga Blitter */
#define FB_ACCEL_CYBERVISION 3 /* Cybervision64 (S3 Trio64) */
+#define FB_ACCEL_RETINAZ3 4 /* RetinaZ3 (NCR77C32BLT) */
#define FB_SYNC_HOR_HIGH_ACT 1 /* horizontal sync high active */
#define FB_SYNC_VERT_HIGH_ACT 2 /* vertical sync high active */
@@ -205,6 +206,7 @@ struct fb_info {
int (*switch_con)(int); /* tell fb to switch consoles */
int (*updatevar)(int); /* tell fb to update the vars */
void (*blank)(int); /* tell fb to (un)blank the screen */
+ int (*setcmap)(struct fb_cmap *, int); /* tell fb to set the colormap */
};
#endif /* __KERNEL__ */
diff --git a/include/linux/file.h b/include/linux/file.h
index 4ba5311e8..0cb531c0c 100644
--- a/include/linux/file.h
+++ b/include/linux/file.h
@@ -13,16 +13,37 @@ extern inline struct file * fget(unsigned long fd)
}
extern int __fput(struct file *, struct inode *);
+extern void insert_file_free(struct file *file);
+
+/* It does not matter which list it is on. */
+extern inline void remove_filp(struct file *file)
+{
+ if(file->f_next)
+ file->f_next->f_pprev = file->f_pprev;
+ *file->f_pprev = file->f_next;
+}
extern inline int fput(struct file *file, struct inode *inode)
{
int count = file->f_count-1;
int error = 0;
- if (!count)
+ if (!count) {
error = __fput(file, inode);
- file->f_count = count;
+ file->f_count = 0;
+ remove_filp(file);
+ insert_file_free(file);
+ } else
+ file->f_count = count;
return error;
}
+extern inline void put_filp(struct file *file)
+{
+ if(--file->f_count == 0) {
+ remove_filp(file);
+ insert_file_free(file);
+ }
+}
+
#endif
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 85e04d184..1918471ab 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -95,7 +95,6 @@ extern int max_files, nr_files;
* Exception: MS_RDONLY is always applied to the entire file system.
*/
#define IS_RDONLY(inode) (((inode)->i_sb) && ((inode)->i_sb->s_flags & MS_RDONLY))
-#define DO_UPDATE_ATIME(inode) (!((inode)->i_flags & MS_NOATIME) && !IS_RDONLY(inode))
#define IS_NOSUID(inode) ((inode)->i_flags & MS_NOSUID)
#define IS_NODEV(inode) ((inode)->i_flags & MS_NODEV)
#define IS_NOEXEC(inode) ((inode)->i_flags & MS_NOEXEC)
@@ -105,6 +104,8 @@ extern int max_files, nr_files;
#define IS_WRITABLE(inode) ((inode)->i_flags & S_WRITE)
#define IS_APPEND(inode) ((inode)->i_flags & S_APPEND)
#define IS_IMMUTABLE(inode) ((inode)->i_flags & S_IMMUTABLE)
+#define IS_NOATIME(inode) ((inode)->i_flags & MS_NOATIME)
+#define DO_UPDATE_ATIME(inode) (!IS_NOATIME(inode) && !IS_RDONLY(inode))
/* the read-only stuff doesn't really belong here, but any other place is
probably as bad and I don't want to create yet another include file. */
@@ -129,7 +130,7 @@ extern int max_files, nr_files;
extern void buffer_init(void);
extern void inode_init(void);
-extern unsigned long file_table_init(unsigned long start, unsigned long end);
+extern void file_table_init(void);
extern unsigned long name_cache_init(unsigned long start, unsigned long end);
typedef char buffer_block[BLOCK_SIZE];
@@ -246,6 +247,7 @@ static inline int buffer_protected(struct buffer_head * bh)
#define ATTR_ATIME_SET 128
#define ATTR_MTIME_SET 256
#define ATTR_FORCE 512 /* Not a change, but a change it */
+#define ATTR_ATTR_FLAG 1024
/*
* This is the Inode Attributes structure, used for notify_change(). It
@@ -265,8 +267,17 @@ struct iattr {
time_t ia_atime;
time_t ia_mtime;
time_t ia_ctime;
+ unsigned int ia_attr_flags;
};
+/*
+ * This is the inode attributes flag definitions
+ */
+#define ATTR_FLAG_SYNCRONOUS 1 /* Syncronous write */
+#define ATTR_FLAG_NOATIME 2 /* Don't update atime */
+#define ATTR_FLAG_APPEND 4 /* Append-only file */
+#define ATTR_FLAG_IMMUTABLE 8 /* Immutable file */
+
#include <linux/quota.h>
struct inode {
@@ -305,9 +316,8 @@ struct inode {
unsigned char i_dirt;
unsigned char i_pipe;
unsigned char i_sock;
- unsigned char i_seek;
- unsigned char i_update;
- unsigned short i_writecount;
+ int i_writecount;
+ unsigned int i_attr_flags;
union {
struct pipe_inode_info pipe_i;
struct minix_inode_info minix_i;
@@ -327,17 +337,21 @@ struct inode {
};
struct file {
- mode_t f_mode;
- loff_t f_pos;
- unsigned short f_flags;
- unsigned short f_count;
- unsigned long f_reada, f_ramax, f_raend, f_ralen, f_rawin;
- struct file *f_next, *f_prev;
- int f_owner; /* pid or -pgrp where SIGIO should be sent */
- struct inode * f_inode;
- struct file_operations * f_op;
- unsigned long f_version;
- void *private_data; /* needed for tty driver, and maybe others */
+ struct file *f_next, **f_pprev;
+ struct inode *f_inode;
+ struct file_operations *f_op;
+ mode_t f_mode;
+ loff_t f_pos;
+ unsigned short f_count, f_flags;
+ unsigned long f_reada, f_ramax, f_raend, f_ralen, f_rawin;
+
+ /* pid or -pgrp where SIGIO should be sent */
+ int f_owner;
+
+ unsigned long f_version;
+
+ /* needed for tty driver, and maybe others */
+ void *private_data;
};
#define FL_POSIX 1
@@ -584,7 +598,7 @@ extern int fs_may_mount(kdev_t dev);
extern int fs_may_umount(kdev_t dev, struct inode * mount_root);
extern int fs_may_remount_ro(kdev_t dev);
-extern struct file *first_file;
+extern struct file *inuse_filps;
extern struct super_block super_blocks[NR_SUPER];
extern void refile_buffer(struct buffer_head * buf);
@@ -597,15 +611,14 @@ extern int nr_buffer_heads;
#define BUF_CLEAN 0
#define BUF_LOCKED 1 /* Buffers scheduled for write */
-#define BUF_LOCKED1 2 /* Supers, inodes */
-#define BUF_DIRTY 3 /* Dirty buffers, not yet scheduled for write */
-#define NR_LIST 4
+#define BUF_DIRTY 2 /* Dirty buffers, not yet scheduled for write */
+#define NR_LIST 3
void mark_buffer_uptodate(struct buffer_head * bh, int on);
extern inline void mark_buffer_clean(struct buffer_head * bh)
{
- if (clear_bit(BH_Dirty, &bh->b_state)) {
+ if (test_and_clear_bit(BH_Dirty, &bh->b_state)) {
if (bh->b_list == BUF_DIRTY)
refile_buffer(bh);
}
@@ -613,7 +626,7 @@ extern inline void mark_buffer_clean(struct buffer_head * bh)
extern inline void mark_buffer_dirty(struct buffer_head * bh, int flag)
{
- if (!set_bit(BH_Dirty, &bh->b_state)) {
+ if (!test_and_set_bit(BH_Dirty, &bh->b_state)) {
set_writetime(bh, flag);
if (bh->b_list != BUF_DIRTY)
refile_buffer(bh);
diff --git a/include/linux/in6.h b/include/linux/in6.h
index 9a6954c29..0996e2d58 100644
--- a/include/linux/in6.h
+++ b/include/linux/in6.h
@@ -104,7 +104,7 @@ struct ipv6_mreq {
*/
#define IPV6_ADDRFORM 1
-#define IPV6_RXINFO 2
+#define IPV6_PKTINFO 2
#define IPV6_RXHOPOPTS 3
#define IPV6_RXDSTOPTS 4
#define IPV6_RXSRCRT 5
@@ -115,8 +115,6 @@ struct ipv6_mreq {
/*
* Alternative names
*/
-#define IPV6_TXINFO IPV6_RXINFO
-#define SCM_SRCINFO IPV6_TXINFO
#define SCM_SRCRT IPV6_RXSRCRT
#define IPV6_UNICAST_HOPS 16
diff --git a/include/linux/inet.h b/include/linux/inet.h
index 9bd28d56e..acb93765f 100644
--- a/include/linux/inet.h
+++ b/include/linux/inet.h
@@ -45,8 +45,8 @@
#ifdef __KERNEL__
extern void inet_proto_init(struct net_proto *pro);
-extern char *in_ntoa(unsigned long in);
-extern unsigned long in_aton(const char *str);
+extern char *in_ntoa(__u32 in);
+extern __u32 in_aton(const char *str);
#endif
#endif /* _LINUX_INET_H */
diff --git a/include/linux/keyboard.h b/include/linux/keyboard.h
index 91dacb14d..d54377d96 100644
--- a/include/linux/keyboard.h
+++ b/include/linux/keyboard.h
@@ -302,7 +302,7 @@ extern struct wait_queue * keypress_wait;
#define K_F243 K(KT_FN,252)
#define K_F244 K(KT_FN,253)
#define K_F245 K(KT_FN,254)
-#define K_F246 K(KT_FN,255)
+#define K_UNDO K(KT_FN,255)
#define K_HOLE K(KT_SPEC,0)
@@ -347,8 +347,10 @@ extern struct wait_queue * keypress_wait;
#define K_PCOMMA K(KT_PAD,15) /* key-pad comma: kludge... */
#define K_PDOT K(KT_PAD,16) /* key-pad dot (period): kludge... */
#define K_PPLUSMINUS K(KT_PAD,17) /* key-pad plus/minus */
+#define K_PPARENL K(KT_PAD,18) /* key-pad left parenthesis */
+#define K_PPARENR K(KT_PAD,19) /* key-pad right parenthesis */
-#define NR_PAD 18
+#define NR_PAD 20
#define K_DGRAVE K(KT_DEAD,0)
#define K_DACUTE K(KT_DEAD,1)
diff --git a/include/linux/locks.h b/include/linux/locks.h
index 37933f63e..9e32ef883 100644
--- a/include/linux/locks.h
+++ b/include/linux/locks.h
@@ -22,7 +22,7 @@ extern inline void wait_on_buffer(struct buffer_head * bh)
extern inline void lock_buffer(struct buffer_head * bh)
{
- while (set_bit(BH_Lock, &bh->b_state))
+ while (test_and_set_bit(BH_Lock, &bh->b_state))
__wait_on_buffer(bh);
}
diff --git a/include/linux/lp_m68k.h b/include/linux/lp_m68k.h
index 6cd60e19d..ca8f7a31d 100644
--- a/include/linux/lp_m68k.h
+++ b/include/linux/lp_m68k.h
@@ -91,7 +91,8 @@ enum lp_type {
LP_UNKNOWN = 0,
LP_AMIGA = 1,
LP_ATARI = 2,
-LP_MFC = 3
+LP_MFC = 3,
+LP_IOEXT = 4
};
/*
@@ -105,10 +106,10 @@ struct lp_struct {
int (*lp_is_busy)(int);
int (*lp_has_pout)(int);
int (*lp_is_online)(int);
- int (*lp_my_interrupt)(int);
+ int (*lp_dummy)(int);
int (*lp_ioctl)(int, unsigned int, unsigned long);
- void (*lp_open)(void); /* for module use counter */
- void (*lp_release)(void); /* for module use counter */
+ int (*lp_open)(int); /* for module use counter */
+ void (*lp_release)(int); /* for module use counter */
int flags; /*for BUSY... */
unsigned int chars; /*busy timeout */
unsigned int time; /*wait time */
@@ -124,7 +125,7 @@ struct lp_struct {
extern struct lp_struct *lp_table[MAX_LP];
extern unsigned int lp_irq;
-void lp_interrupt(int, void *, struct pt_regs *);
+void lp_interrupt(int dev);
int lp_init(void);
int register_parallel(struct lp_struct *, int);
void unregister_parallel(int);
diff --git a/include/linux/major.h b/include/linux/major.h
index ee58c06f0..6e785af86 100644
--- a/include/linux/major.h
+++ b/include/linux/major.h
@@ -70,6 +70,7 @@
#define RISCOM8_NORMAL_MAJOR 48
#define RISCOM8_CALLOUT_MAJOR 49
#define MKISS_MAJOR 55
+#define DSP56K_MAJOR 55 /* DSP56001 processor device */
/*
* Tests for SCSI devices.
diff --git a/include/linux/malloc.h b/include/linux/malloc.h
index 0ef085783..f3ebf1857 100644
--- a/include/linux/malloc.h
+++ b/include/linux/malloc.h
@@ -1,11 +1,5 @@
#ifndef _LINUX_MALLOC_H
#define _LINUX_MALLOC_H
-#include <linux/mm.h>
-
-void * kmalloc(unsigned int size, int priority);
-void kfree(void * obj);
-
-#define kfree_s(a,b) kfree(a)
-
+#include <linux/slab.h>
#endif /* _LINUX_MALLOC_H */
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 9572b3415..6ebf15a55 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -37,18 +37,15 @@ struct vm_area_struct {
unsigned long vm_end;
pgprot_t vm_page_prot;
unsigned short vm_flags;
-/* AVL tree of VM areas per task, sorted by address */
- short vm_avl_height;
- struct vm_area_struct * vm_avl_left;
- struct vm_area_struct * vm_avl_right;
-/* linked list of VM areas per task, sorted by address */
- struct vm_area_struct * vm_next;
-/* for areas with inode, the circular list inode->i_mmap */
-/* for shm areas, the circular list of attaches */
-/* otherwise unused */
- struct vm_area_struct * vm_next_share;
- struct vm_area_struct * vm_prev_share;
-/* more */
+ struct vm_area_struct *vm_next;
+ struct vm_area_struct **vm_pprev;
+
+ /* For areas with inode, the list inode->i_mmap, for shm areas,
+ * the list of attaches, otherwise unused.
+ */
+ struct vm_area_struct *vm_next_share;
+ struct vm_area_struct **vm_pprev_share;
+
struct vm_operations_struct * vm_ops;
unsigned long vm_offset;
struct inode * vm_inode;
@@ -140,6 +137,7 @@ typedef struct page {
#define PG_decr_after 5
#define PG_swap_unlock_after 6
#define PG_DMA 7
+#define PG_Slab 8
#define PG_reserved 31
/* Make it prettier to test the above... */
@@ -152,8 +150,12 @@ typedef struct page {
#define PageDecrAfter(page) (test_bit(PG_decr_after, &(page)->flags))
#define PageSwapUnlockAfter(page) (test_bit(PG_swap_unlock_after, &(page)->flags))
#define PageDMA(page) (test_bit(PG_DMA, &(page)->flags))
+#define PageSlab(page) (test_bit(PG_Slab, &(page)->flags))
#define PageReserved(page) (test_bit(PG_reserved, &(page)->flags))
+#define PageSetSlab(page) (set_bit(PG_Slab, &(page)->flags))
+#define PageClearSlab(page) (clear_bit(PG_Slab, &(page)->flags))
+
/*
* page->reserved denotes a page which must never be accessed (which
* may not even be present).
@@ -263,9 +265,7 @@ extern int remap_page_range(unsigned long from, unsigned long to, unsigned long
extern int zeromap_page_range(unsigned long from, unsigned long size, pgprot_t prot);
extern void vmtruncate(struct inode * inode, unsigned long offset);
-extern void handle_mm_fault(struct vm_area_struct *vma, unsigned long address, int write_access);
-extern void do_wp_page(struct task_struct * tsk, struct vm_area_struct * vma, unsigned long address, int write_access);
-extern void do_no_page(struct task_struct * tsk, struct vm_area_struct * vma, unsigned long address, int write_access);
+extern void handle_mm_fault(struct task_struct *tsk,struct vm_area_struct *vma, unsigned long address, int write_access);
extern unsigned long paging_init(unsigned long start_mem, unsigned long end_mem);
extern void mem_init(unsigned long start_mem, unsigned long end_mem);
@@ -279,8 +279,6 @@ extern unsigned long do_mmap(struct file * file, unsigned long addr, unsigned lo
unsigned long prot, unsigned long flags, unsigned long off);
extern void merge_segments(struct mm_struct *, unsigned long, unsigned long);
extern void insert_vm_struct(struct mm_struct *, struct vm_area_struct *);
-extern void remove_shared_vm_struct(struct vm_area_struct *);
-extern void build_mmap_avl(struct mm_struct *);
extern void exit_mmap(struct mm_struct *);
extern int do_munmap(unsigned long, size_t);
extern unsigned long get_unmapped_area(unsigned long, unsigned long);
@@ -325,38 +323,30 @@ static inline int expand_stack(struct vm_area_struct * vma, unsigned long addres
return 0;
}
-#define avl_empty (struct vm_area_struct *) NULL
-
/* Look up the first VMA which satisfies addr < vm_end, NULL if none. */
static inline struct vm_area_struct * find_vma(struct mm_struct * mm, unsigned long addr)
{
- struct vm_area_struct * result = NULL;
+ struct vm_area_struct *vma = NULL;
if (mm) {
- struct vm_area_struct ** next = &mm->mmap_avl;
- for (;;) {
- struct vm_area_struct *tree = *next;
- if (tree == avl_empty)
- break;
- next = &tree->vm_avl_right;
- if (tree->vm_end <= addr)
- continue;
- next = &tree->vm_avl_left;
- result = tree;
- if (tree->vm_start <= addr)
- break;
+ /* Check the cache first. */
+ vma = mm->mmap_cache;
+ if(!vma || (vma->vm_end <= addr) || (vma->vm_start > addr)) {
+ vma = mm->mmap;
+ while(vma && vma->vm_end <= addr)
+ vma = vma->vm_next;
+ mm->mmap_cache = vma;
}
}
- return result;
+ return vma;
}
/* Look up the first VMA which intersects the interval start_addr..end_addr-1,
NULL if none. Assume start_addr < end_addr. */
static inline struct vm_area_struct * find_vma_intersection(struct mm_struct * mm, unsigned long start_addr, unsigned long end_addr)
{
- struct vm_area_struct * vma;
+ struct vm_area_struct * vma = find_vma(mm,start_addr);
- vma = find_vma(mm,start_addr);
if (vma && end_addr <= vma->vm_start)
vma = NULL;
return vma;
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 58c4e026b..10c0f76b7 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -27,7 +27,7 @@
* displayed at boot time, please report
* - /proc/pci
* - your exact hardware description. Try to find out
- * which device is unknown. It may be you mainboard chipset.
+ * which device is unknown. It may be your mainboard chipset.
* PCI-CPU bridge or PCI-ISA bridge.
* - If you can't find the actual information in your hardware
* booklet, try to read the references of the chip on the board.
@@ -331,6 +331,7 @@
#define PCI_VENDOR_ID_HP 0x103c
#define PCI_DEVICE_ID_HP_J2585A 0x1030
+#define PCI_DEVICE_ID_HP_J2585B 0x1031
#define PCI_VENDOR_ID_PCTECH 0x1042
#define PCI_DEVICE_ID_PCTECH_RZ1000 0x1000
@@ -408,6 +409,9 @@
#define PCI_DEVICE_ID_VISION_QD8500 0x0001
#define PCI_DEVICE_ID_VISION_QD8580 0x0002
+#define PCI_VENDOR_ID_BROOKTREE 0x109e
+#define PCI_DEVICE_ID_BT848 0x0350 /* 0x350 = 848 */
+
#define PCI_VENDOR_ID_SIERRA 0x10a8
#define PCI_DEVICE_ID_SIERRA_STB 0x0000
@@ -595,6 +599,7 @@
#define PCI_DEVICE_ID_INTEL_82437VX 0x7030
#define PCI_DEVICE_ID_INTEL_82371AB 0x7111
#define PCI_DEVICE_ID_INTEL_P6 0x84c4
+#define PCI_DEVICE_ID_INTEL_P6_2 0x84c5
#define PCI_VENDOR_ID_KTI 0x8e2e
#define PCI_DEVICE_ID_KTI_ET32P2 0x3000
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
index 0937a7bc1..48d9ae98f 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -162,12 +162,14 @@ enum scsi_directory_inos {
PROC_SCSI_7000FASST,
PROC_SCSI_IBMMCA,
PROC_SCSI_EATA2X,
+ PROC_SCSI_DC390T,
PROC_SCSI_AM53C974,
PROC_SCSI_SSC,
PROC_SCSI_NCR53C406A,
PROC_SCSI_PPA,
PROC_SCSI_ESP,
PROC_SCSI_QLOGICPTI,
+ PROC_SCSI_AMIGA7XX,
PROC_SCSI_A3000,
PROC_SCSI_A2091,
PROC_SCSI_GVP11,
diff --git a/include/linux/sched.h b/include/linux/sched.h
index c8ec07ab4..215774036 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1,14 +1,6 @@
#ifndef _LINUX_SCHED_H
#define _LINUX_SCHED_H
-/*
- * define DEBUG if you want the wait-queues to have some extra
- * debugging code. It's not normally used, but might catch some
- * wait-queue coding errors.
- *
- * #define DEBUG
- */
-
#include <asm/param.h> /* for HZ */
extern unsigned long event;
@@ -17,6 +9,8 @@ extern unsigned long event;
#include <linux/personality.h>
#include <linux/tasks.h>
#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/times.h>
#include <asm/system.h>
#include <asm/semaphore.h>
@@ -66,9 +60,6 @@ extern unsigned long avenrun[]; /* Load averages */
extern int nr_running, nr_tasks;
extern int last_pid;
-#define FIRST_TASK task[0]
-#define LAST_TASK task[NR_TASKS-1]
-
#include <linux/head.h>
#include <linux/fs.h>
#include <linux/signal.h>
@@ -149,29 +140,28 @@ struct fs_struct {
}
struct mm_struct {
- int count;
+ struct vm_area_struct *mmap, *mmap_cache;
pgd_t * pgd;
+ int count;
+ struct semaphore mmap_sem;
unsigned long context;
unsigned long start_code, end_code, start_data, end_data;
unsigned long start_brk, brk, start_stack, start_mmap;
unsigned long arg_start, arg_end, env_start, env_end;
unsigned long rss, total_vm, locked_vm;
unsigned long def_flags;
- struct vm_area_struct * mmap;
- struct vm_area_struct * mmap_avl;
- struct semaphore mmap_sem;
+ unsigned long cpu_vm_mask;
};
-#define INIT_MM { \
- 1, \
- swapper_pg_dir, \
- 0, \
- 0, 0, 0, 0, \
- 0, 0, 0, 0, \
- 0, 0, 0, 0, \
- 0, 0, 0, \
- 0, \
- &init_mmap, &init_mmap, MUTEX }
+#define INIT_MM { \
+ &init_mmap, NULL, swapper_pg_dir, 1, \
+ MUTEX, \
+ 0, \
+ 0, 0, 0, 0, \
+ 0, 0, 0, 0, \
+ 0, 0, 0, 0, \
+ 0, 0, 0, \
+ 0, 0 }
struct signal_struct {
atomic_t count;
@@ -200,8 +190,6 @@ struct task_struct {
struct linux_binfmt *binfmt;
struct task_struct *next_task, *prev_task;
struct task_struct *next_run, *prev_run;
- unsigned long saved_kernel_stack;
- unsigned long kernel_stack_page;
int exit_code, exit_signal;
/* ??? */
unsigned long personality;
@@ -222,6 +210,14 @@ struct task_struct {
* p->p_pptr->pid)
*/
struct task_struct *p_opptr, *p_pptr, *p_cptr, *p_ysptr, *p_osptr;
+
+ /* PID hash table linkage. */
+ struct task_struct *pidhash_next;
+ struct task_struct **pidhash_pprev;
+
+ /* Pointer to task[] array linkage. */
+ struct task_struct **tarray_ptr;
+
struct wait_queue *wait_chldexit; /* for wait4() */
unsigned short uid,euid,suid,fsuid;
unsigned short gid,egid,sgid,fsgid;
@@ -229,7 +225,8 @@ struct task_struct {
unsigned long it_real_value, it_prof_value, it_virt_value;
unsigned long it_real_incr, it_prof_incr, it_virt_incr;
struct timer_list real_timer;
- long utime, stime, cutime, cstime, start_time;
+ struct tms times;
+ unsigned long start_time;
/* mm fault and swap info: this can arguably be seen as either mm-specific or thread-specific */
unsigned long min_flt, maj_flt, nswap, cmin_flt, cmaj_flt, cnswap;
int swappable:1;
@@ -260,6 +257,7 @@ struct task_struct {
/* signal handlers */
struct signal_struct *sig;
/* SMP state */
+ int has_cpu;
int processor;
int last_processor;
int lock_depth; /* Lock depth. We can context switch in and out of holding a syscall kernel lock... */
@@ -294,6 +292,16 @@ struct task_struct {
#define DEF_PRIORITY (20*HZ/100) /* 200 ms time slices */
+/* Note: This is very ugly I admit. But some versions of gcc will
+ * dump core when an empty structure constant is parsed at
+ * the end of a large top level structure initialization. -DaveM
+ */
+#ifdef __SMP__
+#define INIT_LOCKS SPIN_LOCK_UNLOCKED
+#else
+#define INIT_LOCKS
+#endif
+
/*
* INIT_TASK is used to set up the first task table, touch at
* your own risk!. Base=0, limit=0x1fffff (=2MB)
@@ -304,15 +312,17 @@ struct task_struct {
/* exec domain */&default_exec_domain, \
/* binfmt */ NULL, \
/* schedlink */ &init_task,&init_task, &init_task, &init_task, \
-/* stack */ 0,(unsigned long) &init_kernel_stack, \
/* ec,brk... */ 0,0,0,0,0, \
/* pid etc.. */ 0,0,0,0,0, \
/* suppl grps*/ 0, {0,}, \
-/* proc links*/ &init_task,&init_task,NULL,NULL,NULL,NULL, \
+/* proc links*/ &init_task,&init_task,NULL,NULL,NULL, \
+/* pidhash */ NULL, NULL, \
+/* tarray */ &task[0], \
+/* chld wait */ NULL, \
/* uid etc */ 0,0,0,0,0,0,0,0, \
/* timeout */ 0,SCHED_OTHER,0,0,0,0,0,0,0, \
/* timer */ { NULL, NULL, 0, 0, it_real_fn }, \
-/* utime */ 0,0,0,0,0, \
+/* utime */ {0,0,0,0},0, \
/* flt */ 0,0,0,0,0,0, \
/* swp */ 0,0,0,0,0, \
/* rlimits */ INIT_RLIMITS, \
@@ -326,14 +336,88 @@ struct task_struct {
/* files */ &init_files, \
/* mm */ &init_mm, \
/* signals */ &init_signals, \
-/* SMP */ 0,0,0, \
+/* SMP */ 0,0,0,0, \
+/* locks */ INIT_LOCKS \
}
+union task_union {
+ struct task_struct task;
+ unsigned long stack[2048];
+};
+
+extern union task_union init_task_union;
+
extern struct mm_struct init_mm;
-extern struct task_struct init_task;
extern struct task_struct *task[NR_TASKS];
extern struct task_struct *last_task_used_math;
+extern struct task_struct **tarray_freelist;
+extern spinlock_t taskslot_lock;
+
+extern __inline__ void add_free_taskslot(struct task_struct **t)
+{
+ spin_lock(&taskslot_lock);
+ *t = (struct task_struct *) tarray_freelist;
+ tarray_freelist = t;
+ spin_unlock(&taskslot_lock);
+}
+
+extern __inline__ struct task_struct **get_free_taskslot(void)
+{
+ struct task_struct **tslot;
+
+ spin_lock(&taskslot_lock);
+ if((tslot = tarray_freelist) != NULL)
+ tarray_freelist = (struct task_struct **) *tslot;
+ spin_unlock(&taskslot_lock);
+
+ return tslot;
+}
+
+/* PID hashing. */
+#define PIDHASH_SZ (NR_TASKS >> 2)
+extern struct task_struct *pidhash[PIDHASH_SZ];
+extern spinlock_t pidhash_lock;
+
+#define pid_hashfn(x) ((((x) >> 8) ^ (x)) & (PIDHASH_SZ - 1))
+
+extern __inline__ void hash_pid(struct task_struct *p)
+{
+ struct task_struct **htable = &pidhash[pid_hashfn(p->pid)];
+
+ spin_lock(&pidhash_lock);
+ if((p->pidhash_next = *htable) != NULL)
+ (*htable)->pidhash_pprev = &p->pidhash_next;
+ *htable = p;
+ p->pidhash_pprev = htable;
+ spin_unlock(&pidhash_lock);
+}
+
+extern __inline__ void unhash_pid(struct task_struct *p)
+{
+ spin_lock(&pidhash_lock);
+ if(p->pidhash_next)
+ p->pidhash_next->pidhash_pprev = p->pidhash_pprev;
+ *p->pidhash_pprev = p->pidhash_next;
+ spin_unlock(&pidhash_lock);
+}
+
+extern __inline__ struct task_struct *find_task_by_pid(int pid)
+{
+ struct task_struct **htable = &pidhash[pid_hashfn(pid)];
+ struct task_struct *p;
+
+ spin_lock(&pidhash_lock);
+ for(p = *htable; p && p->pid != pid; p = p->pidhash_next)
+ ;
+ spin_unlock(&pidhash_lock);
+
+ return p;
+}
+
+/* per-UID process charging. */
+extern int charge_uid(struct task_struct *p, int count);
+
#include <asm/current.h>
extern unsigned long volatile jiffies;
@@ -425,15 +509,15 @@ extern inline void __add_wait_queue(struct wait_queue ** p, struct wait_queue *
wait->next = next;
}
-extern spinlock_t waitqueue_lock;
+extern rwlock_t waitqueue_lock;
extern inline void add_wait_queue(struct wait_queue ** p, struct wait_queue * wait)
{
unsigned long flags;
- spin_lock_irqsave(&waitqueue_lock, flags);
+ write_lock_irqsave(&waitqueue_lock, flags);
__add_wait_queue(p, wait);
- spin_unlock_irqrestore(&waitqueue_lock, flags);
+ write_unlock_irqrestore(&waitqueue_lock, flags);
}
extern inline void __remove_wait_queue(struct wait_queue ** p, struct wait_queue * wait)
@@ -454,9 +538,9 @@ extern inline void remove_wait_queue(struct wait_queue ** p, struct wait_queue *
{
unsigned long flags;
- spin_lock_irqsave(&waitqueue_lock, flags);
+ write_lock_irqsave(&waitqueue_lock, flags);
__remove_wait_queue(p, wait);
- spin_unlock_irqrestore(&waitqueue_lock, flags);
+ write_unlock_irqrestore(&waitqueue_lock, flags);
}
extern inline void poll_wait(struct wait_queue ** wait_address, poll_table * p)
diff --git a/include/linux/serial.h b/include/linux/serial.h
index 372a06e51..f03f33dd5 100644
--- a/include/linux/serial.h
+++ b/include/linux/serial.h
@@ -46,7 +46,8 @@ struct serial_struct {
#define PORT_16650 6
#define PORT_16650V2 7
#define PORT_16750 8
-#define PORT_MAX 8
+#define PORT_STARTECH 9
+#define PORT_MAX 9
struct serial_uart_config {
char *name;
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 86a5e6417..a2617b15c 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -123,6 +123,9 @@ struct sk_buff
#endif
};
+/* These are just the default values. This is run time configurable.
+ * FIXME: Probably the config option should go away. -- erics
+ */
#ifdef CONFIG_SKB_LARGE
#define SK_WMEM_MAX 65535
#define SK_RMEM_MAX 65535
@@ -410,13 +413,15 @@ extern __inline__ void skb_unlink(struct sk_buff *skb)
restore_flags(flags);
}
+extern const char skb_put_errstr[];
+extern const char skb_push_errstr[];
+
/*
* Add data to an sk_buff
*/
extern __inline__ unsigned char *skb_put(struct sk_buff *skb, unsigned int len)
{
- extern char *skb_put_errstr;
unsigned char *tmp=skb->tail;
skb->tail+=len;
skb->len+=len;
@@ -431,7 +436,6 @@ here: ;
extern __inline__ unsigned char *skb_push(struct sk_buff *skb, unsigned int len)
{
- extern char *skb_push_errstr;
skb->data-=len;
skb->len+=len;
if(skb->data<skb->head)
diff --git a/include/linux/slab.h b/include/linux/slab.h
index ccd2ba1d3..08be13221 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -12,6 +12,7 @@
typedef struct kmem_cache_s kmem_cache_t;
#include <linux/mm.h>
+#include <asm/cache.h>
/* flags for kmem_cache_alloc() */
#define SLAB_BUFFER GFP_BUFFER /* 0x00 */
@@ -22,38 +23,48 @@ typedef struct kmem_cache_s kmem_cache_t;
#define SLAB_NFS GFP_NFS /* 0x05 */
#define SLAB_DMA GFP_DMA /* 0x08 */
#define SLAB_LEVEL_MASK GFP_LEVEL_MASK /* 0x0f */
-#define SLAB_NO_GROW 0x00001000UL /* don't add another slab during an alloc */
+#define SLAB_NO_GROW 0x00001000UL /* don't grow a cache */
/* flags to pass to kmem_cache_create().
- * The first 3 are only valid when the allocator has been build
+ * The first 3 are only valid when the allocator as been build
* SLAB_DEBUG_SUPPORT.
*/
-#define SLAB_DEBUG_FREE 0x00000100UL /* Peform time consuming ptr checks on free */
-#define SLAB_DEBUG_INITIAL 0x00000200UL /* Call constructor, on release, to conform state */
+#define SLAB_DEBUG_FREE 0x00000100UL /* Peform (expensive) checks on free */
+#define SLAB_DEBUG_INITIAL 0x00000200UL /* Call constructor (as verifier) */
#define SLAB_RED_ZONE 0x00000400UL /* Red zone objs in a cache */
-#define SLAB_HWCACHE_ALIGN 0x00000800UL /* align objs on an hw cache line */
+#define SLAB_POISION 0x00000800UL /* Poision objects */
+#define SLAB_NO_REAP 0x00001000UL /* never reap from the cache */
+#define SLAB_HWCACHE_ALIGN 0x00002000UL /* align objs on a h/w cache lines */
+#if 0
+#define SLAB_HIGH_PACK 0x00004000UL /* XXX */
+#endif
/* flags passed to a constructor func */
#define SLAB_CTOR_CONSTRUCTOR 0x001UL /* if not set, then deconstructor */
#define SLAB_CTOR_ATOMIC 0x002UL /* tell constructor it can't sleep */
-#define SLAB_DTOR_ATOMIC 0x002UL /* tell deconstructor it can't sleep */
#define SLAB_CTOR_VERIFY 0x004UL /* tell constructor it's a verify call */
/* prototypes */
extern long kmem_cache_init(long, long);
extern void kmem_cache_sizes_init(void);
-extern struct kmem_cache_s *kmem_cache_create(const char *, unsigned long, unsigned long, unsigned long, void (*)(void *, int, unsigned long), void (*)(void *, int, unsigned long));
-extern int kmem_cache_destroy(struct kmem_cache_s *);
-extern int kmem_cache_shrink(struct kmem_cache_s *, int);
-extern void *kmem_cache_alloc(struct kmem_cache_s *, unsigned long);
-extern void kmem_cache_free(struct kmem_cache_s *, void *);
-extern void *kmem_alloc(unsigned long, unsigned long);
-extern void kmem_free(void *, unsigned long);
+extern kmem_cache_t *kmem_find_general_cachep(size_t);
+extern kmem_cache_t *kmem_cache_create(const char *, size_t, size_t, unsigned long,
+ void (*)(void *, kmem_cache_t *, unsigned long),
+ void (*)(void *, kmem_cache_t *, unsigned long));
+extern int kmem_cache_shrink(kmem_cache_t *);
+extern void *kmem_cache_alloc(kmem_cache_t *, int);
+extern void kmem_cache_free(kmem_cache_t *, void *);
+
+extern void *kmalloc(size_t, int);
+extern void kfree(void *);
+extern void kfree_s(void *, size_t);
+
extern int kmem_cache_reap(int, int, int);
extern int get_slabinfo(char *);
-/* System wide slabs. */
-extern kmem_cache_t *vm_area_cachep;
+/* System wide caches */
+extern kmem_cache_t *vm_area_cachep;
+extern kmem_cache_t *mm_cachep;
#endif /* __KERNEL__ */
diff --git a/include/linux/smp.h b/include/linux/smp.h
index 72984f154..ff4427960 100644
--- a/include/linux/smp.h
+++ b/include/linux/smp.h
@@ -47,6 +47,7 @@ extern volatile int smp_msg_id;
#define smp_num_cpus 1
#define smp_processor_id() 0
+#define hard_smp_processor_id() 0
#define smp_message_pass(t,m,d,w)
#define smp_threads_ready 1
#define kernel_lock()
diff --git a/include/linux/socket.h b/include/linux/socket.h
index 756d4cca6..6d0ed9158 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -50,7 +50,6 @@ struct cmsghdr {
__kernel_size_t cmsg_len; /* data byte count, including hdr */
int cmsg_level; /* originating protocol */
int cmsg_type; /* protocol-specific type */
- unsigned char cmsg_data[0];
};
/*
@@ -58,17 +57,13 @@ struct cmsghdr {
* Table 5-14 of POSIX 1003.1g
*/
-#define CMSG_DATA(cmsg) (cmsg)->cmsg_data
#define CMSG_NXTHDR(mhdr, cmsg) cmsg_nxthdr(mhdr, cmsg)
#define CMSG_ALIGN(len) ( ((len)+sizeof(long)-1) & ~(sizeof(long)-1) )
-/* Stevens's Adv. API specifies CMSG_SPACE & CMSG_LENGTH,
- * I cannot understand, what the differenece? --ANK
- */
-
-#define CMSG_SPACE(len) CMSG_ALIGN((len)+sizeof(struct cmsghdr))
-#define CMSG_LENGTH(len) CMSG_ALIGN((len)+sizeof(struct cmsghdr))
+#define CMSG_DATA(cmsg) ((void *)(cmsg) + CMSG_ALIGN(sizeof(struct cmsghdr)))
+#define CMSG_SPACE(len) (CMSG_ALIGN(sizeof(struct cmsghdr)) + CMSG_ALIGN(len))
+#define CMSG_LEN(len) (CMSG_ALIGN(sizeof(struct cmsghdr)) + (len))
#define CMSG_FIRSTHDR(msg) ((msg)->msg_controllen >= sizeof(struct cmsghdr) ? \
(struct cmsghdr *)(msg)->msg_control : \
@@ -136,6 +131,7 @@ struct ucred
#define AF_DECNET 12 /* Reserved for DECnet project */
#define AF_NETBEUI 13 /* Reserved for 802.2LLC project*/
#define AF_SECURITY 14 /* Security callback pseudo AF */
+#define pseudo_AF_KEY 15 /* PF_KEY key management API */
#define AF_MAX 32 /* For now.. */
/* Protocol families, same as address families. */
@@ -155,6 +151,7 @@ struct ucred
#define PF_DECNET AF_DECNET
#define PF_NETBEUI AF_NETBEUI
#define PF_SECURITY AF_SECURITY
+#define PF_KEY pseudo_AF_KEY
#define PF_MAX AF_MAX
diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h
index 17e80e975..60fb2d74f 100644
--- a/include/linux/sunrpc/clnt.h
+++ b/include/linux/sunrpc/clnt.h
@@ -23,7 +23,7 @@ struct rpc_portmap {
__u32 pm_prog;
__u32 pm_vers;
__u32 pm_prot;
- __u32 pm_port;
+ __u16 pm_port;
};
/*
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index 0e01fba0f..e66f2bd87 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -104,6 +104,13 @@ enum
/* /proc/sys/net/core */
+enum
+{
+ NET_CORE_WMEM_MAX=1,
+ NET_CORE_RMEM_MAX,
+ NET_CORE_WMEM_DEFAULT,
+ NET_CORE_RMEM_DEFAULT,
+};
/* /proc/sys/net/ethernet */
@@ -140,6 +147,9 @@ enum
NET_IPV4_ACCEPT_REDIRECTS,
NET_IPV4_SECURE_REDIRECTS,
NET_IPV4_RFC1620_REDIRECTS,
+ NET_TCP_SYN_RETRIES,
+ NET_IPFRAG_HIGH_THRESH,
+ NET_IPFRAG_LOW_THRESH,
};
diff --git a/include/linux/tqueue.h b/include/linux/tqueue.h
index acebad9f2..de88d20d1 100644
--- a/include/linux/tqueue.h
+++ b/include/linux/tqueue.h
@@ -83,7 +83,7 @@ extern spinlock_t tqueue_lock;
extern __inline__ void queue_task(struct tq_struct *bh_pointer,
task_queue *bh_list)
{
- if (!set_bit(0,&bh_pointer->sync)) {
+ if (!test_and_set_bit(0,&bh_pointer->sync)) {
unsigned long flags;
spin_lock_irqsave(&tqueue_lock, flags);
bh_pointer->next = *bh_list;
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 7546d632d..109955a8d 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -294,6 +294,7 @@ extern int lp_init(void);
extern int pty_init(void);
extern int tty_init(void);
extern int pcxe_init(void);
+extern int pc_init(void);
extern int vcs_init(void);
extern int cy_init(void);
extern int stl_init(void);
@@ -336,11 +337,15 @@ extern int n_tty_ioctl(struct tty_struct * tty, struct file * file,
/* serial.c */
extern long serial_console_init(long kmem_start, long kmem_end);
-
+
/* pcxx.c */
extern int pcxe_open(struct tty_struct *tty, struct file *filp);
+/* epca.c */
+
+extern int pc_open(struct tty_struct *tty, struct file *filp);
+
/* console.c */
extern void update_screen(int new_console);
diff --git a/include/linux/zorro.h b/include/linux/zorro.h
index e19289877..95148b35d 100644
--- a/include/linux/zorro.h
+++ b/include/linux/zorro.h
@@ -301,648 +301,6 @@
#define PROD_MASTER_CARD_SCSI (0x04) /* Master Card SCSI Controller */
#define PROD_MVD_819 (0x07) /* MVD 819 */
-#define MANUF_DELACOMP (0x0873) /* DelaComp */
-#define PROD_DELACOMP_RAM_2000 (0x01) /* RAM Expansion 2000 */
-
-#define MANUF_VILLAGE_TRONIC (0x0877) /* Village Tronic */
-#define PROD_DOMINO_RAM (0x01) /* Domino Graphics Board */
-#define PROD_DOMINO_REG (0x02)
-#define PROD_PICASSO_II_RAM (0x0B) /* Picasso II/II+ Graphics Board */
-#define PROD_PICASSO_II_REG (0x0C)
-#define PROD_PICASSO_II_SEGM (0x0D) /* Picasso II/II+ (Segmented Mode) */
-#define PROD_PICASSO_IV (0x15) /* Picassio IV Graphics Board */
-#define PROD_PICASSO_IV_2 (0x16)
-#define PROD_PICASSO_IV_3 (0x17)
-#define PROD_PICASSO_IV_4 (0x18)
-#define PROD_ARIADNE (0xC9) /* Ariadne Ethernet */
-
-#define MANUF_UTILITIES_ULTD (0x087B) /* Utilities Unlimited */
-#define PROD_EMPLANT_DELUXE (0x15) /* Emplant Deluxe SCSI Controller */
-#define PROD_EMPLANT_DELUXE2 (0x20) /* Emplant Deluxe SCSI Controller */
-
-#define MANUF_AMITRIX (0x0880) /* Amitrix */
-#define PROD_AMITRIX_MULTI_IO (0x01) /* Multi-IO */
-#define PROD_AMITRIX_CD_RAM (0x02) /* CD-RAM Memory */
-
-#define MANUF_ARMAX (0x0885) /* ArMax */
-#define PROD_OMNIBUS (0x00) /* OmniBus Graphics Board */
-
-#define MANUF_NEWTEK (0x088F) /* NewTek */
-#define PROD_VIDEOTOASTER (0x00) /* VideoToaster */
-
-#define MANUF_MTEC (0x0890) /* M-Tech Germany */
-#define PROD_AT500 (0x01) /* AT500 IDE Controller */
-#define PROD_MTEC_68030 (0x03) /* 68030 Turbo Board */
-#define PROD_MTEC_68020I (0x06) /* 68020i Turbo Board */
-#define PROD_MTEC_T1230 (0x20) /* A1200 T68030/42 RTC Turbo Board */
-#define PROD_MTEC_RAM (0x22) /* MTEC 8MB RAM */
-
-#define MANUF_GVP2 (0x0891) /* Great Valley Products */
-#define PROD_SPECTRUM_RAM (0x01) /* EGS 28/24 Spectrum Graphics Board */
-#define PROD_SPECTRUM_REG (0x02)
-
-#define MANUF_HELFRICH2 (0x0893) /* Helfrich */
-#define PROD_PICCOLO_RAM (0x05) /* Piccolo Graphics Board */
-#define PROD_PICCOLO_REG (0x06)
-#define PROD_PEGGY_PLUS (0x07) /* PeggyPlus MPEG Decoder Board */
-#define PROD_VIDEOCRUNCHER (0x08) /* VideoCruncher */
-#define PROD_SD64_RAM (0x0A) /* SD64 Graphics Board */
-#define PROD_SD64_REG (0x0B)
-
-#define MANUF_MACROSYSTEMS (0x089B) /* MacroSystems USA */
-#define PROD_WARP_ENGINE (0x13) /* Warp Engine 40xx SCSI Controller */
-
-#define MANUF_ELBOX (0x089E) /* ElBox Computer */
-#define PROD_ELBOX_1200 (0x06) /* Elbox 1200/4 RAM */
-
-#define MANUF_HARMS_PROF (0x0A00) /* Harms Professional */
-#define PROD_HARMS_030_PLUS (0x10) /* 030 plus */
-#define PROD_3500_TURBO (0xD0) /* 3500 Turbo board */
-
-#define MANUF_MICRONIK (0x0A50) /* Micronik */
-#define PROD_RCA_120 (0x0A) /* RCA 120 RAM */
-
-#define MANUF_MEGA_MICRO (0x1000) /* MegaMicro */
-#define PROD_SCRAM_500_SCSI (0x03) /* SCRAM 500 SCSI Controller */
-#define PROD_SCRAM_500_RAM (0x04) /* SCRAM 500 RAM */
-
-#define MANUF_IMTRONICS2 (0x1028) /* Imtronics */
-#define PROD_HURRICANE_2800_3 (0x39) /* Hurricane 2800 68030 */
-#define PROD_HURRICANE_2800_4 (0x57) /* Hurricane 2800 68030 */
-
-#define MANUF_KUPKE3 (0x1248) /* Kupke */
-#define PROD_GOLEM_3000 (0x01) /* Golem HD 3000 */
-
-#define MANUF_ITH (0x1388) /* ITH */
-#define PROD_ISDN_MASTER_II (0x01) /* ISDN-Master II */
-
-#define MANUF_VMC (0x1389) /* VMC */
-#define PROD_ISDN_BLASTER_Z2 (0x01) /* ISDN Blaster Z2 */
-#define PROD_HYPERCOM_4 (0x02) /* HyperCom 4 */
-
-#define MANUF_INFORMATION (0x157C) /* Information */
-#define PROD_ISDN_ENGINE_I (0x64) /* ISDN Engine I */
-
-#define MANUF_VORTEX (0x2017) /* Vortex */
-#define PROD_GOLDEN_GATE_386SX (0x07) /* Golden Gate 80386SX Board */
-#define PROD_GOLDEN_GATE_RAM (0x08) /* Golden Gate RAM */
-#define PROD_GOLDEN_GATE_486 (0x09) /* Golden Gate 80486 Board */
-
-#define MANUF_DATAFLYER (0x2062) /* DataFlyer */
-#define PROD_DATAFLYER_4000SXS (0x01) /* DataFlyer 4000SX SCSI Controller */
-#define PROD_DATAFLYER_4000SXR (0x02) /* DataFlyer 4000SX RAM */
-
-#define MANUF_READYSOFT (0x2100) /* ReadySoft */
-#define PROD_AMAX (0x01) /* AMax II/IV */
-
-#define MANUF_PHASE5 (0x2140) /* Phase5 */
-#define PROD_BLIZZARD_RAM (0x01) /* Blizzard RAM */
-#define PROD_BLIZZARD (0x02) /* Blizzard */
-#define PROD_BLIZZARD_1220_IV (0x06) /* Blizzard 1220-IV Turbo Board */
-#define PROD_FASTLANE_RAM (0x0A) /* FastLane RAM */
-#define PROD_FASTLANE_SCSI (0x0B) /* FastLane/Blizzard 1230-II SCSI/CyberSCSI */
-#define PROD_CYBERSTORM_SCSI (0x0C) /* Blizzard 1220/CyberStorm */
-#define PROD_BLIZZARD_1230_III (0x0D) /* Blizzard 1230-III Turbo Board */
-#define PROD_BLIZZARD_1230_IV (0x11) /* Blizzard 1230-IV/1260 Turbo Board */
-#define PROD_BLIZZARD_2060SCSI (0x18) /* Blizzard 2060 SCSI Controller */
-#define PROD_CYBERSTORM_II (0x19) /* CyberStorm Mk II */
-#define PROD_CYBERVISION (0x22) /* CyberVision64 Graphics Board */
-#define PROD_CYBERVISION3D_PRT (0x32) /* CyberVision64-3D Prototype */
-#define PROD_CYBERVISION3D (0x43) /* CyberVision64-3D Graphics Board */
-
-#define MANUF_DPS (0x2169) /* DPS */
-#define PROD_DPS_PAR (0x01) /* Personal Animation Recorder */
-
-#define MANUF_APOLLO2 (0x2200) /* Apollo */
-#define PROD_A620 (0x00) /* A620 68020 Accelerator */
-#define PROD_A620_2 (0x01) /* A620 68020 Accelerator */
-
-#define MANUF_APOLLO (0x2222) /* Apollo */
-#define PROD_AT_APOLLO (0x22) /* AT-Apollo */
-#define PROD_APOLLO_TURBO (0x23) /* Apollo Turbo Board */
-
-#define MANUF_PETSOFF (0x38A5) /* Petsoff LP */
-#define PROD_DELFINA (0x00) /* Delfina DSP */
-
-#define MANUF_UWE_GERLACH (0x3FF7) /* Uwe Gerlach */
-#define PROD_UG_RAM_ROM (0xd4) /* RAM/ROM */
-
-#define MANUF_MACROSYSTEMS2 (0x4754) /* MacroSystems Germany */
-#define PROD_MAESTRO (0x03) /* Maestro */
-#define PROD_VLAB (0x04) /* VLab */
-#define PROD_MAESTRO_PRO (0x05) /* Maestro Pro */
-#define PROD_RETINA_Z2 (0x06) /* Retina Z2 Graphics Board */
-#define PROD_MULTI_EVOLUTION (0x08) /* MultiEvolution */
-#define PROD_TOCCATA (0x0C) /* Toccata Sound Board */
-#define PROD_RETINA_Z3 (0x10) /* Retina Z3 Graphics Board */
-#define PROD_VLAB_MOTION (0x12) /* VLab Motion */
-#define PROD_ALTAIS (0x13) /* Altais Graphics Board */
-#define PROD_FALCON_040 (0xFD) /* Falcon '040 Turbo Board */
-
-#define MANUF_COMBITEC (0x6766) /* Combitec */
-
-#define MANUF_SKI (0x8000) /* SKI Peripherals */
-#define PROD_MAST_FIREBALL (0x08) /* M.A.S.T. Fireball SCSI Controller */
-#define PROD_SKI_SCSI_SERIAL (0x80) /* SCSI / Dual Serial */
-
-#define MANUF_CAMERON (0xAA01) /* Cameron */
-#define PROD_PERSONAL_A4 (0x10) /* Personal A4 */
-
-#define MANUF_REIS_WARE (0xAA11) /* Reis-Ware */
-#define PROD_RW_HANDYSCANNER (0x11) /* Handyscanner */
-
-
-/* Illegal Manufacturer IDs. These do NOT appear in arch/m68k/amiga/zorro.c! */
-
-#define MANUF_HACKER_INC (0x07DB) /* Hacker Inc. */
-#define PROD_HACKER_SCSI (0x01) /* Hacker Inc. SCSI Controller */
-
-#define MANUF_RES_MNGT_FORCE (0x07DB) /* Resource Management Force */
-#define PROD_QUICKNET (0x02) /* QuickNet Ethernet */
-
-#define MANUF_VECTOR2 (0x07DB) /* Vector */
-#define PROD_CONNECTION_2 (0xE0) /* Vector Connection */
-#define PROD_CONNECTION_3 (0xE1) /* Vector Connection */
-#define PROD_CONNECTION_4 (0xE2) /* Vector Connection */
-#define PROD_CONNECTION_5 (0xE3) /* Vector Connection */
-
-
-/*
- * GVP's identifies most of their product through the 'extended
- * product code' (epc). The epc has to be and'ed with the GVP_PRODMASK
- * before the identification.
- */
-
-#define GVP_PRODMASK (0xf8)
-#define GVP_SCSICLKMASK (0x01)
-
-enum GVP_ident {
- GVP_GFORCE_040 = 0x20,
- GVP_GFORCE_040_SCSI = 0x30,
- GVP_A1291_SCSI = 0x40,
- GVP_COMBO_R4 = 0x60,
- GVP_COMBO_R4_SCSI = 0x70,
- GVP_PHONEPAK = 0x78,
- GVP_IOEXT = 0x98,
- GVP_GFORCE_030 = 0xa0,
- GVP_GFORCE_030_SCSI = 0xb0,
- GVP_A530 = 0xc0,
- GVP_A530_SCSI = 0xd0,
- GVP_COMBO_R3 = 0xe0,
- GVP_COMBO_R3_SCSI = 0xf0,
- GVP_SERIESII = 0xf8,
-};
-
-enum GVP_flags {
- GVP_IO = 0x01,
- GVP_ACCEL = 0x02,
- GVP_SCSI = 0x04,
- GVP_24BITDMA = 0x08,
- GVP_25BITDMA = 0x10,
- GVP_NOBANK = 0x20,
- GVP_14MHZ = 0x40,
-};
-
-
-struct Node {
- struct Node *ln_Succ; /* Pointer to next (successor) */
- struct Node *ln_Pred; /* Pointer to previous (predecessor) */
- u_char ln_Type;
- char ln_Pri; /* Priority, for sorting */
- char *ln_Name; /* ID string, null terminated */
-};
-
-struct ExpansionRom {
- /* -First 16 bytes of the expansion ROM */
- u_char er_Type; /* Board type, size and flags */
- u_char er_Product; /* Product number, assigned by manufacturer */
- u_char er_Flags; /* Flags */
- u_char er_Reserved03; /* Must be zero ($ff inverted) */
- u_short er_Manufacturer; /* Unique ID,ASSIGNED BY COMMODORE-AMIGA! */
- u_long er_SerialNumber; /* Available for use by manufacturer */
- u_short er_InitDiagVec; /* Offset to optional "DiagArea" structure */
- u_char er_Reserved0c;
- u_char er_Reserved0d;
- u_char er_Reserved0e;
- u_char er_Reserved0f;
-};
-
-/* er_Type board type bits */
-#define ERT_TYPEMASK 0xc0
-#define ERT_ZORROII 0xc0
-#define ERT_ZORROIII 0x80
-
-/* other bits defined in er_Type */
-#define ERTB_MEMLIST 5 /* Link RAM into free memory list */
-#define ERTF_MEMLIST (1<<5)
-
-struct ConfigDev {
- struct Node cd_Node;
- u_char cd_Flags; /* (read/write) */
- u_char cd_Pad; /* reserved */
- struct ExpansionRom cd_Rom; /* copy of board's expansion ROM */
- void *cd_BoardAddr; /* where in memory the board was placed */
- u_long cd_BoardSize; /* size of board in bytes */
- u_short cd_SlotAddr; /* which slot number (PRIVATE) */
- u_short cd_SlotSize; /* number of slots (PRIVATE) */
- void *cd_Driver; /* pointer to node of driver */
- struct ConfigDev *cd_NextCD; /* linked list of drivers to config */
- u_long cd_Unused[4]; /* for whatever the driver wants */
-};
-
-#else /* __ASSEMBLY__ */
-
-LN_Succ = 0
-LN_Pred = LN_Succ+4
-LN_Type = LN_Pred+4
-LN_Pri = LN_Type+1
-LN_Name = LN_Pri+1
-LN_sizeof = LN_Name+4
-
-ER_Type = 0
-ER_Product = ER_Type+1
-ER_Flags = ER_Product+1
-ER_Reserved03 = ER_Flags+1
-ER_Manufacturer = ER_Reserved03+1
-ER_SerialNumber = ER_Manufacturer+2
-ER_InitDiagVec = ER_SerialNumber+4
-ER_Reserved0c = ER_InitDiagVec+2
-ER_Reserved0d = ER_Reserved0c+1
-ER_Reserved0e = ER_Reserved0d+1
-ER_Reserved0f = ER_Reserved0e+1
-ER_sizeof = ER_Reserved0f+1
-
-CD_Node = 0
-CD_Flags = CD_Node+LN_sizeof
-CD_Pad = CD_Flags+1
-CD_Rom = CD_Pad+1
-CD_BoardAddr = CD_Rom+ER_sizeof
-CD_BoardSize = CD_BoardAddr+4
-CD_SlotAddr = CD_BoardSize+4
-CD_SlotSize = CD_SlotAddr+2
-CD_Driver = CD_SlotSize+2
-CD_NextCD = CD_Driver+4
-CD_Unused = CD_NextCD+4
-CD_sizeof = CD_Unused+(4*4)
-
-#endif /* __ASSEMBLY__ */
-
-#ifndef __ASSEMBLY__
-
-#define ZORRO_NUM_AUTO 16
-
-#ifdef __KERNEL__
-
-extern int zorro_num_autocon; /* # of autoconfig devices found */
-extern struct ConfigDev zorro_autocon[ZORRO_NUM_AUTO];
-
-
-/*
- * Zorro Functions
- */
-
-extern int zorro_find(int manuf, int prod, int part, int index);
-extern struct ConfigDev *zorro_get_board(int key);
-extern void zorro_config_board(int key, int part);
-extern void zorro_unconfig_board(int key, int part);
-
-
-/*
- * Bitmask indicating portions of available Zorro II RAM that are unused
- * by the system. Every bit represents a 64K chunk, for a maximum of 8MB
- * (128 chunks, physical 0x00200000-0x009fffff).
- *
- * If you want to use (= allocate) portions of this RAM, you should clear
- * the corresponding bits.
- */
-
-extern u_long zorro_unused_z2ram[4];
-
-#define Z2RAM_START (0x00200000)
-#define Z2RAM_END (0x00a00000)
-#define Z2RAM_SIZE (0x00800000)
-#define Z2RAM_CHUNKSIZE (0x00010000)
-#define Z2RAM_CHUNKMASK (0x0000ffff)
-#define Z2RAM_CHUNKSHIFT (16)
-
-
-/*
- * Verbose Board Identification
- */
-
-extern void zorro_identify(void);
-extern int zorro_get_list(char *buffer);
-
-#endif /* !__ASSEMBLY__ */
-#endif /* __KERNEL__ */
-
-#endif /* __ZORRO_H */
-/*
- * linux/zorro.h -- Amiga AutoConfig (Zorro) Expansion Device Definitions
- *
- * Copyright (C) 1995 Geert Uytterhoeven
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-#ifndef __ZORRO_H
-#define __ZORRO_H
-
-#ifndef __ASSEMBLY__
-
-/*
- * Defined Board Manufacturers
- *
- * Please update arch/m68k/amiga/zorro.c if you make changes here
- * Many IDs were obtained from ExpName/Identify ((C) Richard Körber)
- * and by looking at the NetBSD-Amiga kernel sources
- */
-
-#define MANUF_PACIFIC (0x00D3) /* Pacific Peripherals */
-#define PROD_SE_2000_A500 (0x00) /* SE 2000 A500 */
-#define PROD_PACIFIC_HD (0x0A) /* HD Controller */
-
-#define MANUF_KUPKE (0x00DD) /* Kupke */
-#define PROD_GOLEM_BOX_2 (0x00) /* Golem RAM Box 2MB */
-
-#define MANUF_MEMPHIS (0x0100) /* Memphis */
-#define PROD_STORMBRINGER (0x00) /* Stormbringer */
-
-#define MANUF_3_STATE (0x0200) /* 3-State */
-#define PROD_MEGAMIX_2000 (0x02) /* Megamix 2000 RAM */
-
-#define MANUF_COMMODORE2 (0x0201) /* Commodore Braunschweig */
-#define PROD_A2088 (0x01) /* CBM A2088 XT Bridgeboard */
-#define PROD_A2286 (0x02) /* CBM A2286 AT Bridgeboard */
-#define PROD_A4091_2 (0x54) /* CBM A4091 SCSI Controller */
-#define PROD_A2386SX (0x67) /* CBM A2386-SX Bridgeboard */
-
-#define MANUF_COMMODORE (0x0202) /* Commodore West Chester */
-#define PROD_A2090A (0x01) /* CBM A2090/A2090A HD Controller */
-#define PROD_A590 (0x02) /* CBM A590 SCSI Controller */
-#define PROD_A2091 (0x03) /* CBM A2091 SCSI Controller */
-#define PROD_A2090B (0x04) /* CBM A2090B 2090 Autoboot Card */
-#define PROD_ARCNET (0x09) /* CBM A2060 Arcnet Card */
-#define PROD_CBMRAM (0x0A) /* CBM A2052/58.RAM | 590/2091.RAM */
-#define PROD_A560RAM (0x20) /* CBM A560 Memory Module */
-#define PROD_A2232PROTO (0x45) /* CBM A2232 Serial Prototype */
-#define PROD_A2232 (0x46) /* CBM A2232 Serial Production */
-#define PROD_A2620 (0x50) /* CBM A2620 68020/RAM Card */
-#define PROD_A2630 (0x51) /* CBM A2630 68030/RAM Card */
-#define PROD_A4091 (0x54) /* CBM A4091 SCSI Controller */
-#define PROD_A2065_2 (0x5A) /* A2065 Ethernet Card */
-#define PROD_ROMULATOR (0x60) /* CBM Romulator Card */
-#define PROD_A3000TESTFIX (0x61) /* CBM A3000 Test Fixture */
-#define PROD_A2386SX_2 (0x67) /* A2386-SX Bridgeboard */
-#define PROD_A2065 (0x70) /* CBM A2065 Ethernet Card */
-
-#define MANUF_COMMODORE3 (0x0203) /* Commodore West Chester */
-#define PROD_A2090A_CM (0x03) /* A2090A Combitec/MacroSystem */
-
-#define MANUF_KCS (0x02FF) /* Kolff Computer Supplies */
-#define PROD_POWER_BOARD (0x00) /* KCS Power PC Board */
-
-#define MANUF_CARDCO (0x03EC) /* Cardco */
-#define PROD_KRONOS_2000_SCSI (0x04) /* Kronos 2000 SCSI Controller */
-#define PROD_A1000_SCSI (0x0C) /* A1000 SCSI Controller */
-#define PROD_ESCORT_SCSI (0x0E) /* Escort SCSI Controller */
-#define PROD_CC_A2410 (0xF5) /* Cardco A2410 Hires Graphics Card */
-
-#define MANUF_A_SQUARED (0x03ED) /* A-Squared */
-#define PROD_LIVE_2000 (0x01) /* Live! 2000 */
-
-#define MANUF_COMSPEC (0x03EE) /* ComSpec Communications */
-#define PROD_AX2000 (0x01) /* AX2000 */
-
-#define MANUF_ANAKIN (0x03F1) /* Anakin */
-#define PROD_EASYL (0x01) /* Easyl Tablet */
-
-#define MANUF_MICROBOTICS (0x03F2) /* MicroBotics */
-#define PROD_STARBOARD_II (0x00) /* StarBoard II */
-#define PROD_STARDRIVE (0x02) /* StarDrive */
-#define PROD_8_UP_A (0x03) /* 8-Up (Rev A) */
-#define PROD_8_UP_Z (0x04) /* 8-Up (Rev Z) */
-#define PROD_DELTA_RAM (0x20) /* Delta Card RAM */
-#define PROD_8_STAR_RAM (0x40) /* 8-Star RAM */
-#define PROD_8_STAR (0x41) /* 8-Star */
-#define PROD_VXL_RAM (0x44) /* VXL RAM */
-#define PROD_VXL_30 (0x45) /* VXL-30 Turbo Board */
-#define PROD_DELTA (0x60) /* Delta Card */
-#define PROD_MBX_1200 (0x81) /* MBX 1200 */
-#define PROD_HARDFRAME_2000 (0x9E) /* Hardframe 2000 */
-#define PROD_MBX_1200_2 (0xC1) /* MBX 1200 */
-
-#define MANUF_ACCESS (0x03F4) /* Access Associates */
-
-#define MANUF_EXPANSION_TECH (0x03F6) /* Expansion Technologies */
-
-#define MANUF_ASDG (0x03FF) /* ASDG */
-#define PROD_ASDG_MEMORY (0x01) /* Memory Expansion */
-#define PROD_ASDG_MEMORY_2 (0x02) /* Memory Expansion */
-#define PROD_LAN_ROVER (0xFE) /* Lan Rover Ethernet */
-#define PROD_TWIN_X (0xFF) /* Twin-X Serial Card */
-
-#define MANUF_IMTRONICS (0x0404) /* Imtronics */
-#define PROD_HURRICANE_2800 (0x39) /* Hurricane 2800 68030 */
-#define PROD_HURRICANE_2800_2 (0x57) /* Hurricane 2800 68030 */
-
-#define MANUF_UNIV_OF_LOWELL (0x0406) /* University of Lowell */
-#define PROD_A2410 (0x00) /* CBM A2410 Hires Graphics Card */
-
-#define MANUF_AMERISTAR (0x041D) /* Ameristar */
-#define PROD_AMERISTAR2065 (0x01) /* A2065 Ethernet Card */
-#define PROD_A560 (0x09) /* Arcnet Card */
-#define PROD_A4066 (0x0A) /* A4066 Ethernet Card */
-
-#define MANUF_SUPRA (0x0420) /* Supra */
-#define PROD_SUPRADRIVE_4x4 (0x01) /* SupraDrive 4x4 SCSI Controller */
-#define PROD_SUPRA_2000 (0x03) /* 2000 DMA HD */
-#define PROD_SUPRA_500 (0x05) /* 500 HD/RAM */
-#define PROD_SUPRA_500XP (0x09) /* 500XP/2000 RAM */
-#define PROD_SUPRA_500RX (0x0A) /* 500RX/2000 RAM */
-#define PROD_SUPRA_2400ZI (0x0B) /* 2400zi Modem */
-#define PROD_WORDSYNC (0x0C) /* Supra Wordsync SCSI Controller */
-#define PROD_WORDSYNC_II (0x0D) /* Supra Wordsync II SCSI Controller */
-#define PROD_SUPRA_2400ZIPLUS (0x10) /* 2400zi+ Modem */
-
-#define MANUF_CSA (0x0422) /* Computer Systems Ass. */
-#define PROD_MAGNUM (0x11) /* Magnum 40 SCSI Controller */
-#define PROD_12GAUGE (0x15) /* 12 Gauge SCSI Controller */
-
-#define MANUF_MTEC2 (0x0502) /* M-Tech */
-#define PROD_AT500_2 (0x03) /* AT500 RAM */
-
-#define MANUF_GVP3 (0x06E1) /* Great Valley Products */
-#define PROD_IMPACT (0x08) /* Impact SCSI/Memory */
-
-#define MANUF_BYTEBOX (0x07DA) /* ByteBox */
-#define PROD_BYTEBOX_A500 (0x00) /* A500 */
-
-#define MANUF_HACKER (0x07DB) /* Test only: no product definitions */
-
-#define MANUF_POWER_COMPUTING (0x07DC) /* Power Computing (DKB) */
-#define PROD_DKB_3128 (0x0E) /* DKB 3128 RAM */
-#define PROD_RAPID_FIRE (0x0F) /* Rapid Fire SCSI Controller */
-#define PROD_DKB_1202 (0x10) /* DKB 1202 RAM */
-#define PROD_VIPER_II_COBRA (0x12) /* Viper II Turbo Board (DKB Cobra) */
-#define PROD_WILDFIRE_060 (0x17) /* WildFire 060 Turbo Board */
-#define PROD_WILDFIRE_060_2 (0xFF) /* WildFire 060 Turbo Board */
-
-#define MANUF_GVP (0x07E1) /* Great Valley Products */
-#define PROD_IMPACT_I_4K (0x01) /* Impact Series-I SCSI 4K */
-#define PROD_IMPACT_I_16K_2 (0x02) /* Impact Series-I SCSI 16K/2 */
-#define PROD_IMPACT_I_16K_3 (0x03) /* Impact Series-I SCSI 16K/3 */
-#define PROD_IMPACT_3001_IDE (0x08) /* Impact 3001 IDE */
-#define PROD_IMPACT_3001_RAM (0x09) /* Impact 3001 RAM */
-#define PROD_GVPIISCSI (0x0B) /* GVP Series II SCSI Controller */
-#define PROD_GVPIISCSI_2 (0x09) /* evidence that the driver works
- for this product code also */
-#define PROD_GVPIIRAM (0x0A) /* GVP Series II RAM */
-#define PROD_GVP (0x0B) /* This code is used by a wide range of
- GVP products - use the epc to
- identify it correctly */
-#define PROD_GVP_A2000_030 (0x0D) /* GVP A2000 68030 Turbo Board */
-#define PROD_IMPACT_3001_IDE_2 (0x0D) /* Impact 3001 IDE */
-#define PROD_GFORCE_040_SCSI (0x16) /* GForce 040 with SCSI (new) */
-#define PROD_GVPIV_24 (0x20) /* GVP IV-24 Graphics Board */
-#define PROD_GFORCE_040 (0xFF) /* GForce 040 Turbo Board */
-/* #define PROD_GVPIO_EXT (0xFF)*/ /* GVP I/O Extender */
-
-#define MANUF_SYNERGY (0x07E5) /* Synergy */
-
-#define MANUF_XETEC (0x07E6) /* Xetec */
-#define PROD_FASTCARD_SCSI (0x01) /* FastCard SCSI Controller */
-#define PROD_FASTCARD_RAM (0x02) /* FastCard RAM */
-
-#define MANUF_PPI (0x07EA) /* Progressive Peripherals Inc. */
-#define PROD_MERCURY (0x00) /* Mercury Turbo Board */
-#define PROD_PPS_A3000_040 (0x01) /* PP&S A3000 68040 Turbo Board */
-#define PROD_PPS_A2000_040 (0x69) /* PP&S A2000 68040 Turbo Board */
-#define PROD_ZEUS (0x96) /* Zeus SCSI Controller */
-#define PROD_PPS_A500_040 (0xBB) /* PP&S A500 68040 Turbo Board */
-
-#define MANUF_XEBEC (0x07EC) /* Xebec */
-
-#define MANUF_SPIRIT (0x07F2) /* Spirit */
-#define PROD_HDA_506 (0x04) /* HDA 506 Harddisk */
-#define PROD_OCTABYTE_RAM (0x06) /* OctaByte RAM */
-
-#define MANUF_BSC (0x07FE) /* BSC */
-#define PROD_ALF_3_SCSI (0x03) /* BSC ALF 3 SCSI Controller */
-
-#define MANUF_BSC3 (0x0801) /* BSC */
-#define PROD_ALF_2_SCSI (0x01) /* ALF 2 SCSI Controller */
-#define PROD_ALF_2_SCSI_2 (0x02) /* ALF 2 SCSI Controller */
-#define PROD_ALF_3_SCSI_2 (0x03) /* ALF 3 SCSI Controller */
-
-#define MANUF_C_LTD (0x0802) /* C Ltd. */
-#define PROD_KRONOS_SCSI (0x04) /* Kronos SCSI Controller */
-#define PROD_A1000_SCSI_2 (0x0C) /* A1000 SCSI Controller */
-
-#define MANUF_JOCHHEIM (0x0804) /* Jochheim */
-#define PROD_JOCHHEIM_RAM (0x01) /* Jochheim RAM */
-
-#define MANUF_CHECKPOINT (0x0807) /* Checkpoint Technologies */
-#define PROD_SERIAL_SOLUTION (0x00) /* Serial Solution */
-
-#define MANUF_ICD (0x0817) /* ICD */
-#define PROD_ADVANTAGE_2000 (0x01) /* Advantage 2000 SCSI Controller */
-
-#define MANUF_KUPKE2 (0x0819) /* Kupke */
-#define PROD_KUPKE_SCSI_II (0x02) /* Golem SCSI-II Controller */
-#define PROD_GOLEM_BOX (0x03) /* Golem Box */
-#define PROD_KUPKE_TURBO (0x04) /* 030/882 Turbo Board */
-#define PROD_KUPKE_SCSI_AT (0x05) /* SCSI/AT Controller */
-
-#define MANUF_GVP4 (0x081D) /* Great Valley Products */
-#define PROD_A2000_RAM8 (0x09) /* A2000-RAM8/2 */
-
-#define MANUF_INTERWORKS_NET (0x081E) /* Interworks Network */
-
-#define MANUF_HARDITAL (0x0820) /* Hardital Synthesis */
-#define PROD_TQM (0x14) /* TQM 68030+68882 Turbo Board */
-
-#define MANUF_BSC2 (0x082C) /* BSC */
-#define PROD_OKTAGON_SCSI (0x05) /* BSC Oktagon 2008 SCSI Controller */
-#define PROD_TANDEM (0x06) /* BSC Tandem AT-2008/508 IDE */
-#define PROD_ALPHA_RAM_1200 (0x07) /* Alpha RAM 1200 */
-#define PROD_OKTAGON_RAM (0x08) /* BSC Oktagon 2008 RAM */
-#define PROD_MULTIFACE_I (0x10) /* Alfa Data MultiFace I */
-#define PROD_MULTIFACE_II (0x11) /* Alfa Data MultiFace II */
-#define PROD_MULTIFACE_III (0x12) /* Alfa Data MultiFace III */
-#define PROD_BSC_FRAEMBUFFER (0x20) /* Framebuffer */
-#define PROD_GRAFFITI_RAM (0x21) /* Graffiti Graphics Board */
-#define PROD_GRAFFITI_REG (0x22)
-#define PROD_ISDN_MASTERCARD (0x40) /* BSC ISDN MasterCard */
-#define PROD_ISDN_MASTERCARD_2 (0x41) /* BSC ISDN MasterCard II */
-
-#define MANUF_ADV_SYS_SOFT (0x0836) /* Advanced Systems & Software */
-#define PROD_NEXUS_SCSI (0x01) /* Nexus SCSI Controller */
-#define PROD_NEXUS_RAM (0x08) /* Nexus RAM */
-
-#define MANUF_IMPULSE (0x0838) /* Impulse */
-#define PROD_FIRECRACKER_24 (0x00) /* FireCracker 24 */
-
-#define MANUF_IVS (0x0840) /* IVS */
-#define PROD_GRANDSLAM_PIC_2 (0x02) /* GrandSlam PIC 2 RAM */
-#define PROD_GRANDSLAM_PIC_1 (0x04) /* GrandSlam PIC 1 RAM */
-#define PROD_IVS_OVERDRIVE (0x10) /* OverDrive HD */
-#define PROD_TRUMPCARD_CLASSIC (0x30) /* Trumpcard Classic SCSI Controller */
-#define PROD_TRUMPCARD_PRO (0x34) /* Trumpcard Pro SCSI Controller */
-#define PROD_META_4 (0x40) /* Meta-4 RAM */
-#define PROD_WAVETOOLS (0xBF) /* Wavetools Sound Board */
-#define PROD_VECTOR (0xF3) /* Vector SCSI Controller */
-#define PROD_VECTOR_2 (0xF4) /* Vector SCSI Controller */
-
-#define MANUF_VECTOR (0x0841) /* Vector */
-#define PROD_CONNECTION (0xE3) /* Connection Serial IO */
-
-#define MANUF_XPERT_PRODEV (0x0845) /* XPert/ProDev */
-#define PROD_VISIONA_RAM (0x01) /* Visiona Graphics Board */
-#define PROD_VISIONA_REG (0x02)
-#define PROD_MERLIN_RAM (0x03) /* Merlin Graphics Board */
-#define PROD_MERLIN_REG (0x04)
-#define PROD_MERLIN_REG_2 (0xC9)
-
-#define MANUF_HYDRA_SYSTEMS (0x0849) /* Hydra Systems */
-#define PROD_AMIGANET (0x01) /* Amiganet Board */
-
-#define MANUF_SUNRIZE (0x084F) /* Sunrize Industries */
-#define PROD_AD1012 (0x01) /* AD1012 Sound Board */
-#define PROD_AD516 (0x02) /* AD516 Sound Board */
-#define PROD_DD512 (0x03) /* DD512 Sound Board */
-
-#define MANUF_TRICERATOPS (0x0850) /* Triceratops */
-#define PROD_TRICERATOPS (0x01) /* Triceratops Multi I/O Board */
-
-#define MANUF_APPLIED_MAGIC (0x0851) /* Applied Magic Inc */
-#define PROD_DMI_RESOLVER (0x01) /* DMI Resolver Graphics Board */
-#define PROD_DIGITAL_BCASTER (0x06) /* Digital Broadcaster */
-
-#define MANUF_GFX_BASE (0x085E) /* GFX-Base */
-#define PROD_GDA_1_RAM (0x00) /* GDA-1 Graphics Board */
-#define PROD_GDA_1_REG (0x01)
-
-#define MANUF_ROCTEC (0x0860) /* RocTec */
-#define PROD_RH_800C (0x01) /* RH 800C Hard Disk Controller */
-#define PROD_RH_800C_RAM (0x01) /* RH 800C RAM */
-
-#define MANUF_HELFRICH1 (0x0861) /* Helfrich */
-#define PROD_RAINBOW3 (0x21) /* Rainbow3 Graphics Board */
-
-#define MANUF_SW_RESULT_ENTS (0x0866) /* Software Result Enterprises */
-#define PROD_GG2PLUS (0x01) /* GG2+ Bus Converter */
-
-#define MANUF_MASOBOSHI (0x086D) /* Masoboshi */
-#define PROD_MASTER_CARD_RAM (0x03) /* Master Card RAM */
-#define PROD_MASTER_CARD_SCSI (0x04) /* Master Card SCSI Controller */
-#define PROD_MVD_819 (0x07) /* MVD 819 */
-
-#define MANUF_DELACOMP (0x0873) /* DelaComp */
-#define PROD_DELACOMP_RAM_2000 (0x01) /* RAM Expansion 2000 */
-
#define MANUF_VILLAGE_TRONIC (0x0877) /* Village Tronic */
#define PROD_DOMINO_RAM (0x01) /* Domino Graphics Board */
#define PROD_DOMINO_REG (0x02)
diff --git a/include/net/ip.h b/include/net/ip.h
index c0e600a37..e5d59dd33 100644
--- a/include/net/ip.h
+++ b/include/net/ip.h
@@ -65,36 +65,6 @@ extern void ip_mc_dropsocket(struct sock *);
extern void ip_mc_dropdevice(struct device *dev);
extern int ip_mc_procinfo(char *, char **, off_t, int, int);
-/* Describe an IP fragment. */
-struct ipfrag
-{
- int offset; /* offset of fragment in IP datagram */
- int end; /* last byte of data in datagram */
- int len; /* length of this fragment */
- struct sk_buff *skb; /* complete received fragment */
- unsigned char *ptr; /* pointer into real fragment data */
- struct ipfrag *next; /* linked list pointers */
- struct ipfrag *prev;
-};
-
-/*
- * Describe an entry in the "incomplete datagrams" queue.
- */
-
-struct ipq
-{
- unsigned char *mac; /* pointer to MAC header */
- struct iphdr *iph; /* pointer to IP header */
- int len; /* total length of original datagram */
- short ihlen; /* length of the IP header */
- short maclen; /* length of the MAC header */
- struct timer_list timer; /* when will this queue expire? */
- struct ipfrag *fragments; /* linked list of received fragments */
- struct ipq *next; /* linked list pointers */
- struct ipq *prev;
- struct device *dev; /* Device - for icmp replies */
-};
-
/*
* Functions provided by ip.c
*/
diff --git a/include/net/sock.h b/include/net/sock.h
index 61936854f..354d8dae5 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -216,6 +216,7 @@ struct tcp_opt
* Options received (usually on last packet, some only on SYN packets).
*/
char tstamp_ok, /* TIMESTAMP seen on SYN packet */
+ wscale_ok, /* Wscale seen on SYN packet */
sack_ok; /* SACK_PERM seen on SYN packet */
char saw_tstamp; /* Saw TIMESTAMP on last packet */
__u16 in_mss; /* MSS option received from sender */
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 3822b461f..cedc7f3b1 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -43,6 +43,17 @@ extern struct sock *tcp_established_hash[TCP_HTABLE_SIZE];
extern struct sock *tcp_listening_hash[TCP_LHTABLE_SIZE];
extern struct sock *tcp_bound_hash[TCP_BHTABLE_SIZE];
+/* tcp_ipv4.c: These sysctl variables need to be shared between v4 and v6
+ * because the v6 tcp code to intialize a connection needs to interoperate
+ * with the v4 code using the same variables.
+ * FIXME: It would be better to rewrite the connection code to be
+ * address family independent and just leave one copy in the ipv4 section.
+ * This would also clean up some code duplication. -- erics
+ */
+extern int sysctl_tcp_sack;
+extern int sysctl_tcp_timestamps;
+extern int sysctl_tcp_window_scaling;
+
/* These are AF independant. */
static __inline__ int tcp_bhashfn(__u16 lport)
{
@@ -224,8 +235,12 @@ struct open_request {
__u16 rmt_port;
__u16 mss;
__u8 snd_wscale;
+ __u8 rcv_wscale;
char sack_ok;
char tstamp_ok;
+ char wscale_ok;
+ __u32 window_clamp; /* window clamp at creation time */
+ __u32 rcv_wnd; /* rcv_wnd offered first time */
__u32 ts_recent;
unsigned long expires;
int retrans;
@@ -452,6 +467,10 @@ struct tcp_sl_timer {
extern struct tcp_sl_timer tcp_slt_array[TCP_SLT_MAX];
+/*
+ * FIXME: this method of choosing when to send a window update
+ * does not seem correct to me. -- erics
+ */
static __inline__ unsigned short tcp_raise_window(struct sock *sk)
{
struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
@@ -553,9 +572,9 @@ static __inline__ void tcp_set_state(struct sock *sk, int state)
* It would be especially magical to compute the checksum for this
* stuff on the fly here.
*/
-extern __inline__ int tcp_syn_build_options(struct sk_buff *skb, int mss, int sack, int ts, int wscale)
+extern __inline__ int tcp_syn_build_options(struct sk_buff *skb, int mss, int sack, int ts, int offer_wscale, int wscale)
{
- int count = 4 + (wscale ? 4 : 0) + ((ts || sack) ? 4 : 0) + (ts ? 8 : 0);
+ int count = 4 + (offer_wscale ? 4 : 0) + ((ts || sack) ? 4 : 0) + (ts ? 8 : 0);
unsigned char *optr = skb_put(skb,count);
__u32 *ptr = (__u32 *)optr;
@@ -579,12 +598,53 @@ extern __inline__ int tcp_syn_build_options(struct sk_buff *skb, int mss, int sa
*ptr++ = htonl((TCPOPT_SACK_PERM << 24) | (TCPOLEN_SACK_PERM << 16)
| (TCPOPT_NOP << 8) | TCPOPT_NOP);
}
- if (wscale)
- *ptr++ = htonl((TCPOPT_WINDOW << 24) | (TCPOLEN_WINDOW << 16) | wscale);
+ if (offer_wscale)
+ *ptr++ = htonl((TCPOPT_WINDOW << 24) | (TCPOLEN_WINDOW << 16) | (wscale << 8));
skb->csum = csum_partial(optr, count, 0);
return count;
}
+/* Determine a window scaling and initial window to offer.
+ * Based on the assumption that the given amount of space
+ * will be offered. Store the results in the tp structure.
+ * NOTE: for smooth operation initial space offering should
+ * be a multiple of mss if possible. We assume here that mss >= 1.
+ * This MUST be enforced by all callers.
+ */
+extern __inline__ void tcp_select_initial_window(__u32 space, __u16 mss,
+ __u32 *rcv_wnd,
+ __u32 *window_clamp,
+ int wscale_ok,
+ __u8 *rcv_wscale)
+{
+ /* If no clamp set the clamp to the max possible scaled window */
+ if (*window_clamp == 0)
+ (*window_clamp) = (65535<<14);
+ space = min(*window_clamp,space);
+
+ /* Quantize space offering to a multiple of mss if possible. */
+ if (space > mss)
+ space = (space/mss)*mss;
+
+ /* NOTE: offering an initial window larger than 32767
+ * will break some buggy TCP stacks. We try to be nice.
+ * If we are not window scaling, then this truncates
+ * our initial window offering to 32k. There should also
+ * be a sysctl option to stop being nice.
+ */
+ (*rcv_wnd) = min(space,32767);
+ (*rcv_wscale) = 0;
+ if (wscale_ok) {
+ /* See RFC1323 for an explanation of the limit to 14 */
+ while (space > 65535 && (*rcv_wscale) < 14) {
+ space >>= 1;
+ (*rcv_wscale)++;
+ }
+ }
+ /* Set the clamp no higher than max representable value */
+ (*window_clamp) = min(65535<<(*rcv_wscale),*window_clamp);
+}
+
extern __inline__ void tcp_synq_unlink(struct tcp_opt *tp, struct open_request *req)
{
if(req->dl_next)
diff --git a/init/main.c b/init/main.c
index 882ed0bdc..ba1f17e7c 100644
--- a/init/main.c
+++ b/init/main.c
@@ -69,8 +69,8 @@ extern int kswapd(void *);
extern void init_IRQ(void);
extern void init_modules(void);
extern long console_init(long, long);
-extern long kmalloc_init(long,long);
extern void sock_init(void);
+extern void uidcache_init(void);
extern unsigned long pci_init(unsigned long, unsigned long);
extern long mca_init(long, long);
extern long sbus_init(long, long);
@@ -178,6 +178,9 @@ extern void teles_setup(char *str, int *ints);
#ifdef CONFIG_ISDN_DRV_HISAX
extern void HiSax_setup(char *str, int *ints);
#endif
+#ifdef CONFIG_DIGIEPCA
+extern void epca_setup(char *str, int *ints);
+#endif
#ifdef CONFIG_ISDN_DRV_PCBIT
extern void pcbit_setup(char *str, int *ints);
#endif
@@ -193,7 +196,11 @@ extern void atari_scsi_setup (char *str, int *ints);
#endif
extern void wd33c93_setup (char *str, int *ints);
extern void gvp11_setup (char *str, int *ints);
+extern void ncr53c7xx_setup (char *str, int *ints);
+#ifdef CONFIG_CYCLADES
+extern void cy_setup(char *str, int *ints);
+#endif
#ifdef CONFIG_DIGI
extern void pcxx_setup(char *str, int *ints);
#endif
@@ -268,7 +275,7 @@ extern void dquot_init(void);
static char * argv_init[MAX_INIT_ARGS+2] = { "init", NULL, };
static char * envp_init[MAX_INIT_ENVS+2] = { "HOME=/", "TERM=linux", NULL, };
-__initfunc(char *get_options(char *str, int *ints))
+char *get_options(char *str, int *ints)
{
char *cur = str;
int i=1;
@@ -482,6 +489,9 @@ struct {
#ifdef CONFIG_ATARI_SCSI
{ "atascsi=", atari_scsi_setup },
#endif
+#if defined(CONFIG_A4000T_SCSI) || defined(CONFIG_WARPENGINE_SCSI) || defined(CONFIG_A4091_SCSI)
+ { "53c7xx=", ncr53c7xx_setup },
+#endif
#if defined(CONFIG_A3000_SCSI) || defined(CONFIG_A2091_SCSI) \
|| defined(CONFIG_GVP11_SCSI) || defined(CONFIG_SCSI_SGIWD93)
{ "wd33c93=", wd33c93_setup },
@@ -489,9 +499,15 @@ struct {
#if defined(CONFIG_GVP11_SCSI)
{ "gvp11=", gvp11_setup },
#endif
+#ifdef CONFIG_CYCLADES
+ { "cyclades=", cy_setup },
+#endif
#ifdef CONFIG_DIGI
{ "digi=", pcxx_setup },
#endif
+#ifdef CONFIG_DIGIEPCA
+ { "digiepca=", epca_setup },
+#endif
#ifdef CONFIG_RISCOM8
{ "riscom8=", riscom8_setup },
#endif
@@ -649,6 +665,7 @@ __initfunc(static void parse_root_dev(char * line))
{ "gscd", 0x1000 },
{ "sbpcd", 0x1900 },
{ "sonycd", 0x1800 },
+ { "eda", 0x2400 },
{ "eza", 0x2800 },
{ "bpcd", 0x2900 },
#if CONFIG_APBLOCK
@@ -790,43 +807,11 @@ int cpu_idle(void *unused)
extern int cpu_idle(void * unused);
-/*
- * Activate a secondary processor.
- */
-
-__initfunc(asmlinkage void start_secondary(void))
-{
- trap_init();
- init_IRQ();
- smp_callin();
- cpu_idle(NULL);
-}
-
-
-
/* Called by boot processor to activate the rest. */
__initfunc(static void smp_init(void))
{
- int i, j;
-
/* Get other processors into their bootup holding patterns. */
smp_boot_cpus();
-
- /* Create the slave init tasks as sharing pid 0. This should only
- * happen if we have virtual CPU numbers higher than 0.
- */
- for (i=1; i<smp_num_cpus; i++)
- {
- /* We use kernel_thread for the idlers which are
- * unlocked tasks running in kernel space.
- */
- kernel_thread(cpu_idle, NULL, CLONE_PID);
-
- /* Don't assume linear processor numbering */
- j = cpu_logical_map[i];
- current_set[j]=task[i];
- current_set[j]->processor=j;
- }
}
/*
@@ -843,6 +828,8 @@ __initfunc(static void smp_begin(void))
#endif
+extern void initialize_secondary(void);
+
/*
* Activate the first processor.
*/
@@ -851,18 +838,14 @@ __initfunc(asmlinkage void start_kernel(void))
{
char * command_line;
-/*
- * This little check will move.
- */
-
#ifdef __SMP__
- static int first_cpu=1;
-
- if(!first_cpu)
- start_secondary();
- first_cpu=0;
-
-#endif
+ static int boot_cpu = 1;
+ /* "current" has been set up, we need to load it now */
+ if (!boot_cpu)
+ initialize_secondary();
+ boot_cpu = 0;
+#endif
+
/*
* Interrupts are still disabled. Do necessary setups, then
* enable them
@@ -907,11 +890,9 @@ __initfunc(asmlinkage void start_kernel(void))
#ifdef CONFIG_MCA
memory_start = mca_init(memory_start,memory_end);
#endif
- memory_start = kmalloc_init(memory_start,memory_end);
memory_start = kmem_cache_init(memory_start, memory_end);
sti();
calibrate_delay();
- memory_start = file_table_init(memory_start,memory_end);
memory_start = name_cache_init(memory_start,memory_end);
#ifdef CONFIG_BLK_DEV_INITRD
if (initrd_start && !initrd_below_start_ok && initrd_start < memory_start) {
@@ -921,13 +902,15 @@ __initfunc(asmlinkage void start_kernel(void))
}
#endif
mem_init(memory_start,memory_end);
+ kmem_cache_sizes_init();
#ifdef CONFIG_PROC_FS
proc_root_init();
#endif
- kmem_cache_sizes_init();
+ uidcache_init();
vma_init();
buffer_init();
inode_init();
+ file_table_init();
sock_init();
#if defined(CONFIG_SYSVIPC) || defined(CONFIG_KERNELD)
ipc_init();
@@ -989,8 +972,10 @@ static int init(void * unused)
/* Launch bdflush from here, instead of the old syscall way. */
kernel_thread(bdflush, NULL, 0);
+printk("init() #1\n");while(1);
/* Start the background pageout daemon. */
kernel_thread(kswapd, NULL, 0);
+printk("init() #2\n");while(1);
#if CONFIG_AP1000
/* Start the async paging daemon. */
@@ -1006,7 +991,9 @@ static int init(void * unused)
if (initrd_start && mount_initrd) root_mountflags &= ~MS_RDONLY;
else mount_initrd =0;
#endif
+printk("init() #3\n");while(1);
setup();
+printk("init() #4\n");while(1);
#ifdef __SMP__
/*
diff --git a/ipc/msg.c b/ipc/msg.c
index fcef8357f..49d8f043f 100644
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -17,6 +17,7 @@
#include <linux/interrupt.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
+#include <linux/init.h>
#include <asm/uaccess.h>
@@ -39,7 +40,7 @@ static int kerneld_msqid = -1;
static int kerneld_arr[MAX_KERNELDS];
static int n_kernelds = 0;
-void msg_init (void)
+__initfunc(void msg_init (void))
{
int id;
diff --git a/ipc/sem.c b/ipc/sem.c
index 8aecbfb48..f63f2a7a9 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -40,6 +40,7 @@
#include <linux/malloc.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
+#include <linux/init.h>
#include <asm/uaccess.h>
@@ -55,7 +56,7 @@ static int max_semid = 0;
static unsigned short sem_seq = 0;
-void sem_init (void)
+__initfunc(void sem_init (void))
{
int i;
diff --git a/ipc/shm.c b/ipc/shm.c
index ab5974fed..d2afb7d2f 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -16,6 +16,7 @@
#include <linux/swap.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
+#include <linux/init.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
@@ -44,7 +45,7 @@ static ulong swap_attempts = 0;
static ulong swap_successes = 0;
static ulong used_segs = 0;
-void shm_init (void)
+__initfunc(void shm_init (void))
{
int id;
@@ -402,42 +403,21 @@ static struct vm_operations_struct shm_vm_ops = {
shm_swap_in /* swapin */
};
-/* Insert shmd into the circular list shp->attaches */
+/* Insert shmd into the list shp->attaches */
static inline void insert_attach (struct shmid_ds * shp, struct vm_area_struct * shmd)
{
- struct vm_area_struct * attaches;
-
- if ((attaches = shp->attaches)) {
- shmd->vm_next_share = attaches;
- shmd->vm_prev_share = attaches->vm_prev_share;
- shmd->vm_prev_share->vm_next_share = shmd;
- attaches->vm_prev_share = shmd;
- } else
- shp->attaches = shmd->vm_next_share = shmd->vm_prev_share = shmd;
+ if((shmd->vm_next_share = shp->attaches) != NULL)
+ shp->attaches->vm_pprev_share = &shmd->vm_next_share;
+ shp->attaches = shmd;
+ shmd->vm_pprev_share = &shp->attaches;
}
-/* Remove shmd from circular list shp->attaches */
+/* Remove shmd from list shp->attaches */
static inline void remove_attach (struct shmid_ds * shp, struct vm_area_struct * shmd)
{
- if (shmd->vm_next_share == shmd) {
- if (shp->attaches != shmd) {
- printk("shm_close: shm segment (id=%ld) attach list inconsistent\n",
- SWP_OFFSET(shmd->vm_pte) & SHM_ID_MASK);
- printk("shm_close: %08lx-%08lx %c%c%c%c %08lx %08lx\n",
- shmd->vm_start, shmd->vm_end,
- shmd->vm_flags & VM_READ ? 'r' : '-',
- shmd->vm_flags & VM_WRITE ? 'w' : '-',
- shmd->vm_flags & VM_EXEC ? 'x' : '-',
- shmd->vm_flags & VM_MAYSHARE ? 's' : 'p',
- shmd->vm_offset, shmd->vm_pte);
- }
- shp->attaches = NULL;
- } else {
- if (shp->attaches == shmd)
- shp->attaches = shmd->vm_next_share;
- shmd->vm_prev_share->vm_next_share = shmd->vm_next_share;
- shmd->vm_next_share->vm_prev_share = shmd->vm_prev_share;
- }
+ if(shmd->vm_next_share)
+ shmd->vm_next_share->vm_pprev_share = shmd->vm_pprev_share;
+ *shmd->vm_pprev_share = shmd->vm_next_share;
}
/*
@@ -575,7 +555,6 @@ asmlinkage int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr)
shmd->vm_flags = VM_SHM | VM_MAYSHARE | VM_SHARED
| VM_MAYREAD | VM_MAYEXEC | VM_READ | VM_EXEC
| ((shmflg & SHM_RDONLY) ? 0 : VM_MAYWRITE | VM_WRITE);
- shmd->vm_next_share = shmd->vm_prev_share = NULL;
shmd->vm_inode = NULL;
shmd->vm_offset = 0;
shmd->vm_ops = &shm_vm_ops;
@@ -825,9 +804,10 @@ int shm_swap (int prio, int dma)
if (shmd->vm_mm->rss > 0)
shmd->vm_mm->rss--;
flush_tlb_page(shmd, tmp);
- /* continue looping through circular list */
+ /* continue looping through the linked list */
} while (0);
- if ((shmd = shmd->vm_next_share) == shp->attaches)
+ shmd = shmd->vm_next_share;
+ if (!shmd)
break;
}
diff --git a/ipc/util.c b/ipc/util.c
index e81afc36f..88e63c6fc 100644
--- a/ipc/util.c
+++ b/ipc/util.c
@@ -11,6 +11,7 @@
#include <linux/msg.h>
#include <linux/shm.h>
#include <linux/stat.h>
+#include <linux/init.h>
#include <asm/uaccess.h>
@@ -18,7 +19,7 @@
extern void sem_init (void), msg_init (void), shm_init (void);
-void ipc_init (void)
+__initfunc(void ipc_init (void))
{
sem_init();
msg_init();
diff --git a/kernel/exit.c b/kernel/exit.c
index 0d03916e8..3fce2a2d7 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -4,8 +4,6 @@
* Copyright (C) 1991, 1992 Linus Torvalds
*/
-#undef DEBUG_PROC_TREE
-
#include <linux/config.h>
#include <linux/wait.h>
#include <linux/errno.h>
@@ -16,6 +14,7 @@
#include <linux/mm.h>
#include <linux/tty.h>
#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
@@ -127,130 +126,27 @@ void notify_parent(struct task_struct * tsk)
void release(struct task_struct * p)
{
- int i;
-
- if (!p)
- return;
- if (p == current) {
- printk("task releasing itself\n");
- return;
- }
- for (i=1 ; i<NR_TASKS ; i++)
- if (task[i] == p) {
+ if (p != current) {
#ifdef __SMP__
- /* FIXME! Cheesy, but kills the window... -DaveM */
- while(p->processor != NO_PROC_ID)
- barrier();
- spin_unlock_wait(&scheduler_lock);
+ /* FIXME! Cheesy, but kills the window... -DaveM */
+ while (p->has_cpu)
+ barrier();
+ spin_unlock_wait(&scheduler_lock);
#endif
- nr_tasks--;
- task[i] = NULL;
- REMOVE_LINKS(p);
- release_thread(p);
- if (STACK_MAGIC != *(unsigned long *)p->kernel_stack_page)
- printk(KERN_ALERT "release: %s kernel stack corruption. Aiee\n", p->comm);
- free_kernel_stack(p->kernel_stack_page);
- current->cmin_flt += p->min_flt + p->cmin_flt;
- current->cmaj_flt += p->maj_flt + p->cmaj_flt;
- current->cnswap += p->nswap + p->cnswap;
- free_task_struct(p);
- return;
- }
- panic("trying to release non-existent task");
-}
-
-#ifdef DEBUG_PROC_TREE
-/*
- * Check to see if a task_struct pointer is present in the task[] array
- * Return 0 if found, and 1 if not found.
- */
-int bad_task_ptr(struct task_struct *p)
-{
- int i;
-
- if (!p)
- return 0;
- for (i=0 ; i<NR_TASKS ; i++)
- if (task[i] == p)
- return 0;
- return 1;
-}
-
-/*
- * This routine scans the pid tree and makes sure the rep invariant still
- * holds. Used for debugging only, since it's very slow....
- *
- * It looks a lot scarier than it really is.... we're doing nothing more
- * than verifying the doubly-linked list found in p_ysptr and p_osptr,
- * and checking it corresponds with the process tree defined by p_cptr and
- * p_pptr;
- */
-void audit_ptree(void)
-{
- int i;
-
- for (i=1 ; i<NR_TASKS ; i++) {
- if (!task[i])
- continue;
- if (bad_task_ptr(task[i]->p_pptr))
- printk("Warning, pid %d's parent link is bad\n",
- task[i]->pid);
- if (bad_task_ptr(task[i]->p_cptr))
- printk("Warning, pid %d's child link is bad\n",
- task[i]->pid);
- if (bad_task_ptr(task[i]->p_ysptr))
- printk("Warning, pid %d's ys link is bad\n",
- task[i]->pid);
- if (bad_task_ptr(task[i]->p_osptr))
- printk("Warning, pid %d's os link is bad\n",
- task[i]->pid);
- if (task[i]->p_pptr == task[i])
- printk("Warning, pid %d parent link points to self\n",
- task[i]->pid);
- if (task[i]->p_cptr == task[i])
- printk("Warning, pid %d child link points to self\n",
- task[i]->pid);
- if (task[i]->p_ysptr == task[i])
- printk("Warning, pid %d ys link points to self\n",
- task[i]->pid);
- if (task[i]->p_osptr == task[i])
- printk("Warning, pid %d os link points to self\n",
- task[i]->pid);
- if (task[i]->p_osptr) {
- if (task[i]->p_pptr != task[i]->p_osptr->p_pptr)
- printk(
- "Warning, pid %d older sibling %d parent is %d\n",
- task[i]->pid, task[i]->p_osptr->pid,
- task[i]->p_osptr->p_pptr->pid);
- if (task[i]->p_osptr->p_ysptr != task[i])
- printk(
- "Warning, pid %d older sibling %d has mismatched ys link\n",
- task[i]->pid, task[i]->p_osptr->pid);
- }
- if (task[i]->p_ysptr) {
- if (task[i]->p_pptr != task[i]->p_ysptr->p_pptr)
- printk(
- "Warning, pid %d younger sibling %d parent is %d\n",
- task[i]->pid, task[i]->p_osptr->pid,
- task[i]->p_osptr->p_pptr->pid);
- if (task[i]->p_ysptr->p_osptr != task[i])
- printk(
- "Warning, pid %d younger sibling %d has mismatched os link\n",
- task[i]->pid, task[i]->p_ysptr->pid);
- }
- if (task[i]->p_cptr) {
- if (task[i]->p_cptr->p_pptr != task[i])
- printk(
- "Warning, pid %d youngest child %d has mismatched parent link\n",
- task[i]->pid, task[i]->p_cptr->pid);
- if (task[i]->p_cptr->p_ysptr)
- printk(
- "Warning, pid %d youngest child %d has non-NULL ys link\n",
- task[i]->pid, task[i]->p_cptr->pid);
- }
+ charge_uid(p, -1);
+ nr_tasks--;
+ add_free_taskslot(p->tarray_ptr);
+ unhash_pid(p);
+ REMOVE_LINKS(p);
+ release_thread(p);
+ current->cmin_flt += p->min_flt + p->cmin_flt;
+ current->cmaj_flt += p->maj_flt + p->cmaj_flt;
+ current->cnswap += p->nswap + p->cnswap;
+ free_task_struct(p);
+ } else {
+ printk("task releasing itself\n");
}
}
-#endif /* DEBUG_PROC_TREE */
/*
* This checks not only the pgrp, but falls back on the pid if no
@@ -348,17 +244,12 @@ int kill_proc(int pid, int sig, int priv)
retval = -EINVAL;
if (sig >= 0 && sig <= 32) {
- struct task_struct *p;
+ struct task_struct *p = find_task_by_pid(pid);
- retval = -ESRCH;
- read_lock(&tasklist_lock);
- for_each_task(p) {
- if (p->pid != pid)
- continue;
- retval = send_sig(sig,p,priv);
- break;
- }
- read_unlock(&tasklist_lock);
+ if(p)
+ retval = send_sig(sig, p, priv);
+ else
+ retval = -ESRCH;
}
return retval;
}
@@ -551,7 +442,7 @@ static inline void __exit_mm(struct task_struct * tsk)
if (!--mm->count) {
exit_mmap(mm);
free_page_tables(mm);
- kfree(mm);
+ kmem_cache_free(mm_cachep, mm);
}
}
}
@@ -735,8 +626,8 @@ repeat:
retval = p->pid;
goto end_wait4;
case TASK_ZOMBIE:
- current->cutime += p->utime + p->cutime;
- current->cstime += p->stime + p->cstime;
+ current->times.tms_cutime += p->times.tms_utime + p->times.tms_cutime;
+ current->times.tms_cstime += p->times.tms_stime + p->times.tms_cstime;
read_unlock(&tasklist_lock);
if (ru != NULL)
getrusage(p, RUSAGE_BOTH, ru);
diff --git a/kernel/fork.c b/kernel/fork.c
index 6204ffeaf..804e37bd5 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -33,68 +33,177 @@ int nr_running=1;
unsigned long int total_forks=0; /* Handle normal Linux uptimes. */
int last_pid=0;
-static inline int find_empty_process(void)
+/* SLAB cache for mm_struct's. */
+kmem_cache_t *mm_cachep;
+
+struct task_struct *pidhash[PIDHASH_SZ];
+spinlock_t pidhash_lock = SPIN_LOCK_UNLOCKED;
+
+struct task_struct **tarray_freelist = NULL;
+spinlock_t taskslot_lock = SPIN_LOCK_UNLOCKED;
+
+/* UID task count cache, to prevent walking entire process list every
+ * single fork() operation.
+ */
+#define UIDHASH_SZ (PIDHASH_SZ >> 2)
+
+static struct uid_taskcount {
+ struct uid_taskcount *next, **pprev;
+ unsigned short uid;
+ int task_count;
+} *uidhash[UIDHASH_SZ];
+static spinlock_t uidhash_lock = SPIN_LOCK_UNLOCKED;
+
+kmem_cache_t *uid_cachep;
+
+#define uidhashfn(uid) (((uid >> 8) ^ uid) & (UIDHASH_SZ - 1))
+
+static inline void uid_hash_insert(struct uid_taskcount *up, unsigned int hashent)
{
- int i;
+ spin_lock(&uidhash_lock);
+ if((up->next = uidhash[hashent]) != NULL)
+ uidhash[hashent]->pprev = &up->next;
+ up->pprev = &uidhash[hashent];
+ uidhash[hashent] = up;
+ spin_unlock(&uidhash_lock);
+}
- if (nr_tasks >= NR_TASKS - MIN_TASKS_LEFT_FOR_ROOT) {
- if (current->uid)
+static inline void uid_hash_remove(struct uid_taskcount *up)
+{
+ spin_lock(&uidhash_lock);
+ if(up->next)
+ up->next->pprev = up->pprev;
+ *up->pprev = up->next;
+ spin_unlock(&uidhash_lock);
+}
+
+static inline struct uid_taskcount *uid_find(unsigned short uid, unsigned int hashent)
+{
+ struct uid_taskcount *up;
+
+ spin_lock(&uidhash_lock);
+ for(up = uidhash[hashent]; (up && up->uid != uid); up = up->next)
+ ;
+ spin_unlock(&uidhash_lock);
+ return up;
+}
+
+int charge_uid(struct task_struct *p, int count)
+{
+ unsigned int hashent = uidhashfn(p->uid);
+ struct uid_taskcount *up = uid_find(p->uid, hashent);
+
+ if(up) {
+ int limit = p->rlim[RLIMIT_NPROC].rlim_cur;
+ int newcnt = up->task_count + count;
+
+ if(newcnt > limit)
return -EAGAIN;
- }
- if (current->uid) {
- long max_tasks = current->rlim[RLIMIT_NPROC].rlim_cur;
-
- max_tasks--; /* count the new process.. */
- if (max_tasks < nr_tasks) {
- struct task_struct *p;
- read_lock(&tasklist_lock);
- for_each_task (p) {
- if (p->uid == current->uid)
- if (--max_tasks < 0) {
- read_unlock(&tasklist_lock);
- return -EAGAIN;
- }
- }
- read_unlock(&tasklist_lock);
+ else if(newcnt == 0) {
+ uid_hash_remove(up);
+ kmem_cache_free(uid_cachep, up);
+ return 0;
}
+ } else {
+ up = kmem_cache_alloc(uid_cachep, SLAB_KERNEL);
+ if(!up)
+ return -EAGAIN;
+ up->uid = p->uid;
+ up->task_count = 0;
+ uid_hash_insert(up, hashent);
}
- for (i = 0 ; i < NR_TASKS ; i++) {
- if (!task[i])
- return i;
+ up->task_count += count;
+ return 0;
+}
+
+void uidcache_init(void)
+{
+ int i;
+
+ uid_cachep = kmem_cache_create("uid_cache", sizeof(struct uid_taskcount),
+ 0,
+ SLAB_HWCACHE_ALIGN, NULL, NULL);
+ if(!uid_cachep)
+ panic("Cannot create uid taskcount SLAB cache\n");
+
+ for(i = 0; i < UIDHASH_SZ; i++)
+ uidhash[i] = 0;
+}
+
+static inline int find_empty_process(void)
+{
+ struct task_struct **tslot;
+
+ if(current->uid) {
+ int error;
+
+ if(nr_tasks >= NR_TASKS - MIN_TASKS_LEFT_FOR_ROOT)
+ return -EAGAIN;
+ if((error = charge_uid(current, 1)) < 0)
+ return error;
}
+ tslot = get_free_taskslot();
+ if(tslot)
+ return tslot - &task[0];
return -EAGAIN;
}
+/* Protects next_safe and last_pid. */
+static spinlock_t lastpid_lock = SPIN_LOCK_UNLOCKED;
+
static int get_pid(unsigned long flags)
{
+ static int next_safe = PID_MAX;
struct task_struct *p;
if (flags & CLONE_PID)
return current->pid;
- read_lock(&tasklist_lock);
-repeat:
- if ((++last_pid) & 0xffff8000)
- last_pid=1;
- for_each_task (p) {
- if (p->pid == last_pid ||
- p->pgrp == last_pid ||
- p->session == last_pid)
- goto repeat;
+ spin_lock(&lastpid_lock);
+ if((++last_pid) & 0xffff8000) {
+ last_pid = 300; /* Skip daemons etc. */
+ goto inside;
+ }
+ if(last_pid >= next_safe) {
+inside:
+ next_safe = PID_MAX;
+ read_lock(&tasklist_lock);
+ repeat:
+ for_each_task(p) {
+ if(p->pid == last_pid ||
+ p->pgrp == last_pid ||
+ p->session == last_pid) {
+ if(++last_pid >= next_safe) {
+ if(last_pid & 0xffff8000)
+ last_pid = 300;
+ next_safe = PID_MAX;
+ goto repeat;
+ }
+ }
+ if(p->pid > last_pid && next_safe > p->pid)
+ next_safe = p->pid;
+ if(p->pgrp > last_pid && next_safe > p->pgrp)
+ next_safe = p->pgrp;
+ if(p->session > last_pid && next_safe > p->session)
+ next_safe = p->session;
+ }
+ read_unlock(&tasklist_lock);
}
- read_unlock(&tasklist_lock);
+ spin_unlock(&lastpid_lock);
return last_pid;
}
static inline int dup_mmap(struct mm_struct * mm)
{
- struct vm_area_struct * mpnt, **p, *tmp;
+ struct vm_area_struct * mpnt, *tmp, **pprev;
- mm->mmap = NULL;
- p = &mm->mmap;
+ mm->mmap = mm->mmap_cache = NULL;
flush_cache_mm(current->mm);
+ pprev = &mm->mmap;
for (mpnt = current->mm->mmap ; mpnt ; mpnt = mpnt->vm_next) {
+ struct inode *inode;
+
tmp = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
if (!tmp) {
exit_mmap(mm);
@@ -105,12 +214,18 @@ static inline int dup_mmap(struct mm_struct * mm)
tmp->vm_flags &= ~VM_LOCKED;
tmp->vm_mm = mm;
tmp->vm_next = NULL;
- if (tmp->vm_inode) {
- tmp->vm_inode->i_count++;
+ inode = tmp->vm_inode;
+ if (inode) {
+ inode->i_count++;
+ if (tmp->vm_flags & VM_DENYWRITE)
+ inode->i_writecount--;
+
/* insert tmp into the share list, just after mpnt */
- tmp->vm_next_share->vm_prev_share = tmp;
+ if((tmp->vm_next_share = mpnt->vm_next_share) != NULL)
+ mpnt->vm_next_share->vm_pprev_share =
+ &tmp->vm_next_share;
mpnt->vm_next_share = tmp;
- tmp->vm_prev_share = mpnt;
+ tmp->vm_pprev_share = &mpnt->vm_next_share;
}
if (copy_page_range(mm, current->mm, tmp)) {
exit_mmap(mm);
@@ -119,24 +234,35 @@ static inline int dup_mmap(struct mm_struct * mm)
}
if (tmp->vm_ops && tmp->vm_ops->open)
tmp->vm_ops->open(tmp);
- *p = tmp;
- p = &tmp->vm_next;
+
+ /* Ok, finally safe to link it in. */
+ if((tmp->vm_next = *pprev) != NULL)
+ (*pprev)->vm_pprev = &tmp->vm_next;
+ *pprev = tmp;
+ tmp->vm_pprev = pprev;
+
+ pprev = &tmp->vm_next;
}
flush_tlb_mm(current->mm);
- build_mmap_avl(mm);
return 0;
}
static inline int copy_mm(unsigned long clone_flags, struct task_struct * tsk)
{
if (!(clone_flags & CLONE_VM)) {
- struct mm_struct * mm = kmalloc(sizeof(*tsk->mm), GFP_KERNEL);
+ struct mm_struct * mm = kmem_cache_alloc(mm_cachep, SLAB_KERNEL);
if (!mm)
return -1;
*mm = *current->mm;
init_new_context(mm);
mm->count = 1;
mm->def_flags = 0;
+
+ /* It has not run yet, so cannot be present in anyone's
+ * cache or tlb.
+ */
+ mm->cpu_vm_mask = 0;
+
tsk->mm = mm;
tsk->min_flt = tsk->maj_flt = 0;
tsk->cmin_flt = tsk->cmaj_flt = 0;
@@ -146,7 +272,7 @@ static inline int copy_mm(unsigned long clone_flags, struct task_struct * tsk)
if (dup_mmap(mm)) {
free_page_tables(mm);
free_mm:
- kfree(mm);
+ kmem_cache_free(mm_cachep, mm);
return -1;
}
return 0;
@@ -232,20 +358,17 @@ int do_fork(unsigned long clone_flags, unsigned long usp, struct pt_regs *regs)
{
int nr;
int error = -ENOMEM;
- unsigned long new_stack;
struct task_struct *p;
lock_kernel();
p = alloc_task_struct();
if (!p)
goto bad_fork;
- new_stack = alloc_kernel_stack(p);
- if (!new_stack)
- goto bad_fork_free_p;
+
error = -EAGAIN;
nr = find_empty_process();
if (nr < 0)
- goto bad_fork_free_stack;
+ goto bad_fork_free;
*p = *current;
@@ -256,8 +379,6 @@ int do_fork(unsigned long clone_flags, unsigned long usp, struct pt_regs *regs)
p->did_exec = 0;
p->swappable = 0;
- p->kernel_stack_page = new_stack;
- *(unsigned long *) p->kernel_stack_page = STACK_MAGIC;
p->state = TASK_UNINTERRUPTIBLE;
p->flags &= ~(PF_PTRACED|PF_TRACESYS|PF_SUPERPRIV);
p->flags |= PF_FORKNOEXEC;
@@ -274,15 +395,18 @@ int do_fork(unsigned long clone_flags, unsigned long usp, struct pt_regs *regs)
p->real_timer.data = (unsigned long) p;
p->leader = 0; /* session leadership doesn't inherit */
p->tty_old_pgrp = 0;
- p->utime = p->stime = 0;
- p->cutime = p->cstime = 0;
+ p->times.tms_utime = p->times.tms_stime = 0;
+ p->times.tms_cutime = p->times.tms_cstime = 0;
#ifdef __SMP__
+ p->has_cpu = 0;
p->processor = NO_PROC_ID;
#endif
p->lock_depth = 0;
p->start_time = jiffies;
- task[nr] = p;
+ p->tarray_ptr = &task[nr];
+ *p->tarray_ptr = p;
SET_LINKS(p);
+ hash_pid(p);
nr_tasks++;
error = -ENOMEM;
@@ -330,16 +454,16 @@ bad_fork_cleanup_fs:
bad_fork_cleanup_files:
exit_files(p);
bad_fork_cleanup:
+ charge_uid(current, -1);
if (p->exec_domain && p->exec_domain->module)
__MOD_DEC_USE_COUNT(p->exec_domain->module);
if (p->binfmt && p->binfmt->module)
__MOD_DEC_USE_COUNT(p->binfmt->module);
- task[nr] = NULL;
+ add_free_taskslot(p->tarray_ptr);
+ unhash_pid(p);
REMOVE_LINKS(p);
nr_tasks--;
-bad_fork_free_stack:
- free_kernel_stack(new_stack);
-bad_fork_free_p:
+bad_fork_free:
free_task_struct(p);
bad_fork:
fork_out:
diff --git a/kernel/ksyms.c b/kernel/ksyms.c
index f5f202c8e..ec0be876f 100644
--- a/kernel/ksyms.c
+++ b/kernel/ksyms.c
@@ -52,10 +52,6 @@
#include <linux/ctype.h>
#include <linux/file.h>
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_HD) || defined(CONFIG_BLK_DEV_IDE_MODULE) || defined(CONFIG_BLK_DEV_HD_MODULE)
-extern struct drive_info_struct drive_info;
-#endif
-
extern unsigned char aux_device_present, kbd_read_mask;
#ifdef CONFIG_PCI
@@ -124,8 +120,14 @@ EXPORT_SYMBOL(exit_files);
/* internal kernel memory management */
EXPORT_SYMBOL(__get_free_pages);
EXPORT_SYMBOL(free_pages);
+EXPORT_SYMBOL(kmem_find_general_cachep);
+EXPORT_SYMBOL(kmem_cache_create);
+EXPORT_SYMBOL(kmem_cache_shrink);
+EXPORT_SYMBOL(kmem_cache_alloc);
+EXPORT_SYMBOL(kmem_cache_free);
EXPORT_SYMBOL(kmalloc);
EXPORT_SYMBOL(kfree);
+EXPORT_SYMBOL(kfree_s);
EXPORT_SYMBOL(vmalloc);
EXPORT_SYMBOL(vfree);
EXPORT_SYMBOL(mem_map);
@@ -134,10 +136,6 @@ EXPORT_SYMBOL(max_mapnr);
EXPORT_SYMBOL(num_physpages);
EXPORT_SYMBOL(high_memory);
EXPORT_SYMBOL(update_vm_cache);
-EXPORT_SYMBOL(kmem_cache_create);
-EXPORT_SYMBOL(kmem_cache_destroy);
-EXPORT_SYMBOL(kmem_cache_alloc);
-EXPORT_SYMBOL(kmem_cache_free);
/* filesystem internal functions */
EXPORT_SYMBOL(getname);
@@ -150,6 +148,7 @@ EXPORT_SYMBOL(lnamei);
EXPORT_SYMBOL(open_namei);
EXPORT_SYMBOL(sys_close);
EXPORT_SYMBOL(close_fp);
+EXPORT_SYMBOL(insert_file_free);
EXPORT_SYMBOL(check_disk_change);
EXPORT_SYMBOL(invalidate_buffers);
EXPORT_SYMBOL(invalidate_inodes);
@@ -215,10 +214,6 @@ EXPORT_SYMBOL(gendisk_head);
EXPORT_SYMBOL(resetup_one_dev);
EXPORT_SYMBOL(unplug_device);
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_HD) || defined(CONFIG_BLK_DEV_IDE_MODULE) || defined(CONFIG_BLK_DEV_HD_MODULE)
-EXPORT_SYMBOL(drive_info);
-#endif
-
/* tty routines */
EXPORT_SYMBOL(tty_hangup);
EXPORT_SYMBOL(tty_wait_until_sent);
@@ -300,7 +295,6 @@ EXPORT_SYMBOL(wake_up_interruptible);
EXPORT_SYMBOL(sleep_on);
EXPORT_SYMBOL(interruptible_sleep_on);
EXPORT_SYMBOL(schedule);
-EXPORT_SYMBOL(current_set);
EXPORT_SYMBOL(jiffies);
EXPORT_SYMBOL(xtime);
EXPORT_SYMBOL(do_gettimeofday);
diff --git a/kernel/panic.c b/kernel/panic.c
index deaa2f339..c5482bffe 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -15,6 +15,7 @@
#include <linux/delay.h>
#include <linux/smp.h>
#include <linux/reboot.h>
+#include <linux/init.h>
#include <asm/sgialib.h>
@@ -24,7 +25,7 @@ extern int C_A_D;
int panic_timeout = 0;
-void panic_setup(char *str, int *ints)
+__initfunc(void panic_setup(char *str, int *ints))
{
if (ints[0] == 1)
panic_timeout = ints[1];
diff --git a/kernel/printk.c b/kernel/printk.c
index 0d5d619b0..3d409f2d5 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -25,6 +25,7 @@
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/console.h>
+#include <linux/init.h>
#include <asm/uaccess.h>
@@ -261,7 +262,7 @@ void unblank_console(void)
* print any messages that were printed by the kernel before the
* console driver was initialized.
*/
-void register_console(struct console * console)
+__initfunc(void register_console(struct console * console))
{
int i,j,len;
int p = log_start;
diff --git a/kernel/resource.c b/kernel/resource.c
index 27abcf4dc..ff7c7492a 100644
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -12,6 +12,7 @@
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/ioport.h>
+#include <linux/init.h>
#define IOTABLE_SIZE 128
@@ -181,7 +182,7 @@ unsigned long occupy_region(unsigned long base, unsigned long end,
#endif
/* Called from init/main.c to reserve IO ports. */
-void reserve_setup(char *str, int *ints)
+__initfunc(void reserve_setup(char *str, int *ints))
{
int i;
diff --git a/kernel/sched.c b/kernel/sched.c
index bc256d029..9f32305ee 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -32,6 +32,7 @@
#include <linux/mm.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
+#include <linux/init.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -88,21 +89,6 @@ unsigned long prof_shift = 0;
extern void mem_use(void);
-#ifdef __mips__
-unsigned long init_kernel_stack[2048] = { STACK_MAGIC, };
-unsigned long init_user_stack[2048] = { STACK_MAGIC, };
-#else
-unsigned long init_kernel_stack[1024] = { STACK_MAGIC, };
-unsigned long init_user_stack[1024] = { STACK_MAGIC, };
-#endif
-static struct vm_area_struct init_mmap = INIT_MMAP;
-static struct fs_struct init_fs = INIT_FS;
-static struct files_struct init_files = INIT_FILES;
-static struct signal_struct init_signals = INIT_SIGNALS;
-
-struct mm_struct init_mm = INIT_MM;
-struct task_struct init_task = INIT_TASK;
-
unsigned long volatile jiffies=0;
/*
@@ -110,7 +96,6 @@ unsigned long volatile jiffies=0;
* via the SMP irq return path.
*/
-struct task_struct *current_set[NR_CPUS] = {&init_task, };
struct task_struct *last_task_used_math = NULL;
struct task_struct * task[NR_TASKS] = {&init_task, };
@@ -119,12 +104,6 @@ struct kernel_stat kstat = { 0 };
static inline void add_to_runqueue(struct task_struct * p)
{
-#if 1 /* sanity tests */
- if (p->next_run || p->prev_run) {
- printk("task already on run-queue\n");
- return;
- }
-#endif
if (p->counter > current->counter + 3)
need_resched = 1;
nr_running++;
@@ -138,20 +117,6 @@ static inline void del_from_runqueue(struct task_struct * p)
struct task_struct *next = p->next_run;
struct task_struct *prev = p->prev_run;
-#if 1 /* sanity tests */
- if (!next || !prev) {
- printk("task not on run-queue\n");
- return;
- }
-#endif
- if (!p->pid) {
- static int nr = 0;
- if (nr < 5) {
- nr++;
- printk("idle task may not sleep\n");
- }
- return;
- }
nr_running--;
next->prev_run = prev;
prev->next_run = next;
@@ -255,7 +220,7 @@ static inline int goodness(struct task_struct * p, struct task_struct * prev, in
#ifdef __SMP__
/* Give a largish advantage to the same processor... */
/* (this is equivalent to penalizing other processors) */
- if (p->last_processor == this_cpu)
+ if (p->processor == this_cpu)
weight += PROC_CHANGE_PENALTY;
#endif
@@ -267,10 +232,127 @@ static inline int goodness(struct task_struct * p, struct task_struct * prev, in
return weight;
}
+/*
+ * Event timer code
+ */
+#define TVN_BITS 6
+#define TVR_BITS 8
+#define TVN_SIZE (1 << TVN_BITS)
+#define TVR_SIZE (1 << TVR_BITS)
+#define TVN_MASK (TVN_SIZE - 1)
+#define TVR_MASK (TVR_SIZE - 1)
+
+struct timer_vec {
+ int index;
+ struct timer_list *vec[TVN_SIZE];
+};
+
+struct timer_vec_root {
+ int index;
+ struct timer_list *vec[TVR_SIZE];
+};
+
+static struct timer_vec tv5 = { 0 };
+static struct timer_vec tv4 = { 0 };
+static struct timer_vec tv3 = { 0 };
+static struct timer_vec tv2 = { 0 };
+static struct timer_vec_root tv1 = { 0 };
+
+static struct timer_vec * const tvecs[] = {
+ (struct timer_vec *)&tv1, &tv2, &tv3, &tv4, &tv5
+};
+
+#define NOOF_TVECS (sizeof(tvecs) / sizeof(tvecs[0]))
+
+static unsigned long timer_jiffies = 0;
+
+static inline void insert_timer(struct timer_list *timer,
+ struct timer_list **vec, int idx)
+{
+ if ((timer->next = vec[idx]))
+ vec[idx]->prev = timer;
+ vec[idx] = timer;
+ timer->prev = (struct timer_list *)&vec[idx];
+}
+
+static inline void internal_add_timer(struct timer_list *timer)
+{
+ /*
+ * must be cli-ed when calling this
+ */
+ unsigned long expires = timer->expires;
+ unsigned long idx = expires - timer_jiffies;
+
+ if (idx < TVR_SIZE) {
+ int i = expires & TVR_MASK;
+ insert_timer(timer, tv1.vec, i);
+ } else if (idx < 1 << (TVR_BITS + TVN_BITS)) {
+ int i = (expires >> TVR_BITS) & TVN_MASK;
+ insert_timer(timer, tv2.vec, i);
+ } else if (idx < 1 << (TVR_BITS + 2 * TVN_BITS)) {
+ int i = (expires >> (TVR_BITS + TVN_BITS)) & TVN_MASK;
+ insert_timer(timer, tv3.vec, i);
+ } else if (idx < 1 << (TVR_BITS + 3 * TVN_BITS)) {
+ int i = (expires >> (TVR_BITS + 2 * TVN_BITS)) & TVN_MASK;
+ insert_timer(timer, tv4.vec, i);
+ } else if (expires < timer_jiffies) {
+ /* can happen if you add a timer with expires == jiffies,
+ * or you set a timer to go off in the past
+ */
+ insert_timer(timer, tv1.vec, tv1.index);
+ } else if (idx < 0xffffffffUL) {
+ int i = (expires >> (TVR_BITS + 3 * TVN_BITS)) & TVN_MASK;
+ insert_timer(timer, tv5.vec, i);
+ } else {
+ /* Can only get here on architectures with 64-bit jiffies */
+ timer->next = timer->prev = timer;
+ }
+}
+
+static spinlock_t timerlist_lock = SPIN_LOCK_UNLOCKED;
+
+void add_timer(struct timer_list *timer)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&timerlist_lock, flags);
+ internal_add_timer(timer);
+ spin_unlock_irqrestore(&timerlist_lock, flags);
+}
+
+static inline int detach_timer(struct timer_list *timer)
+{
+ int ret = 0;
+ struct timer_list *next, *prev;
+ next = timer->next;
+ prev = timer->prev;
+ if (next) {
+ next->prev = prev;
+ }
+ if (prev) {
+ ret = 1;
+ prev->next = next;
+ }
+ return ret;
+}
+
+
+int del_timer(struct timer_list * timer)
+{
+ int ret;
+ unsigned long flags;
+
+ spin_lock_irqsave(&timerlist_lock, flags);
+ ret = detach_timer(timer);
+ timer->next = timer->prev = 0;
+ spin_unlock_irqrestore(&timerlist_lock, flags);
+ return ret;
+}
+
#ifdef __SMP__
#define idle_task (task[cpu_number_map[this_cpu]])
-#define can_schedule(p) ((p)->processor == NO_PROC_ID)
+#define can_schedule(p) (!(p)->has_cpu)
#else
@@ -297,12 +379,10 @@ asmlinkage void schedule(void)
int this_cpu;
need_resched = 0;
- this_cpu = smp_processor_id();
- if (local_irq_count[this_cpu]) {
- printk("Scheduling in interrupt\n");
- *(char *)0 = 0;
- }
prev = current;
+ this_cpu = smp_processor_id();
+ if (local_irq_count[this_cpu])
+ goto scheduling_in_interrupt;
release_kernel_lock(prev, this_cpu, lock_depth);
if (bh_active & bh_mask)
do_bottom_half();
@@ -312,16 +392,8 @@ asmlinkage void schedule(void)
/* move an exhausted RR process to be last.. */
if (!prev->counter && prev->policy == SCHED_RR) {
- if (prev->pid) {
- prev->counter = prev->priority;
- move_last_runqueue(prev);
- } else {
- static int count = 5;
- if (count) {
- count--;
- printk("Moving pid 0 last\n");
- }
- }
+ prev->counter = prev->priority;
+ move_last_runqueue(prev);
}
timeout = 0;
switch (prev->state) {
@@ -354,7 +426,7 @@ asmlinkage void schedule(void)
*/
spin_unlock_irq(&runqueue_lock);
#ifdef __SMP__
- prev->processor = NO_PROC_ID;
+ prev->has_cpu = 0;
#endif
/*
@@ -386,8 +458,10 @@ asmlinkage void schedule(void)
}
}
+#ifdef __SMP__
+ next->has_cpu = 1;
next->processor = this_cpu;
- next->last_processor = this_cpu;
+#endif
if (prev != next) {
struct timer_list timer;
@@ -410,6 +484,11 @@ asmlinkage void schedule(void)
spin_unlock(&scheduler_lock);
reacquire_kernel_lock(prev, smp_processor_id(), lock_depth);
+ return;
+
+scheduling_in_interrupt:
+ printk("Scheduling in interrupt\n");
+ *(int *)0 = 0;
}
#ifndef __alpha__
@@ -427,67 +506,53 @@ asmlinkage int sys_pause(void)
#endif
-spinlock_t waitqueue_lock;
+rwlock_t waitqueue_lock = RW_LOCK_UNLOCKED;
/*
* wake_up doesn't wake up stopped processes - they have to be awakened
* with signals or similar.
+ *
+ * Note that we only need a read lock for the wait queue (and thus do not
+ * have to protect against interrupts), as the actual removal from the
+ * queue is handled by the process itself.
*/
void wake_up(struct wait_queue **q)
{
- unsigned long flags;
struct wait_queue *next;
- struct wait_queue *head;
- spin_lock_irqsave(&waitqueue_lock, flags);
+ read_lock(&waitqueue_lock);
if (q && (next = *q)) {
+ struct wait_queue *head;
+
head = WAIT_QUEUE_HEAD(q);
while (next != head) {
struct task_struct *p = next->task;
next = next->next;
- if (p != NULL) {
- if ((p->state == TASK_UNINTERRUPTIBLE) ||
- (p->state == TASK_INTERRUPTIBLE))
- wake_up_process(p);
- }
- if (next)
- continue;
- printk("wait_queue is bad (eip = %p)\n",
- __builtin_return_address(0));
- printk(" q = %p\n",q);
- printk(" *q = %p\n",*q);
- break;
+ if ((p->state == TASK_UNINTERRUPTIBLE) ||
+ (p->state == TASK_INTERRUPTIBLE))
+ wake_up_process(p);
}
}
- spin_unlock_irqrestore(&waitqueue_lock, flags);
+ read_unlock(&waitqueue_lock);
}
void wake_up_interruptible(struct wait_queue **q)
{
- unsigned long flags;
struct wait_queue *next;
- struct wait_queue *head;
- spin_lock_irqsave(&waitqueue_lock, flags);
+ read_lock(&waitqueue_lock);
if (q && (next = *q)) {
+ struct wait_queue *head;
+
head = WAIT_QUEUE_HEAD(q);
while (next != head) {
struct task_struct *p = next->task;
next = next->next;
- if (p != NULL) {
- if (p->state == TASK_INTERRUPTIBLE)
- wake_up_process(p);
- }
- if (next)
- continue;
- printk("wait_queue is bad (eip = %p)\n",
- __builtin_return_address(0));
- printk(" q = %p\n",q);
- printk(" *q = %p\n",*q);
- break;
+ if (p->state == TASK_INTERRUPTIBLE)
+ wake_up_process(p);
}
}
- spin_unlock_irqrestore(&waitqueue_lock, flags);
+ read_unlock(&waitqueue_lock);
}
/*
@@ -606,17 +671,14 @@ static inline void __sleep_on(struct wait_queue **p, int state)
if (!p)
return;
- if (current == task[0])
- panic("task[0] trying to sleep");
current->state = state;
- spin_lock_irqsave(&waitqueue_lock, flags);
+ write_lock_irqsave(&waitqueue_lock, flags);
__add_wait_queue(p, &wait);
- spin_unlock(&waitqueue_lock);
- sti();
+ write_unlock(&waitqueue_lock);
schedule();
- spin_lock_irq(&waitqueue_lock);
+ write_lock_irq(&waitqueue_lock);
__remove_wait_queue(p, &wait);
- spin_unlock_irqrestore(&waitqueue_lock, flags);
+ write_unlock_irqrestore(&waitqueue_lock, flags);
}
void interruptible_sleep_on(struct wait_queue **p)
@@ -629,133 +691,6 @@ void sleep_on(struct wait_queue **p)
__sleep_on(p,TASK_UNINTERRUPTIBLE);
}
-
-#define TVN_BITS 6
-#define TVR_BITS 8
-#define TVN_SIZE (1 << TVN_BITS)
-#define TVR_SIZE (1 << TVR_BITS)
-#define TVN_MASK (TVN_SIZE - 1)
-#define TVR_MASK (TVR_SIZE - 1)
-
-#define SLOW_BUT_DEBUGGING_TIMERS 0
-
-struct timer_vec {
- int index;
- struct timer_list *vec[TVN_SIZE];
-};
-
-struct timer_vec_root {
- int index;
- struct timer_list *vec[TVR_SIZE];
-};
-
-static struct timer_vec tv5 = { 0 };
-static struct timer_vec tv4 = { 0 };
-static struct timer_vec tv3 = { 0 };
-static struct timer_vec tv2 = { 0 };
-static struct timer_vec_root tv1 = { 0 };
-
-static struct timer_vec * const tvecs[] = {
- (struct timer_vec *)&tv1, &tv2, &tv3, &tv4, &tv5
-};
-
-#define NOOF_TVECS (sizeof(tvecs) / sizeof(tvecs[0]))
-
-static unsigned long timer_jiffies = 0;
-
-static inline void insert_timer(struct timer_list *timer,
- struct timer_list **vec, int idx)
-{
- if ((timer->next = vec[idx]))
- vec[idx]->prev = timer;
- vec[idx] = timer;
- timer->prev = (struct timer_list *)&vec[idx];
-}
-
-static inline void internal_add_timer(struct timer_list *timer)
-{
- /*
- * must be cli-ed when calling this
- */
- unsigned long expires = timer->expires;
- unsigned long idx = expires - timer_jiffies;
-
- if (idx < TVR_SIZE) {
- int i = expires & TVR_MASK;
- insert_timer(timer, tv1.vec, i);
- } else if (idx < 1 << (TVR_BITS + TVN_BITS)) {
- int i = (expires >> TVR_BITS) & TVN_MASK;
- insert_timer(timer, tv2.vec, i);
- } else if (idx < 1 << (TVR_BITS + 2 * TVN_BITS)) {
- int i = (expires >> (TVR_BITS + TVN_BITS)) & TVN_MASK;
- insert_timer(timer, tv3.vec, i);
- } else if (idx < 1 << (TVR_BITS + 3 * TVN_BITS)) {
- int i = (expires >> (TVR_BITS + 2 * TVN_BITS)) & TVN_MASK;
- insert_timer(timer, tv4.vec, i);
- } else if (expires < timer_jiffies) {
- /* can happen if you add a timer with expires == jiffies,
- * or you set a timer to go off in the past
- */
- insert_timer(timer, tv1.vec, tv1.index);
- } else if (idx < 0xffffffffUL) {
- int i = (expires >> (TVR_BITS + 3 * TVN_BITS)) & TVN_MASK;
- insert_timer(timer, tv5.vec, i);
- } else {
- /* Can only get here on architectures with 64-bit jiffies */
- timer->next = timer->prev = timer;
- }
-}
-
-static spinlock_t timerlist_lock = SPIN_LOCK_UNLOCKED;
-
-void add_timer(struct timer_list *timer)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&timerlist_lock, flags);
-#if SLOW_BUT_DEBUGGING_TIMERS
- if (timer->next || timer->prev) {
- printk("add_timer() called with non-zero list from %p\n",
- __builtin_return_address(0));
- goto out;
- }
-#endif
- internal_add_timer(timer);
-#if SLOW_BUT_DEBUGGING_TIMERS
-out:
-#endif
- spin_unlock_irqrestore(&timerlist_lock, flags);
-}
-
-static inline int detach_timer(struct timer_list *timer)
-{
- int ret = 0;
- struct timer_list *next, *prev;
- next = timer->next;
- prev = timer->prev;
- if (next) {
- next->prev = prev;
- }
- if (prev) {
- ret = 1;
- prev->next = next;
- }
- return ret;
-}
-
-
-int del_timer(struct timer_list * timer)
-{
- int ret;
- unsigned long flags;
-
- spin_lock_irqsave(&timerlist_lock, flags);
- ret = detach_timer(timer);
- timer->next = timer->prev = 0;
- spin_unlock_irqrestore(&timerlist_lock, flags);
- return ret;
-}
-
static inline void cascade_timers(struct timer_vec *tv)
{
/* cascade all the timers from tv up one level */
@@ -847,17 +782,18 @@ unsigned long avenrun[3] = { 0,0,0 };
*/
static unsigned long count_active_tasks(void)
{
- struct task_struct **p;
+ struct task_struct *p;
unsigned long nr = 0;
- for(p = &LAST_TASK; p > &FIRST_TASK; --p)
- if (*p && ((*p)->state == TASK_RUNNING ||
- (*p)->state == TASK_UNINTERRUPTIBLE ||
- (*p)->state == TASK_SWAPPING))
+ read_lock(&tasklist_lock);
+ for_each_task(p) {
+ if (p->pid &&
+ (p->state == TASK_RUNNING ||
+ p->state == TASK_UNINTERRUPTIBLE ||
+ p->state == TASK_SWAPPING))
nr += FIXED_1;
-#ifdef __SMP__
- nr-=(smp_num_cpus-1)*FIXED_1;
-#endif
+ }
+ read_unlock(&tasklist_lock);
return nr;
}
@@ -1065,16 +1001,14 @@ static inline void do_process_times(struct task_struct *p,
{
long psecs;
- p->utime += user;
- p->stime += system;
-
- psecs = (p->stime + p->utime) / HZ;
- if (psecs > p->rlim[RLIMIT_CPU].rlim_cur) {
+ psecs = (p->times.tms_utime += user);
+ psecs += (p->times.tms_stime += system);
+ if (psecs / HZ > p->rlim[RLIMIT_CPU].rlim_cur) {
/* Send SIGXCPU every second.. */
- if (psecs * HZ == p->stime + p->utime)
+ if (!(psecs % HZ))
send_sig(SIGXCPU, p, 1);
/* and SIGKILL when we go over max.. */
- if (psecs > p->rlim[RLIMIT_CPU].rlim_max)
+ if (psecs / HZ > p->rlim[RLIMIT_CPU].rlim_max)
send_sig(SIGKILL, p, 1);
}
}
@@ -1344,22 +1278,12 @@ asmlinkage int sys_nice(int increment)
#endif
-static struct task_struct *find_process_by_pid(pid_t pid)
+static inline struct task_struct *find_process_by_pid(pid_t pid)
{
- struct task_struct *p;
-
- p = current;
- if (pid) {
- read_lock(&tasklist_lock);
- for_each_task(p) {
- if (p->pid == pid)
- goto found;
- }
- p = NULL;
-found:
- read_unlock(&tasklist_lock);
- }
- return p;
+ if (pid)
+ return find_task_by_pid(pid);
+ else
+ return current;
}
static int setscheduler(pid_t pid, int policy,
@@ -1572,7 +1496,7 @@ asmlinkage int sys_nanosleep(struct timespec *rqtp, struct timespec *rmtp)
static void show_task(int nr,struct task_struct * p)
{
- unsigned long free;
+ unsigned long free = 0;
static const char * stat_nam[] = { "R", "S", "D", "Z", "T", "W" };
printk("%-8s %3d ", p->comm, (p == current) ? -nr : nr);
@@ -1591,10 +1515,12 @@ static void show_task(int nr,struct task_struct * p)
else
printk(" %016lx ", thread_saved_pc(&p->tss));
#endif
+#if 0
for (free = 1; free < PAGE_SIZE/sizeof(long) ; free++) {
if (((unsigned long *)p->kernel_stack_page)[free])
break;
}
+#endif
printk("%5lu %5d %6d ", free*sizeof(long), p->pid, p->p_pptr->pid);
if (p->p_cptr)
printk("%5d ", p->p_cptr->pid);
@@ -1612,7 +1538,7 @@ static void show_task(int nr,struct task_struct * p)
void show_state(void)
{
- int i;
+ struct task_struct *p;
#if ((~0UL) == 0xffffffff)
printk("\n"
@@ -1623,25 +1549,30 @@ void show_state(void)
" free sibling\n");
printk(" task PC stack pid father child younger older\n");
#endif
- for (i=0 ; i<NR_TASKS ; i++)
- if (task[i])
- show_task(i,task[i]);
+ read_lock(&tasklist_lock);
+ for_each_task(p)
+ show_task((p->tarray_ptr - &task[0]),p);
+ read_unlock(&tasklist_lock);
}
-void sched_init(void)
+__initfunc(void sched_init(void))
{
/*
* We have to do a little magic to get the first
* process right in SMP mode.
*/
- int cpu=smp_processor_id();
-#ifndef __SMP__
- current_set[cpu]=&init_task;
-#else
+ int cpu=hard_smp_processor_id();
+ int nr = NR_TASKS;
+
init_task.processor=cpu;
- for(cpu = 0; cpu < NR_CPUS; cpu++)
- current_set[cpu] = &init_task;
-#endif
+
+ /* Init task array free list and pidhash table. */
+ while(--nr > 0)
+ add_free_taskslot(&task[nr]);
+
+ for(nr = 0; nr < PIDHASH_SZ; nr++)
+ pidhash[nr] = NULL;
+
init_bh(TIMER_BH, timer_bh);
init_bh(TQUEUE_BH, tqueue_bh);
init_bh(IMMEDIATE_BH, immediate_bh);
diff --git a/kernel/softirq.c b/kernel/softirq.c
index 6b9b41aa5..de398bcff 100644
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -62,13 +62,14 @@ static inline void run_bottom_halves(void)
asmlinkage void do_bottom_half(void)
{
- int cpu = smp_processor_id();
+ if (softirq_trylock()) {
+ int cpu = smp_processor_id();
- if (hardirq_trylock(cpu)) {
- if (softirq_trylock()) {
+ if (hardirq_trylock(cpu)) {
+ __sti();
run_bottom_halves();
- softirq_endlock();
+ hardirq_endlock(cpu);
}
- hardirq_endlock(cpu);
+ softirq_endlock();
}
}
diff --git a/kernel/sys.c b/kernel/sys.c
index 934108fa8..311527865 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -370,8 +370,8 @@ int acct_process(long exitcode)
if (acct_active) {
strncpy(ac.ac_comm, current->comm, ACCT_COMM);
ac.ac_comm[ACCT_COMM-1] = '\0';
- ac.ac_utime = current->utime;
- ac.ac_stime = current->stime;
+ ac.ac_utime = current->times.tms_utime;
+ ac.ac_stime = current->times.tms_stime;
ac.ac_btime = CT_TO_SECS(current->start_time) + (xtime.tv_sec - (jiffies / HZ));
ac.ac_etime = CURRENT_TIME - ac.ac_btime;
ac.ac_uid = current->uid;
@@ -523,16 +523,15 @@ asmlinkage int sys_old_syscall(void)
*/
asmlinkage int sys_setreuid(uid_t ruid, uid_t euid)
{
- int old_ruid;
- int old_euid;
+ int old_ruid, old_euid, new_ruid;
- old_ruid = current->uid;
+ new_ruid = old_ruid = current->uid;
old_euid = current->euid;
if (ruid != (uid_t) -1) {
if ((old_ruid == ruid) ||
(current->euid==ruid) ||
suser())
- current->uid = ruid;
+ new_ruid = ruid;
else
return -EPERM;
}
@@ -542,10 +541,8 @@ asmlinkage int sys_setreuid(uid_t ruid, uid_t euid)
(current->suid == euid) ||
suser())
current->fsuid = current->euid = euid;
- else {
- current->uid = old_ruid;
+ else
return -EPERM;
- }
}
if (ruid != (uid_t) -1 ||
(euid != (uid_t) -1 && euid != old_ruid))
@@ -553,6 +550,18 @@ asmlinkage int sys_setreuid(uid_t ruid, uid_t euid)
current->fsuid = current->euid;
if (current->euid != old_euid)
current->dumpable = 0;
+
+ if(new_ruid != old_ruid) {
+ /* What if a process setreuid()'s and this brings the
+ * new uid over his NPROC rlimit? We can check this now
+ * cheaply with the new uid cache, so if it matters
+ * we should be checking for it. -DaveM
+ */
+ charge_uid(current, -1);
+ current->uid = new_ruid;
+ if(new_ruid)
+ charge_uid(current, 1);
+ }
return 0;
}
@@ -570,9 +579,11 @@ asmlinkage int sys_setreuid(uid_t ruid, uid_t euid)
asmlinkage int sys_setuid(uid_t uid)
{
int old_euid = current->euid;
+ int old_ruid, new_ruid;
+ old_ruid = new_ruid = current->uid;
if (suser())
- current->uid = current->euid = current->suid = current->fsuid = uid;
+ new_ruid = current->euid = current->suid = current->fsuid = uid;
else if ((uid == current->uid) || (uid == current->suid))
current->fsuid = current->euid = uid;
else
@@ -580,6 +591,14 @@ asmlinkage int sys_setuid(uid_t uid)
if (current->euid != old_euid)
current->dumpable = 0;
+
+ if(new_ruid != old_ruid) {
+ /* See comment above about NPROC rlimit issues... */
+ charge_uid(current, -1);
+ current->uid = new_ruid;
+ if(new_ruid)
+ charge_uid(current, 1);
+ }
return 0;
}
@@ -605,8 +624,13 @@ asmlinkage int sys_setresuid(uid_t ruid, uid_t euid, uid_t suid)
if ((suid != (uid_t) -1) && (suid != current->uid) &&
(suid != current->euid) && (suid != current->suid))
return -EPERM;
- if (ruid != (uid_t) -1)
+ if (ruid != (uid_t) -1) {
+ /* See above commentary about NPROC rlimit issues here. */
+ charge_uid(current, -1);
current->uid = ruid;
+ if(ruid)
+ charge_uid(current, 1);
+ }
if (euid != (uid_t) -1)
current->euid = euid;
if (suid != (uid_t) -1)
@@ -671,16 +695,9 @@ asmlinkage long sys_times(struct tms * tbuf)
* atomically safe type this is just fine. Conceptually its
* as if the syscall took an instant longer to occur.
*/
- if (tbuf)
- {
- /* ?? use copy_to_user() */
- if(!access_ok(VERIFY_READ, tbuf, sizeof(struct tms)) ||
- __put_user(current->utime,&tbuf->tms_utime)||
- __put_user(current->stime,&tbuf->tms_stime) ||
- __put_user(current->cutime,&tbuf->tms_cutime) ||
- __put_user(current->cstime,&tbuf->tms_cstime))
+ if (tbuf)
+ if (copy_to_user(tbuf, &current->times, sizeof(struct tms)))
return -EFAULT;
- }
return jiffies;
}
@@ -709,22 +726,13 @@ asmlinkage int sys_setpgid(pid_t pid, pid_t pgid)
if (pgid < 0)
return -EINVAL;
- read_lock(&tasklist_lock);
- for_each_task(p) {
- if (p->pid == pid) {
- /* NOTE: I haven't dropped tasklist_lock, this is
- * on purpose. -DaveM
- */
- goto found_task;
- }
- }
- read_unlock(&tasklist_lock);
- return -ESRCH;
+ if((p = find_task_by_pid(pid)) == NULL)
+ return -ESRCH;
-found_task:
/* From this point forward we keep holding onto the tasklist lock
* so that our parent does not change from under us. -DaveM
*/
+ read_lock(&tasklist_lock);
err = -ESRCH;
if (p->p_pptr == current || p->p_opptr == current) {
err = -EPERM;
@@ -762,18 +770,12 @@ asmlinkage int sys_getpgid(pid_t pid)
if (!pid) {
return current->pgrp;
} else {
- struct task_struct *p;
- int ret = -ESRCH;
-
- read_lock(&tasklist_lock);
- for_each_task(p) {
- if (p->pid == pid) {
- ret = p->pgrp;
- break;
- }
- }
- read_unlock(&tasklist_lock);
- return ret;
+ struct task_struct *p = find_task_by_pid(pid);
+
+ if(p)
+ return p->pgrp;
+ else
+ return -ESRCH;
}
}
@@ -785,25 +787,16 @@ asmlinkage int sys_getpgrp(void)
asmlinkage int sys_getsid(pid_t pid)
{
- struct task_struct * p;
- int ret;
-
- /* SMP: The 'self' case requires no lock */
if (!pid) {
- ret = current->session;
+ return current->session;
} else {
- ret = -ESRCH;
+ struct task_struct *p = find_task_by_pid(pid);
- read_lock(&tasklist_lock);
- for_each_task(p) {
- if (p->pid == pid) {
- ret = p->session;
- break;
- }
- }
- read_unlock(&tasklist_lock);
+ if(p)
+ return p->session;
+ else
+ return -ESRCH;
}
- return ret;
}
asmlinkage int sys_setsid(void)
@@ -1030,28 +1023,28 @@ int getrusage(struct task_struct *p, int who, struct rusage *ru)
memset((char *) &r, 0, sizeof(r));
switch (who) {
case RUSAGE_SELF:
- r.ru_utime.tv_sec = CT_TO_SECS(p->utime);
- r.ru_utime.tv_usec = CT_TO_USECS(p->utime);
- r.ru_stime.tv_sec = CT_TO_SECS(p->stime);
- r.ru_stime.tv_usec = CT_TO_USECS(p->stime);
+ r.ru_utime.tv_sec = CT_TO_SECS(p->times.tms_utime);
+ r.ru_utime.tv_usec = CT_TO_USECS(p->times.tms_utime);
+ r.ru_stime.tv_sec = CT_TO_SECS(p->times.tms_stime);
+ r.ru_stime.tv_usec = CT_TO_USECS(p->times.tms_stime);
r.ru_minflt = p->min_flt;
r.ru_majflt = p->maj_flt;
r.ru_nswap = p->nswap;
break;
case RUSAGE_CHILDREN:
- r.ru_utime.tv_sec = CT_TO_SECS(p->cutime);
- r.ru_utime.tv_usec = CT_TO_USECS(p->cutime);
- r.ru_stime.tv_sec = CT_TO_SECS(p->cstime);
- r.ru_stime.tv_usec = CT_TO_USECS(p->cstime);
+ r.ru_utime.tv_sec = CT_TO_SECS(p->times.tms_cutime);
+ r.ru_utime.tv_usec = CT_TO_USECS(p->times.tms_cutime);
+ r.ru_stime.tv_sec = CT_TO_SECS(p->times.tms_cstime);
+ r.ru_stime.tv_usec = CT_TO_USECS(p->times.tms_cstime);
r.ru_minflt = p->cmin_flt;
r.ru_majflt = p->cmaj_flt;
r.ru_nswap = p->cnswap;
break;
default:
- r.ru_utime.tv_sec = CT_TO_SECS(p->utime + p->cutime);
- r.ru_utime.tv_usec = CT_TO_USECS(p->utime + p->cutime);
- r.ru_stime.tv_sec = CT_TO_SECS(p->stime + p->cstime);
- r.ru_stime.tv_usec = CT_TO_USECS(p->stime + p->cstime);
+ r.ru_utime.tv_sec = CT_TO_SECS(p->times.tms_utime + p->times.tms_cutime);
+ r.ru_utime.tv_usec = CT_TO_USECS(p->times.tms_utime + p->times.tms_cutime);
+ r.ru_stime.tv_sec = CT_TO_SECS(p->times.tms_stime + p->times.tms_cstime);
+ r.ru_stime.tv_usec = CT_TO_USECS(p->times.tms_stime + p->times.tms_cstime);
r.ru_minflt = p->min_flt + p->cmin_flt;
r.ru_majflt = p->maj_flt + p->cmaj_flt;
r.ru_nswap = p->nswap + p->cnswap;
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 9e0bb0fd8..3f2e86a6b 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -24,6 +24,7 @@
#include <linux/swapctl.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
+#include <linux/init.h>
#include <asm/bitops.h>
#include <asm/uaccess.h>
@@ -210,7 +211,7 @@ static ctl_table dev_table[] = {
};
-void sysctl_init(void)
+__initfunc(void sysctl_init(void))
{
#ifdef CONFIG_PROC_FS
register_proc_table(root_table, &proc_sys_root);
diff --git a/mm/Makefile b/mm/Makefile
index 5f5156049..c64eefbd2 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -9,7 +9,7 @@
O_TARGET := mm.o
O_OBJS := memory.o mmap.o filemap.o mprotect.o mlock.o mremap.o \
- kmalloc.o vmalloc.o slab.o \
+ vmalloc.o slab.o \
swap.o vmscan.o page_io.o page_alloc.o swap_state.o swapfile.o
include $(TOPDIR)/Rules.make
diff --git a/mm/filemap.c b/mm/filemap.c
index 6f58da546..88c2fd49d 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -171,7 +171,7 @@ int shrink_mmap(int priority, int dma)
switch (atomic_read(&page->count)) {
case 1:
/* If it has been referenced recently, don't free it */
- if (clear_bit(PG_referenced, &page->flags))
+ if (test_and_clear_bit(PG_referenced, &page->flags))
break;
/* is it a page cache page? */
@@ -1342,7 +1342,7 @@ generic_file_write(struct inode *inode, struct file *file, const char *buf, unsi
}
lockit:
- while (set_bit(PG_locked, &page->flags))
+ while (test_and_set_bit(PG_locked, &page->flags))
wait_on_page(page);
/*
diff --git a/mm/kmalloc.c b/mm/kmalloc.c
deleted file mode 100644
index 9de1bff51..000000000
--- a/mm/kmalloc.c
+++ /dev/null
@@ -1,453 +0,0 @@
-/*
- * linux/mm/kmalloc.c
- *
- * Copyright (C) 1991, 1992 Linus Torvalds & Roger Wolff.
- *
- * Written by R.E. Wolff Sept/Oct '93.
- *
- */
-
-/*
- * Modified by Alex Bligh (alex@cconcepts.co.uk) 4 Apr 1994 to use multiple
- * pages. So for 'page' throughout, read 'area'.
- *
- * Largely rewritten.. Linus
- */
-
-#include <linux/mm.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-
-#include <asm/system.h>
-#include <asm/dma.h>
-
-/* Define this if you want slow routines that try to trip errors */
-#undef SADISTIC_KMALLOC
-
-/* Private flags. */
-
-#define MF_USED 0xffaa0055
-#define MF_DMA 0xff00aa55
-#define MF_FREE 0x0055ffaa
-
-
-/*
- * Much care has gone into making these routines in this file reentrant.
- *
- * The fancy bookkeeping of nbytesmalloced and the like are only used to
- * report them to the user (oooohhhhh, aaaaahhhhh....) are not
- * protected by cli(). (If that goes wrong. So what?)
- *
- * These routines restore the interrupt status to allow calling with ints
- * off.
- */
-
-/*
- * A block header. This is in front of every malloc-block, whether free or not.
- */
-struct block_header {
- unsigned long bh_flags;
- union {
- unsigned long ubh_length;
- struct block_header *fbh_next;
- } vp;
-};
-
-
-#define bh_length vp.ubh_length
-#define bh_next vp.fbh_next
-#define BH(p) ((struct block_header *)(p))
-
-
-/*
- * The page descriptor is at the front of every page that malloc has in use.
- */
-struct page_descriptor {
- struct page_descriptor *next;
- struct block_header *firstfree;
- int order;
- int nfree;
-};
-
-
-#define PAGE_DESC(p) ((struct page_descriptor *)(((unsigned long)(p)) & PAGE_MASK))
-
-
-/*
- * A size descriptor describes a specific class of malloc sizes.
- * Each class of sizes has its own freelist.
- */
-struct size_descriptor {
- struct page_descriptor *firstfree;
- struct page_descriptor *dmafree; /* DMA-able memory */
- int nblocks;
-
- int nmallocs;
- int nfrees;
- int nbytesmalloced;
- int npages;
- unsigned long gfporder; /* number of pages in the area required */
-};
-
-/*
- * For now it is unsafe to allocate bucket sizes between n and
- * n-sizeof(page_descriptor) where n is PAGE_SIZE * any power of two
- *
- * The blocksize and sizes arrays _must_ match!
- */
-#if PAGE_SIZE == 4096
-static const unsigned int blocksize[] = {
- 32,
- 64,
- 128,
- 252,
- 508,
- 1020,
- 2040,
- 4096 - 16,
- 8192 - 16,
- 16384 - 16,
- 32768 - 16,
- 65536 - 16,
- 131072 - 16,
- 0
-};
-
-static struct size_descriptor sizes[] =
-{
- {NULL, NULL, 127, 0, 0, 0, 0, 0},
- {NULL, NULL, 63, 0, 0, 0, 0, 0},
- {NULL, NULL, 31, 0, 0, 0, 0, 0},
- {NULL, NULL, 16, 0, 0, 0, 0, 0},
- {NULL, NULL, 8, 0, 0, 0, 0, 0},
- {NULL, NULL, 4, 0, 0, 0, 0, 0},
- {NULL, NULL, 2, 0, 0, 0, 0, 0},
- {NULL, NULL, 1, 0, 0, 0, 0, 0},
- {NULL, NULL, 1, 0, 0, 0, 0, 1},
- {NULL, NULL, 1, 0, 0, 0, 0, 2},
- {NULL, NULL, 1, 0, 0, 0, 0, 3},
- {NULL, NULL, 1, 0, 0, 0, 0, 4},
- {NULL, NULL, 1, 0, 0, 0, 0, 5},
- {NULL, NULL, 0, 0, 0, 0, 0, 0}
-};
-#elif PAGE_SIZE == 8192
-static const unsigned int blocksize[] = {
- 64,
- 128,
- 248,
- 504,
- 1016,
- 2040,
- 4080,
- 8192 - 32,
- 16384 - 32,
- 32768 - 32,
- 65536 - 32,
- 131072 - 32,
- 262144 - 32,
- 0
-};
-
-struct size_descriptor sizes[] =
-{
- {NULL, NULL, 127, 0, 0, 0, 0, 0},
- {NULL, NULL, 63, 0, 0, 0, 0, 0},
- {NULL, NULL, 31, 0, 0, 0, 0, 0},
- {NULL, NULL, 16, 0, 0, 0, 0, 0},
- {NULL, NULL, 8, 0, 0, 0, 0, 0},
- {NULL, NULL, 4, 0, 0, 0, 0, 0},
- {NULL, NULL, 2, 0, 0, 0, 0, 0},
- {NULL, NULL, 1, 0, 0, 0, 0, 0},
- {NULL, NULL, 1, 0, 0, 0, 0, 1},
- {NULL, NULL, 1, 0, 0, 0, 0, 2},
- {NULL, NULL, 1, 0, 0, 0, 0, 3},
- {NULL, NULL, 1, 0, 0, 0, 0, 4},
- {NULL, NULL, 1, 0, 0, 0, 0, 5},
- {NULL, NULL, 0, 0, 0, 0, 0, 0}
-};
-#else
-#error you need to make a version for your pagesize
-#endif
-
-#define NBLOCKS(order) (sizes[order].nblocks)
-#define BLOCKSIZE(order) (blocksize[order])
-#define AREASIZE(order) (PAGE_SIZE<<(sizes[order].gfporder))
-
-/*
- * Create a small cache of page allocations: this helps a bit with
- * those pesky 8kB+ allocations for NFS when we're temporarily
- * out of memory..
- *
- * This is a _truly_ small cache, we just cache one single page
- * order (for orders 0, 1 and 2, that is 4, 8 and 16kB on x86).
- */
-#define MAX_CACHE_ORDER 3
-struct page_descriptor * kmalloc_cache[MAX_CACHE_ORDER];
-
-static inline struct page_descriptor * get_kmalloc_pages(unsigned long priority,
- unsigned long order, int dma)
-{
- return (struct page_descriptor *) __get_free_pages(priority, order, dma);
-}
-
-static inline void free_kmalloc_pages(struct page_descriptor * page,
- unsigned long order, int dma)
-{
- if (!dma && order < MAX_CACHE_ORDER) {
- page = xchg(kmalloc_cache+order, page);
- if (!page)
- return;
- }
- free_pages((unsigned long) page, order);
-}
-
-long kmalloc_init(long start_mem, long end_mem)
-{
- int order;
-
-/*
- * Check the static info array. Things will blow up terribly if it's
- * incorrect. This is a late "compile time" check.....
- */
- for (order = 0; BLOCKSIZE(order); order++) {
- if ((NBLOCKS(order) * BLOCKSIZE(order) + sizeof(struct page_descriptor)) >
- AREASIZE(order)) {
- printk("Cannot use %d bytes out of %d in order = %d block mallocs\n",
- (int) (NBLOCKS(order) * BLOCKSIZE(order) +
- sizeof(struct page_descriptor)),
- (int) AREASIZE(order),
- BLOCKSIZE(order));
- panic("This only happens if someone messes with kmalloc");
- }
- }
- return start_mem;
-}
-
-
-/*
- * Ugh, this is ugly, but we want the default case to run
- * straight through, which is why we have the ugly goto's
- */
-void *kmalloc(size_t size, int priority)
-{
- unsigned long flags;
- unsigned long type;
- int order, dma;
- struct block_header *p;
- struct page_descriptor *page, **pg;
- struct size_descriptor *bucket = sizes;
-
- /* Get order */
- order = 0;
- {
- unsigned int realsize = size + sizeof(struct block_header);
- for (;;) {
- int ordersize = BLOCKSIZE(order);
- if (realsize <= ordersize)
- break;
- order++;
- bucket++;
- if (ordersize)
- continue;
- printk("kmalloc of too large a block (%d bytes).\n", (int) size);
- return NULL;
- }
- }
-
- dma = 0;
- type = MF_USED;
- pg = &bucket->firstfree;
- if (priority & GFP_DMA) {
- dma = 1;
- type = MF_DMA;
- pg = &bucket->dmafree;
- }
-
- priority &= GFP_LEVEL_MASK;
-
-/* Sanity check... */
-
- if (in_interrupt() && priority != GFP_ATOMIC) {
- static int count = 0;
- if (++count < 5) {
- printk("kmalloc called nonatomically from interrupt %p\n",
- return_address());
- priority = GFP_ATOMIC;
- }
- }
-
- save_flags(flags);
- cli();
- page = *pg;
- if (!page)
- goto no_bucket_page;
-
- p = page->firstfree;
- if (p->bh_flags != MF_FREE)
- goto not_free_on_freelist;
-
-found_it:
- page->firstfree = p->bh_next;
- page->nfree--;
- if (!page->nfree)
- *pg = page->next;
- restore_flags(flags);
- bucket->nmallocs++;
- bucket->nbytesmalloced += size;
- p->bh_flags = type; /* As of now this block is officially in use */
- p->bh_length = size;
-#ifdef SADISTIC_KMALLOC
- memset(p+1, 0xf0, size);
-#endif
- return p + 1; /* Pointer arithmetic: increments past header */
-
-
-no_bucket_page:
- /*
- * If we didn't find a page already allocated for this
- * bucket size, we need to get one..
- *
- * This can be done with ints on: it is private to this invocation
- */
- restore_flags(flags);
-
- {
- int i, sz;
-
- /* sz is the size of the blocks we're dealing with */
- sz = BLOCKSIZE(order);
-
- page = get_kmalloc_pages(priority, bucket->gfporder, dma);
- if (!page)
- goto no_free_page;
-found_cached_page:
-
- bucket->npages++;
-
- page->order = order;
- /* Loop for all but last block: */
- i = (page->nfree = bucket->nblocks) - 1;
- p = BH(page + 1);
- while (i > 0) {
- i--;
- p->bh_flags = MF_FREE;
- p->bh_next = BH(((long) p) + sz);
- p = p->bh_next;
- }
- /* Last block: */
- p->bh_flags = MF_FREE;
- p->bh_next = NULL;
-
- p = BH(page+1);
- }
-
- /*
- * Now we're going to muck with the "global" freelist
- * for this size: this should be uninterruptible
- */
- cli();
- page->next = *pg;
- *pg = page;
- goto found_it;
-
-
-no_free_page:
- /*
- * No free pages, check the kmalloc cache of
- * pages to see if maybe we have something available
- */
- if (!dma && order < MAX_CACHE_ORDER) {
- page = xchg(kmalloc_cache+order, page);
- if (page)
- goto found_cached_page;
- }
- {
- static unsigned long last = 0;
- if (priority != GFP_BUFFER && (last + 10 * HZ < jiffies)) {
- last = jiffies;
- printk("Couldn't get a free page.....\n");
- }
- return NULL;
- }
-
-not_free_on_freelist:
- restore_flags(flags);
- printk("Problem: block on freelist at %08lx isn't free.\n", (long) p);
- return NULL;
-}
-
-void kfree(void *__ptr)
-{
- int dma;
- unsigned long flags;
- unsigned int order;
- struct page_descriptor *page, **pg;
- struct size_descriptor *bucket;
-
- if (!__ptr)
- goto null_kfree;
-#define ptr ((struct block_header *) __ptr)
- page = PAGE_DESC(ptr);
- __ptr = ptr - 1;
- if (~PAGE_MASK & (unsigned long)page->next)
- goto bad_order;
- order = page->order;
- if (order >= sizeof(sizes) / sizeof(sizes[0]))
- goto bad_order;
- bucket = sizes + order;
- dma = 0;
- pg = &bucket->firstfree;
- if (ptr->bh_flags == MF_DMA) {
- dma = 1;
- ptr->bh_flags = MF_USED;
- pg = &bucket->dmafree;
- }
- if (ptr->bh_flags != MF_USED)
- goto bad_order;
- ptr->bh_flags = MF_FREE; /* As of now this block is officially free */
-#ifdef SADISTIC_KMALLOC
- memset(ptr+1, 0x0e, ptr->bh_length);
-#endif
- save_flags(flags);
- cli();
-
- bucket->nfrees++;
- bucket->nbytesmalloced -= ptr->bh_length;
-
- ptr->bh_next = page->firstfree;
- page->firstfree = ptr;
- if (!page->nfree++) {
-/* Page went from full to one free block: put it on the freelist. */
- if (bucket->nblocks == 1)
- goto free_page;
- page->next = *pg;
- *pg = page;
- }
-/* If page is completely free, free it */
- if (page->nfree == bucket->nblocks) {
- for (;;) {
- struct page_descriptor *tmp = *pg;
- if (!tmp)
- goto not_on_freelist;
- if (tmp == page)
- break;
- pg = &tmp->next;
- }
- *pg = page->next;
-free_page:
- bucket->npages--;
- free_kmalloc_pages(page, bucket->gfporder, dma);
- }
- restore_flags(flags);
-null_kfree:
- return;
-
-bad_order:
- printk("kfree of non-kmalloced memory: %p, next= %p, order=%d\n",
- ptr+1, page->next, page->order);
- return;
-
-not_on_freelist:
- printk("Ooops. page %p doesn't show on freelist.\n", page);
- restore_flags(flags);
-}
diff --git a/mm/memory.c b/mm/memory.c
index 27dc33efe..530a65ca9 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -589,26 +589,13 @@ unsigned long put_dirty_page(struct task_struct * tsk, unsigned long page, unsig
* change only once the write actually happens. This avoids a few races,
* and potentially makes it more efficient.
*/
-void do_wp_page(struct task_struct * tsk, struct vm_area_struct * vma,
- unsigned long address, int write_access)
+static void do_wp_page(struct task_struct * tsk, struct vm_area_struct * vma,
+ unsigned long address, int write_access, pte_t *page_table)
{
- pgd_t *page_dir;
- pmd_t *page_middle;
- pte_t *page_table, pte;
+ pte_t pte;
unsigned long old_page, new_page;
new_page = __get_free_page(GFP_KERNEL);
- page_dir = pgd_offset(vma->vm_mm, address);
- if (pgd_none(*page_dir))
- goto end_wp_page;
- if (pgd_bad(*page_dir))
- goto bad_wp_pagedir;
- page_middle = pmd_offset(page_dir, address);
- if (pmd_none(*page_middle))
- goto end_wp_page;
- if (pmd_bad(*page_middle))
- goto bad_wp_pagemiddle;
- page_table = pte_offset(page_middle, address);
pte = *page_table;
if (!pte_present(pte))
goto end_wp_page;
@@ -650,14 +637,6 @@ void do_wp_page(struct task_struct * tsk, struct vm_area_struct * vma,
bad_wp_page:
printk("do_wp_page: bogus page at address %08lx (%08lx)\n",address,old_page);
send_sig(SIGKILL, tsk, 1);
- goto end_wp_page;
-bad_wp_pagemiddle:
- printk("do_wp_page: bogus page-middle at address %08lx (%08lx)\n", address, pmd_val(*page_middle));
- send_sig(SIGKILL, tsk, 1);
- goto end_wp_page;
-bad_wp_pagedir:
- printk("do_wp_page: bogus page-dir entry at address %08lx (%08lx)\n", address, pgd_val(*page_dir));
- send_sig(SIGKILL, tsk, 1);
end_wp_page:
if (new_page)
free_page(new_page);
@@ -746,7 +725,7 @@ void vmtruncate(struct inode * inode, unsigned long offset)
flush_cache_range(mm, start, end);
zap_page_range(mm, start, len);
flush_tlb_range(mm, start, end);
- } while ((mpnt = mpnt->vm_next_share) != inode->i_mmap);
+ } while ((mpnt = mpnt->vm_next_share) != NULL);
}
@@ -785,25 +764,11 @@ static inline void do_swap_page(struct task_struct * tsk,
* As this is called only for pages that do not currently exist, we
* do not need to flush old virtual caches or the TLB.
*/
-void do_no_page(struct task_struct * tsk, struct vm_area_struct * vma,
- unsigned long address, int write_access)
+static void do_no_page(struct task_struct * tsk, struct vm_area_struct * vma,
+ unsigned long address, int write_access, pte_t *page_table, pte_t entry)
{
- pgd_t * pgd;
- pmd_t * pmd;
- pte_t * page_table;
- pte_t entry;
unsigned long page;
- pgd = pgd_offset(tsk->mm, address);
- pmd = pmd_alloc(pgd, address);
- if (!pmd)
- goto no_memory;
- page_table = pte_alloc(pmd, address);
- if (!page_table)
- goto no_memory;
- entry = *page_table;
- if (pte_present(entry))
- goto is_present;
if (!pte_none(entry))
goto swap_page;
address &= PAGE_MASK;
@@ -865,18 +830,9 @@ sigbus:
swap_page:
do_swap_page(tsk, vma, address, page_table, entry, write_access);
return;
-
-no_memory:
- oom(tsk);
-is_present:
- return;
}
/*
- * The above separate functions for the no-page and wp-page
- * cases will go away (they mostly do the same thing anyway),
- * and we'll instead use only a general "handle_mm_fault()".
- *
* These routines also need to handle stuff like marking pages dirty
* and/or accessed for architectures that don't do it in hardware (most
* RISC architectures). The early dirtying is also good on the i386.
@@ -885,27 +841,30 @@ is_present:
* with external mmu caches can use to update those (ie the Sparc or
* PowerPC hashed page tables that act as extended TLBs).
*/
-static inline void handle_pte_fault(struct vm_area_struct * vma, unsigned long address,
+static inline void handle_pte_fault(struct task_struct *tsk,
+ struct vm_area_struct * vma, unsigned long address,
int write_access, pte_t * pte)
{
- if (!pte_present(*pte)) {
- do_no_page(current, vma, address, write_access);
+ pte_t entry = *pte;
+
+ if (!pte_present(entry)) {
+ do_no_page(tsk, vma, address, write_access, pte, entry);
return;
}
- set_pte(pte, pte_mkyoung(*pte));
+ set_pte(pte, pte_mkyoung(entry));
flush_tlb_page(vma, address);
if (!write_access)
return;
- if (pte_write(*pte)) {
- set_pte(pte, pte_mkdirty(*pte));
+ if (pte_write(entry)) {
+ set_pte(pte, pte_mkdirty(entry));
flush_tlb_page(vma, address);
return;
}
- do_wp_page(current, vma, address, write_access);
+ do_wp_page(tsk, vma, address, write_access, pte);
}
-void handle_mm_fault(struct vm_area_struct * vma, unsigned long address,
- int write_access)
+void handle_mm_fault(struct task_struct *tsk, struct vm_area_struct * vma,
+ unsigned long address, int write_access)
{
pgd_t *pgd;
pmd_t *pmd;
@@ -918,9 +877,9 @@ void handle_mm_fault(struct vm_area_struct * vma, unsigned long address,
pte = pte_alloc(pmd, address);
if (!pte)
goto no_memory;
- handle_pte_fault(vma, address, write_access, pte);
+ handle_pte_fault(tsk, vma, address, write_access, pte);
update_mmu_cache(vma, address, *pte);
return;
no_memory:
- oom(current);
+ oom(tsk);
}
diff --git a/mm/mmap.c b/mm/mmap.c
index 4a5ed16a3..13b19bec0 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -16,13 +16,13 @@
#include <linux/swap.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
+#include <linux/init.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/pgtable.h>
-/*
- * description of effects of mapping type and prot in current implementation.
+/* description of effects of mapping type and prot in current implementation.
* this is due to the limited x86 page protection hardware. The expected
* behavior is in parens:
*
@@ -37,7 +37,6 @@
* x: (no) no x: (no) yes x: (no) yes x: (yes) yes
*
*/
-
pgprot_t protection_map[16] = {
__P000, __P001, __P010, __P011, __P100, __P101, __P110, __P111,
__S000, __S001, __S010, __S011, __S100, __S101, __S110, __S111
@@ -48,20 +47,18 @@ kmem_cache_t *vm_area_cachep;
int sysctl_overcommit_memory;
-/*
- * Check that a process has enough memory to allocate a
+/* Check that a process has enough memory to allocate a
* new virtual mapping.
*/
int vm_enough_memory(long pages)
{
- /*
- * stupid algorithm to decide if we have enough memory: while
+ /* Stupid algorithm to decide if we have enough memory: while
* simple, it hopefully works in most obvious cases.. Easy to
* fool it, but this should catch most mistakes.
*/
long freepages;
- /* sometimes we want to use more memory than we have. */
+ /* Sometimes we want to use more memory than we have. */
if (sysctl_overcommit_memory)
return 1;
@@ -74,6 +71,20 @@ int vm_enough_memory(long pages)
return freepages > pages;
}
+/* Remove one vm structure from the inode's i_mmap ring. */
+static inline void remove_shared_vm_struct(struct vm_area_struct *vma)
+{
+ struct inode * inode = vma->vm_inode;
+
+ if (inode) {
+ if (vma->vm_flags & VM_DENYWRITE)
+ inode->i_writecount++;
+ if(vma->vm_next_share)
+ vma->vm_next_share->vm_pprev_share = vma->vm_pprev_share;
+ *vma->vm_pprev_share = vma->vm_next_share;
+ }
+}
+
asmlinkage unsigned long sys_brk(unsigned long brk)
{
unsigned long rlim, retval;
@@ -91,17 +102,14 @@ asmlinkage unsigned long sys_brk(unsigned long brk)
goto out;
}
- /*
- * Always allow shrinking brk
- */
+ /* Always allow shrinking brk. */
if (brk <= mm->brk) {
retval = mm->brk = brk;
do_munmap(newbrk, oldbrk-newbrk);
goto out;
}
- /*
- * Check against rlimit and stack..
- */
+
+ /* Check against rlimit and stack.. */
retval = mm->brk;
rlim = current->rlim[RLIMIT_DATA].rlim_cur;
if (rlim >= RLIM_INFINITY)
@@ -109,21 +117,15 @@ asmlinkage unsigned long sys_brk(unsigned long brk)
if (brk - mm->end_code > rlim)
goto out;
- /*
- * Check against existing mmap mappings.
- */
+ /* Check against existing mmap mappings. */
if (find_vma_intersection(mm, oldbrk, newbrk+PAGE_SIZE))
goto out;
- /*
- * Check if we have enough memory..
- */
+ /* Check if we have enough memory.. */
if (!vm_enough_memory((newbrk-oldbrk) >> PAGE_SHIFT))
goto out;
- /*
- * Ok, looks good - let it rip.
- */
+ /* Ok, looks good - let it rip. */
if(do_mmap(NULL, oldbrk, newbrk-oldbrk,
PROT_READ|PROT_WRITE|PROT_EXEC,
MAP_FIXED|MAP_PRIVATE, 0) == oldbrk)
@@ -134,8 +136,7 @@ out:
return retval;
}
-/*
- * Combine the mmap "prot" and "flags" argument into one "vm_flags" used
+/* Combine the mmap "prot" and "flags" argument into one "vm_flags" used
* internally. Essentially, translate the "PROT_xxx" and "MAP_xxx" bits
* into "VM_xxx".
*/
@@ -162,6 +163,7 @@ unsigned long do_mmap(struct file * file, unsigned long addr, unsigned long len,
{
struct mm_struct * mm = current->mm;
struct vm_area_struct * vma;
+ int correct_wcount = 0;
if ((len = PAGE_ALIGN(len)) == 0)
return addr;
@@ -181,20 +183,17 @@ unsigned long do_mmap(struct file * file, unsigned long addr, unsigned long len,
return -EAGAIN;
}
- /*
- * do simple checking here so the lower-level routines won't have
+ /* Do simple checking here so the lower-level routines won't have
* to. we assume access permissions have been handled by the open
* of the memory object, so we don't do any here.
*/
-
if (file != NULL) {
switch (flags & MAP_TYPE) {
case MAP_SHARED:
if ((prot & PROT_WRITE) && !(file->f_mode & 2))
return -EACCES;
- /*
- * make sure there are no mandatory locks on the file.
- */
+
+ /* make sure there are no mandatory locks on the file. */
if (locks_verify_locked(file->f_inode))
return -EAGAIN;
/* fall through */
@@ -206,18 +205,12 @@ unsigned long do_mmap(struct file * file, unsigned long addr, unsigned long len,
default:
return -EINVAL;
}
- if (flags & MAP_DENYWRITE) {
- if (file->f_inode->i_writecount > 0)
- return -ETXTBSY;
- }
} else if ((flags & MAP_TYPE) != MAP_PRIVATE)
return -EINVAL;
- /*
- * obtain the address to map to. we verify (or select) it and ensure
+ /* Obtain the address to map to. we verify (or select) it and ensure
* that it represents a valid section of the address space.
*/
-
if (flags & MAP_FIXED) {
if (addr & ~PAGE_MASK)
return -EINVAL;
@@ -227,8 +220,7 @@ unsigned long do_mmap(struct file * file, unsigned long addr, unsigned long len,
return -ENOMEM;
}
- /*
- * determine the object being mapped and call the appropriate
+ /* Determine the object being mapped and call the appropriate
* specific mapper. the address has already been validated, but
* not unmapped, but the maps are removed from the list.
*/
@@ -249,8 +241,8 @@ unsigned long do_mmap(struct file * file, unsigned long addr, unsigned long len,
vma->vm_flags |= VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC;
if (flags & MAP_SHARED) {
vma->vm_flags |= VM_SHARED | VM_MAYSHARE;
- /*
- * This looks strange, but when we don't have the file open
+
+ /* This looks strange, but when we don't have the file open
* for writing, we can demote the shared mapping to a simpler
* private mapping. That also takes care of a security hole
* with ptrace() writing to a shared mapping without write
@@ -289,9 +281,26 @@ unsigned long do_mmap(struct file * file, unsigned long addr, unsigned long len,
}
if (file) {
- int error = file->f_op->mmap(file->f_inode, file, vma);
+ int error = 0;
+ if (vma->vm_flags & VM_DENYWRITE) {
+ if (file->f_inode->i_writecount > 0)
+ error = -ETXTBSY;
+ else {
+ /* f_op->mmap might possibly sleep
+ * (generic_file_mmap doesn't, but other code
+ * might). In any case, this takes care of any
+ * race that this might cause.
+ */
+ file->f_inode->i_writecount--;
+ correct_wcount = 1;
+ }
+ }
+ if (!error)
+ error = file->f_op->mmap(file->f_inode, file, vma);
if (error) {
+ if (correct_wcount)
+ file->f_inode->i_writecount++;
kmem_cache_free(vm_area_cachep, vma);
return error;
}
@@ -299,6 +308,8 @@ unsigned long do_mmap(struct file * file, unsigned long addr, unsigned long len,
flags = vma->vm_flags;
insert_vm_struct(mm, vma);
+ if (correct_wcount)
+ file->f_inode->i_writecount++;
merge_segments(mm, vma->vm_start, vma->vm_end);
/* merge_segments might have merged our vma, so we can't use it any more */
@@ -317,8 +328,7 @@ unsigned long do_mmap(struct file * file, unsigned long addr, unsigned long len,
return addr;
}
-/*
- * Get an address range which is currently unmapped.
+/* Get an address range which is currently unmapped.
* For mmap() without MAP_FIXED and shmat() with addr=0.
* Return value 0 means ENOMEM.
*/
@@ -342,376 +352,7 @@ unsigned long get_unmapped_area(unsigned long addr, unsigned long len)
}
}
-/*
- * Searching a VMA in the linear list task->mm->mmap is horribly slow.
- * Use an AVL (Adelson-Velskii and Landis) tree to speed up this search
- * from O(n) to O(log n), where n is the number of VMAs of the task
- * (typically around 6, but may reach 3000 in some cases).
- * Written by Bruno Haible <haible@ma2s2.mathematik.uni-karlsruhe.de>.
- */
-
-/* We keep the list and tree sorted by address. */
-#define vm_avl_key vm_end
-#define vm_avl_key_t unsigned long /* typeof(vma->avl_key) */
-
-/*
- * task->mm->mmap_avl is the AVL tree corresponding to task->mm->mmap
- * or, more exactly, its root.
- * A vm_area_struct has the following fields:
- * vm_avl_left left son of a tree node
- * vm_avl_right right son of a tree node
- * vm_avl_height 1+max(heightof(left),heightof(right))
- * The empty tree is represented as NULL.
- */
-
-/* Since the trees are balanced, their height will never be large. */
-#define avl_maxheight 41 /* why this? a small exercise */
-#define heightof(tree) ((tree) == avl_empty ? 0 : (tree)->vm_avl_height)
-/*
- * Consistency and balancing rules:
- * 1. tree->vm_avl_height == 1+max(heightof(tree->vm_avl_left),heightof(tree->vm_avl_right))
- * 2. abs( heightof(tree->vm_avl_left) - heightof(tree->vm_avl_right) ) <= 1
- * 3. foreach node in tree->vm_avl_left: node->vm_avl_key <= tree->vm_avl_key,
- * foreach node in tree->vm_avl_right: node->vm_avl_key >= tree->vm_avl_key.
- */
-
-/* Look up the nodes at the left and at the right of a given node. */
-static inline void avl_neighbours (struct vm_area_struct * node, struct vm_area_struct * tree, struct vm_area_struct ** to_the_left, struct vm_area_struct ** to_the_right)
-{
- vm_avl_key_t key = node->vm_avl_key;
-
- *to_the_left = *to_the_right = NULL;
- for (;;) {
- if (tree == avl_empty) {
- printk("avl_neighbours: node not found in the tree\n");
- return;
- }
- if (key == tree->vm_avl_key)
- break;
- if (key < tree->vm_avl_key) {
- *to_the_right = tree;
- tree = tree->vm_avl_left;
- } else {
- *to_the_left = tree;
- tree = tree->vm_avl_right;
- }
- }
- if (tree != node) {
- printk("avl_neighbours: node not exactly found in the tree\n");
- return;
- }
- if (tree->vm_avl_left != avl_empty) {
- struct vm_area_struct * node;
- for (node = tree->vm_avl_left; node->vm_avl_right != avl_empty; node = node->vm_avl_right)
- continue;
- *to_the_left = node;
- }
- if (tree->vm_avl_right != avl_empty) {
- struct vm_area_struct * node;
- for (node = tree->vm_avl_right; node->vm_avl_left != avl_empty; node = node->vm_avl_left)
- continue;
- *to_the_right = node;
- }
- if ((*to_the_left && ((*to_the_left)->vm_next != node)) || (node->vm_next != *to_the_right))
- printk("avl_neighbours: tree inconsistent with list\n");
-}
-
-/*
- * Rebalance a tree.
- * After inserting or deleting a node of a tree we have a sequence of subtrees
- * nodes[0]..nodes[k-1] such that
- * nodes[0] is the root and nodes[i+1] = nodes[i]->{vm_avl_left|vm_avl_right}.
- */
-static inline void avl_rebalance (struct vm_area_struct *** nodeplaces_ptr, int count)
-{
- for ( ; count > 0 ; count--) {
- struct vm_area_struct ** nodeplace = *--nodeplaces_ptr;
- struct vm_area_struct * node = *nodeplace;
- struct vm_area_struct * nodeleft = node->vm_avl_left;
- struct vm_area_struct * noderight = node->vm_avl_right;
- int heightleft = heightof(nodeleft);
- int heightright = heightof(noderight);
- if (heightright + 1 < heightleft) {
- /* */
- /* * */
- /* / \ */
- /* n+2 n */
- /* */
- struct vm_area_struct * nodeleftleft = nodeleft->vm_avl_left;
- struct vm_area_struct * nodeleftright = nodeleft->vm_avl_right;
- int heightleftright = heightof(nodeleftright);
- if (heightof(nodeleftleft) >= heightleftright) {
- /* */
- /* * n+2|n+3 */
- /* / \ / \ */
- /* n+2 n --> / n+1|n+2 */
- /* / \ | / \ */
- /* n+1 n|n+1 n+1 n|n+1 n */
- /* */
- node->vm_avl_left = nodeleftright; nodeleft->vm_avl_right = node;
- nodeleft->vm_avl_height = 1 + (node->vm_avl_height = 1 + heightleftright);
- *nodeplace = nodeleft;
- } else {
- /* */
- /* * n+2 */
- /* / \ / \ */
- /* n+2 n --> n+1 n+1 */
- /* / \ / \ / \ */
- /* n n+1 n L R n */
- /* / \ */
- /* L R */
- /* */
- nodeleft->vm_avl_right = nodeleftright->vm_avl_left;
- node->vm_avl_left = nodeleftright->vm_avl_right;
- nodeleftright->vm_avl_left = nodeleft;
- nodeleftright->vm_avl_right = node;
- nodeleft->vm_avl_height = node->vm_avl_height = heightleftright;
- nodeleftright->vm_avl_height = heightleft;
- *nodeplace = nodeleftright;
- }
- }
- else if (heightleft + 1 < heightright) {
- /* similar to the above, just interchange 'left' <--> 'right' */
- struct vm_area_struct * noderightright = noderight->vm_avl_right;
- struct vm_area_struct * noderightleft = noderight->vm_avl_left;
- int heightrightleft = heightof(noderightleft);
- if (heightof(noderightright) >= heightrightleft) {
- node->vm_avl_right = noderightleft; noderight->vm_avl_left = node;
- noderight->vm_avl_height = 1 + (node->vm_avl_height = 1 + heightrightleft);
- *nodeplace = noderight;
- } else {
- noderight->vm_avl_left = noderightleft->vm_avl_right;
- node->vm_avl_right = noderightleft->vm_avl_left;
- noderightleft->vm_avl_right = noderight;
- noderightleft->vm_avl_left = node;
- noderight->vm_avl_height = node->vm_avl_height = heightrightleft;
- noderightleft->vm_avl_height = heightright;
- *nodeplace = noderightleft;
- }
- }
- else {
- int height = (heightleft<heightright ? heightright : heightleft) + 1;
- if (height == node->vm_avl_height)
- break;
- node->vm_avl_height = height;
- }
- }
-}
-
-/* Insert a node into a tree. */
-static inline void avl_insert (struct vm_area_struct * new_node, struct vm_area_struct ** ptree)
-{
- vm_avl_key_t key = new_node->vm_avl_key;
- struct vm_area_struct ** nodeplace = ptree;
- struct vm_area_struct ** stack[avl_maxheight];
- int stack_count = 0;
- struct vm_area_struct *** stack_ptr = &stack[0]; /* = &stack[stackcount] */
- for (;;) {
- struct vm_area_struct * node = *nodeplace;
- if (node == avl_empty)
- break;
- *stack_ptr++ = nodeplace; stack_count++;
- if (key < node->vm_avl_key)
- nodeplace = &node->vm_avl_left;
- else
- nodeplace = &node->vm_avl_right;
- }
- new_node->vm_avl_left = avl_empty;
- new_node->vm_avl_right = avl_empty;
- new_node->vm_avl_height = 1;
- *nodeplace = new_node;
- avl_rebalance(stack_ptr,stack_count);
-}
-
-/* Insert a node into a tree, and
- * return the node to the left of it and the node to the right of it.
- */
-static inline void avl_insert_neighbours (struct vm_area_struct * new_node, struct vm_area_struct ** ptree,
- struct vm_area_struct ** to_the_left, struct vm_area_struct ** to_the_right)
-{
- vm_avl_key_t key = new_node->vm_avl_key;
- struct vm_area_struct ** nodeplace = ptree;
- struct vm_area_struct ** stack[avl_maxheight];
- int stack_count = 0;
- struct vm_area_struct *** stack_ptr = &stack[0]; /* = &stack[stackcount] */
- *to_the_left = *to_the_right = NULL;
- for (;;) {
- struct vm_area_struct * node = *nodeplace;
- if (node == avl_empty)
- break;
- *stack_ptr++ = nodeplace; stack_count++;
- if (key < node->vm_avl_key) {
- *to_the_right = node;
- nodeplace = &node->vm_avl_left;
- } else {
- *to_the_left = node;
- nodeplace = &node->vm_avl_right;
- }
- }
- new_node->vm_avl_left = avl_empty;
- new_node->vm_avl_right = avl_empty;
- new_node->vm_avl_height = 1;
- *nodeplace = new_node;
- avl_rebalance(stack_ptr,stack_count);
-}
-
-/* Removes a node out of a tree. */
-static inline void avl_remove (struct vm_area_struct * node_to_delete, struct vm_area_struct ** ptree)
-{
- vm_avl_key_t key = node_to_delete->vm_avl_key;
- struct vm_area_struct ** nodeplace = ptree;
- struct vm_area_struct ** stack[avl_maxheight];
- int stack_count = 0;
- struct vm_area_struct *** stack_ptr = &stack[0]; /* = &stack[stackcount] */
- struct vm_area_struct ** nodeplace_to_delete;
- for (;;) {
- struct vm_area_struct * node = *nodeplace;
- if (node == avl_empty) {
- /* what? node_to_delete not found in tree? */
- printk("avl_remove: node to delete not found in tree\n");
- return;
- }
- *stack_ptr++ = nodeplace; stack_count++;
- if (key == node->vm_avl_key)
- break;
- if (key < node->vm_avl_key)
- nodeplace = &node->vm_avl_left;
- else
- nodeplace = &node->vm_avl_right;
- }
- nodeplace_to_delete = nodeplace;
- /* Have to remove node_to_delete = *nodeplace_to_delete. */
- if (node_to_delete->vm_avl_left == avl_empty) {
- *nodeplace_to_delete = node_to_delete->vm_avl_right;
- stack_ptr--; stack_count--;
- } else {
- struct vm_area_struct *** stack_ptr_to_delete = stack_ptr;
- struct vm_area_struct ** nodeplace = &node_to_delete->vm_avl_left;
- struct vm_area_struct * node;
- for (;;) {
- node = *nodeplace;
- if (node->vm_avl_right == avl_empty)
- break;
- *stack_ptr++ = nodeplace; stack_count++;
- nodeplace = &node->vm_avl_right;
- }
- *nodeplace = node->vm_avl_left;
- /* node replaces node_to_delete */
- node->vm_avl_left = node_to_delete->vm_avl_left;
- node->vm_avl_right = node_to_delete->vm_avl_right;
- node->vm_avl_height = node_to_delete->vm_avl_height;
- *nodeplace_to_delete = node; /* replace node_to_delete */
- *stack_ptr_to_delete = &node->vm_avl_left; /* replace &node_to_delete->vm_avl_left */
- }
- avl_rebalance(stack_ptr,stack_count);
-}
-
-#ifdef DEBUG_AVL
-
-/* print a list */
-static void printk_list (struct vm_area_struct * vma)
-{
- printk("[");
- while (vma) {
- printk("%08lX-%08lX", vma->vm_start, vma->vm_end);
- vma = vma->vm_next;
- if (!vma)
- break;
- printk(" ");
- }
- printk("]");
-}
-
-/* print a tree */
-static void printk_avl (struct vm_area_struct * tree)
-{
- if (tree != avl_empty) {
- printk("(");
- if (tree->vm_avl_left != avl_empty) {
- printk_avl(tree->vm_avl_left);
- printk("<");
- }
- printk("%08lX-%08lX", tree->vm_start, tree->vm_end);
- if (tree->vm_avl_right != avl_empty) {
- printk(">");
- printk_avl(tree->vm_avl_right);
- }
- printk(")");
- }
-}
-
-static char *avl_check_point = "somewhere";
-
-/* check a tree's consistency and balancing */
-static void avl_checkheights (struct vm_area_struct * tree)
-{
- int h, hl, hr;
-
- if (tree == avl_empty)
- return;
- avl_checkheights(tree->vm_avl_left);
- avl_checkheights(tree->vm_avl_right);
- h = tree->vm_avl_height;
- hl = heightof(tree->vm_avl_left);
- hr = heightof(tree->vm_avl_right);
- if ((h == hl+1) && (hr <= hl) && (hl <= hr+1))
- return;
- if ((h == hr+1) && (hl <= hr) && (hr <= hl+1))
- return;
- printk("%s: avl_checkheights: heights inconsistent\n",avl_check_point);
-}
-
-/* check that all values stored in a tree are < key */
-static void avl_checkleft (struct vm_area_struct * tree, vm_avl_key_t key)
-{
- if (tree == avl_empty)
- return;
- avl_checkleft(tree->vm_avl_left,key);
- avl_checkleft(tree->vm_avl_right,key);
- if (tree->vm_avl_key < key)
- return;
- printk("%s: avl_checkleft: left key %lu >= top key %lu\n",avl_check_point,tree->vm_avl_key,key);
-}
-
-/* check that all values stored in a tree are > key */
-static void avl_checkright (struct vm_area_struct * tree, vm_avl_key_t key)
-{
- if (tree == avl_empty)
- return;
- avl_checkright(tree->vm_avl_left,key);
- avl_checkright(tree->vm_avl_right,key);
- if (tree->vm_avl_key > key)
- return;
- printk("%s: avl_checkright: right key %lu <= top key %lu\n",avl_check_point,tree->vm_avl_key,key);
-}
-
-/* check that all values are properly increasing */
-static void avl_checkorder (struct vm_area_struct * tree)
-{
- if (tree == avl_empty)
- return;
- avl_checkorder(tree->vm_avl_left);
- avl_checkorder(tree->vm_avl_right);
- avl_checkleft(tree->vm_avl_left,tree->vm_avl_key);
- avl_checkright(tree->vm_avl_right,tree->vm_avl_key);
-}
-
-/* all checks */
-static void avl_check (struct task_struct * task, char *caller)
-{
- avl_check_point = caller;
-/* printk("task \"%s\", %s\n",task->comm,caller); */
-/* printk("task \"%s\" list: ",task->comm); printk_list(task->mm->mmap); printk("\n"); */
-/* printk("task \"%s\" tree: ",task->comm); printk_avl(task->mm->mmap_avl); printk("\n"); */
- avl_checkheights(task->mm->mmap_avl);
- avl_checkorder(task->mm->mmap_avl);
-}
-
-#endif
-
-
-/*
- * Normal function to fix up a mapping
+/* Normal function to fix up a mapping
* This function is the default for when an area has no specific
* function. This may be used as part of a more specific routine.
* This function works out what part of an area is affected and
@@ -738,19 +379,11 @@ static void unmap_fixup(struct vm_area_struct *area,
struct vm_area_struct *mpnt;
unsigned long end = addr + len;
- if (addr < area->vm_start || addr >= area->vm_end ||
- end <= area->vm_start || end > area->vm_end ||
- end < addr)
- {
- printk("unmap_fixup: area=%lx-%lx, unmap %lx-%lx!!\n",
- area->vm_start, area->vm_end, addr, end);
- return;
- }
area->vm_mm->total_vm -= len >> PAGE_SHIFT;
if (area->vm_flags & VM_LOCKED)
area->vm_mm->locked_vm -= len >> PAGE_SHIFT;
- /* Unmapping the whole area */
+ /* Unmapping the whole area. */
if (addr == area->vm_start && end == area->vm_end) {
if (area->vm_ops && area->vm_ops->close)
area->vm_ops->close(area);
@@ -759,15 +392,13 @@ static void unmap_fixup(struct vm_area_struct *area,
return;
}
- /* Work out to one of the ends */
+ /* Work out to one of the ends. */
if (end == area->vm_end)
area->vm_end = addr;
- else
- if (addr == area->vm_start) {
+ else if (addr == area->vm_start) {
area->vm_offset += (end - area->vm_start);
area->vm_start = end;
- }
- else {
+ } else {
/* Unmapping a hole: area->vm_start < addr <= end < area->vm_end */
/* Add end mapping -- leave beginning for below */
mpnt = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
@@ -785,7 +416,7 @@ static void unmap_fixup(struct vm_area_struct *area,
insert_vm_struct(current->mm, mpnt);
}
- /* construct whatever mapping is needed */
+ /* Construct whatever mapping is needed. */
mpnt = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
if (!mpnt)
return;
@@ -809,15 +440,14 @@ asmlinkage int sys_munmap(unsigned long addr, size_t len)
return ret;
}
-/*
- * Munmap is split into 2 main parts -- this part which finds
+/* Munmap is split into 2 main parts -- this part which finds
* what needs doing, and the areas themselves, which do the
* work. This now handles partial unmappings.
* Jeremy Fitzhardine <jeremy@sw.oz.au>
*/
int do_munmap(unsigned long addr, size_t len)
{
- struct vm_area_struct *mpnt, *prev, *next, **npp, *free;
+ struct vm_area_struct *mpnt, *next, *free;
if ((addr & ~PAGE_MASK) || addr > TASK_SIZE || len > TASK_SIZE-addr)
return -EINVAL;
@@ -825,33 +455,36 @@ int do_munmap(unsigned long addr, size_t len)
if ((len = PAGE_ALIGN(len)) == 0)
return 0;
- /*
- * Check if this memory area is ok - put it on the temporary
+ /* Check if this memory area is ok - put it on the temporary
* list if so.. The checks here are pretty simple --
* every area affected in some way (by any overlap) is put
* on the list. If nothing is put on, nothing is affected.
*/
- mpnt = find_vma(current->mm, addr);
+ mpnt = current->mm->mmap;
+ while(mpnt && mpnt->vm_end <= addr)
+ mpnt = mpnt->vm_next;
if (!mpnt)
return 0;
- avl_neighbours(mpnt, current->mm->mmap_avl, &prev, &next);
- /* we have prev->vm_next == mpnt && mpnt->vm_next = next */
- /* and addr < mpnt->vm_end */
- npp = (prev ? &prev->vm_next : &current->mm->mmap);
+ next = mpnt->vm_next;
+
+ /* we have mpnt->vm_next = next and addr < mpnt->vm_end */
free = NULL;
- for ( ; mpnt && mpnt->vm_start < addr+len; mpnt = *npp) {
- *npp = mpnt->vm_next;
+ for ( ; mpnt && mpnt->vm_start < addr+len; ) {
+ struct vm_area_struct *next = mpnt->vm_next;
+
+ if(mpnt->vm_next)
+ mpnt->vm_next->vm_pprev = mpnt->vm_pprev;
+ *mpnt->vm_pprev = mpnt->vm_next;
+
mpnt->vm_next = free;
free = mpnt;
- avl_remove(mpnt, &current->mm->mmap_avl);
+ mpnt = next;
}
-
if (free == NULL)
return 0;
- /*
- * Ok - we have the memory areas we should free on the 'free' list,
+ /* Ok - we have the memory areas we should free on the 'free' list,
* so release them, and unmap the page range..
* If the one of the segments is only being partially unmapped,
* it will put new vm_area_struct(s) into the address space.
@@ -871,36 +504,27 @@ int do_munmap(unsigned long addr, size_t len)
if (mpnt->vm_ops && mpnt->vm_ops->unmap)
mpnt->vm_ops->unmap(mpnt, st, size);
+
flush_cache_range(current->mm, st, end);
zap_page_range(current->mm, st, size);
flush_tlb_range(current->mm, st, end);
+
unmap_fixup(mpnt, st, size);
+
kmem_cache_free(vm_area_cachep, mpnt);
} while (free);
- /* we could zap the page tables here too.. */
-
+ current->mm->mmap_cache = NULL; /* Kill the cache. */
return 0;
}
-/* Build the AVL tree corresponding to the VMA list. */
-void build_mmap_avl(struct mm_struct * mm)
-{
- struct vm_area_struct * vma;
-
- mm->mmap_avl = NULL;
- for (vma = mm->mmap; vma; vma = vma->vm_next)
- avl_insert(vma, &mm->mmap_avl);
-}
-
/* Release all mmaps. */
void exit_mmap(struct mm_struct * mm)
{
struct vm_area_struct * mpnt;
mpnt = mm->mmap;
- mm->mmap = NULL;
- mm->mmap_avl = NULL;
+ mm->mmap = mm->mmap_cache = NULL;
mm->rss = 0;
mm->total_vm = 0;
mm->locked_vm = 0;
@@ -925,81 +549,38 @@ void exit_mmap(struct mm_struct * mm)
}
}
-/*
- * Insert vm structure into process list sorted by address
+/* Insert vm structure into process list sorted by address
* and into the inode's i_mmap ring.
*/
void insert_vm_struct(struct mm_struct *mm, struct vm_area_struct *vmp)
{
- struct vm_area_struct *share;
+ struct vm_area_struct **pprev = &mm->mmap;
struct inode * inode;
-#if 0 /* equivalent, but slow */
- struct vm_area_struct **p, *mpnt;
+ /* Find where to link it in. */
+ while(*pprev && (*pprev)->vm_start <= vmp->vm_start)
+ pprev = &(*pprev)->vm_next;
- p = &mm->mmap;
- while ((mpnt = *p) != NULL) {
- if (mpnt->vm_start > vmp->vm_start)
- break;
- if (mpnt->vm_end > vmp->vm_start)
- printk("insert_vm_struct: overlapping memory areas\n");
- p = &mpnt->vm_next;
- }
- vmp->vm_next = mpnt;
- *p = vmp;
-#else
- struct vm_area_struct * prev, * next;
-
- avl_insert_neighbours(vmp, &mm->mmap_avl, &prev, &next);
- if ((prev ? prev->vm_next : mm->mmap) != next)
- printk("insert_vm_struct: tree inconsistent with list\n");
- if (prev)
- prev->vm_next = vmp;
- else
- mm->mmap = vmp;
- vmp->vm_next = next;
-#endif
+ /* Insert it. */
+ if((vmp->vm_next = *pprev) != NULL)
+ (*pprev)->vm_pprev = &vmp->vm_next;
+ *pprev = vmp;
+ vmp->vm_pprev = pprev;
inode = vmp->vm_inode;
- if (!inode)
- return;
-
- /* insert vmp into inode's circular share list */
- if ((share = inode->i_mmap)) {
- vmp->vm_next_share = share->vm_next_share;
- vmp->vm_next_share->vm_prev_share = vmp;
- share->vm_next_share = vmp;
- vmp->vm_prev_share = share;
- } else
- inode->i_mmap = vmp->vm_next_share = vmp->vm_prev_share = vmp;
-}
-
-/*
- * Remove one vm structure from the inode's i_mmap ring.
- */
-void remove_shared_vm_struct(struct vm_area_struct *mpnt)
-{
- struct inode * inode = mpnt->vm_inode;
-
- if (!inode)
- return;
-
- if (mpnt->vm_next_share == mpnt) {
- if (inode->i_mmap != mpnt)
- printk("Inode i_mmap ring corrupted\n");
- inode->i_mmap = NULL;
- return;
+ if (inode) {
+ if (vmp->vm_flags & VM_DENYWRITE)
+ inode->i_writecount--;
+
+ /* insert vmp into inode's share list */
+ if((vmp->vm_next_share = inode->i_mmap) != NULL)
+ inode->i_mmap->vm_pprev_share = &vmp->vm_next_share;
+ inode->i_mmap = vmp;
+ vmp->vm_pprev_share = &inode->i_mmap;
}
-
- if (inode->i_mmap == mpnt)
- inode->i_mmap = mpnt->vm_next_share;
-
- mpnt->vm_prev_share->vm_next_share = mpnt->vm_next_share;
- mpnt->vm_next_share->vm_prev_share = mpnt->vm_prev_share;
}
-/*
- * Merge the list of memory segments if possible.
+/* Merge the list of memory segments if possible.
* Redundant vm_area_structs are freed.
* This assumes that the list is ordered by address.
* We don't need to traverse the entire list, only those segments
@@ -1010,13 +591,19 @@ void merge_segments (struct mm_struct * mm, unsigned long start_addr, unsigned l
struct vm_area_struct *prev, *mpnt, *next;
down(&mm->mmap_sem);
- mpnt = find_vma(mm, start_addr);
+
+ prev = NULL;
+ mpnt = mm->mmap;
+ while(mpnt && mpnt->vm_end <= start_addr) {
+ prev = mpnt;
+ mpnt = mpnt->vm_next;
+ }
if (!mpnt)
goto no_vma;
- avl_neighbours(mpnt, mm->mmap_avl, &prev, &next);
- /* we have prev->vm_next == mpnt && mpnt->vm_next = next */
+ next = mpnt->vm_next;
+ /* we have prev->vm_next == mpnt && mpnt->vm_next = next */
if (!prev) {
prev = mpnt;
mpnt = next;
@@ -1026,41 +613,32 @@ void merge_segments (struct mm_struct * mm, unsigned long start_addr, unsigned l
* start_addr < mpnt->vm_end && prev->vm_start < end_addr
*/
for ( ; mpnt && prev->vm_start < end_addr ; prev = mpnt, mpnt = next) {
-#if 0
- printk("looping in merge_segments, mpnt=0x%lX\n", (unsigned long) mpnt);
-#endif
-
next = mpnt->vm_next;
- /*
- * To share, we must have the same inode, operations..
- */
- if (mpnt->vm_inode != prev->vm_inode)
- continue;
- if (mpnt->vm_pte != prev->vm_pte)
- continue;
- if (mpnt->vm_ops != prev->vm_ops)
- continue;
- if (mpnt->vm_flags != prev->vm_flags)
+ /* To share, we must have the same inode, operations.. */
+ if ((mpnt->vm_inode != prev->vm_inode) ||
+ (mpnt->vm_pte != prev->vm_pte) ||
+ (mpnt->vm_ops != prev->vm_ops) ||
+ (mpnt->vm_flags != prev->vm_flags) ||
+ (prev->vm_end != mpnt->vm_start))
continue;
- if (prev->vm_end != mpnt->vm_start)
- continue;
- /*
- * and if we have an inode, the offsets must be contiguous..
- */
+
+ /* and if we have an inode, the offsets must be contiguous.. */
if ((mpnt->vm_inode != NULL) || (mpnt->vm_flags & VM_SHM)) {
- if (prev->vm_offset + prev->vm_end - prev->vm_start != mpnt->vm_offset)
+ unsigned long off = prev->vm_offset+prev->vm_end-prev->vm_start;
+ if (off != mpnt->vm_offset)
continue;
}
- /*
- * merge prev with mpnt and set up pointers so the new
+ /* merge prev with mpnt and set up pointers so the new
* big segment can possibly merge with the next one.
* The old unused mpnt is freed.
*/
- avl_remove(mpnt, &mm->mmap_avl);
+ if(mpnt->vm_next)
+ mpnt->vm_next->vm_pprev = mpnt->vm_pprev;
+ *mpnt->vm_pprev = mpnt->vm_next;
+
prev->vm_end = mpnt->vm_end;
- prev->vm_next = mpnt->vm_next;
if (mpnt->vm_ops && mpnt->vm_ops->close) {
mpnt->vm_offset += mpnt->vm_end - mpnt->vm_start;
mpnt->vm_start = mpnt->vm_end;
@@ -1072,16 +650,24 @@ void merge_segments (struct mm_struct * mm, unsigned long start_addr, unsigned l
kmem_cache_free(vm_area_cachep, mpnt);
mpnt = prev;
}
+ mm->mmap_cache = NULL; /* Kill the cache. */
no_vma:
up(&mm->mmap_sem);
}
-void vma_init(void)
+__initfunc(void vma_init(void))
{
vm_area_cachep = kmem_cache_create("vm_area_struct",
sizeof(struct vm_area_struct),
- sizeof(long)*8, SLAB_HWCACHE_ALIGN,
+ 0, SLAB_HWCACHE_ALIGN,
NULL, NULL);
if(!vm_area_cachep)
panic("vma_init: Cannot alloc vm_area_struct cache.");
+
+ mm_cachep = kmem_cache_create("mm_struct",
+ sizeof(struct mm_struct),
+ 0, SLAB_HWCACHE_ALIGN,
+ NULL, NULL);
+ if(!mm_cachep)
+ panic("vma_init: Cannot alloc mm_struct cache.");
}
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 7b71a1ec7..19b3aa125 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -18,12 +18,14 @@
#include <linux/fs.h>
#include <linux/swapctl.h>
#include <linux/interrupt.h>
+#include <linux/init.h>
#include <asm/dma.h>
#include <asm/system.h> /* for cli()/sti() */
#include <asm/uaccess.h> /* for copy_to/from_user */
#include <asm/bitops.h>
#include <asm/pgtable.h>
+#include <asm/spinlock.h>
int nr_swap_pages = 0;
int nr_free_pages = 0;
@@ -88,10 +90,6 @@ static inline void remove_mem_queue(struct page * entry)
*
* With the above two rules, you get a straight-line execution path
* for the normal case, giving better asm-code.
- *
- * free_page() may sleep since the page being freed may be a buffer
- * page or present in the swap cache. It will not sleep, however,
- * for a freshly allocated page (get_free_page()).
*/
/*
@@ -99,6 +97,8 @@ static inline void remove_mem_queue(struct page * entry)
*
* Hint: -mask = 1+~mask
*/
+static spinlock_t page_alloc_lock;
+
static inline void free_pages_ok(unsigned long map_nr, unsigned long order)
{
struct free_area_struct *area = free_area + order;
@@ -106,15 +106,14 @@ static inline void free_pages_ok(unsigned long map_nr, unsigned long order)
unsigned long mask = (~0UL) << order;
unsigned long flags;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&page_alloc_lock, flags);
#define list(x) (mem_map+(x))
map_nr &= mask;
nr_free_pages -= mask;
while (mask + (1 << (NR_MEM_LISTS-1))) {
- if (!change_bit(index, area->map))
+ if (!test_and_change_bit(index, area->map))
break;
remove_mem_queue(list(map_nr ^ -mask));
mask <<= 1;
@@ -126,7 +125,7 @@ static inline void free_pages_ok(unsigned long map_nr, unsigned long order)
#undef list
- restore_flags(flags);
+ spin_unlock_irqrestore(&page_alloc_lock, flags);
}
void __free_page(struct page *page)
@@ -172,7 +171,7 @@ do { struct free_area_struct * area = free_area+order; \
MARK_USED(map_nr, new_order, area); \
nr_free_pages -= 1 << order; \
EXPAND(ret, map_nr, order, new_order, area); \
- restore_flags(flags); \
+ spin_unlock_irqrestore(&page_alloc_lock, flags); \
return ADDRESS(map_nr); \
} \
prev = ret; \
@@ -214,15 +213,14 @@ unsigned long __get_free_pages(int priority, unsigned long order, int dma)
reserved_pages = 5;
if (priority != GFP_NFS)
reserved_pages = min_free_pages;
- save_flags(flags);
repeat:
- cli();
+ spin_lock_irqsave(&page_alloc_lock, flags);
if ((priority==GFP_ATOMIC) || nr_free_pages > reserved_pages) {
RMQUEUE(order, dma);
- restore_flags(flags);
+ spin_unlock_irqrestore(&page_alloc_lock, flags);
return 0;
}
- restore_flags(flags);
+ spin_unlock_irqrestore(&page_alloc_lock, flags);
if (priority != GFP_BUFFER && try_to_free_page(priority, dma, 1))
goto repeat;
return 0;
@@ -239,8 +237,7 @@ void show_free_areas(void)
unsigned long total = 0;
printk("Free pages: %6dkB\n ( ",nr_free_pages<<(PAGE_SHIFT-10));
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&page_alloc_lock, flags);
for (order=0 ; order < NR_MEM_LISTS; order++) {
struct page * tmp;
unsigned long nr = 0;
@@ -250,7 +247,7 @@ void show_free_areas(void)
total += nr * ((PAGE_SIZE>>10) << order);
printk("%lu*%lukB ", nr, (unsigned long)((PAGE_SIZE>>10) << order));
}
- restore_flags(flags);
+ spin_unlock_irqrestore(&page_alloc_lock, flags);
printk("= %lukB)\n", total);
#ifdef SWAP_CACHE_INFO
show_swap_cache_info();
@@ -265,7 +262,7 @@ void show_free_areas(void)
* - mark all memory queues empty
* - clear the memory bitmaps
*/
-unsigned long free_area_init(unsigned long start_mem, unsigned long end_mem)
+__initfunc(unsigned long free_area_init(unsigned long start_mem, unsigned long end_mem))
{
mem_map_t * p;
unsigned long mask = PAGE_MASK;
@@ -273,7 +270,7 @@ unsigned long free_area_init(unsigned long start_mem, unsigned long end_mem)
/*
* select nr of pages we try to keep free for important stuff
- * with a minimum of 16 pages. This is totally arbitrary
+ * with a minimum of 48 pages. This is totally arbitrary
*/
i = (end_mem - PAGE_OFFSET) >> (PAGE_SHIFT+7);
if (i < 48)
diff --git a/mm/page_io.c b/mm/page_io.c
index 9980c52b7..6a16ccee8 100644
--- a/mm/page_io.c
+++ b/mm/page_io.c
@@ -67,7 +67,7 @@ void rw_swap_page(int rw, unsigned long entry, char * buf, int wait)
return;
}
/* Make sure we are the only process doing I/O with this swap page. */
- while (set_bit(offset,p->swap_lockmap)) {
+ while (test_and_set_bit(offset,p->swap_lockmap)) {
run_task_queue(&tq_disk);
sleep_on(&lock_queue);
}
@@ -136,7 +136,7 @@ void rw_swap_page(int rw, unsigned long entry, char * buf, int wait)
} else
printk("rw_swap_page: no swap file or device\n");
atomic_dec(&page->count);
- if (offset && !clear_bit(offset,p->swap_lockmap))
+ if (offset && !test_and_clear_bit(offset,p->swap_lockmap))
printk("rw_swap_page: lock already cleared\n");
wake_up(&lock_queue);
}
@@ -158,7 +158,7 @@ void swap_after_unlock_page (unsigned long entry)
printk("swap_after_unlock_page: weirdness\n");
return;
}
- if (!clear_bit(offset,p->swap_lockmap))
+ if (!test_and_clear_bit(offset,p->swap_lockmap))
printk("swap_after_unlock_page: lock already cleared\n");
wake_up(&lock_queue);
}
@@ -187,7 +187,7 @@ void ll_rw_page(int rw, kdev_t dev, unsigned long offset, char * buffer)
panic("ll_rw_page: bad block dev cmd, must be R/W");
}
page = mem_map + MAP_NR(buffer);
- if (set_bit(PG_locked, &page->flags))
+ if (test_and_set_bit(PG_locked, &page->flags))
panic ("ll_rw_page: page already locked");
brw_page(rw, page, dev, &block, PAGE_SIZE, 0);
}
diff --git a/mm/slab.c b/mm/slab.c
index baa4f027f..addd0796a 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -1,8 +1,81 @@
/*
* linux/mm/slab.c
- * Written by Mark Hemment, 1996.
+ * Written by Mark Hemment, 1996/97.
* (markhe@nextd.demon.co.uk)
+ *
+ * 11 April '97. Started multi-threading - markhe
+ * The global cache-chain is protected by the semaphore 'cache_chain_sem'.
+ * The sem is only needed when accessing/extending the cache-chain, which
+ * can never happen inside an interrupt (kmem_cache_create(),
+ * kmem_cache_shrink() and kmem_cache_reap()).
+ * This is a medium-term exclusion lock.
+ *
+ * Each cache has its own lock; 'c_spinlock'. This lock is needed only
+ * when accessing non-constant members of a cache-struct.
+ * Note: 'constant members' are assigned a value in kmem_cache_create() before
+ * the cache is linked into the cache-chain. The values never change, so not
+ * even a multi-reader lock is needed for these members.
+ * The c_spinlock is only ever held for a few cycles.
+ *
+ * To prevent kmem_cache_shrink() trying to shrink a 'growing' cache (which
+ * maybe be sleeping and therefore not holding the semaphore/lock), the
+ * c_growing field is used. This also prevents reaping from a cache.
+ *
+ * Note, caches can _never_ be destroyed. When a sub-system (eg module) has
+ * finished with a cache, it can only be shrunk. This leaves the cache empty,
+ * but already enabled for re-use, eg. during a module re-load.
+ *
+ * Notes:
+ * o Constructors/deconstructors are called while the cache-lock
+ * is _not_ held. Therefore they _must_ be threaded.
+ * o Constructors must not attempt to allocate memory from the
+ * same cache that they are a constructor for - infinite loop!
+ * (There is no easy way to trap this.)
+ * o The per-cache locks must be obtained with local-interrupts disabled.
+ * o When compiled with debug support, and an object-verify (upon release)
+ * is request for a cache, the verify-function is called with the cache
+ * lock held. This helps debugging.
+ * o The functions called from try_to_free_page() must not attempt
+ * to allocate memory from a cache which is being grown.
+ * The buffer sub-system might try to allocate memory, via buffer_cachep.
+ * As this pri is passed to the SLAB, and then (if necessary) onto the
+ * gfp() funcs (which avoid calling try_to_free_page()), no deadlock
+ * should happen.
+ *
+ * The positioning of the per-cache lock is tricky. If the lock is
+ * placed on the same h/w cache line as commonly accessed members
+ * the number of L1 cache-line faults is reduced. However, this can
+ * lead to the cache-line ping-ponging between processors when the
+ * lock is in contention (and the common members are being accessed).
+ * Decided to keep it away from common members.
+ *
+ * More fine-graining is possible, with per-slab locks...but this might be
+ * taking fine graining too far, but would have the advantage;
+ * During most allocs/frees no writes occur to the cache-struct.
+ * Therefore a multi-reader/one writer lock could be used (the writer
+ * needed when the slab chain is being link/unlinked).
+ * As we would not have an exclusion lock for the cache-structure, one
+ * would be needed per-slab (for updating s_free ptr, and/or the contents
+ * of s_index).
+ * The above locking would allow parallel operations to different slabs within
+ * the same cache with reduced spinning.
+ *
+ * Per-engine slab caches, backed by a global cache (as in Mach's Zone allocator),
+ * would allow most allocations from the same cache to execute in parallel.
+ *
+ * At present, each engine can be growing a cache. This should be blocked.
+ *
+ * It is not currently 100% safe to examine the page_struct outside of a kernel
+ * or global cli lock. The risk is v. small, and non-fatal.
+ *
+ * Calls to printk() are not 100% safe (the function is not threaded). However,
+ * printk() is only used under an error condition, and the risk is v. small (not
+ * sure if the console write functions 'enjoy' executing multiple contextes in
+ * parallel. I guess they don't...).
+ * Note, for most calls to printk() any held cache-lock is dropped. This is not
+ * always done for text size reasons - having *_unlock() everywhere is bloat.
*/
+
/*
* An implementation of the Slab Allocator as described in outline in;
* UNIX Internals: The New Frontiers by Uresh Vahalia
@@ -10,156 +83,251 @@
* or with a little more detail in;
* The Slab Allocator: An Object-Caching Kernel Memory Allocator
* Jeff Bonwick (Sun Microsystems).
- * Presented at: USENIX Summer 1994 Technical Conference
+ * Presented at: USENIX Summer 1994 Technical Conference
+ */
+
+/*
+ * This implementation deviates from Bonwick's paper as it
+ * does not use a hash-table for large objects, but rather a per slab
+ * index to hold the bufctls. This allows the bufctl structure to
+ * be small (one word), but limits the number of objects a slab (not
+ * a cache) can contain when off-slab bufctls are used. The limit is the
+ * size of the largest general-cache that does not use off-slab bufctls,
+ * divided by the size of a bufctl. For 32bit archs, is this 256/4 = 64.
+ * This is not serious, as it is only for large objects, when it is unwise
+ * to have too many per slab.
+ * Note: This limit can be raised by introducing a general-cache whose size
+ * is less than 512 (PAGE_SIZE<<3), but greater than 256.
*/
-#include <linux/slab.h>
#include <linux/mm.h>
+#include <linux/slab.h>
#include <linux/interrupt.h>
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+
#include <asm/system.h>
-#include <asm/cache.h>
-
-/* SLAB_MGMT_CHECKS - define to enable extra checks in
- * kmem_cache_[create|destroy|shrink].
- * If you're not messing around with these funcs, then undef this.
- * SLAB_HIGH_PACK - define to allow 'bufctl's to be stored within objs that do not
- * have a state. This allows more objs per slab, but removes the
- * ability to sanity check an addr on release (if the addr is
- * within any slab, anywhere, kmem_cache_free() will accept it!).
- * SLAB_DEBUG_SUPPORT - when defined, kmem_cache_create() will honour; SLAB_DEBUG_FREE,
- * SLAB_DEBUG_INITIAL and SLAB_RED_ZONE.
+#include <asm/atomic.h>
+#include <asm/smp_lock.h>
+#include <asm/spinlock.h>
+
+/* If there is a different PAGE_SIZE around, and it works with this allocator,
+ * then change the following.
*/
-#define SLAB_MGMT_CHECKS
-#undef SLAB_HIGH_PACK
-#define SLAB_DEBUG_SUPPORT /* undef this when your cache is stable */
+#if (PAGE_SIZE != 8192 && PAGE_SIZE != 4096)
+#error Your page size is probably not correctly supported - please check
+#endif
+
+/* SLAB_MGMT_CHECKS - 1 to enable extra checks in kmem_cache_create().
+ * 0 if you wish to reduce memory usage.
+ *
+ * SLAB_DEBUG_SUPPORT - 1 for kmem_cache_create() to honour; SLAB_DEBUG_FREE,
+ * SLAB_DEBUG_INITIAL, SLAB_RED_ZONE & SLAB_POISION.
+ * 0 for faster, smaller, code (espically in the critical paths).
+ *
+ * SLAB_STATS - 1 to collect stats for /proc/slabinfo.
+ * 0 for faster, smaller, code (espically in the critical paths).
+ *
+ * SLAB_SELFTEST - 1 to perform a few tests, mainly for developement.
+ */
+#define SLAB_MGMT_CHECKS 1
+#define SLAB_DEBUG_SUPPORT 0
+#define SLAB_STATS 0
+#define SLAB_SELFTEST 0
-#define BYTES_PER_WORD sizeof(void *)
+/* Shouldn't this be in a header file somewhere? */
+#define BYTES_PER_WORD sizeof(void *)
-/* legal flag mask for kmem_cache_create() */
-#if defined(SLAB_DEBUG_SUPPORT)
-#define SLAB_C_MASK (SLAB_DEBUG_FREE|SLAB_DEBUG_INITIAL|SLAB_HWCACHE_ALIGN|SLAB_RED_ZONE)
+/* Legal flag mask for kmem_cache_create(). */
+#if SLAB_DEBUG_SUPPORT
+#if 0
+#define SLAB_C_MASK (SLAB_DEBUG_FREE|SLAB_DEBUG_INITIAL|SLAB_RED_ZONE| \
+ SLAB_POISION|SLAB_HWCACHE_ALIGN|SLAB_NO_REAP| \
+ SLAB_HIGH_PACK)
+#endif
+#define SLAB_C_MASK (SLAB_DEBUG_FREE|SLAB_DEBUG_INITIAL|SLAB_RED_ZONE| \
+ SLAB_POISION|SLAB_HWCACHE_ALIGN|SLAB_NO_REAP)
#else
-#define SLAB_C_MASK (SLAB_HWCACHE_ALIGN)
+#if 0
+#define SLAB_C_MASK (SLAB_HWCACHE_ALIGN|SLAB_NO_REAP|SLAB_HIGH_PACK)
+#endif
+#define SLAB_C_MASK (SLAB_HWCACHE_ALIGN|SLAB_NO_REAP)
#endif /* SLAB_DEBUG_SUPPORT */
-/* Magic num for red zoning.
- * Placed in the first word after the end of an obj
- */
-#define SLAB_RED_MAGIC1 0x5A2CF071UL /* when obj is active */
-#define SLAB_RED_MAGIC2 0x170FC2A5UL /* when obj is inactive */
+/* Slab management struct.
+ * Manages the objs in a slab. Placed either at the end of mem allocated
+ * for a slab, or from an internal obj cache (cache_slabp).
+ * Slabs are chained into a partially ordered list; fully used first, partial
+ * next, and then fully free slabs.
+ * The first 4 members are referenced during an alloc/free operation, and
+ * should always appear on the same cache line.
+ * Note: The offset between some members _must_ match offsets within
+ * the kmem_cache_t - see kmem_cache_init() for the checks. */
+
+#define SLAB_OFFSET_BITS 16 /* could make this larger for 64bit archs */
+
+typedef struct kmem_slab_s {
+ struct kmem_bufctl_s *s_freep; /* ptr to first inactive obj in slab */
+ struct kmem_bufctl_s *s_index;
+ unsigned long s_magic;
+ unsigned long s_inuse; /* num of objs active in slab */
+
+ struct kmem_slab_s *s_nextp;
+ struct kmem_slab_s *s_prevp;
+ void *s_mem; /* addr of first obj in slab */
+ unsigned long s_offset:SLAB_OFFSET_BITS,
+ s_dma:1;
+} kmem_slab_t;
-/* Used for linking objs within a slab. How much of the struct is
- * used, and where its placed, depends on the packing used in a cache.
- * Don't mess with the order!
+/* When the slab mgmt is on-slab, this gives the size to use. */
+#define slab_align_size (L1_CACHE_ALIGN(sizeof(kmem_slab_t)))
+
+/* Test for end of slab chain. */
+#define kmem_slab_end(x) ((kmem_slab_t*)&((x)->c_offset))
+
+/* s_magic */
+#define SLAB_MAGIC_ALLOC 0xA5C32F2BUL /* slab is alive */
+#define SLAB_MAGIC_DESTROYED 0xB2F23C5AUL /* slab has been destoryed */
+
+/* Bufctl's are used for linking objs within a slab, identifying what slab an obj
+ * is in, and the address of the associated obj (for sanity checking with off-slab
+ * bufctls). What a bufctl contains depends upon the state of the obj and
+ * the organisation of the cache.
*/
typedef struct kmem_bufctl_s {
- struct kmem_bufctl_s *buf_nextp;
- struct kmem_slab_s *buf_slabp;
- void *buf_objp; /* start of obj */
- struct kmem_bufctl_s *buf_hnextp;
- struct kmem_bufctl_s **buf_hashp;
+ union {
+ struct kmem_bufctl_s *buf_nextp;
+ kmem_slab_t *buf_slabp; /* slab for obj */
+ void * buf_objp;
+ } u;
} kmem_bufctl_t;
-/* different portions of the bufctl are used - so need some macros */
-#define kmem_bufctl_offset(x) ((unsigned long)&((kmem_bufctl_t *)0)->x)
-#define kmem_bufctl_short_size (kmem_bufctl_offset(buf_objp))
-#define kmem_bufctl_very_short_size (kmem_bufctl_offset(buf_slabp))
+/* ...shorthand... */
+#define buf_nextp u.buf_nextp
+#define buf_slabp u.buf_slabp
+#define buf_objp u.buf_objp
-/* Slab management struct.
- * Manages the objs in a slab. Placed either at the end of mem allocated
- * for the slab, or from an internal obj cache (SLAB_CFLGS_OFF_SLAB).
- * Slabs are chain into a partially ordered list. The linking ptrs must
- * be first in the struct!
- * The size of the struct is important(ish); it should align well on
- * cache line(s)
+#if SLAB_DEBUG_SUPPORT
+/* Magic nums for obj red zoning.
+ * Placed in the first word before and the first word after an obj.
*/
-typedef struct kmem_slab_s {
- struct kmem_slab_s *s_nextp;
- struct kmem_slab_s *s_prevp;
- void *s_mem; /* addr of mem allocated for slab */
- unsigned long s_jiffies;
- kmem_bufctl_t *s_freep; /* ptr to first inactive obj in slab */
- unsigned long s_flags;
- unsigned long s_magic;
- unsigned long s_inuse; /* num of objs active in slab */
-} kmem_slab_t;
-
-/* to test for end of slab chain */
-#define kmem_slab_end(x) ((kmem_slab_t*)&((x)->c_firstp))
+#define SLAB_RED_MAGIC1 0x5A2CF071UL /* when obj is active */
+#define SLAB_RED_MAGIC2 0x170FC2A5UL /* when obj is inactive */
-/* s_magic */
-#define SLAB_MAGIC_ALLOC 0xA5C32F2BUL
-#define SLAB_MAGIC_UNALLOC 0xB2F23C5AUL
+/* ...and for poisioning */
+#define SLAB_POISION_BYTE 0x5a /* byte value for poisioning */
+#define SLAB_POISION_END 0xa5 /* end-byte of poisioning */
-/* s_flags */
-#define SLAB_SFLGS_DMA 0x000001UL /* slab's mem can do DMA */
+#endif /* SLAB_DEBUG_SUPPORT */
-/* cache struct - manages a cache.
- * c_lastp must appear immediately after c_firstp!
+/* Cache struct - manages a cache.
+ * First four members are commonly referenced during an alloc/free operation.
*/
struct kmem_cache_s {
kmem_slab_t *c_freep; /* first slab w. free objs */
- unsigned long c_flags;
+ unsigned long c_flags; /* constant flags */
unsigned long c_offset;
- struct kmem_bufctl_s **c_hashp; /* ptr for off-slab bufctls */
- kmem_slab_t *c_firstp; /* first slab in chain */
- kmem_slab_t *c_lastp; /* last slab in chain */
- unsigned long c_hashbits;
unsigned long c_num; /* # of objs per slab */
- unsigned long c_gfporder; /* order of pgs per slab (2^n) */
- unsigned long c_org_size;
+
unsigned long c_magic;
unsigned long c_inuse; /* kept at zero */
- void (*c_ctor)(void *, int, unsigned long); /* constructor func */
- void (*c_dtor)(void *, int, unsigned long); /* de-constructor func */
+ kmem_slab_t *c_firstp; /* first slab in chain */
+ kmem_slab_t *c_lastp; /* last slab in chain */
+
+ spinlock_t c_spinlock;
+ unsigned long c_growing;
+ unsigned long c_dflags; /* dynamic flags */
+ size_t c_org_size;
+ unsigned long c_gfporder; /* order of pgs per slab (2^n) */
+ void (*c_ctor)(void *, kmem_cache_t *, unsigned long); /* constructor func */
+ void (*c_dtor)(void *, kmem_cache_t *, unsigned long); /* de-constructor func */
unsigned long c_align; /* alignment of objs */
- unsigned long c_colour; /* cache colouring range */
- unsigned long c_colour_next;/* cache colouring */
+ size_t c_colour; /* cache colouring range */
+ size_t c_colour_next;/* cache colouring */
+ unsigned long c_failures;
const char *c_name;
struct kmem_cache_s *c_nextp;
+ kmem_cache_t *c_index_cachep;
+#if SLAB_STATS
+ unsigned long c_num_active;
+ unsigned long c_num_allocations;
+ unsigned long c_high_mark;
+ unsigned long c_grown;
+ unsigned long c_reaped;
+ atomic_t c_errors;
+#endif /* SLAB_STATS */
};
-/* magic # for c_magic - used to detect out-of-slabs in __kmem_cache_alloc() */
-#define SLAB_C_MAGIC 0x4F17A36DUL
-
/* internal c_flags */
#define SLAB_CFLGS_OFF_SLAB 0x010000UL /* slab mgmt in own cache */
#define SLAB_CFLGS_BUFCTL 0x020000UL /* bufctls in own cache */
-#define SLAB_CFLGS_RELEASED 0x040000UL /* cache is/being destroyed */
+#define SLAB_CFLGS_GENERAL 0x080000UL /* a general-cache */
-#if defined(SLAB_HIGH_PACK)
-#define SLAB_CFLGS_PTR_IN_OBJ 0x080000UL /* free ptr in obj */
-#endif
+/* c_dflags (dynamic flags). Need to hold the spinlock to access this member */
+#define SLAB_CFLGS_GROWN 0x000002UL /* don't reap a recently grown */
#define SLAB_OFF_SLAB(x) ((x) & SLAB_CFLGS_OFF_SLAB)
#define SLAB_BUFCTL(x) ((x) & SLAB_CFLGS_BUFCTL)
-#define SLAB_RELEASED(x) ((x) & SLAB_CFLGS_RELEASED)
-#if defined(SLAB_HIGH_PACK)
-#define SLAB_PTR_IN_OBJ(x) ((x) & SLAB_CFLGS_PTR_IN_OBJ)
+#define SLAB_GROWN(x) ((x) & SLAB_CFLGS_GROWN)
+
+#if SLAB_STATS
+#define SLAB_STATS_INC_ACTIVE(x) ((x)->c_num_active++)
+#define SLAB_STATS_DEC_ACTIVE(x) ((x)->c_num_active--)
+#define SLAB_STATS_INC_ALLOCED(x) ((x)->c_num_allocations++)
+#define SLAB_STATS_INC_GROWN(x) ((x)->c_grown++)
+#define SLAB_STATS_INC_REAPED(x) ((x)->c_reaped++)
+#define SLAB_STATS_SET_HIGH(x) do { if ((x)->c_num_active > (x)->c_high_mark) \
+ (x)->c_high_mark = (x)->c_num_active; \
+ } while (0)
+#define SLAB_STATS_INC_ERR(x) (atomic_inc(&(x)->c_errors))
#else
-#define SLAB_PTR_IN_OBJ(x) (0)
+#define SLAB_STATS_INC_ACTIVE(x)
+#define SLAB_STATS_DEC_ACTIVE(x)
+#define SLAB_STATS_INC_ALLOCED(x)
+#define SLAB_STATS_INC_GROWN(x)
+#define SLAB_STATS_INC_REAPED(x)
+#define SLAB_STATS_SET_HIGH(x)
+#define SLAB_STATS_INC_ERR(x)
+#endif /* SLAB_STATS */
+
+#if SLAB_SELFTEST
+#if !SLAB_DEBUG_SUPPORT
+#error Debug support needed for self-test
#endif
+static void kmem_self_test(void);
+#endif /* SLAB_SELFTEST */
+
+/* c_magic - used to detect 'out of slabs' in __kmem_cache_alloc() */
+#define SLAB_C_MAGIC 0x4F17A36DUL
/* maximum size of an obj (in 2^order pages) */
#define SLAB_OBJ_MAX_ORDER 5 /* 32 pages */
-/* maximum num of pages for a slab (avoids trying to ask for too may contigious pages) */
+/* maximum num of pages for a slab (prevents large requests to the VM layer) */
#define SLAB_MAX_GFP_ORDER 5 /* 32 pages */
/* the 'prefered' minimum num of objs per slab - maybe less for large objs */
#define SLAB_MIN_OBJS_PER_SLAB 4
-/* if the num of objs per slab is <= SLAB_MIN_OBJS_PER_SLAB,
- * then the page order must be less than this before trying the next order
+/* If the num of objs per slab is <= SLAB_MIN_OBJS_PER_SLAB,
+ * then the page order must be less than this before trying the next order.
*/
#define SLAB_BREAK_GFP_ORDER 2
-/* size of hash tables for caches which use off-slab bufctls (SLAB_CFLGS_BUFCTL) */
-#define KMEM_HASH_SIZE 128
+/* Macros for storing/retrieving the cachep and or slab from the
+ * global 'mem_map'. With off-slab bufctls, these are used to find the
+ * slab an obj belongs to. With kmalloc(), and kfree(), these are used
+ * to find the cache which an obj belongs to.
+ */
+#define SLAB_SET_PAGE_CACHE(pg, x) ((pg)->next = (struct page *)(x))
+#define SLAB_GET_PAGE_CACHE(pg) ((kmem_cache_t *)(pg)->next)
+#define SLAB_SET_PAGE_SLAB(pg, x) ((pg)->prev = (struct page *)(x))
+#define SLAB_GET_PAGE_SLAB(pg) ((kmem_slab_t *)(pg)->prev)
-/* size description struct for general-caches */
+/* Size description struct for general-caches. */
typedef struct cache_sizes {
- unsigned long cs_size;
+ size_t cs_size;
kmem_cache_t *cs_cachep;
} cache_sizes_t;
@@ -175,177 +343,177 @@ static cache_sizes_t cache_sizes[] = {
{2048, NULL},
{4096, NULL},
{8192, NULL},
-#if PAGE_SIZE == 8192
{16384, NULL},
-#endif
+ {32768, NULL},
+ {65536, NULL},
+ {131072, NULL},
{0, NULL}
};
-/* Names for the general-caches.
- * Not placed into the sizes struct for a good reason; the
- * string ptr is not needed while searching in kmem_alloc()/
- * kmem_free(), and would 'get-in-the-way' - think about it.
+/* Names for the general-caches. Not placed into the sizes struct for
+ * a good reason; the string ptr is not needed while searching in kmalloc(),
+ * and would 'get-in-the-way' in the h/w cache.
*/
static char *cache_sizes_name[] = {
#if PAGE_SIZE == 4096
- "cache-32",
+ "size-32",
#endif
- "cache-64",
- "cache-128",
- "cache-256",
- "cache-512",
- "cache-1024",
- "cache-2048",
- "cache-4096",
-#if PAGE_SIZE == 4096
- "cache-8192"
-#elif PAGE_SIZE == 8192
- "cache-8192",
- "cache-16384"
-#else
-#error Your page size is not supported for the general-caches - please fix
-#endif
-};
-
-static void kmem_hash_ctor(void *ptr, int , unsigned long); /* fwd ref */
-extern kmem_cache_t cache_cache; /* fwd ref */
-
-/* internal cache of hash objs, only used when bufctls are off-slab */
-static kmem_cache_t cache_hash = {
-/* freep, flags */ kmem_slab_end(&cache_hash), 0,
-/* offset, hashp */ sizeof(kmem_bufctl_t*)*KMEM_HASH_SIZE, NULL,
-/* firstp, lastp */ kmem_slab_end(&cache_hash), kmem_slab_end(&cache_hash),
-/* hashbits, num, gfporder */ 0, 0, 0,
-/* org_size, magic */ sizeof(kmem_bufctl_t*)*KMEM_HASH_SIZE, SLAB_C_MAGIC,
-/* inuse, ctor, dtor, align */ 0, kmem_hash_ctor, NULL, L1_CACHE_BYTES,
-/* colour, colour_next */ 0, 0,
-/* name, nextp */ "hash_cache", &cache_cache
-};
-
-/* internal cache of freelist mgmnt objs, only use when bufctls are off-slab */
-static kmem_cache_t cache_bufctl = {
-/* freep, flags */ kmem_slab_end(&cache_bufctl), 0,
-/* offset, hashp */ sizeof(kmem_bufctl_t), NULL,
-/* firstp, lastp */ kmem_slab_end(&cache_bufctl), kmem_slab_end(&cache_bufctl),
-/* hashbits, num, gfporder */ 0, 0, 0,
-/* org_size, magic */ sizeof(kmem_bufctl_t), SLAB_C_MAGIC,
-/* inuse, ctor, dtor, align */ 0, NULL, NULL, BYTES_PER_WORD*2,
-/* colour, colour_next */ 0, 0,
-/* name, nextp */ "bufctl_cache", &cache_hash
-};
-
-/* internal cache of slab mngmnt objs, only used when slab mgmt is off-slab */
-static kmem_cache_t cache_slab = {
-/* freep, flags */ kmem_slab_end(&cache_slab), 0,
-/* offset, hashp */ sizeof(kmem_slab_t), NULL,
-/* firstp, lastp */ kmem_slab_end(&cache_slab), kmem_slab_end(&cache_slab),
-/* hashbits, num, gfporder */ 0, 0, 0,
-/* org_size, magic */ sizeof(kmem_slab_t), SLAB_C_MAGIC,
-/* inuse, ctor, dtor, align */ 0, NULL, NULL, L1_CACHE_BYTES,
-/* colour, colour_next */ 0, 0,
-/* name, nextp */ "slab_cache", &cache_bufctl
+ "size-64",
+ "size-128",
+ "size-256",
+ "size-512",
+ "size-1024",
+ "size-2048",
+ "size-4096",
+ "size-8192",
+ "size-16384",
+ "size-32768",
+ "size-65536",
+ "size-131072"
};
/* internal cache of cache description objs */
static kmem_cache_t cache_cache = {
-/* freep, flags */ kmem_slab_end(&cache_cache), 0,
-/* offset, hashp */ sizeof(kmem_cache_t), NULL,
+/* freep, flags */ kmem_slab_end(&cache_cache), SLAB_NO_REAP,
+/* offset, num */ sizeof(kmem_cache_t), 0,
+/* c_magic, c_inuse */ SLAB_C_MAGIC, 0,
/* firstp, lastp */ kmem_slab_end(&cache_cache), kmem_slab_end(&cache_cache),
-/* hashbits, num, gfporder */ 0, 0, 0,
-/* org_size, magic */ sizeof(kmem_cache_t), SLAB_C_MAGIC,
-/* inuse, ctor, dtor, align */ 0, NULL, NULL, L1_CACHE_BYTES,
+/* spinlock */ SPIN_LOCK_UNLOCKED,
+/* growing */ 0,
+/* dflags */ 0,
+/* org_size, gfp */ 0, 0,
+/* ctor, dtor, align */ NULL, NULL, L1_CACHE_BYTES,
/* colour, colour_next */ 0, 0,
+/* failures */ 0,
/* name */ "kmem_cache",
-/* nextp */ &cache_slab
+/* nextp */ &cache_cache,
+/* index */ NULL,
};
-/* constructor for hash tables */
-static void kmem_hash_ctor(void *ptr, int size, unsigned long flags)
-{
- memset(ptr, 0, sizeof(kmem_bufctl_t*)*KMEM_HASH_SIZE);
-}
+/* Guard access to the cache-chain. */
+static struct semaphore cache_chain_sem;
-/* place maintainer for reaping */
+/* Place maintainer for reaping. */
static kmem_cache_t *clock_searchp = &cache_cache;
-/* Init an internal cache */
-static void
-kmem_own_cache_init(kmem_cache_t *cachep)
-{
- unsigned long size, i;
+/* Internal slab mgmt cache, for when slab mgmt is off-slab. */
+static kmem_cache_t *cache_slabp = NULL;
- if (cachep->c_inuse || cachep->c_magic != SLAB_C_MAGIC) {
- panic("Bad init of internal cache %s", cachep->c_name);
- /* NOTREACHED */
- }
- size = cachep->c_offset + kmem_bufctl_short_size;
- i = size % cachep->c_align;
- if (i)
- size += (cachep->c_align-i);
- cachep->c_offset = size-kmem_bufctl_short_size;
-
- i = ((PAGE_SIZE<<cachep->c_gfporder)-sizeof(kmem_slab_t));
- cachep->c_num = i / size; /* num of objs per slab */
-
- /* cache colouring */
- cachep->c_colour = 1 + (i-(cachep->c_num*size))/cachep->c_align;
- cachep->c_colour_next = cachep->c_colour;
-}
+/* Max number of objs-per-slab for caches which use bufctl's.
+ * Needed to avoid a possible looping condition in kmem_cache_grow().
+ */
+static unsigned long bufctl_limit = 0;
-/* Initialisation - setup all internal caches */
-long
-kmem_cache_init(long start, long end)
+/* Initialisation - setup the `cache' cache. */
+__initfunc(long kmem_cache_init(long start, long end))
{
- /* sanity */
+ size_t size, i;
+
+#define kmem_slab_offset(x) ((unsigned long)&((kmem_slab_t *)0)->x)
+#define kmem_slab_diff(a,b) (kmem_slab_offset(a) - kmem_slab_offset(b))
#define kmem_cache_offset(x) ((unsigned long)&((kmem_cache_t *)0)->x)
-#define kmem_slab_offset(x) ((unsigned long)&((kmem_slab_t *)0)->x)
- if (((kmem_cache_offset(c_magic)-kmem_cache_offset(c_firstp)) != kmem_slab_offset(s_magic)) ||
- ((kmem_cache_offset(c_inuse)-kmem_cache_offset(c_firstp)) != kmem_slab_offset(s_inuse))) {
+#define kmem_cache_diff(a,b) (kmem_cache_offset(a) - kmem_cache_offset(b))
+
+ /* Sanity checks... */
+ if (kmem_cache_diff(c_firstp, c_magic) != kmem_slab_diff(s_nextp, s_magic) ||
+ kmem_cache_diff(c_firstp, c_inuse) != kmem_slab_diff(s_nextp, s_inuse) ||
+ ((kmem_cache_offset(c_lastp) -
+ ((unsigned long) kmem_slab_end((kmem_cache_t*)NULL))) !=
+ kmem_slab_offset(s_prevp)) ||
+ kmem_cache_diff(c_lastp, c_firstp) != kmem_slab_diff(s_prevp, s_nextp)) {
/* Offsets to the magic are incorrect, either the structures have
* been incorrectly changed, or adjustments are needed for your
* architecture.
*/
- panic("kmem_cache_init(): Offsets are different - been messed with!\n");
+ panic("kmem_cache_init(): Offsets are wrong - I've been messed with!");
/* NOTREACHED */
}
#undef kmem_cache_offset
+#undef kmem_cache_diff
#undef kmem_slab_offset
+#undef kmem_slab_diff
+
+ cache_chain_sem = MUTEX;
+
+ size = cache_cache.c_offset + sizeof(kmem_bufctl_t);
+ size += (L1_CACHE_BYTES-1);
+ size &= ~(L1_CACHE_BYTES-1);
+ cache_cache.c_offset = size-sizeof(kmem_bufctl_t);
+
+ i = (PAGE_SIZE<<cache_cache.c_gfporder)-slab_align_size;
+ cache_cache.c_num = i / size; /* num of objs per slab */
+
+ /* Cache colouring. */
+ cache_cache.c_colour = (i-(cache_cache.c_num*size))/L1_CACHE_BYTES;
+ cache_cache.c_colour_next = cache_cache.c_colour;
- kmem_own_cache_init(&cache_cache);
- kmem_own_cache_init(&cache_slab);
- kmem_own_cache_init(&cache_bufctl);
- kmem_own_cache_init(&cache_hash);
return start;
}
-/* Initialisation - setup general caches */
-void
-kmem_cache_sizes_init(void)
+/* Initialisation - setup remaining internal and general caches.
+ * Called after the gfp() functions have been enabled, and before smp_init().
+ */
+__initfunc(void kmem_cache_sizes_init(void))
{
- unsigned long i;
-
- i = sizeof(cache_sizes)/sizeof(cache_sizes[0])-1;
- while (i--)
- cache_sizes[i].cs_cachep = kmem_cache_create(cache_sizes_name[i],
- cache_sizes[i].cs_size,
- 0, 0, NULL, NULL);
+ unsigned int found = 0;
+
+ cache_slabp = kmem_cache_create("slab_cache", sizeof(kmem_slab_t),
+ 0, SLAB_HWCACHE_ALIGN, NULL, NULL);
+ if (cache_slabp) {
+ char **names = cache_sizes_name;
+ cache_sizes_t *sizes = cache_sizes;
+ do {
+ /* For performance, all the general-caches are L1 aligned.
+ * This should be particularly beneficial on SMP boxes, as it
+ * elimantes "false sharing".
+ * Note for systems short on memory removing the alignment will
+ * allow tighter packing of the smaller caches. */
+ if (!(sizes->cs_cachep =
+ kmem_cache_create(*names++, sizes->cs_size,
+ 0, SLAB_HWCACHE_ALIGN, NULL, NULL)))
+ goto panic_time;
+ if (!found) {
+ /* Inc off-slab bufctl limit until the ceiling is hit. */
+ if (SLAB_BUFCTL(sizes->cs_cachep->c_flags))
+ found++;
+ else
+ bufctl_limit =
+ (sizes->cs_size/sizeof(kmem_bufctl_t));
+ }
+ sizes->cs_cachep->c_flags |= SLAB_CFLGS_GENERAL;
+ sizes++;
+ } while (sizes->cs_size);
+#if SLAB_SELFTEST
+ kmem_self_test();
+#endif /* SLAB_SELFTEST */
+ return;
+ }
+panic_time:
+ panic("kmem_cache_sizes_init: Error creating caches");
+ /* NOTREACHED */
}
-/* Interface to system's page allocator.
- * dma pts to non-zero if all of the mem is suitable for DMA
+/* Interface to system's page allocator. Dma pts to non-zero if all
+ * of memory is DMAable. No need to hold the cache-lock.
*/
static inline void *
-kmem_getpages(const kmem_cache_t *cachep, unsigned long flags, unsigned int *dma)
+kmem_getpages(kmem_cache_t *cachep, unsigned long flags, unsigned int *dma)
{
- struct page *page;
void *addr;
- addr = (void*) __get_free_pages(flags & SLAB_LEVEL_MASK, \
- cachep->c_gfporder, flags & SLAB_DMA);
- *dma = 1<<cachep->c_gfporder;
- if (!(flags & SLAB_DMA) && addr) {
- /* need to check if can dma */
- page = mem_map + MAP_NR(addr);
+ *dma = flags & SLAB_DMA;
+ addr = (void*) __get_free_pages(flags & SLAB_LEVEL_MASK,
+ cachep->c_gfporder, *dma);
+ /* Assume that now we have the pages no one else can legally
+ * messes with the 'struct page's.
+ * However vm_scan() might try to test the structure to see if
+ * it is a named-page or buffer-page. The members it tests are
+ * of no interest here.....
+ */
+ if (!*dma && addr) {
+ /* Need to check if can dma. */
+ struct page *page = mem_map + MAP_NR(addr);
+ *dma = 1<<cachep->c_gfporder;
while ((*dma)--) {
if (!PageDMA(page)) {
*dma = 0;
@@ -357,58 +525,52 @@ kmem_getpages(const kmem_cache_t *cachep, unsigned long flags, unsigned int *dma
return addr;
}
-/* Interface to system's page release */
+/* Interface to system's page release. */
static inline void
kmem_freepages(kmem_cache_t *cachep, void *addr)
{
+ unsigned long i = (1<<cachep->c_gfporder);
+ struct page *page = &mem_map[MAP_NR(addr)];
+
+ /* free_pages() does not clear the type bit - we do that.
+ * The pages have been unlinked from their cache-slab,
+ * but their 'struct page's might be accessed in
+ * vm_scan(). Shouldn't be a worry.
+ */
+ while (i--) {
+ PageClearSlab(page);
+ page++;
+ }
free_pages((unsigned long)addr, cachep->c_gfporder);
}
-/* Hashing function - used for caches with off-slab bufctls */
-static inline int
-kmem_hash(const kmem_cache_t *cachep, const void *objp)
+#if SLAB_DEBUG_SUPPORT
+static inline void
+kmem_poision_obj(kmem_cache_t *cachep, void *addr)
{
- return (((unsigned long)objp >> cachep->c_hashbits) & (KMEM_HASH_SIZE-1));
+ memset(addr, SLAB_POISION_BYTE, cachep->c_org_size);
+ *(unsigned char *)(addr+cachep->c_org_size-1) = SLAB_POISION_END;
}
-/* Link bufctl into a hash table - used for caches with off-slab bufctls
- * - called with ints disabled
- */
-static inline void *
-kmem_add_to_hash(kmem_cache_t *cachep, kmem_bufctl_t *bufp)
+static inline int
+kmem_check_poision_obj(kmem_cache_t *cachep, void *addr)
{
- kmem_bufctl_t **bufpp = bufp->buf_hashp;
-
- bufp->buf_hnextp = *bufpp;
- return (*bufpp = bufp)->buf_objp;
+ void *end;
+ end = memchr(addr, SLAB_POISION_END, cachep->c_org_size);
+ if (end != (addr+cachep->c_org_size-1))
+ return 1;
+ return 0;
}
+#endif /* SLAB_DEBUG_SUPPORT */
-/* Find bufcntl for given obj addr, and unlink.
- * - called with ints disabled
+/* Three slab chain funcs - all called with ints disabled and the appropiate
+ * cache-lock held.
*/
-static inline kmem_bufctl_t *
-kmem_remove_from_hash(kmem_cache_t *cachep, const void *objp)
-{
- kmem_bufctl_t *bufp;
- kmem_bufctl_t **bufpp = &cachep->c_hashp[kmem_hash(cachep, objp)];
-
- for (;*bufpp; bufpp = &(*bufpp)->buf_hnextp) {
- if ((*bufpp)->buf_objp != objp)
- continue;
- bufp = *bufpp;
- *bufpp = bufp->buf_hnextp;
- return bufp;
- }
- return NULL;
-}
-
-/* Three slab chain funcs - all called with ints disabled */
static inline void
kmem_slab_unlink(kmem_slab_t *slabp)
{
kmem_slab_t *prevp = slabp->s_prevp;
kmem_slab_t *nextp = slabp->s_nextp;
-
prevp->s_nextp = nextp;
nextp->s_prevp = prevp;
}
@@ -416,781 +578,881 @@ kmem_slab_unlink(kmem_slab_t *slabp)
static inline void
kmem_slab_link_end(kmem_cache_t *cachep, kmem_slab_t *slabp)
{
+ kmem_slab_t *lastp = cachep->c_lastp;
slabp->s_nextp = kmem_slab_end(cachep);
- slabp->s_prevp = cachep->c_lastp;
- kmem_slab_end(cachep)->s_prevp = slabp;
- slabp->s_prevp->s_nextp = slabp;
+ slabp->s_prevp = lastp;
+ cachep->c_lastp = slabp;
+ lastp->s_nextp = slabp;
}
static inline void
kmem_slab_link_free(kmem_cache_t *cachep, kmem_slab_t *slabp)
{
kmem_slab_t *nextp = cachep->c_freep;
-
+ kmem_slab_t *prevp = nextp->s_prevp;
slabp->s_nextp = nextp;
- cachep->c_freep = slabp;
- slabp->s_prevp = nextp->s_prevp;
+ slabp->s_prevp = prevp;
nextp->s_prevp = slabp;
slabp->s_prevp->s_nextp = slabp;
}
-/* Cal the num objs, wastage, and bytes left over for a given slab size */
-static int
-kmem_cache_cal_waste(unsigned long gfporder, unsigned long size,
- unsigned long extra, unsigned long flags,
- unsigned long *left_over, unsigned long *num)
+/* Destroy all the objs in a slab, and release the mem back to the system.
+ * Before calling the slab must have been unlinked from the cache.
+ * The cache-lock is not held/needed.
+ */
+static void
+kmem_slab_destroy(kmem_cache_t *cachep, kmem_slab_t *slabp)
{
- unsigned long wastage;
+ if (cachep->c_dtor
+#if SLAB_DEBUG_SUPPORT
+ || cachep->c_flags & (SLAB_POISION || SLAB_RED_ZONE)
+#endif /*SLAB_DEBUG_SUPPORT*/
+ ) {
+ /* Doesn't use the bufctl ptrs to find objs. */
+ unsigned long num = cachep->c_num;
+ void *objp = slabp->s_mem;
+ do {
+#if SLAB_DEBUG_SUPPORT
+ if (cachep->c_flags & SLAB_RED_ZONE) {
+ if (*((unsigned long*)(objp)) != SLAB_RED_MAGIC1)
+ printk(KERN_ERR "kmem_slab_destroy: "
+ "Bad front redzone - %s\n",
+ cachep->c_name);
+ objp += BYTES_PER_WORD;
+ if (*((unsigned long*)(objp+cachep->c_org_size)) !=
+ SLAB_RED_MAGIC1)
+ printk(KERN_ERR "kmem_slab_destroy: "
+ "Bad rear redzone - %s\n",
+ cachep->c_name);
+ }
+ if (cachep->c_dtor)
+#endif /*SLAB_DEBUG_SUPPORT*/
+ (cachep->c_dtor)(objp, cachep, 0);
+#if SLAB_DEBUG_SUPPORT
+ else if (cachep->c_flags & SLAB_POISION) {
+ if (kmem_check_poision_obj(cachep, objp))
+ printk(KERN_ERR "kmem_slab_destory: "
+ "Bad poision - %s\n", cachep->c_name);
+ }
+ if (cachep->c_flags & SLAB_RED_ZONE)
+ objp -= BYTES_PER_WORD;
+#endif /* SLAB_DEBUG_SUPPORT */
+ objp += cachep->c_offset;
+ if (!slabp->s_index)
+ objp += sizeof(kmem_bufctl_t);
+ } while (--num);
+ }
- wastage = PAGE_SIZE << gfporder;
- gfporder = 0;
- if (!SLAB_OFF_SLAB(flags))
- gfporder = sizeof(kmem_slab_t);
+ slabp->s_magic = SLAB_MAGIC_DESTROYED;
+ kmem_freepages(cachep, slabp->s_mem-slabp->s_offset);
+ if (slabp->s_index)
+ kmem_cache_free(cachep->c_index_cachep, slabp->s_index);
+ if (SLAB_OFF_SLAB(cachep->c_flags))
+ kmem_cache_free(cache_slabp, slabp);
+}
+
+/* Cal the num objs, wastage, and bytes left over for a given slab size. */
+static inline size_t
+kmem_cache_cal_waste(unsigned long gfporder, size_t size, size_t extra,
+ unsigned long flags, size_t *left_over, unsigned long *num)
+{
+ size_t wastage = PAGE_SIZE<<gfporder;
+
+ if (SLAB_OFF_SLAB(flags))
+ gfporder = 0;
+ else
+ gfporder = slab_align_size;
wastage -= gfporder;
*num = wastage / size;
wastage -= (*num * size);
*left_over = wastage;
- wastage += (extra * *num);
- wastage += gfporder;
-
- return wastage;
+ return (wastage + gfporder + (extra * *num));
}
-/* Create a cache
+/* Create a cache:
* Returns a ptr to the cache on success, NULL on failure.
* Cannot be called within a int, but can be interrupted.
* NOTE: The 'name' is assumed to be memory that is _not_ going to disappear.
*/
kmem_cache_t *
-kmem_cache_create(const char *name, unsigned long size, unsigned long align,
- unsigned long flags, void (*ctor)(void*, int, unsigned long),
- void (*dtor)(void*, int, unsigned long))
+kmem_cache_create(const char *name, size_t size, size_t offset,
+ unsigned long flags, void (*ctor)(void*, kmem_cache_t *, unsigned long),
+ void (*dtor)(void*, kmem_cache_t *, unsigned long))
{
- const char *func_nm="kmem_create: ";
- kmem_cache_t *searchp, *cachep;
- unsigned long words, i;
- unsigned long num, left_over;
+ const char *func_nm= KERN_ERR "kmem_create: ";
+ kmem_cache_t *searchp;
+ kmem_cache_t *cachep=NULL;
+ size_t extra;
+ size_t left_over;
+ size_t align;
- /* sanity checks */
-#if defined(SLAB_MGMT_CHECKS)
+ /* Sanity checks... */
+#if SLAB_MGMT_CHECKS
if (!name) {
- printk(KERN_ERR "%sNULL ptr\n", func_nm);
- return NULL;
+ printk("%sNULL ptr\n", func_nm);
+ goto opps;
}
if (in_interrupt()) {
- printk(KERN_ERR "%sCalled during int - %s\n", func_nm, name);
- return NULL;
+ printk("%sCalled during int - %s\n", func_nm, name);
+ goto opps;
}
- if (size < kmem_bufctl_very_short_size) {
- printk(KERN_WARNING "%sSize too small %lu - %s\n", func_nm, size, name);
- size = kmem_bufctl_very_short_size;
+ if (size < BYTES_PER_WORD) {
+ printk("%sSize too small %d - %s\n", func_nm, (int) size, name);
+ size = BYTES_PER_WORD;
}
if (size > ((1<<SLAB_OBJ_MAX_ORDER)*PAGE_SIZE)) {
- printk(KERN_ERR "%sSize too large %lu - %s\n", func_nm, size, name);
- return NULL;
- }
-#endif /* SLAB_MGMT_CHECKS */
-
- /* always checks flags, a caller might be expecting debug support which
- * isn't available
- */
- if (flags & ~SLAB_C_MASK) {
- /* Illegal flags */
- printk(KERN_WARNING "%sIllgl flg %lX - %s\n", func_nm, flags, name);
- flags &= SLAB_C_MASK;
+ printk("%sSize too large %d - %s\n", func_nm, (int) size, name);
+ goto opps;
}
-#if defined(SLAB_MGMT_CHECKS)
- if (align < 0 || align >= size) {
- printk(KERN_WARNING "%sAlign weired %lu - %s\n", func_nm, align, name);
- align = 0;
+ if (dtor && !ctor) {
+ /* Decon, but no con - doesn't make sense */
+ printk("%sDecon but no con - %s\n", func_nm, name);
+ goto opps;
}
- if (dtor && !ctor) {
- /* Descon, but no con - doesn't make sense */
- printk(KERN_ERR "%sDecon but no con - %s\n", func_nm, name);
- return NULL;
+ if (offset < 0 || offset > size) {
+ printk("%sOffset weired %d - %s\n", func_nm, (int) offset, name);
+ offset = 0;
}
+#if SLAB_DEBUG_SUPPORT
if ((flags & SLAB_DEBUG_INITIAL) && !ctor) {
/* No constructor, but inital state check requested */
- printk(KERN_WARNING "%sNo con, but init state check requested - %s\n",
- func_nm, name);
+ printk("%sNo con, but init state check requested - %s\n", func_nm, name);
flags &= ~SLAB_DEBUG_INITIAL;
}
+
+ if ((flags & SLAB_POISION) && ctor) {
+ /* request for poisioning, but we can't do that with a constructor */
+ printk("%sPoisioning requested, but con given - %s\n", func_nm, name);
+ flags &= ~SLAB_POISION;
+ }
+#if 0
+ if ((flags & SLAB_HIGH_PACK) && ctor) {
+ printk("%sHigh pack requested, but con given - %s\n", func_nm, name);
+ flags &= ~SLAB_HIGH_PACK;
+ }
+ if ((flags & SLAB_HIGH_PACK) && (flags & (SLAB_POISION|SLAB_RED_ZONE))) {
+ printk("%sHigh pack requested, but with poisioning/red-zoning - %s\n",
+ func_nm, name);
+ flags &= ~SLAB_HIGH_PACK;
+ }
+#endif
+#endif /* SLAB_DEBUG_SUPPORT */
#endif /* SLAB_MGMT_CHECKS */
- /* get cache's description obj */
+ /* Always checks flags, a caller might be expecting debug
+ * support which isn't available.
+ */
+ if (flags & ~SLAB_C_MASK) {
+ printk("%sIllgl flg %lX - %s\n", func_nm, flags, name);
+ flags &= SLAB_C_MASK;
+ }
+
+ /* Get cache's description obj. */
cachep = (kmem_cache_t *) kmem_cache_alloc(&cache_cache, SLAB_KERNEL);
if (!cachep)
goto opps;
+ memset(cachep, 0, sizeof(kmem_cache_t));
- /* remember original size, so can be passed to a constructor or decon.
- * Allows the same con/decon to be used for caches of similar objs
- * that have a different size data buffer assoicated with them
+ /* Check that size is in terms of words. This is needed to avoid
+ * unaligned accesses for some archs when redzoning is used, and makes
+ * sure any on-slab bufctl's are also correctly aligned.
*/
- cachep->c_org_size = size;
+ if (size & (BYTES_PER_WORD-1)) {
+ size += (BYTES_PER_WORD-1);
+ size &= ~(BYTES_PER_WORD-1);
+ printk("%sForcing size word alignment - %s\n", func_nm, name);
+ }
-#if defined(SLAB_DEBUG_SUPPORT)
- if (flags & SLAB_RED_ZONE)
- size += BYTES_PER_WORD; /* word for redzone */
+#if SLAB_DEBUG_SUPPORT
+ if (flags & SLAB_RED_ZONE) {
+ /* There is no point trying to honour cache alignment when redzoning. */
+ flags &= ~SLAB_HWCACHE_ALIGN;
+ size += 2*BYTES_PER_WORD; /* words for redzone */
+ }
#endif /* SLAB_DEBUG_SUPPORT */
+ cachep->c_org_size = size;
- /* Make a guess if slab mngmnt obj and/or bufctls are 'on' or 'off' slab */
- i = kmem_bufctl_short_size;
+ align = BYTES_PER_WORD;
+ if (flags & SLAB_HWCACHE_ALIGN)
+ align = L1_CACHE_BYTES;
+
+ /* Determine if the slab mgmt and/or bufclts are 'on' or 'off' slab. */
+ extra = sizeof(kmem_bufctl_t);
if (size < (PAGE_SIZE>>3)) {
- /* Size is small(ish). Use format where bufctl size per
- * obj is low, and slab mngmnt is on-slab
+ /* Size is small(ish). Use packing where bufctl size per
+ * obj is low, and slab mngmnt is on-slab.
*/
- if (!ctor && !dtor && !(flags & SLAB_RED_ZONE)) {
- /* the objs in this cache have no state - can store
- * store freelist ptr within obj. (redzoning is a state)
+#if 0
+ if ((flags & SLAB_HIGH_PACK)) {
+ /* Special high packing for small objects
+ * (mainly for vm_mapping structs, but
+ * others can use it).
*/
-#if defined(SLAB_HIGH_PACK)
- i=0;
- flags |= SLAB_CFLGS_PTR_IN_OBJ;
-#else
- i = kmem_bufctl_very_short_size;
-#endif
+ if (size == (L1_CACHE_BYTES/4) || size == (L1_CACHE_BYTES/2) ||
+ size == L1_CACHE_BYTES) {
+ /* The bufctl is stored with the object. */
+ extra = 0;
+ } else
+ flags &= ~SLAB_HIGH_PACK;
}
+#endif
} else {
/* Size is large, assume best to place the slab mngmnt obj
- * off-slab (should allow better packing of objs)
+ * off-slab (should allow better packing of objs).
*/
flags |= SLAB_CFLGS_OFF_SLAB;
- if (!(size & ~PAGE_MASK) ||
- size == (PAGE_SIZE+PAGE_SIZE/2) ||
- size == (PAGE_SIZE/2) ||
- size == (PAGE_SIZE/4) ||
- size == (PAGE_SIZE/8)) {
- /* to avoid waste the bufctls are off-slab */
+ if (!(size & ~PAGE_MASK) || size == (PAGE_SIZE/2)
+ || size == (PAGE_SIZE/4) || size == (PAGE_SIZE/8)) {
+ /* To avoid waste the bufctls are off-slab... */
flags |= SLAB_CFLGS_BUFCTL;
- /* get hash table for cache */
- cachep->c_hashp = kmem_cache_alloc(&cache_hash, SLAB_KERNEL);
- if (cachep->c_hashp == NULL) {
- kmem_cache_free(&cache_cache, cachep);
- goto opps;
- }
- i = 0;
- cachep->c_hashbits = PAGE_SHIFT;
- if (size <= (PAGE_SIZE/2)) {
- cachep->c_hashbits--;
- if (size <= (PAGE_SIZE/4)) cachep->c_hashbits--;
- if (size <= (PAGE_SIZE/8)) cachep->c_hashbits -= 2;
+ extra = 0;
+ } /* else slab mngmnt is off-slab, but freelist ptrs are on. */
+ }
+ size += extra;
+
+ if (flags & SLAB_HWCACHE_ALIGN) {
+ /* Need to adjust size so that objs are cache aligned. */
+ if (size > (L1_CACHE_BYTES/2)) {
+ size_t words = size % L1_CACHE_BYTES;
+ if (words)
+ size += (L1_CACHE_BYTES-words);
+ } else {
+ /* Small obj size, can get at least two per cache line. */
+ int num_per_line = L1_CACHE_BYTES/size;
+ left_over = L1_CACHE_BYTES - (num_per_line*size);
+ if (left_over) {
+ /* Need to adjust size so objs cache align. */
+ if (left_over%num_per_line) {
+ /* Odd num of objs per line - fixup. */
+ num_per_line--;
+ left_over += size;
+ }
+ size += (left_over/num_per_line);
}
- } /* else slab mngmnt is off-slab, but freelist ptrs are on */
+ }
+ } else if (!(size%L1_CACHE_BYTES)) {
+ /* Size happens to cache align... */
+ flags |= SLAB_HWCACHE_ALIGN;
+ align = L1_CACHE_BYTES;
}
- size += i;
-
- /* Adjust the mem used for objs so they will align correctly.
- * Force objs to start on word boundaries, but caller may specify
- * h/w cache line boundaries. This 'alignment' is slightly different
- * to the 'align' argument. Objs may be requested to start on h/w
- * lines (as that is how the members of the obj have been organised),
- * but the 'align' may be quite high (say 64) as the first 64 bytes
- * are commonly accessed/modified within a loop (stops h/w line
- * thrashing). The 'align' is the slab colouring.
- */
- words = BYTES_PER_WORD;
- if (flags & SLAB_HWCACHE_ALIGN)
- words = L1_CACHE_BYTES;
- words--;
- size += words;
- size = size & ~words;
- /* alignment might not be a factor of the boundary alignment - fix-up */
- align += words;
- align = align & ~words;
-
/* Cal size (in pages) of slabs, and the num of objs per slab.
- * This could be made much more intelligent. */
- cachep->c_gfporder=0;
+ * This could be made much more intelligent. For now, try to avoid
+ * using high page-orders for slabs. When the gfp() funcs are more
+ * friendly towards high-order requests, this should be changed.
+ */
do {
- unsigned long wastage;
- wastage = kmem_cache_cal_waste(cachep->c_gfporder, size, i,
- flags, &left_over, &num);
- if (!num)
+ size_t wastage;
+ unsigned int break_flag = 0;
+cal_wastage:
+ wastage = kmem_cache_cal_waste(cachep->c_gfporder, size, extra,
+ flags, &left_over, &cachep->c_num);
+ if (!cachep->c_num)
goto next;
- if (SLAB_PTR_IN_OBJ(flags))
+ if (break_flag)
break;
+ if (SLAB_BUFCTL(flags) && cachep->c_num > bufctl_limit) {
+ /* Oops, this num of objs will cause problems. */
+ cachep->c_gfporder--;
+ break_flag++;
+ goto cal_wastage;
+ }
if (cachep->c_gfporder == SLAB_MAX_GFP_ORDER)
break;
- /* large num of objs is good, but v. large slabs are bad for the
- * VM sub-system
+
+ /* Large num of objs is good, but v. large slabs are currently
+ * bad for the gfp()s.
*/
- if (num <= SLAB_MIN_OBJS_PER_SLAB) {
+ if (cachep->c_num <= SLAB_MIN_OBJS_PER_SLAB) {
if (cachep->c_gfporder < SLAB_BREAK_GFP_ORDER)
goto next;
}
- /* stop caches with small objs having a large num of pages */
- if (left_over <= sizeof(kmem_slab_t))
+
+ /* Stop caches with small objs having a large num of pages. */
+ if (left_over <= slab_align_size)
break;
if ((wastage*8) <= (PAGE_SIZE<<cachep->c_gfporder))
- break; /* acceptable wastage */
+ break; /* Acceptable internal fragmentation. */
next:
cachep->c_gfporder++;
} while (1);
- cachep->c_num = num;
- /* try with requested alignment, but reduce it if that will
- * allow at least some alignment words
+ /* If the slab has been placed off-slab, and we have enough space then
+ * move it on-slab. This is at the expense of any extra colouring.
*/
- words++;
- if (left_over < align)
- align = (left_over / words) * words;
- else if (!align && words <= left_over) {
- /* no alignment given, but space enough - give one */
- align = words;
- if (words == BYTES_PER_WORD) {
- if (BYTES_PER_WORD*4 <= left_over)
- align += align;
- if (BYTES_PER_WORD*8 <= left_over)
- align += align;
+ if ((flags & SLAB_CFLGS_OFF_SLAB) && !SLAB_BUFCTL(flags) &&
+ left_over >= slab_align_size) {
+ flags &= ~SLAB_CFLGS_OFF_SLAB;
+ left_over -= slab_align_size;
+ }
+
+ /* Offset must be a factor of the alignment. */
+ offset += (align-1);
+ offset &= ~(align-1);
+
+ /* Mess around with the offset alignment. */
+ if (!left_over) {
+ offset = 0;
+ } else if (left_over < offset) {
+ offset = align;
+ if (flags & SLAB_HWCACHE_ALIGN) {
+ if (left_over < offset)
+ offset = 0;
+ } else {
+ /* Offset is BYTES_PER_WORD, and left_over is at
+ * least BYTES_PER_WORD.
+ */
+ if (left_over >= (BYTES_PER_WORD*2)) {
+ offset >>= 1;
+ if (left_over >= (BYTES_PER_WORD*4))
+ offset >>= 1;
+ }
+ }
+ } else if (!offset) {
+ /* No offset requested, but space enough - give one. */
+ offset = left_over/align;
+ if (flags & SLAB_HWCACHE_ALIGN) {
+ if (offset >= 8) {
+ /* A large number of colours - use a larger alignment. */
+ align <<= 1;
+ }
+ } else {
+ if (offset >= 10) {
+ align <<= 1;
+ if (offset >= 16)
+ align <<= 1;
+ }
}
+ offset = align;
}
- cachep->c_align = align;
#if 0
- printk("Size:%lu Orig:%lu Left:%lu Align %lu Pages:%d - %s\n",
- size, cachep->c_org_size, left_over, align, 1<<cachep->c_gfporder, name);
- if (SLAB_OFF_SLAB(flags)) printk("OFF SLAB\n");
- if (SLAB_BUFCTL(flags)) printk("BUFCTL PTRS\n");
+printk("%s: Left_over:%d Align:%d Size:%d\n", name, left_over, offset, size);
#endif
- /* if the bufctl's are on-slab, c_offset does not inc the size of the bufctl */
+ if ((cachep->c_align = (unsigned long) offset))
+ cachep->c_colour = (left_over/offset);
+ cachep->c_colour_next = cachep->c_colour;
+
+ /* If the bufctl's are on-slab, c_offset does not include the size of bufctl. */
if (!SLAB_BUFCTL(flags))
- size -= kmem_bufctl_short_size;
+ size -= sizeof(kmem_bufctl_t);
+ else
+ cachep->c_index_cachep =
+ kmem_find_general_cachep(cachep->c_num*sizeof(kmem_bufctl_t));
+ cachep->c_offset = (unsigned long) size;
cachep->c_freep = kmem_slab_end(cachep);
- cachep->c_flags = flags;
- cachep->c_offset = size;
cachep->c_firstp = kmem_slab_end(cachep);
cachep->c_lastp = kmem_slab_end(cachep);
+ cachep->c_flags = flags;
cachep->c_ctor = ctor;
cachep->c_dtor = dtor;
cachep->c_magic = SLAB_C_MAGIC;
- cachep->c_inuse = 0; /* always zero */
- cachep->c_name = name; /* simply point to the name */
+ cachep->c_name = name; /* Simply point to the name. */
+ spin_lock_init(&cachep->c_spinlock);
- cachep->c_colour = 1;
- if (align)
- cachep->c_colour += (left_over/align);
- cachep->c_colour_next = cachep->c_colour;
-
- /* warn on dup cache names */
+ /* Need the semaphore to access the chain. */
+ down(&cache_chain_sem);
searchp = &cache_cache;
do {
+ /* The name field is constant - no lock needed. */
if (!strcmp(searchp->c_name, name)) {
- printk(KERN_WARNING "%sDup name - %s\n", func_nm, name);
+ printk("%sDup name - %s\n", func_nm, name);
break;
}
searchp = searchp->c_nextp;
} while (searchp != &cache_cache);
+
+ /* There is no reason to lock our new cache before we
+ * link it in - no one knows about it yet...
+ */
cachep->c_nextp = cache_cache.c_nextp;
cache_cache.c_nextp = cachep;
- return cachep;
+ up(&cache_chain_sem);
opps:
- printk(KERN_WARNING "%sOut of mem creating cache %s\n", func_nm, name);
- return NULL;
-}
-
-/* Destroy all the objs in a slab, and release the mem back to the system.
- * Before calling the slab must have been unlinked
- */
-static void
-kmem_slab_destroy(kmem_cache_t *cachep, kmem_slab_t *slabp, unsigned long flags)
-{
- if (cachep->c_dtor || SLAB_BUFCTL(cachep->c_flags)) {
- kmem_bufctl_t *bufp = slabp->s_freep;
-
- /* for each obj in slab... */
- while (bufp) {
- kmem_bufctl_t *freep;
- if (cachep->c_dtor) {
- void *objp = ((void*)bufp)-cachep->c_offset;
- if (SLAB_BUFCTL(cachep->c_flags))
- objp = bufp->buf_objp;
- (cachep->c_dtor)(objp, cachep->c_org_size, flags);
- }
- freep = bufp;
- bufp = bufp->buf_nextp;
- if (SLAB_BUFCTL(cachep->c_flags))
- kmem_cache_free(&cache_bufctl, freep);
- }
- }
-
- slabp->s_magic = SLAB_MAGIC_UNALLOC;
- kmem_freepages(cachep, slabp->s_mem);
- if (SLAB_OFF_SLAB(cachep->c_flags))
- kmem_cache_free(&cache_slab, slabp);
-}
-
-/* Destroy (remove) a cache.
- * All objs in the cache should be inactive
- */
-int
-kmem_cache_destroy(kmem_cache_t *cachep)
-{
- kmem_cache_t **searchp;
- kmem_slab_t *slabp;
- unsigned long save_flags;
-
-#if defined(SLAB_MGMT_CHECKS)
- if (!cachep) {
- printk(KERN_ERR "kmem_dest: NULL ptr\n");
- goto err_end;
- }
-
- if (in_interrupt()) {
- printk(KERN_ERR "kmem_dest: Called during int - %s\n", cachep->c_name);
-err_end:
- return 1;
- }
-#endif /* SLAB_MGMT_CHECKS */
-
- /* unlink the cache from the chain of active caches.
- * Note: the chain is never modified during an int
- */
- searchp = &(cache_cache.c_nextp);
- for (;*searchp != &cache_cache; searchp = &((*searchp)->c_nextp)) {
- if (*searchp != cachep)
- continue;
- goto good_cache;
- }
- printk(KERN_ERR "kmem_dest: Invalid cache addr %p\n", cachep);
- return 1;
-good_cache:
- /* disable cache so attempts to allocated from an int can
- * be caught.
- */
- save_flags(save_flags);
- cli();
- if (cachep->c_freep != kmem_slab_end(cachep)) {
- restore_flags(save_flags);
- printk(KERN_ERR "kmem_dest: active cache - %s\n", cachep->c_name);
- return 2;
- }
- *searchp = cachep->c_nextp; /* remove from cache chain */
- cachep->c_flags |= SLAB_CFLGS_RELEASED;
- cachep->c_freep = kmem_slab_end(cachep);
- if (cachep == clock_searchp)
- clock_searchp = cachep->c_nextp;
- restore_flags(save_flags);
-
- while ((slabp = cachep->c_firstp) != kmem_slab_end(cachep)) {
- kmem_slab_unlink(slabp);
- kmem_slab_destroy(cachep, slabp, 0);
- }
-
- if (SLAB_BUFCTL(cachep->c_flags))
- kmem_cache_free(&cache_hash, cachep->c_hashp);
- kmem_cache_free(&cache_cache, cachep);
- return 0;
+ return cachep;
}
-/* Shrink a cache, ie. remove _all_ inactive slabs.
- * Can be called when a user of a cache knows they are not going to be
- * needing any new objs for a while.
- * NOTE: This func is probably going to disappear - let me know if you
- * are using it!
+/* Shrink a cache. Releases as many slabs as possible for a cache.
+ * It is expected this function will be called by a module when it is
+ * unloaded. The cache is _not_ removed, this creates too many problems and
+ * the cache-structure does not take up much room. A module should keep its
+ * cache pointer(s) in unloaded memory, so when reloaded it knows the cache
+ * is available. To help debugging, a zero exit status indicates all slabs
+ * were released.
*/
int
-kmem_cache_shrink(kmem_cache_t *cachep, int wait)
+kmem_cache_shrink(kmem_cache_t *cachep)
{
+ kmem_cache_t *searchp;
kmem_slab_t *slabp;
- unsigned long dtor_flags;
- unsigned long save_flags, num_freed=0;
+ int ret;
-#if defined(SLAB_MGMT_CHECKS)
if (!cachep) {
printk(KERN_ERR "kmem_shrink: NULL ptr\n");
- goto end;
+ return 2;
}
-
if (in_interrupt()) {
printk(KERN_ERR "kmem_shrink: Called during int - %s\n", cachep->c_name);
- goto end;
+ return 2;
}
-#endif /* SLAB_MGMT_CHECKS */
- dtor_flags = 0;
- if (!wait) /* not allowed to wait */
- dtor_flags = SLAB_DTOR_ATOMIC;
+ /* Find the cache in the chain of caches. */
+ down(&cache_chain_sem); /* Semaphore is needed. */
+ searchp = &cache_cache;
+ for (;searchp->c_nextp != &cache_cache; searchp = searchp->c_nextp) {
+ if (searchp->c_nextp != cachep)
+ continue;
- save_flags(save_flags);
- while (0) {
- cli();
- slabp = cachep->c_lastp;
- if (slabp == kmem_slab_end(cachep) || slabp->s_inuse) {
- restore_flags(save_flags);
- goto end;
- }
- kmem_slab_unlink(slabp);
- if (cachep->c_freep == slabp)
- cachep->c_freep = kmem_slab_end(cachep);
- restore_flags(save_flags);
- num_freed++;
- kmem_slab_destroy(cachep, slabp, dtor_flags);
+ /* Accessing clock_searchp is safe - we hold the mutex. */
+ if (cachep == clock_searchp)
+ clock_searchp = cachep->c_nextp;
+ goto found;
}
-end:
- return num_freed;
-}
-
-/* Search for a slab whose objs are suitable for DMA.
- * Note: since testing the first free slab (in __kmem_cache_alloc()),
- * ints must not have been enabled!
- */
-static inline kmem_slab_t *
-kmem_cache_search_dma(kmem_cache_t *cachep)
-{
- kmem_slab_t *slabp = cachep->c_freep->s_nextp;
+ up(&cache_chain_sem);
+ printk(KERN_ERR "kmem_shrink: Invalid cache addr %p\n", cachep);
+ return 2;
+found:
+ /* Relase the sempahore before getting the cache-lock. This could
+ * mean multiple engines are shrinking the cache, but so what...
+ */
+ up(&cache_chain_sem);
+ spin_lock_irq(&cachep->c_spinlock);
- for (; slabp != kmem_slab_end(cachep); slabp = slabp->s_nextp) {
- if (!(slabp->s_flags & SLAB_SFLGS_DMA))
- continue;
+ /* If the cache is growing, stop shrinking. */
+ while (!cachep->c_growing) {
+ slabp = cachep->c_lastp;
+ if (slabp->s_inuse || slabp == kmem_slab_end(cachep))
+ break;
kmem_slab_unlink(slabp);
- kmem_slab_link_free(cachep, slabp);
- return slabp;
+ spin_unlock_irq(&cachep->c_spinlock);
+ kmem_slab_destroy(cachep, slabp);
+ spin_lock_irq(&cachep->c_spinlock);
}
- return NULL;
+ ret = 1;
+ if (cachep->c_lastp == kmem_slab_end(cachep))
+ ret--; /* Cache is empty. */
+ spin_unlock_irq(&cachep->c_spinlock);
+ return ret;
}
-/* get the mem for a slab mgmt obj */
+/* Get the mem for a slab mgmt obj. */
static inline kmem_slab_t *
-kmem_cache_slabmgmt(kmem_cache_t *cachep, void *objp, unsigned long local_flags, unsigned long offset)
+kmem_cache_slabmgmt(kmem_cache_t *cachep, void *objp, int local_flags)
{
kmem_slab_t *slabp;
if (SLAB_OFF_SLAB(cachep->c_flags)) {
- /* slab mngmnt obj is off-slab */
- if (!(slabp = kmem_cache_alloc(&cache_slab, local_flags)))
- return NULL;
+ /* Slab mgmt obj is off-slab. */
+ slabp = kmem_cache_alloc(cache_slabp, local_flags);
} else {
- /* slab mngmnt at end of slab mem */
- slabp = objp + (PAGE_SIZE << cachep->c_gfporder);
- slabp--;
- if (!SLAB_PTR_IN_OBJ(cachep->c_flags)) {
- /* A bit of extra help for the L1 cache; try to position the slab
- * mgmnt struct at different offsets within the gap at the end
- * of a slab. This helps avoid thrashing the h/w cache lines,
- * that map to the end of a page, too much...
- */
- unsigned long gap = cachep->c_offset;
- if (!SLAB_BUFCTL(cachep->c_flags))
- gap += kmem_bufctl_short_size;
- gap = (PAGE_SIZE << cachep->c_gfporder)-((gap*cachep->c_num)+offset+sizeof(*slabp));
- gap /= (sizeof(*slabp)/2);
- gap *= (sizeof(*slabp)/2);
- slabp = (((void*)slabp)-gap);
- }
+ /* Slab mgmnt at end of slab mem, placed so that
+ * the position is 'coloured'.
+ */
+ void *end;
+ end = objp + (cachep->c_num * cachep->c_offset);
+ if (!SLAB_BUFCTL(cachep->c_flags))
+ end += (cachep->c_num * sizeof(kmem_bufctl_t));
+ slabp = (kmem_slab_t *) L1_CACHE_ALIGN((unsigned long)end);
}
- slabp->s_flags = slabp->s_inuse = slabp->s_jiffies = 0;
+ if (slabp) {
+ slabp->s_inuse = 0;
+ slabp->s_dma = 0;
+ slabp->s_index = NULL;
+ }
return slabp;
}
-static inline int
-kmem_cache_init_objs(kmem_cache_t *cachep, kmem_slab_t *slabp, void *objp,
- unsigned long local_flags, unsigned long ctor_flags)
+static inline void
+kmem_cache_init_objs(kmem_cache_t * cachep, kmem_slab_t * slabp, void *objp,
+ unsigned long ctor_flags)
{
kmem_bufctl_t **bufpp = &slabp->s_freep;
- unsigned long num = cachep->c_num;
+ unsigned long num = cachep->c_num-1;
do {
- if (SLAB_BUFCTL(cachep->c_flags)) {
- if (!(*bufpp = kmem_cache_alloc(&cache_bufctl, local_flags))) {
- kmem_slab_destroy(cachep, slabp, 0);
- return 1;
- }
- (*bufpp)->buf_objp = objp;
- (*bufpp)->buf_hashp = &cachep->c_hashp[kmem_hash(cachep, objp)];
+#if SLAB_DEBUG_SUPPORT
+ if (cachep->c_flags & SLAB_RED_ZONE) {
+ *((unsigned long*)(objp)) = SLAB_RED_MAGIC1;
+ objp += BYTES_PER_WORD;
+ *((unsigned long*)(objp+cachep->c_org_size)) = SLAB_RED_MAGIC1;
}
+#endif /* SLAB_DEBUG_SUPPORT */
+ /* Constructors are not allowed to allocate memory from the same cache
+ * which they are a constructor for. Otherwise, deadlock.
+ * They must also be threaded.
+ */
if (cachep->c_ctor)
- cachep->c_ctor(objp, cachep->c_org_size, ctor_flags);
+ cachep->c_ctor(objp, cachep, ctor_flags);
+#if SLAB_DEBUG_SUPPORT
+ else if (cachep->c_flags & SLAB_POISION) {
+ /* need to poision the objs */
+ kmem_poision_obj(cachep, objp);
+ }
-#if defined(SLAB_DEBUG_SUPPORT)
- if (cachep->c_flags & SLAB_RED_ZONE)
- *((unsigned long*)(objp+cachep->c_org_size)) = SLAB_RED_MAGIC1;
+ if (cachep->c_flags & SLAB_RED_ZONE) {
+ if (*((unsigned long*)(objp+cachep->c_org_size)) !=
+ SLAB_RED_MAGIC1) {
+ *((unsigned long*)(objp+cachep->c_org_size)) =
+ SLAB_RED_MAGIC1;
+ printk(KERN_ERR "kmem_init_obj: Bad rear redzone "
+ "after constructor - %s\n", cachep->c_name);
+ }
+ objp -= BYTES_PER_WORD;
+ if (*((unsigned long*)(objp)) != SLAB_RED_MAGIC1) {
+ *((unsigned long*)(objp)) = SLAB_RED_MAGIC1;
+ printk(KERN_ERR "kmem_init_obj: Bad front redzone "
+ "after constructor - %s\n", cachep->c_name);
+ }
+ }
#endif /* SLAB_DEBUG_SUPPORT */
objp += cachep->c_offset;
- if (!SLAB_BUFCTL(cachep->c_flags)) {
+ if (!slabp->s_index) {
*bufpp = objp;
- objp += kmem_bufctl_short_size;
- }
- if (!SLAB_PTR_IN_OBJ(cachep->c_flags))
- (*bufpp)->buf_slabp = slabp;
+ objp += sizeof(kmem_bufctl_t);
+ } else
+ *bufpp = &slabp->s_index[num];
bufpp = &(*bufpp)->buf_nextp;
- } while (--num);
+ } while (num--);
+
*bufpp = NULL;
- return 0;
}
-/* Grow (by 1) the number of slabs within a cache.
- * This is called by kmem_cache_alloc() when there are no
- * inactive objs left in a cache
+/* Grow (by 1) the number of slabs within a cache. This is called by
+ * kmem_cache_alloc() when there are no active objs left in a cache.
*/
-static void
-kmem_cache_grow(kmem_cache_t *cachep, unsigned long flags)
+static int
+kmem_cache_grow(kmem_cache_t * cachep, int flags)
{
kmem_slab_t *slabp;
+ struct page *page;
void *objp;
- unsigned int offset, dma;
- unsigned long ctor_flags, local_flags, save_flags;
+ size_t offset;
+ unsigned int dma, local_flags;
+ unsigned long ctor_flags;
+ unsigned long save_flags;
+
+ /* Be lazy and only check for valid flags here,
+ * keeping it out of the critical path in kmem_cache_alloc().
+ */
+ if (flags & ~(SLAB_DMA|SLAB_LEVEL_MASK|SLAB_NO_GROW)) {
+ printk(KERN_WARNING "kmem_grow: Illegal flgs %X (correcting) - %s\n",
+ flags, cachep->c_name);
+ flags &= (SLAB_DMA|SLAB_LEVEL_MASK|SLAB_NO_GROW);
+ }
if (flags & SLAB_NO_GROW)
- return; /* caller doesn't want us to grow */
+ return 0;
- save_flags(save_flags);
/* The test for missing atomic flag is performed here, rather than
* the more obvious place, simply to reduce the critical path length
- * in kmem_cache_alloc(). If a caller is slightly mis-behaving,
- * will eventually be caught here (where it matters)
+ * in kmem_cache_alloc(). If a caller is slightly mis-behaving they
+ * will eventually be caught here (where it matters).
*/
if (in_interrupt() && (flags & SLAB_LEVEL_MASK) != SLAB_ATOMIC) {
- static int count = 0;
- if (count < 8) {
- printk(KERN_ERR "kmem_grow: Called nonatomically from "
- "int - %s\n", cachep->c_name);
- count++;
- }
+ printk(KERN_ERR "kmem_grow: Called nonatomically from int - %s\n",
+ cachep->c_name);
flags &= ~SLAB_LEVEL_MASK;
flags |= SLAB_ATOMIC;
}
- local_flags = (flags & SLAB_LEVEL_MASK);
ctor_flags = SLAB_CTOR_CONSTRUCTOR;
- if ((flags & SLAB_LEVEL_MASK) == SLAB_ATOMIC) {
- /* Not allowed to sleep.
- * Need to tell a constructor about this - it
- * might need to know....
+ local_flags = (flags & SLAB_LEVEL_MASK);
+ if (local_flags == SLAB_ATOMIC) {
+ /* Not allowed to sleep. Need to tell a constructor about
+ * this - it might need to know...
*/
ctor_flags |= SLAB_CTOR_ATOMIC;
}
- slabp = NULL;
- /* get mem for the objs */
- if (!(objp = kmem_getpages(cachep, flags, &dma)))
- goto opps1;
+ /* About to mess with non-constant members - lock. */
+ spin_lock_irqsave(&cachep->c_spinlock, save_flags);
- /* get colour for the slab, and cal the next value */
- cli();
- if (!(offset = --(cachep->c_colour_next)))
+ /* Get colour for the slab, and cal the next value. */
+ if (!(offset = cachep->c_colour_next--))
cachep->c_colour_next = cachep->c_colour;
- restore_flags(save_flags);
offset *= cachep->c_align;
+ cachep->c_dflags = SLAB_CFLGS_GROWN;
+
+ cachep->c_growing++;
+re_try:
+ spin_unlock_irqrestore(&cachep->c_spinlock, save_flags);
+
+ /* A series of memory allocations for a new slab.
+ * Neither the cache-chain semaphore, or cache-lock, are
+ * held, but the incrementing c_growing prevents this
+ * this cache from being reaped or shrunk.
+ * Note: The cache could be selected in for reaping in
+ * kmem_cache_reap(), but when the final test is made the
+ * growing value will be seen.
+ */
+
+ /* Get mem for the objs. */
+ if (!(objp = kmem_getpages(cachep, flags, &dma)))
+ goto failed;
- /* get slab mgmt */
- if (!(slabp = kmem_cache_slabmgmt(cachep, objp, local_flags, offset)))
- goto opps2;
+ /* Get slab mgmt. */
+ if (!(slabp = kmem_cache_slabmgmt(cachep, objp+offset, local_flags)))
+ goto opps1;
if (dma)
- slabp->s_flags = SLAB_SFLGS_DMA;
-
+ slabp->s_dma = 1;
+ if (SLAB_BUFCTL(cachep->c_flags)) {
+ slabp->s_index = kmem_cache_alloc(cachep->c_index_cachep, local_flags);
+ if (!slabp->s_index)
+ goto opps2;
+ }
+
+ /* Nasty!!!!!! I hope this is OK. */
+ dma = 1 << cachep->c_gfporder;
+ page = &mem_map[MAP_NR(objp)];
+ do {
+ SLAB_SET_PAGE_CACHE(page, cachep);
+ SLAB_SET_PAGE_SLAB(page, slabp);
+ PageSetSlab(page);
+ page++;
+ } while (--dma);
+
+ slabp->s_offset = offset; /* It will fit... */
+ objp += offset; /* Address of first object. */
slabp->s_mem = objp;
- objp += offset; /* address of first object */
/* For on-slab bufctls, c_offset is the distance between the start of
* an obj and its related bufctl. For off-slab bufctls, c_offset is
* the distance between objs in the slab.
- * Reason for bufctl at end of obj (when on slab), as opposed to the front;
- * if stored within the obj (has no state), and the obj is 'used' after being
- * freed then (normally) most activity occurs at the beginning of the obj.
- * By keeping the bufctl ptr away from the front, should reduce the chance of
- * corruption. Also, allows easier alignment of objs onto cache lines when
- * bufctl is not stored with the objs.
- * Downsize; if, while an obj is active, a write is made past its end, then the
- * bufctl will be corrupted :(
*/
- if (kmem_cache_init_objs(cachep, slabp, objp, local_flags, ctor_flags))
- goto no_objs;
+ kmem_cache_init_objs(cachep, slabp, objp, ctor_flags);
+
+ spin_lock_irq(&cachep->c_spinlock);
- cli();
- /* make slab active */
+ /* Make slab active. */
slabp->s_magic = SLAB_MAGIC_ALLOC;
kmem_slab_link_end(cachep, slabp);
if (cachep->c_freep == kmem_slab_end(cachep))
cachep->c_freep = slabp;
- restore_flags(save_flags);
- return;
-no_objs:
- kmem_freepages(cachep, slabp->s_mem);
+ SLAB_STATS_INC_GROWN(cachep);
+ cachep->c_failures = 0;
+ cachep->c_growing--;
+
+ spin_unlock_irqrestore(&cachep->c_spinlock, save_flags);
+ return 1;
opps2:
- kmem_freepages(cachep, objp);
+ if (SLAB_OFF_SLAB(cachep->c_flags))
+ kmem_cache_free(cache_slabp, slabp);
opps1:
- if (slabp && SLAB_OFF_SLAB(cachep->c_flags))
- kmem_cache_free(&cache_slab, slabp);
- /* printk("kmem_alloc: Out of mem - %s\n", cachep->c_name); */
- return;
+ kmem_freepages(cachep, objp);
+failed:
+ if (local_flags != SLAB_ATOMIC && cachep->c_gfporder) {
+ /* For large order (>0) slabs, we try again.
+ * Needed because the gfp() functions are not good at giving
+ * out contigious pages unless pushed (but do not push too hard).
+ */
+ spin_lock_irq(&cachep->c_spinlock);
+ if (cachep->c_failures++ < 4 && cachep->c_freep == kmem_slab_end(cachep))
+ goto re_try;
+ cachep->c_failures = 1; /* Memory is low, don't try as hard next time. */
+ cachep->c_growing--;
+ spin_unlock_irqrestore(&cachep->c_spinlock, save_flags);
+ }
+ return 0;
+}
+
+static void
+kmem_report_alloc_err(const char *str, kmem_cache_t * cachep)
+{
+ if (cachep)
+ SLAB_STATS_INC_ERR(cachep); /* this is atomic */
+ printk(KERN_ERR "kmem_alloc: %s (name=%s)\n",
+ str, cachep ? cachep->c_name : "unknown");
+}
+
+static void
+kmem_report_free_err(const char *str, void *objp, kmem_cache_t * cachep)
+{
+ if (cachep)
+ SLAB_STATS_INC_ERR(cachep);
+ printk(KERN_ERR "kmem_free: %s (objp=%p, name=%s)\n",
+ str, objp, cachep ? cachep->c_name : "unknown");
+}
+
+/* Search for a slab whose objs are suitable for DMA.
+ * Note: since testing the first free slab (in __kmem_cache_alloc()),
+ * ints must not have been enabled, or the cache-lock released!
+ */
+static inline kmem_slab_t *
+kmem_cache_search_dma(kmem_cache_t * cachep)
+{
+ kmem_slab_t *slabp = cachep->c_freep->s_nextp;
+
+ for (; slabp != kmem_slab_end(cachep); slabp = slabp->s_nextp) {
+ if (!(slabp->s_dma))
+ continue;
+ kmem_slab_unlink(slabp);
+ kmem_slab_link_free(cachep, slabp);
+ cachep->c_freep = slabp;
+ break;
+ }
+ return slabp;
}
-#if defined(SLAB_DEBUG_SUPPORT)
-/* Perform extra freeing checks.
- * Currently, this check is only for caches that use bufctl structures
- * within the slab. Those which use bufctl's from the internal cache
- * have a reasonable check when the address is searched for.
+#if SLAB_DEBUG_SUPPORT
+/* Perform extra freeing checks. Currently, this check is only for caches
+ * that use bufctl structures within the slab. Those which use bufctl's
+ * from the internal cache have a reasonable check when the address is
+ * searched for. Called with the cache-lock held.
*/
static void *
-kmem_extra_free_checks(const kmem_cache_t *cachep, kmem_bufctl_t *search_bufp,
- const kmem_bufctl_t *bufp, void * objp)
+kmem_extra_free_checks(kmem_cache_t * cachep, kmem_bufctl_t *search_bufp,
+ kmem_bufctl_t *bufp, void * objp)
{
if (SLAB_BUFCTL(cachep->c_flags))
- goto end;
+ return objp;
- /* check slab's freelist to see if this obj is there */
+ /* Check slab's freelist to see if this obj is there. */
for (; search_bufp; search_bufp = search_bufp->buf_nextp) {
if (search_bufp != bufp)
continue;
- printk(KERN_ERR "kmem_free: Double free detected during checking "
- "%p - %s\n", objp, cachep->c_name);
return NULL;
}
-end:
return objp;
}
#endif /* SLAB_DEBUG_SUPPORT */
+/* Called with cache lock held. */
static inline void
kmem_cache_full_free(kmem_cache_t *cachep, kmem_slab_t *slabp)
{
- if (!slabp->s_nextp->s_inuse)
- return; /* at correct position */
- slabp->s_jiffies = jiffies; /* set release time */
- if (cachep->c_freep == slabp)
- cachep->c_freep = slabp->s_nextp;
- kmem_slab_unlink(slabp);
- kmem_slab_link_end(cachep, slabp);
-
- return;
+ if (slabp->s_nextp->s_inuse) {
+ /* Not at correct position. */
+ if (cachep->c_freep == slabp)
+ cachep->c_freep = slabp->s_nextp;
+ kmem_slab_unlink(slabp);
+ kmem_slab_link_end(cachep, slabp);
+ }
}
+/* Called with cache lock held. */
static inline void
kmem_cache_one_free(kmem_cache_t *cachep, kmem_slab_t *slabp)
{
- if (slabp->s_nextp->s_inuse != cachep->c_num) {
- cachep->c_freep = slabp;
- return;
+ if (slabp->s_nextp->s_inuse == cachep->c_num) {
+ kmem_slab_unlink(slabp);
+ kmem_slab_link_free(cachep, slabp);
}
- kmem_slab_unlink(slabp);
- kmem_slab_link_free(cachep, slabp);
- return;
+ cachep->c_freep = slabp;
}
-/* Returns a ptr to an obj in the given cache.
- * The obj is in the initial state (if there is one)
- */
+/* Returns a ptr to an obj in the given cache. */
static inline void *
-__kmem_cache_alloc(kmem_cache_t *cachep, unsigned long flags)
+__kmem_cache_alloc(kmem_cache_t *cachep, int flags)
{
kmem_slab_t *slabp;
kmem_bufctl_t *bufp;
void *objp;
unsigned long save_flags;
- /* sanity check */
+ /* Sanity check. */
if (!cachep)
goto nul_ptr;
- save_flags(save_flags);
- cli();
- /* get slab alloc is to come from */
+ spin_lock_irqsave(&cachep->c_spinlock, save_flags);
+try_again:
+ /* Get slab alloc is to come from. */
slabp = cachep->c_freep;
- /* magic is a sanity check _and_ says if we need a new slab */
+ /* Magic is a sanity check _and_ says if we need a new slab. */
if (slabp->s_magic != SLAB_MAGIC_ALLOC)
goto alloc_new_slab;
-try_again:
- /* DMA allocations are 'rare' - keep out of critical path */
+ /* DMA requests are 'rare' - keep out of the critical path. */
if (flags & SLAB_DMA)
goto search_dma;
try_again_dma:
+ SLAB_STATS_INC_ALLOCED(cachep);
+ SLAB_STATS_INC_ACTIVE(cachep);
+ SLAB_STATS_SET_HIGH(cachep);
slabp->s_inuse++;
bufp = slabp->s_freep;
slabp->s_freep = bufp->buf_nextp;
- if (!SLAB_BUFCTL(cachep->c_flags)) {
- /* Nasty - we want the 'if' to be taken in the common case */
- if (slabp->s_freep) {
-short_finished:
+ if (slabp->s_freep) {
+ret_obj:
+ if (!slabp->s_index) {
+ bufp->buf_slabp = slabp;
objp = ((void*)bufp) - cachep->c_offset;
- restore_flags(save_flags);
-#if defined(SLAB_DEBUG_SUPPORT)
+finished:
+ /* The lock is not needed by the red-zone or poision ops, and the
+ * obj has been removed from the slab. Should be safe to drop
+ * the lock here.
+ */
+ spin_unlock_irqrestore(&cachep->c_spinlock, save_flags);
+#if SLAB_DEBUG_SUPPORT
if (cachep->c_flags & SLAB_RED_ZONE)
goto red_zone;
+ret_red:
+ if ((cachep->c_flags & SLAB_POISION) && kmem_check_poision_obj(cachep, objp))
+ kmem_report_alloc_err("Bad poision", cachep);
#endif /* SLAB_DEBUG_SUPPORT */
return objp;
- } else {
- cachep->c_freep = slabp->s_nextp;
- goto short_finished;
}
+ /* Update index ptr. */
+ objp = ((bufp-slabp->s_index)*cachep->c_offset) + slabp->s_mem;
+ bufp->buf_objp = objp;
+ goto finished;
}
+ cachep->c_freep = slabp->s_nextp;
+ goto ret_obj;
- if (!slabp->s_freep)
- cachep->c_freep = slabp->s_nextp;
-
- /* link into hash chain */
- objp = kmem_add_to_hash(cachep, bufp);
- restore_flags(save_flags);
-#if defined(SLAB_DEBUG_SUPPORT)
- if (!(cachep->c_flags & SLAB_RED_ZONE))
-#endif /* SLAB_DEBUG_SUPPORT */
- return objp;
-
-#if defined(SLAB_DEBUG_SUPPORT)
+#if SLAB_DEBUG_SUPPORT
red_zone:
- /* set alloc red-zone, and check old one */
+ /* Set alloc red-zone, and check old one. */
+ if (xchg((unsigned long *)objp, SLAB_RED_MAGIC2) != SLAB_RED_MAGIC1)
+ kmem_report_alloc_err("Bad front redzone", cachep);
+ objp += BYTES_PER_WORD;
if (xchg((unsigned long *)(objp+cachep->c_org_size), SLAB_RED_MAGIC2) != SLAB_RED_MAGIC1)
- printk(KERN_ERR "kmem_alloc: Bad redzone %p - %s\n",
- objp, cachep->c_name);
- return objp;
+ kmem_report_alloc_err("Bad rear redzone", cachep);
+ goto ret_red;
#endif /* SLAB_DEBUG_SUPPORT */
search_dma:
- if (slabp->s_flags & SLAB_SFLGS_DMA)
- goto try_again_dma;
- /* need to search... */
- if ((slabp = kmem_cache_search_dma(cachep)))
+ if (slabp->s_dma || (slabp = kmem_cache_search_dma(cachep))!=kmem_slab_end(cachep))
goto try_again_dma;
alloc_new_slab:
- /* Either out of slabs, or magic number corruption */
- if (slabp != kmem_slab_end(cachep))
- goto bad_slab;
- /* need a new slab */
- restore_flags(save_flags);
- if (SLAB_RELEASED(cachep->c_flags)) {
- printk(KERN_ERR "kmem_alloc: destroyed cache\n");
- goto end;
- }
-
- /* Be lazy and only check for valid flags
- * here (keeping it out of the critical path above)
- */
- if (flags & ~(SLAB_DMA|SLAB_LEVEL_MASK|SLAB_NO_GROW)) {
- printk(KERN_ERR "kmem_alloc: Illegal flgs %lX (correcting) - %s\n",
- flags, cachep->c_name);
- flags &= (SLAB_DMA|SLAB_LEVEL_MASK|SLAB_NO_GROW);
+ /* Either out of slabs, or magic number corruption. */
+ if (slabp == kmem_slab_end(cachep)) {
+ /* Need a new slab. Release the lock before calling kmem_cache_grow().
+ * This allows objs to be released back into the cache while growing.
+ */
+ spin_unlock_irqrestore(&cachep->c_spinlock, save_flags);
+ if (kmem_cache_grow(cachep, flags)) {
+ /* Someone may have stolen our objs. Doesn't matter, we'll
+ * just come back here again.
+ */
+ goto try_again;
+ }
+ /* Couldn't grow, but some objs may have been freed. */
+ spin_lock_irq(&cachep->c_spinlock);
+ if (cachep->c_freep != kmem_slab_end(cachep))
+ goto try_again;
+ } else {
+ /* Very serious error - maybe panic() here? */
+ kmem_report_alloc_err("Bad slab magic (corrupt)", cachep);
}
-
- kmem_cache_grow(cachep, flags);
- cli();
- if ((slabp=cachep->c_freep) != kmem_slab_end(cachep))
- goto try_again;
- restore_flags(save_flags);
-end:
+ spin_unlock_irqrestore(&cachep->c_spinlock, save_flags);
+err_exit:
return NULL;
-bad_slab:
- /* v. serious error - maybe panic() here? */
- printk(KERN_ERR "kmem_alloc: Bad slab magic (corruption) - %s\n",
- cachep->c_name);
- goto end;
nul_ptr:
- printk(KERN_ERR "kmem_alloc: NULL ptr\n");
- goto end;
+ kmem_report_alloc_err("NULL ptr", NULL);
+ goto err_exit;
}
-/* Release an obj back to its cache.
- * If the obj has a constructed state, it should be
- * in this state _before_ it is released.
+/* Release an obj back to its cache. If the obj has a constructed state,
+ * it should be in this state _before_ it is released.
*/
static inline void
__kmem_cache_free(kmem_cache_t *cachep, void *objp)
@@ -1199,128 +1461,137 @@ __kmem_cache_free(kmem_cache_t *cachep, void *objp)
kmem_bufctl_t *bufp;
unsigned long save_flags;
- /* basic sanity checks */
- if (!cachep)
- goto nul_cache;
- if (!objp)
- goto nul_obj;
+ /* Basic sanity checks. */
+ if (!cachep || !objp)
+ goto null_addr;
- save_flags(save_flags);
-#if defined(SLAB_DEBUG_SUPPORT)
+#if SLAB_DEBUG_SUPPORT
+ if (cachep->c_flags & SLAB_RED_ZONE)
+ objp -= BYTES_PER_WORD;
+#endif /* SLAB_DEBUG_SUPPORT */
+
+
+#if SLAB_DEBUG_SUPPORT
+ /* A verify func is called without the cache-lock held. */
if (cachep->c_flags & SLAB_DEBUG_INITIAL)
goto init_state_check;
finished_initial:
#endif /* SLAB_DEBUG_SUPPORT */
+ spin_lock_irqsave(&cachep->c_spinlock, save_flags);
+
if (SLAB_BUFCTL(cachep->c_flags))
goto bufctl;
-
bufp = (kmem_bufctl_t *)(objp+cachep->c_offset);
- /* get slab for the obj */
- if (SLAB_PTR_IN_OBJ(cachep->c_flags)) {
- /* if SLAB_HIGH_PACK is undef, the below is optimised away */
- slabp = (kmem_slab_t *)((((unsigned long)objp)&PAGE_MASK)+PAGE_SIZE);
- slabp--;
- } else
- slabp = (kmem_slab_t *) bufp->buf_slabp;
+ /* Get slab for the object. */
+#if 0
+ /* _NASTY_IF/ELSE_, but avoids a 'distant' memory ref for some objects.
+ * Is this worth while? XXX
+ */
+ if (cachep->c_flags & SLAB_HIGH_PACK)
+ slabp = SLAB_GET_PAGE_SLAB(&mem_map[MAP_NR(bufp)]);
+ else
+#endif
+ slabp = bufp->buf_slabp;
- if (slabp->s_magic != SLAB_MAGIC_ALLOC) /* sanity check */
- goto bad_obj;
- cli();
+check_magic:
+ if (slabp->s_magic != SLAB_MAGIC_ALLOC) /* Sanity check. */
+ goto bad_slab;
-#if defined(SLAB_DEBUG_SUPPORT)
- if (cachep->c_flags & (SLAB_DEBUG_FREE|SLAB_RED_ZONE))
+#if SLAB_DEBUG_SUPPORT
+ if (cachep->c_flags & SLAB_DEBUG_FREE)
goto extra_checks;
+passed_extra:
#endif /* SLAB_DEBUG_SUPPORT */
-passed_extra:
- if (!slabp->s_inuse) /* sanity check */
- goto too_many;
- bufp->buf_nextp = slabp->s_freep;
- slabp->s_freep = bufp;
- if (--(slabp->s_inuse)) {
- if (bufp->buf_nextp) {
- restore_flags(save_flags);
- return;
+ if (slabp->s_inuse) { /* Sanity check. */
+ SLAB_STATS_DEC_ACTIVE(cachep);
+ slabp->s_inuse--;
+ bufp->buf_nextp = slabp->s_freep;
+ slabp->s_freep = bufp;
+ if (slabp->s_inuse) {
+ if (bufp->buf_nextp) {
+ /* (hopefully) The most common case. */
+finished:
+#if SLAB_DEBUG_SUPPORT
+ /* Need to poision the obj while holding the lock. */
+ if (cachep->c_flags & SLAB_POISION)
+ kmem_poision_obj(cachep, objp);
+ if (cachep->c_flags & SLAB_RED_ZONE)
+ goto red_zone;
+return_red:
+#endif /* SLAB_DEBUG_SUPPORT */
+ spin_unlock_irqrestore(&cachep->c_spinlock, save_flags);
+ return;
+ }
+ kmem_cache_one_free(cachep, slabp);
+ goto finished;
}
- kmem_cache_one_free(cachep, slabp);
- restore_flags(save_flags);
- return;
+ kmem_cache_full_free(cachep, slabp);
+ goto finished;
}
- kmem_cache_full_free(cachep, slabp);
- restore_flags(save_flags);
+
+ /* Don't add to freelist. */
+ spin_unlock_irqrestore(&cachep->c_spinlock, save_flags);
+ kmem_report_free_err("free with no active objs", objp, cachep);
return;
bufctl:
- /* Off-slab bufctls. Need to search hash for bufctl, and hence the slab.
- * No 'extra' checks are performed for objs stored this way, finding
- * the obj a check enough
+ /* No 'extra' checks are performed for objs stored this way, finding
+ * the obj is check enough.
*/
- cli();
- if ((bufp = kmem_remove_from_hash(cachep, objp))) {
- slabp = (kmem_slab_t *) bufp->buf_slabp;
-#if defined(SLAB_DEBUG_SUPPORT)
- if (cachep->c_flags & SLAB_RED_ZONE)
- goto red_zone;
-#endif /* SLAB_DEBUG_SUPPORT */
- goto passed_extra;
- }
- restore_flags(save_flags);
- printk(KERN_ERR "kmem_free: Either bad obj addr or double free: %p - %s\n",
- objp, cachep->c_name);
+ slabp = SLAB_GET_PAGE_SLAB(&mem_map[MAP_NR(objp)]);
+ bufp = &slabp->s_index[(objp - slabp->s_mem)/cachep->c_offset];
+ if (bufp->buf_objp == objp)
+ goto check_magic;
+ spin_unlock_irqrestore(&cachep->c_spinlock, save_flags);
+ kmem_report_free_err("Either bad obj addr or double free", objp, cachep);
return;
-#if defined(SLAB_DEBUG_SUPPORT)
-red_zone:
- if (xchg((unsigned long *)(objp+cachep->c_org_size), SLAB_RED_MAGIC1) != SLAB_RED_MAGIC2) {
- /* Either write past end of the object, or a double free */
- printk(KERN_ERR "kmem_free: Bad redzone %p - %s\n",
- objp, cachep->c_name);
- }
- goto passed_extra;
+#if SLAB_DEBUG_SUPPORT
init_state_check:
- /* Need to call the slab's constructor so that
- * the caller can perform a verify of its state (debugging)
+ /* Need to call the slab's constructor so the
+ * caller can perform a verify of its state (debugging).
*/
- cachep->c_ctor(objp, cachep->c_org_size, SLAB_CTOR_CONSTRUCTOR|SLAB_CTOR_VERIFY);
+ cachep->c_ctor(objp, cachep, SLAB_CTOR_CONSTRUCTOR|SLAB_CTOR_VERIFY);
goto finished_initial;
extra_checks:
- if ((cachep->c_flags & SLAB_DEBUG_FREE) &&
- (objp != kmem_extra_free_checks(cachep, slabp->s_freep, bufp, objp))) {
- restore_flags(save_flags);
+ if (!kmem_extra_free_checks(cachep, slabp->s_freep, bufp, objp)) {
+ spin_unlock_irqrestore(&cachep->c_spinlock, save_flags);
+ kmem_report_free_err("Double free detected during checks", objp, cachep);
return;
}
- if (cachep->c_flags & SLAB_RED_ZONE)
- goto red_zone;
goto passed_extra;
-#endif /* SLAB_DEBUG_SUPPORT */
-bad_obj:
- /* The addr of the slab doesn't contain the correct
- * magic num
+red_zone:
+ /* We hold the cache-lock while checking the red-zone, just incase
+ * some tries to take this obj from us...
*/
- if (slabp->s_magic == SLAB_MAGIC_UNALLOC) {
- /* magic num says this is an unalloc slab */
- printk(KERN_ERR "kmem_free: obj %p from destroyed slab - %s\n",
- objp, cachep->c_name);
- return;
+ if (xchg((unsigned long *)objp, SLAB_RED_MAGIC1) != SLAB_RED_MAGIC2) {
+ /* Either write before start of obj, or a double free. */
+ kmem_report_free_err("Bad front redzone", objp, cachep);
}
- printk(KERN_ERR "kmem_free: Bad obj %p - %s\n", objp, cachep->c_name);
- return;
-too_many:
- /* don't add to freelist */
- restore_flags(save_flags);
- printk(KERN_ERR "kmem_free: obj free for slab with no active objs - %s\n",
- cachep->c_name);
- return;
-nul_obj:
- printk(KERN_ERR "kmem_free: NULL obj - %s\n", cachep->c_name);
+ objp += BYTES_PER_WORD;
+ if (xchg((unsigned long *)(objp+cachep->c_org_size), SLAB_RED_MAGIC1) != SLAB_RED_MAGIC2) {
+ /* Either write past end of obj, or a double free. */
+ kmem_report_free_err("Bad rear redzone", objp, cachep);
+ }
+ goto return_red;
+#endif /* SLAB_DEBUG_SUPPORT */
+bad_slab:
+ /* Slab doesn't contain the correct magic num. */
+ if (slabp->s_magic == SLAB_MAGIC_DESTROYED) {
+ /* Magic num says this is a destroyed slab. */
+ kmem_report_free_err("free from inactive slab", objp, cachep);
+ } else
+ kmem_report_free_err("Bad obj addr", objp, cachep);
+ spin_unlock_irqrestore(&cachep->c_spinlock, save_flags);
return;
-nul_cache:
- printk(KERN_ERR "kmem_free: NULL cache ptr\n");
+null_addr:
+ kmem_report_free_err("NULL ptr", objp, cachep);
return;
}
void *
-kmem_cache_alloc(kmem_cache_t *cachep, unsigned long flags)
+kmem_cache_alloc(kmem_cache_t *cachep, int flags)
{
return __kmem_cache_alloc(cachep, flags);
}
@@ -1332,163 +1603,249 @@ kmem_cache_free(kmem_cache_t *cachep, void *objp)
}
void *
-kmem_alloc(unsigned long size, unsigned long flags)
+kmalloc(size_t size, int flags)
{
- cache_sizes_t *cachep = cache_sizes;
+ cache_sizes_t *csizep = cache_sizes;
- for (; cachep->cs_size; cachep++) {
- if (size > cachep->cs_size)
+ for (; csizep->cs_size; csizep++) {
+ if (size > csizep->cs_size)
continue;
- /* should the inline version be used here? */
- return kmem_cache_alloc(cachep->cs_cachep, flags);
+ return __kmem_cache_alloc(csizep->cs_cachep, flags);
}
- printk(KERN_ERR "kmem_alloc: Size (%lu) too large\n", size);
+ printk(KERN_ERR "kmalloc: Size (%lu) too large\n", (unsigned long) size);
return NULL;
}
void
-kmem_free(void *objp, unsigned long size)
+kfree(void *objp)
{
- cache_sizes_t *cachep = cache_sizes;
+ struct page *page;
+ int nr;
- for (; cachep->cs_size; cachep++) {
- if (size > cachep->cs_size)
- continue;
- /* should the inline version be used here? */
- kmem_cache_free(cachep->cs_cachep, objp);
- return;
+ if (!objp)
+ goto null_ptr;
+ nr = MAP_NR(objp);
+ if (nr >= max_mapnr)
+ goto null_ptr;
+
+ /* Assume we own the page structure - hence no locking.
+ * If someone is misbehaving (eg. someone calling us with a bad
+ * address), then access to the page structure can race with the
+ * kmem_slab_destory() code. Need to add a spin_lock to each page
+ * structure, which would be useful in threading the gfp() functions....
+ */
+ page = &mem_map[nr];
+ if (PageSlab(page)) {
+ kmem_cache_t *cachep;
+
+ /* Here, we (again) assume the obj address is good.
+ * If it isn't, and happens to map onto another
+ * general-cache page which has no active objs, then
+ * we race....
+ */
+ cachep = SLAB_GET_PAGE_CACHE(page);
+ if (cachep && (cachep->c_flags & SLAB_CFLGS_GENERAL)) {
+ __kmem_cache_free(cachep, objp);
+ return;
+ }
+ }
+null_ptr:
+ printk(KERN_ERR "kfree: Bad obj %p\n", objp);
+while(1);
+ return;
+}
+
+void
+kfree_s(void *objp, size_t size)
+{
+ struct page *page;
+ int nr;
+
+ if (!objp)
+ goto null_ptr;
+ nr = MAP_NR(objp);
+ if (nr >= max_mapnr)
+ goto null_ptr;
+ /* See comment in kfree() */
+ page = &mem_map[nr];
+ if (PageSlab(page)) {
+ kmem_cache_t *cachep;
+ /* See comment in kfree() */
+ cachep = SLAB_GET_PAGE_CACHE(page);
+ if (cachep && cachep->c_flags & SLAB_CFLGS_GENERAL) {
+ if (size <= cachep->c_org_size) { /* XXX better check */
+ __kmem_cache_free(cachep, objp);
+ return;
+ }
+ }
}
- printk(KERN_ERR "kmem_free: Size (%lu) too large - strange\n", size);
+null_ptr:
+ printk(KERN_ERR "kfree_s: Bad obj %p\n", objp);
+ return;
}
+kmem_cache_t *
+kmem_find_general_cachep(size_t size)
+{
+ cache_sizes_t *csizep = cache_sizes;
+
+ /* This function could be moved to the header-file, and
+ * made inline so consumers can quickly determine what
+ * cache-ptr they require.
+ */
+ for (; csizep->cs_size; csizep++) {
+ if (size > csizep->cs_size)
+ continue;
+ break;
+ }
+ return csizep->cs_cachep;
+}
/* Called from try_to_free_page().
- * Ideal solution would have a weight for each cache, based on;
- * o num of fully free slabs
- * o if the objs have a constructor/deconstructor
- * o length of time slabs have been fully free (ie. ageing)
* This function _cannot_ be called within a int, but it
* can be interrupted.
*/
int
kmem_cache_reap(int pri, int dma, int wait)
{
- unsigned long dtor_flags = 0;
- unsigned long best_jiffie;
- unsigned long now;
- int count = 8;
- kmem_slab_t *best_slabp = NULL;
- kmem_cache_t *best_cachep = NULL;
kmem_slab_t *slabp;
kmem_cache_t *searchp;
- unsigned long save_flags;
+ kmem_cache_t *best_cachep;
+ unsigned long scan;
+ unsigned long reap_level;
- /* 'pri' maps to the number of caches to examine, not the number of slabs.
- * This avoids only checking the jiffies for slabs in one cache at the
- * expensive spending more cycles
+ if (in_interrupt()) {
+ printk("kmem_cache_reap() called within int!\n");
+ return 0;
+ }
+ scan = 9-pri;
+ reap_level = pri >> 1;
+
+ /* We really need a test semphore op so we can avoid sleeping when
+ * !wait is true.
*/
- pri = (9 - pri);
- if (!wait) /* not allowed to wait */
- dtor_flags = SLAB_DTOR_ATOMIC;
+ down(&cache_chain_sem);
+ best_cachep = NULL;
searchp = clock_searchp;
- save_flags(save_flags);
- now = jiffies;
- best_jiffie = now - (2*HZ); /* 2secs - avoid heavy thrashing */
- while (pri--) {
- kmem_slab_t *local_slabp;
- unsigned long local_jiffie;
- if (searchp == &cache_cache)
+ do {
+ unsigned long full_free;
+ /* It's safe to test this without holding the cache-lock. */
+ if (searchp->c_flags & SLAB_NO_REAP)
goto next;
-
- /* sanity check for corruption */
+ spin_lock_irq(&searchp->c_spinlock);
+ if (searchp->c_growing)
+ goto next_unlock;
+ if (searchp->c_dflags & SLAB_CFLGS_GROWN) {
+ searchp->c_dflags &= ~SLAB_CFLGS_GROWN;
+ goto next_unlock;
+ }
+ /* Sanity check for corruption of static values. */
if (searchp->c_inuse || searchp->c_magic != SLAB_C_MAGIC) {
- printk(KERN_ERR "kmem_reap: Corrupted cache struct for %s\n",
- searchp->c_name);
+ spin_unlock_irq(&searchp->c_spinlock);
+ printk(KERN_ERR "kmem_reap: Corrupted cache struct for %s\n", searchp->c_name);
goto next;
}
+ full_free = 0;
- local_slabp = NULL;
- local_jiffie = now - (2*HZ);
- cli();
- /* As the fully free slabs, within a cache, have no particular
- * order, we need to test them all. Infact, we only check 'count'
- * slabs.
+ /* Count num of fully free slabs. Hopefully there are not many,
+ * we are holding the cache lock....
*/
slabp = searchp->c_lastp;
- for (;count && slabp != kmem_slab_end(searchp) && !slabp->s_inuse; slabp = slabp->s_prevp, count--) {
- if (slabp->s_jiffies >= local_jiffie)
- continue;
+ while (!slabp->s_inuse && slabp != kmem_slab_end(searchp)) {
+ slabp = slabp->s_prevp;
+ full_free++;
+ }
+ spin_unlock_irq(&searchp->c_spinlock);
- /* weight caches with a con/decon */
- if ((searchp->c_ctor || searchp->c_dtor) && slabp->s_jiffies >= (local_jiffie - (2*HZ)))
- continue;
+ if (full_free) {
+ if (full_free >= 10) {
+ best_cachep = searchp;
+ break;
+ }
- /* weight caches with high page orders. Avoids stressing the
- * VM sub-system by reducing the frequency requests for a large
- * num of contigious pages
+ /* Try to avoid slabs with constructors and/or
+ * more than one page per slab (as it can be difficult
+ * to get high orders from gfp()).
*/
- if (searchp->c_gfporder > 1 && slabp->s_jiffies >= (local_jiffie - (4*HZ)))
- continue;
-
- local_jiffie = slabp->s_jiffies;
- local_slabp = slabp;
- if (!searchp->c_gfporder && (now-local_jiffie) >= (300*HZ)) {
- /* an old, one page slab. Make a quick get away... */
- pri = 0;
- break;
+ if (pri == 6) { /* magic '6' from try_to_free_page() */
+ if (searchp->c_ctor)
+ full_free--;
+ if (full_free && searchp->c_gfporder)
+ full_free--;
}
- }
- if (local_slabp) {
- if (!count || local_jiffie < best_jiffie) {
- best_slabp = local_slabp;
- best_jiffie = local_jiffie;
+ if (full_free >= reap_level) {
+ reap_level = full_free;
best_cachep = searchp;
- if (!count)
- break;
}
}
- restore_flags(save_flags);
+ goto next;
+next_unlock:
+ spin_unlock_irq(&searchp->c_spinlock);
next:
searchp = searchp->c_nextp;
- if (searchp == clock_searchp)
- break;
- count = 8; /* # of slabs at which we force a reap */
- }
-
- /* only move along with we didn't find an over allocated cache */
- if (count)
- clock_searchp = clock_searchp->c_nextp;
+ } while (--scan && searchp != clock_searchp);
- if (!best_slabp)
- return 0;
+ clock_searchp = searchp;
+ up(&cache_chain_sem);
- cli();
- if (best_slabp->s_inuse) {
- /* an object in our selected slab has been
- * allocated. This souldn't happen v. often, so we
- * simply fail - which isn't ideal but will do.
- * NOTE: No test for the case where an obj has been
- * allocated from the slab, and then freed. While
- * this would change our idea of the best slab to
- * reap, it's not worth the re-calculation effort.
- */
- restore_flags(save_flags);
+ if (!best_cachep) {
+ /* couldn't find anthying to reap */
return 0;
}
- if (best_cachep->c_freep == best_slabp)
- best_cachep->c_freep = best_slabp->s_nextp;
- kmem_slab_unlink(best_slabp);
+ spin_lock_irq(&best_cachep->c_spinlock);
+ if (!best_cachep->c_growing && !(slabp = best_cachep->c_lastp)->s_inuse && slabp != kmem_slab_end(best_cachep)) {
+ if (slabp == best_cachep->c_freep)
+ best_cachep->c_freep = kmem_slab_end(best_cachep);
+ kmem_slab_unlink(slabp);
+ SLAB_STATS_INC_REAPED(best_cachep);
- restore_flags(save_flags);
- kmem_slab_destroy(best_cachep, best_slabp, dtor_flags);
+ /* Safe to drop the lock. The slab is no longer linked to the
+ * cache.
+ */
+ spin_unlock_irq(&best_cachep->c_spinlock);
+ kmem_slab_destroy(best_cachep, slabp);
+ return 1;
+ }
+ spin_unlock_irq(&best_cachep->c_spinlock);
+ return 0;
+}
- return 1;
+#if SLAB_SELFTEST
+/* A few v. simple tests */
+static void
+kmem_self_test(void)
+{
+ kmem_cache_t *test_cachep;
+
+ printk(KERN_INFO "kmem_test() - start\n");
+ test_cachep = kmem_cache_create("test-cachep", 16, 0, SLAB_RED_ZONE|SLAB_POISION, NULL, NULL);
+ if (test_cachep) {
+ char *objp = kmem_cache_alloc(test_cachep, SLAB_KERNEL);
+ if (objp) {
+ /* Write in front and past end, red-zone test. */
+ *(objp-1) = 1;
+ *(objp+16) = 1;
+ kmem_cache_free(test_cachep, objp);
+
+ /* Mess up poisioning. */
+ *objp = 10;
+ objp = kmem_cache_alloc(test_cachep, SLAB_KERNEL);
+ kmem_cache_free(test_cachep, objp);
+
+ /* Mess up poisioning (again). */
+ *objp = 10;
+ kmem_cache_shrink(test_cachep);
+ }
+ }
+ printk(KERN_INFO "kmem_test() - finished\n");
}
+#endif /* SLAB_SELFTEST */
+#if defined(CONFIG_PROC_FS)
/* /proc/slabinfo
- * cache-name num-active-objs total-objs num-active-slabs total-slabs num-pages-per-slab
+ * cache-name num-active-objs total-objs num-active-slabs total-slabs num-pages-per-slab
*/
int
get_slabinfo(char *buf)
@@ -1496,31 +1853,62 @@ get_slabinfo(char *buf)
kmem_cache_t *cachep;
kmem_slab_t *slabp;
unsigned long active_objs;
- unsigned long num_slabs, active_slabs;
unsigned long save_flags;
+ unsigned long num_slabs;
+ unsigned long num_objs;
int len=0;
+#if SLAB_STATS
+ unsigned long active_slabs;
+#endif /* SLAB_STATS */
- /* output format version, so at least we can change it without _too_
- * many complaints
+ __save_flags(save_flags);
+
+ /* Output format version, so at least we can change it without _too_
+ * many complaints.
*/
+#if SLAB_STATS
+ len = sprintf(buf, "slabinfo - version: 1.0 (statistics)\n");
+#else
len = sprintf(buf, "slabinfo - version: 1.0\n");
- save_flags(save_flags);
+#endif /* SLAB_STATS */
+ down(&cache_chain_sem);
cachep = &cache_cache;
do {
- active_slabs = num_slabs = active_objs = 0;
- cli();
- for (slabp = cachep->c_firstp;
- slabp != kmem_slab_end(cachep);
- slabp = slabp->s_nextp) {
- num_slabs++;
+#if SLAB_STATS
+ active_slabs = 0;
+#endif /* SLAB_STATS */
+ num_slabs = active_objs = 0;
+ spin_lock_irq(&cachep->c_spinlock);
+ for (slabp = cachep->c_firstp; slabp != kmem_slab_end(cachep); slabp = slabp->s_nextp) {
active_objs += slabp->s_inuse;
+ num_slabs++;
+#if SLAB_STATS
if (slabp->s_inuse)
active_slabs++;
+#endif /* SLAB_STATS */
}
- restore_flags(save_flags);
- len += sprintf(buf+len, "%-20s%lu %lu %lu %lu %d\n", cachep->c_name,
- active_objs, cachep->c_num*num_slabs,
- active_slabs, num_slabs, 1<<cachep->c_gfporder);
+ num_objs = cachep->c_num*num_slabs;
+#if SLAB_STATS
+ {
+ unsigned long errors;
+ unsigned long high = cachep->c_high_mark;
+ unsigned long grown = cachep->c_grown;
+ unsigned long reaped = cachep->c_reaped;
+ unsigned long allocs = cachep->c_num_allocations;
+ errors = (unsigned long) atomic_read(&cachep->c_errors);
+ spin_unlock_irqrestore(&cachep->c_spinlock, save_flags);
+ len += sprintf(buf+len, "%-16s %6lu %6lu %4lu %4lu %4lu %6lu %7lu %5lu %4lu %4lu\n",
+ cachep->c_name, active_objs, num_objs, active_slabs, num_slabs,
+ (1<<cachep->c_gfporder)*num_slabs,
+ high, allocs, grown, reaped, errors);
+ }
+#else
+ spin_unlock_irqrestore(&cachep->c_spinlock, save_flags);
+ len += sprintf(buf+len, "%-17s %6lu %6lu\n", cachep->c_name, active_objs, num_objs);
+#endif /* SLAB_STATS */
} while ((cachep = cachep->c_nextp) != &cache_cache);
+ up(&cache_chain_sem);
+
return len;
}
+#endif /* CONFIG_PROC_FS */
diff --git a/mm/swap.c b/mm/swap.c
index 7b6a0eb49..80817ecf1 100644
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -23,6 +23,7 @@
#include <linux/fs.h>
#include <linux/swapctl.h>
#include <linux/pagemap.h>
+#include <linux/init.h>
#include <asm/dma.h>
#include <asm/system.h> /* for cli()/sti() */
@@ -67,7 +68,7 @@ swapstat_t swapstats = {0};
/* General swap control */
/* Parse the kernel command line "swap=" option at load time: */
-void swap_setup(char *str, int *ints)
+__initfunc(void swap_setup(char *str, int *ints))
{
int * swap_vars[8] = {
&MAX_PAGE_AGE,
@@ -87,7 +88,7 @@ void swap_setup(char *str, int *ints)
}
/* Parse the kernel command line "buff=" option at load time: */
-void buff_setup(char *str, int *ints)
+__initfunc(void buff_setup(char *str, int *ints))
{
int * buff_vars[6] = {
&MAX_BUFF_AGE,
diff --git a/mm/swap_state.c b/mm/swap_state.c
index 044180721..f3ffa46d5 100644
--- a/mm/swap_state.c
+++ b/mm/swap_state.c
@@ -16,6 +16,7 @@
#include <linux/swap.h>
#include <linux/fs.h>
#include <linux/swapctl.h>
+#include <linux/init.h>
#include <asm/dma.h>
#include <asm/system.h> /* for cli()/sti() */
@@ -69,8 +70,8 @@ int add_to_swap_cache(unsigned long index, unsigned long entry)
return 0;
}
-unsigned long init_swap_cache(unsigned long mem_start,
- unsigned long mem_end)
+__initfunc(unsigned long init_swap_cache(unsigned long mem_start,
+ unsigned long mem_end))
{
unsigned long swap_cache_size;
diff --git a/mm/swapfile.c b/mm/swapfile.c
index 91221a415..32a5ed8b0 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -298,24 +298,25 @@ static int unuse_process(struct mm_struct * mm, unsigned int type, unsigned long
*/
static int try_to_unuse(unsigned int type)
{
- int nr;
unsigned long page = get_free_page(GFP_KERNEL);
+ struct task_struct *p;
if (!page)
return -ENOMEM;
- nr = 0;
- while (nr < NR_TASKS) {
- struct task_struct * p = task[nr];
- if (p) {
- if (unuse_process(p->mm, type, page)) {
- page = get_free_page(GFP_KERNEL);
- if (!page)
- return -ENOMEM;
- continue;
- }
+again:
+ read_lock(&tasklist_lock);
+ for_each_task(p) {
+ read_unlock(&tasklist_lock);
+ if(unuse_process(p->mm, type, page)) {
+ page = get_free_page(GFP_KERNEL);
+ if(!page)
+ return -ENOMEM;
+ goto again;
}
- nr++;
+ read_lock(&tasklist_lock);
}
+ read_unlock(&tasklist_lock);
+
free_page(page);
return 0;
}
diff --git a/mm/vmscan.c b/mm/vmscan.c
index b25c0a0ac..d890be5df 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -271,54 +271,72 @@ static int swap_out_process(struct task_struct * p, int dma, int wait)
static int swap_out(unsigned int priority, int dma, int wait)
{
- static int swap_task;
- int loop, counter;
+ static int skip_factor = 0;
+ int limit = nr_tasks - 1;
+ int loop, counter, i;
struct task_struct *p;
counter = ((PAGEOUT_WEIGHT * nr_tasks) >> 10) >> priority;
+ if(skip_factor > nr_tasks)
+ skip_factor = 0;
+
+ read_lock(&tasklist_lock);
+ p = init_task.next_task;
+ i = skip_factor;
+ while(i--)
+ p = p->next_task;
for(; counter >= 0; counter--) {
- /*
- * Check that swap_task is suitable for swapping. If not, look for
- * the next suitable process.
- */
+ /* Check if task is suitable for swapping. */
loop = 0;
while(1) {
- if (swap_task >= NR_TASKS) {
- swap_task = 1;
+ if(!--limit) {
+ limit = nr_tasks - 1;
+ /* See if all processes are unswappable or
+ * already swapped out.
+ */
if (loop)
- /* all processes are unswappable or already swapped out */
- return 0;
+ goto out;
loop = 1;
}
-
- p = task[swap_task];
- if (p && p->swappable && p->mm->rss)
+ if (p->swappable && p->mm->rss)
break;
-
- swap_task++;
+ if((p = p->next_task) == &init_task)
+ p = p->next_task;
}
+ skip_factor++;
- /*
- * Determine the number of pages to swap from this process.
- */
+ /* Determine the number of pages to swap from this process. */
if (!p->swap_cnt) {
- /* Normalise the number of pages swapped by
+ /* Normalise the number of pages swapped by
multiplying by (RSS / 1MB) */
p->swap_cnt = AGE_CLUSTER_SIZE(p->mm->rss);
}
if (!--p->swap_cnt)
- swap_task++;
+ skip_factor++;
+ read_unlock(&tasklist_lock);
+
switch (swap_out_process(p, dma, wait)) {
- case 0:
- if (p->swap_cnt)
- swap_task++;
- break;
- case 1:
- return 1;
- default:
- break;
- }
+ case 0:
+ if (p->swap_cnt)
+ skip_factor++;
+ break;
+ case 1:
+ return 1;
+ default:
+ break;
+ };
+
+ /* Whoever we swapped may not even exist now, in fact we cannot
+ * assume anything about the list we were searching previously.
+ */
+ read_lock(&tasklist_lock);
+ p = init_task.next_task;
+ i = skip_factor;
+ while(i--)
+ p = p->next_task;
}
+out:
+ read_unlock(&tasklist_lock);
return 0;
}
diff --git a/net/.cvsignore b/net/.cvsignore
index 4671378ae..b9c8aa2e0 100644
--- a/net/.cvsignore
+++ b/net/.cvsignore
@@ -1 +1,9 @@
+! RCS SCCS CVS CVS.adm
+RCSLOG cvslog.*
+tags TAGS
+.make.state .nse_depinfo
+*~ #* .#* ,* _$* *$
+*.old *.bak *.BAK *.orig *.rej .del-*
+*.a *.olb *.o *.obj *.so *.exe
+*.Z *.elc *.ln
.depend
diff --git a/net/802/llc_macinit.c b/net/802/llc_macinit.c
index 1ee0a9699..c72be3d4d 100644
--- a/net/802/llc_macinit.c
+++ b/net/802/llc_macinit.c
@@ -26,6 +26,7 @@
#include <linux/malloc.h>
#include <linux/unistd.h>
#include <linux/netdevice.h>
+#include <linux/init.h>
#include <net/p8022.h>
#include <asm/byteorder.h>
@@ -202,7 +203,7 @@ EXPORT_SYMBOL(llc_xid_request);
#define ALL_TYPES_8022 0
-void llc_init(struct net_proto *proto)
+__initfunc(void llc_init(struct net_proto *proto))
{
printk(KERN_NOTICE "IEEE 802.2 LLC for Linux 2.1 (c) 1996 Tim Alpaerts\n");
return;
diff --git a/net/802/p8022.c b/net/802/p8022.c
index 23e6f2fad..1a12f4d60 100644
--- a/net/802/p8022.c
+++ b/net/802/p8022.c
@@ -23,6 +23,7 @@
#include <net/datalink.h>
#include <linux/mm.h>
#include <linux/in.h>
+#include <linux/init.h>
#include <net/p8022.h>
static struct datalink_proto *p8022_list = NULL;
@@ -90,7 +91,7 @@ static struct packet_type p8022_packet_type =
EXPORT_SYMBOL(register_8022_client);
EXPORT_SYMBOL(unregister_8022_client);
-void p8022_proto_init(struct net_proto *pro)
+__initfunc(void p8022_proto_init(struct net_proto *pro))
{
p8022_packet_type.type=htons(ETH_P_802_2);
dev_add_pack(&p8022_packet_type);
diff --git a/net/802/p8022tr.c b/net/802/p8022tr.c
index 6a5864d54..ef6a4976a 100644
--- a/net/802/p8022tr.c
+++ b/net/802/p8022tr.c
@@ -15,6 +15,7 @@
#include <net/datalink.h>
#include <linux/mm.h>
#include <linux/in.h>
+#include <linux/init.h>
#include <net/p8022tr.h>
#define SNAP_HEADER_LEN 8
@@ -91,7 +92,7 @@ static struct packet_type p8022tr_packet_type =
EXPORT_SYMBOL(register_8022tr_client);
EXPORT_SYMBOL(unregister_8022tr_client);
-void p8022tr_proto_init(struct net_proto *pro)
+__initfunc(void p8022tr_proto_init(struct net_proto *pro))
{
p8022tr_packet_type.type=htons(ETH_P_TR_802_2);
dev_add_pack(&p8022tr_packet_type);
diff --git a/net/802/psnap.c b/net/802/psnap.c
index bdcb5efd2..6ce58da35 100644
--- a/net/802/psnap.c
+++ b/net/802/psnap.c
@@ -19,6 +19,7 @@
#include <net/psnap.h>
#include <linux/mm.h>
#include <linux/in.h>
+#include <linux/init.h>
static struct datalink_proto *snap_list = NULL;
static struct datalink_proto *snap_dl = NULL; /* 802.2 DL for SNAP */
@@ -87,7 +88,7 @@ static void snap_datalink_header(struct datalink_proto *dl, struct sk_buff *skb,
EXPORT_SYMBOL(register_snap_client);
EXPORT_SYMBOL(unregister_snap_client);
-void snap_proto_init(struct net_proto *pro)
+__initfunc(void snap_proto_init(struct net_proto *pro))
{
snap_dl=register_8022_client(0xAA, snap_rcv);
if(snap_dl==NULL)
diff --git a/net/802/tr.c b/net/802/tr.c
index e903924f7..627dd9a99 100644
--- a/net/802/tr.c
+++ b/net/802/tr.c
@@ -31,6 +31,7 @@
#include <linux/timer.h>
#include <linux/net.h>
#include <linux/proc_fs.h>
+#include <linux/init.h>
#include <net/arp.h>
static void tr_source_route(struct trh_hdr *trh, struct device *dev);
@@ -460,7 +461,7 @@ int rif_get_info(char *buffer,char **start, off_t offset, int length, int dummy)
* too much for this.
*/
-void rif_init(struct net_proto *unused)
+__initfunc(void rif_init(struct net_proto *unused))
{
rif_timer.expires = RIF_TIMEOUT;
diff --git a/net/TUNABLE b/net/TUNABLE
index bd6066126..2e5cc1b6e 100644
--- a/net/TUNABLE
+++ b/net/TUNABLE
@@ -1,6 +1,5 @@
-The following parameters should be tunable but aren't, until we get sysctl
-or similar schemes. For now you'll have to dig around. Various CONFIG_xxx
-items that should be configurable using sysctl omitted.
+The following parameters should be tunable at compile time. Some of them
+exist as sysctls too.
This is far from complete
@@ -54,8 +53,6 @@ MASQUERADE_EXPIRE_TCP_FIN Time we keep a masquerade for after a FIN
MASQUERADE_EXPIRE_UDP Time we keep a UDP masquerade for (tunable)
MAXVIFS Maximum mrouted vifs (1-32)
MFC_LINES Lines in the multicast router cache (tunable)
-SK_RMEM_MAX Max memory a socket owns for receive (tunable)
-SK_WMEM_MAX Max memory a socket owns for send (tunable)
NetROM parameters are tunable via an ioctl passing a struct
diff --git a/net/appletalk/aarp.c b/net/appletalk/aarp.c
index e3e87f9e4..9ad9b8e93 100644
--- a/net/appletalk/aarp.c
+++ b/net/appletalk/aarp.c
@@ -47,6 +47,7 @@
#include <net/datalink.h>
#include <net/psnap.h>
#include <linux/atalk.h>
+#include <linux/init.h>
/*
* Lists of aarp entries
@@ -796,7 +797,7 @@ static struct notifier_block aarp_notifier={
static char aarp_snap_id[]={0x00,0x00,0x00,0x80,0xF3};
-void aarp_proto_init(void)
+__initfunc(void aarp_proto_init(void))
{
if((aarp_dl=register_snap_client(aarp_snap_id, aarp_rcv))==NULL)
printk(KERN_CRIT "Unable to register AARP with SNAP.\n");
diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c
index eba533a23..4dbcc0a9c 100644
--- a/net/appletalk/ddp.c
+++ b/net/appletalk/ddp.c
@@ -67,6 +67,7 @@
#include <linux/proc_fs.h>
#include <linux/stat.h>
#include <linux/firewall.h>
+#include <linux/init.h>
#undef APPLETALK_DEBUG
@@ -2034,7 +2035,7 @@ static struct proc_dir_entry proc_atalk_iface = {
/* Called by proto.c on kernel start up */
-void atalk_proto_init(struct net_proto *pro)
+__initfunc(void atalk_proto_init(struct net_proto *pro))
{
(void) sock_register(&atalk_family_ops);
if ((ddp_dl = register_snap_client(ddp_snap_id, atalk_rcv)) == NULL)
diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c
index 489993da6..f3692d833 100644
--- a/net/ax25/af_ax25.c
+++ b/net/ax25/af_ax25.c
@@ -126,6 +126,7 @@
#include <linux/stat.h>
#include <linux/firewall.h>
#include <linux/sysctl.h>
+#include <linux/init.h>
#include <net/ip.h>
#include <net/arp.h>
@@ -1795,7 +1796,7 @@ static struct proc_dir_entry proc_ax25_calls = {
};
#endif
-void ax25_proto_init(struct net_proto *pro)
+__initfunc(void ax25_proto_init(struct net_proto *pro))
{
sock_register(&ax25_family_ops);
ax25_packet_type.type = htons(ETH_P_AX25);
diff --git a/net/core/dev.c b/net/core/dev.c
index c02d4052e..07a5c1706 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -986,6 +986,9 @@ static int dev_ifconf(char *arg)
/*
* Loop over the interfaces, and write an info block for each.
*/
+
+ dev_lock_wait();
+ dev_lock_list();
for (dev = dev_base; dev != NULL; dev = dev->next)
{
@@ -1013,6 +1016,8 @@ static int dev_ifconf(char *arg)
len -= sizeof(struct ifreq);
}
+ dev_unlock_list();
+
/*
* All done. Write the updated control block back to the caller.
*/
diff --git a/net/core/firewall.c b/net/core/firewall.c
index 32cf52655..44e0709cf 100644
--- a/net/core/firewall.c
+++ b/net/core/firewall.c
@@ -10,6 +10,7 @@
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/firewall.h>
+#include <linux/init.h>
#include <asm/semaphore.h>
struct semaphore firewall_sem = MUTEX;
@@ -150,7 +151,7 @@ EXPORT_SYMBOL(call_in_firewall);
EXPORT_SYMBOL(call_out_firewall);
EXPORT_SYMBOL(call_fw_firewall);
-void fwchain_init(void)
+__initfunc(void fwchain_init(void))
{
int i;
for(i=0;i<NPROTO;i++)
diff --git a/net/core/scm.c b/net/core/scm.c
index 3aa0c7b17..d88ab0ae7 100644
--- a/net/core/scm.c
+++ b/net/core/scm.c
@@ -1,6 +1,7 @@
/* scm.c - Socket level control messages processing.
*
* Author: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
+ * Alignment and value checking mods by Craig Metz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -60,12 +61,12 @@ static int scm_fp_copy(struct cmsghdr *cmsg, struct scm_fp_list **fplp)
int num;
struct scm_fp_list *fpl = *fplp;
struct file **fpp;
- int *fdp = (int*)cmsg->cmsg_data;
+ int *fdp = (int*)CMSG_DATA(cmsg);
int i;
- num = (cmsg->cmsg_len - sizeof(struct cmsghdr))/sizeof(int);
+ num = (cmsg->cmsg_len - CMSG_ALIGN(sizeof(struct cmsghdr)))/sizeof(int);
- if (!num)
+ if (num <= 0)
return 0;
if (num > SCM_MAX_FD)
@@ -153,9 +154,9 @@ int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *p)
goto error;
break;
case SCM_CREDENTIALS:
- if (cmsg->cmsg_len < sizeof(*cmsg) + sizeof(struct ucred))
+ if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct ucred)))
goto error;
- memcpy(&p->creds, cmsg->cmsg_data, sizeof(struct ucred));
+ memcpy(&p->creds, CMSG_DATA(cmsg), sizeof(struct ucred));
err = scm_check_creds(&p->creds);
if (err)
goto error;
@@ -163,9 +164,9 @@ int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *p)
case SCM_CONNECT:
if (scm_flags)
goto error;
- if (cmsg->cmsg_len < sizeof(*cmsg) + sizeof(int))
+ if (cmsg->cmsg_len != CMSG_LEN(sizeof(int)))
goto error;
- memcpy(&acc_fd, cmsg->cmsg_data, sizeof(int));
+ memcpy(&acc_fd, CMSG_DATA(cmsg), sizeof(int));
p->sock = NULL;
if (acc_fd != -1) {
if (acc_fd < 0 || acc_fd >= NR_OPEN ||
@@ -207,7 +208,7 @@ error:
void put_cmsg(struct msghdr * msg, int level, int type, int len, void *data)
{
struct cmsghdr *cm = (struct cmsghdr*)msg->msg_control;
- int cmlen = sizeof(*cm) + len;
+ int cmlen = CMSG_LEN(len);
int err;
if (cm==NULL || msg->msg_controllen < sizeof(*cm)) {
@@ -224,9 +225,9 @@ void put_cmsg(struct msghdr * msg, int level, int type, int len, void *data)
if (!err)
err = put_user(cmlen, &cm->cmsg_len);
if (!err)
- err = copy_to_user(cm->cmsg_data, data, cmlen - sizeof(*cm));
+ err = copy_to_user(CMSG_DATA(cm), data, cmlen - sizeof(struct cmsghdr));
if (!err) {
- cmlen = CMSG_ALIGN(cmlen);
+ cmlen = CMSG_SPACE(len);
msg->msg_control += cmlen;
msg->msg_controllen -= cmlen;
}
@@ -243,22 +244,21 @@ void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm)
int i;
struct file **fp = scm->fp->fp;
- if (fdnum > fdmax)
+ if (fdnum < fdmax)
fdmax = fdnum;
- for (i=0, cmfptr=(int*)cm->cmsg_data; i<fdmax; i++, cmfptr++)
+ for (i=0, cmfptr=(int*)CMSG_DATA(cm); i<fdmax; i++, cmfptr++)
{
int new_fd = get_unused_fd();
if (new_fd < 0)
break;
current->files->fd[new_fd] = fp[i];
err = put_user(new_fd, cmfptr);
- cmfptr++;
}
if (i > 0)
{
- int cmlen = i*sizeof(int) + sizeof(struct cmsghdr);
+ int cmlen = CMSG_LEN(i*sizeof(int));
if (!err)
err = put_user(SOL_SOCKET, &cm->cmsg_level);
if (!err)
@@ -266,7 +266,7 @@ void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm)
if (!err)
err = put_user(cmlen, &cm->cmsg_len);
if (!err) {
- cmlen = CMSG_ALIGN(cmlen);
+ cmlen = CMSG_SPACE(i*sizeof(int));
msg->msg_control += cmlen;
msg->msg_controllen -= cmlen;
}
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 00a87e0e2..06c321e4f 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -64,14 +64,15 @@ static atomic_t net_skbcount = ATOMIC_INIT(0);
static atomic_t net_allocs = ATOMIC_INIT(0);
static atomic_t net_fails = ATOMIC_INIT(0);
+
extern atomic_t ip_frag_mem;
/*
* Strings we don't want inline's duplicating
*/
-char *skb_push_errstr="skpush:under: %p:%d";
-char *skb_put_errstr ="skput:over: %p:%d";
+const char skb_push_errstr[]="skpush:under: %p:%d";
+const char skb_put_errstr[] ="skput:over: %p:%d";
void show_net_buffers(void)
{
diff --git a/net/core/sock.c b/net/core/sock.c
index 8c008c0f2..f28ea828e 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -118,6 +118,12 @@
#define min(a,b) ((a)<(b)?(a):(b))
+/* Run time adjustable parameters. */
+__u32 sysctl_wmem_max = SK_WMEM_MAX;
+__u32 sysctl_rmem_max = SK_RMEM_MAX;
+__u32 sysctl_wmem_default = SK_WMEM_MAX;
+__u32 sysctl_rmem_default = SK_RMEM_MAX;
+
/*
* This is meant for all protocols to use and covers goings on
* at the socket level. Everything here is generic.
@@ -146,13 +152,8 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
}
#endif
- if(optlen<sizeof(int)) {
-#if 1 /* DaveM Debugging */
- printk("sock_setsockopt: optlen is %d, going on anyways.\n", optlen);
-#else
+ if(optlen<sizeof(int))
return(-EINVAL);
-#endif
- }
err = get_user(val, (int *)optval);
if (err)
@@ -189,15 +190,15 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
* is best
*/
- if(val > SK_WMEM_MAX*2)
+ /* printk(KERN_DEBUG "setting SO_SNDBUF %d\n", val); */
+ if (val > sysctl_wmem_max)
return -EINVAL;
- /*
- * Once this is all 32bit values we can
- * drop this check.
+
+ /* FIXME: the tcp code should be made to work even
+ * with small sndbuf values.
*/
- if(val > 65535)
- return -EINVAL;
- sk->sndbuf = max(val,2048);
+ sk->sndbuf = max(val*2,2048);
+
/*
* Wake up sending tasks if we
* upped the value.
@@ -206,12 +207,13 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
break;
case SO_RCVBUF:
- if(val > SK_RMEM_MAX*2)
- return -EINVAL;
- /* Can go soon: FIXME */
- if(val > 65535)
+ /* printk(KERN_DEBUG "setting SO_RCVBUF %d\n", val); */
+
+ if (val > sysctl_rmem_max)
return -EINVAL;
- sk->rcvbuf = max(val,256);
+
+ /* FIXME: is this lower bound the right one? */
+ sk->rcvbuf = max(val*2,256);
break;
case SO_KEEPALIVE:
@@ -533,15 +535,29 @@ struct sk_buff *sock_rmalloc(struct sock *sk, unsigned long size, int force, int
}
+/* FIXME: this is insane. We are trying suppose to be controlling how
+ * how much space we have for data bytes, not packet headers.
+ * This really points out that we need a better system for doing the
+ * receive buffer. -- erics
+ * WARNING: This is currently ONLY used in tcp. If you need it else where
+ * this will probably not be what you want. Possibly these two routines
+ * should move over to the ipv4 directory.
+ */
unsigned long sock_rspace(struct sock *sk)
{
int amt;
- if (sk != NULL)
- {
- if (atomic_read(&sk->rmem_alloc) >= sk->rcvbuf-2*MIN_WINDOW)
- return(0);
- amt = min((sk->rcvbuf-atomic_read(&sk->rmem_alloc))/2-MIN_WINDOW, MAX_WINDOW);
+ if (sk != NULL) {
+ /* This used to have some bizzare complications that
+ * to attempt to reserve some amount of space. This doesn't
+ * make sense, since the number returned here does not
+ * actually reflect allocated space, but rather the amount
+ * of space we committed to. We gamble that we won't
+ * run out of memory, and returning a smaller number does
+ * not change the gamble. If we loose the gamble tcp still
+ * works, it may just slow down for retransmissions.
+ */
+ amt = sk->rcvbuf - atomic_read(&sk->rmem_alloc);
if (amt < 0)
return(0);
return(amt);
@@ -550,10 +566,10 @@ unsigned long sock_rspace(struct sock *sk)
}
+/* FIXME: this is also insane. See above comment */
unsigned long sock_wspace(struct sock *sk)
{
- if (sk != NULL)
- {
+ if (sk != NULL) {
if (sk->shutdown & SEND_SHUTDOWN)
return(0);
if (atomic_read(&sk->wmem_alloc) >= sk->sndbuf)
@@ -868,8 +884,8 @@ void sock_init_data(struct socket *sock, struct sock *sk)
init_timer(&sk->timer);
sk->allocation = GFP_KERNEL;
- sk->rcvbuf = SK_RMEM_MAX;
- sk->sndbuf = SK_WMEM_MAX;
+ sk->rcvbuf = sysctl_rmem_default*2;
+ sk->sndbuf = sysctl_wmem_default*2;
sk->priority = SOPRI_NORMAL;
sk->state = TCP_CLOSE;
sk->zapped = 1;
diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c
index 8b5848e6b..fd770becd 100644
--- a/net/core/sysctl_net_core.c
+++ b/net/core/sysctl_net_core.c
@@ -8,6 +8,23 @@
#include <linux/mm.h>
#include <linux/sysctl.h>
+extern __u32 sysctl_wmem_max;
+extern __u32 sysctl_rmem_max;
+extern __u32 sysctl_wmem_default;
+extern __u32 sysctl_rmem_default;
+
ctl_table core_table[] = {
- {0}
+ {NET_CORE_WMEM_MAX, "wmem_max",
+ &sysctl_wmem_max, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+ {NET_CORE_RMEM_MAX, "rmem_max",
+ &sysctl_rmem_max, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+ {NET_CORE_WMEM_DEFAULT, "wmem_default",
+ &sysctl_wmem_default, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+ {NET_CORE_RMEM_DEFAULT, "rmem_default",
+ &sysctl_rmem_default, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+ { 0 }
};
diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c
index 9f4477807..bdc6b37fd 100644
--- a/net/ethernet/eth.c
+++ b/net/ethernet/eth.c
@@ -36,8 +36,6 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
-#include <asm/uaccess.h>
-#include <asm/system.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/sched.h>
@@ -52,16 +50,17 @@
#include <linux/skbuff.h>
#include <linux/errno.h>
#include <linux/config.h>
+#include <linux/init.h>
#include <net/dst.h>
#include <net/arp.h>
#include <net/sock.h>
#include <net/ipv6.h>
-
-
+#include <asm/uaccess.h>
+#include <asm/system.h>
#include <asm/checksum.h>
-void eth_setup(char *str, int *ints)
+__initfunc(void eth_setup(char *str, int *ints))
{
struct device *d = dev_base;
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index d96910bb0..a3a126529 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -76,6 +76,7 @@
#include <linux/interrupt.h>
#include <linux/proc_fs.h>
#include <linux/stat.h>
+#include <linux/init.h>
#include <asm/uaccess.h>
#include <asm/system.h>
@@ -1063,7 +1064,7 @@ extern void tcp_init(void);
* Called by socket.c on kernel startup.
*/
-void inet_proto_init(struct net_proto *pro)
+__initfunc(void inet_proto_init(struct net_proto *pro))
{
struct sk_buff *dummy_skb;
struct inet_protocol *p;
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
index 8ef0be2af..ebf2c6c6b 100644
--- a/net/ipv4/arp.c
+++ b/net/ipv4/arp.c
@@ -90,6 +90,7 @@
#include <linux/skbuff.h>
#include <linux/proc_fs.h>
#include <linux/stat.h>
+#include <linux/init.h>
#include <net/ip.h>
#include <net/icmp.h>
@@ -378,7 +379,7 @@ static void arp_neigh_destroy(struct neighbour *neigh)
extern atomic_t hh_count;
atomic_dec(&hh_count);
#endif
- kfree_s(hh, sizeof(struct(struct hh_cache)));
+ kfree_s(hh, sizeof(struct hh_cache));
}
}
}
@@ -1976,7 +1977,7 @@ static struct proc_dir_entry proc_net_arp = {
};
#endif
-void arp_init (void)
+__initfunc(void arp_init (void))
{
dev_add_pack(&arp_packet_type);
/* Start with the regular checks for expired arp entries. */
diff --git a/net/ipv4/fib.c b/net/ipv4/fib.c
index c2182728c..b25187a20 100644
--- a/net/ipv4/fib.c
+++ b/net/ipv4/fib.c
@@ -42,6 +42,7 @@
#include <linux/if_arp.h>
#include <linux/proc_fs.h>
#include <linux/skbuff.h>
+#include <linux/init.h>
#include <net/ip.h>
#include <net/protocol.h>
@@ -1646,16 +1647,21 @@ int ip_rt_ioctl(unsigned int cmd, void *arg)
{
case SIOCADDRT: /* Add a route */
case SIOCDELRT: /* Delete a route */
+printk("ip_rt_ioctl() #1\n");
if (!suser())
return -EPERM;
+printk("ip_rt_ioctl() #2\n");
err = get_rt_from_user(&m.rtmsg, arg);
if (err)
return err;
+printk("ip_rt_ioctl() #3\n");
fib_lock();
+printk("ip_rt_ioctl() #4\n");
dummy_nlh.nlmsg_type = cmd == SIOCDELRT ? RTMSG_DELROUTE
: RTMSG_NEWROUTE;
err = rtmsg_process(&dummy_nlh, &m.rtmsg);
fib_unlock();
+printk("ip_rt_ioctl() #5: err == %d\n", err);
return err;
case SIOCRTMSG:
if (!suser())
@@ -2020,7 +2026,7 @@ int ip_rt_event(int event, struct device *dev)
}
-void ip_fib_init()
+__initfunc(void ip_fib_init(void))
{
struct in_rtrulemsg r;
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index 6b697d001..79bf058c5 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -256,6 +256,7 @@
#include <net/sock.h>
#include <linux/errno.h>
#include <linux/timer.h>
+#include <linux/init.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <net/checksum.h>
@@ -373,7 +374,7 @@ struct socket *icmp_socket=&icmp_inode.u.socket_i;
#ifndef CONFIG_NO_ICMP_LIMIT
-static void xrlim_init(void)
+__initfunc(static void xrlim_init(void))
{
int type, entry;
struct icmp_xrlim *xr;
@@ -1020,7 +1021,7 @@ int icmp_chkaddr(struct sk_buff *skb)
{
struct tcphdr *th = (struct tcphdr *)(((unsigned char *)iph)+(iph->ihl<<2));
- sk = tcp_v4_lookup(iph->saddr, th->source, iph->daddr, th->dest);
+ sk = tcp_v4_lookup(iph->daddr, th->dest, iph->saddr, th->source);
if (!sk) return 0;
if (sk->saddr != iph->saddr) return 0;
if (sk->daddr != iph->daddr) return 0;
@@ -1034,7 +1035,7 @@ int icmp_chkaddr(struct sk_buff *skb)
{
struct udphdr *uh = (struct udphdr *)(((unsigned char *)iph)+(iph->ihl<<2));
- sk = udp_v4_lookup(iph->saddr, uh->source, iph->daddr, uh->dest);
+ sk = udp_v4_lookup(iph->daddr, uh->dest, iph->saddr, uh->source);
if (!sk) return 0;
if (sk->saddr != iph->saddr && __ip_chk_addr(iph->saddr) != IS_MYADDR)
return 0;
@@ -1167,7 +1168,7 @@ static struct icmp_control icmp_pointers[NR_ICMP_TYPES+1] = {
{ &icmp_statistics.IcmpOutAddrMaskReps, &icmp_statistics.IcmpInAddrMaskReps, icmp_address_reply, 0, NULL }
};
-void icmp_init(struct net_proto_family *ops)
+__initfunc(void icmp_init(struct net_proto_family *ops))
{
int err;
diff --git a/net/ipv4/ip_alias.c b/net/ipv4/ip_alias.c
index 74ff42a74..a78eef17a 100644
--- a/net/ipv4/ip_alias.c
+++ b/net/ipv4/ip_alias.c
@@ -26,6 +26,7 @@
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/route.h>
+#include <linux/init.h>
#include <net/route.h>
#ifdef ALIAS_USER_LAND_DEBUG
@@ -137,7 +138,7 @@ struct net_alias_type ip_alias_type =
* ip_alias module initialization
*/
-int ip_alias_init(void)
+__initfunc(int ip_alias_init(void))
{
return register_net_alias_type(&ip_alias_type, AF_INET);
}
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index bf549b047..290f871a1 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -5,11 +5,15 @@
*
* The IP fragmentation functionality.
*
+ * Version: $Id: ip_fragment.c,v 1.22 1997/05/17 05:21:56 freitag Exp $
+ *
* Authors: Fred N. van Kempen <waltje@uWalt.NL.Mugnet.ORG>
* Alan Cox <Alan.Cox@linux.org>
*
* Fixes:
* Alan Cox : Split from ip.c , see ip_input.c for history.
+ * David S. Miller : Begin massive cleanup...
+ * Andi Kleen : Add sysctls.
*/
#include <linux/types.h>
@@ -29,31 +33,49 @@
#include <linux/ip_fw.h>
#include <net/checksum.h>
-/*
- * Fragment cache limits. We will commit 256K at one time. Should we
- * cross that limit we will prune down to 192K. This should cope with
- * even the most extreme cases without allowing an attacker to measurably
- * harm machine performance.
- */
-
-#define IPFRAG_HIGH_THRESH (256*1024)
-#define IPFRAG_LOW_THRESH (192*1024)
-
-/*
- * This fragment handler is a bit of a heap. On the other hand it works quite
- * happily and handles things quite well.
+/* Fragment cache limits. We will commit 256K at one time. Should we
+ * cross that limit we will prune down to 192K. This should cope with
+ * even the most extreme cases without allowing an attacker to measurably
+ * harm machine performance.
*/
-
-static struct ipq *ipqueue = NULL; /* IP fragment queue */
+int sysctl_ipfrag_high_thresh = 256*1024;
+int sysctl_ipfrag_low_thresh = 192*1024;
+
+/* Describe an IP fragment. */
+struct ipfrag {
+ int offset; /* offset of fragment in IP datagram */
+ int end; /* last byte of data in datagram */
+ int len; /* length of this fragment */
+ struct sk_buff *skb; /* complete received fragment */
+ unsigned char *ptr; /* pointer into real fragment data */
+ struct ipfrag *next; /* linked list pointers */
+ struct ipfrag *prev;
+};
+
+/* Describe an entry in the "incomplete datagrams" queue. */
+struct ipq {
+ struct iphdr *iph; /* pointer to IP header */
+ struct ipq *next; /* linked list pointers */
+ struct ipfrag *fragments; /* linked list of received fragments */
+ int len; /* total length of original datagram */
+ short ihlen; /* length of the IP header */
+ struct timer_list timer; /* when will this queue expire? */
+ struct ipq **pprev;
+ struct device *dev; /* Device - for icmp replies */
+};
+
+#define IPQ_HASHSZ 64
+
+struct ipq *ipq_hash[IPQ_HASHSZ];
+
+#define ipqhashfn(id, saddr, daddr, prot) \
+ ((((id) >> 1) ^ (saddr) ^ (daddr) ^ (prot)) & (IPQ_HASHSZ - 1))
atomic_t ip_frag_mem = ATOMIC_INIT(0); /* Memory used for fragments */
-char *in_ntoa(unsigned long in);
+char *in_ntoa(__u32 in);
-/*
- * Memory Tracking Functions
- */
-
+/* Memory Tracking Functions. */
extern __inline__ void frag_kfree_skb(struct sk_buff *skb, int type)
{
atomic_sub(skb->truesize, &ip_frag_mem);
@@ -69,28 +91,24 @@ extern __inline__ void frag_kfree_s(void *ptr, int len)
extern __inline__ void *frag_kmalloc(int size, int pri)
{
void *vp=kmalloc(size,pri);
+
if(!vp)
return NULL;
atomic_add(size, &ip_frag_mem);
return vp;
}
-/*
- * Create a new fragment entry.
- */
-
-static struct ipfrag *ip_frag_create(int offset, int end, struct sk_buff *skb, unsigned char *ptr)
+/* Create a new fragment entry. */
+static struct ipfrag *ip_frag_create(int offset, int end,
+ struct sk_buff *skb, unsigned char *ptr)
{
struct ipfrag *fp;
- unsigned long flags;
fp = (struct ipfrag *) frag_kmalloc(sizeof(struct ipfrag), GFP_ATOMIC);
- if (fp == NULL)
- {
+ if (fp == NULL) {
NETDEBUG(printk(KERN_ERR "IP: frag_create: no memory left !\n"));
return(NULL);
}
- memset(fp, 0, sizeof(struct ipfrag));
/* Fill in the structure. */
fp->offset = offset;
@@ -98,85 +116,63 @@ static struct ipfrag *ip_frag_create(int offset, int end, struct sk_buff *skb, u
fp->len = end - offset;
fp->skb = skb;
fp->ptr = ptr;
+ fp->next = fp->prev = NULL;
- /*
- * Charge for the SKB as well.
- */
-
- save_flags(flags);
- cli();
+ /* Charge for the SKB as well. */
atomic_add(skb->truesize, &ip_frag_mem);
- restore_flags(flags);
return(fp);
}
-
-/*
- * Find the correct entry in the "incomplete datagrams" queue for
- * this IP datagram, and return the queue entry address if found.
+/* Find the correct entry in the "incomplete datagrams" queue for
+ * this IP datagram, and return the queue entry address if found.
*/
-
-static struct ipq *ip_find(struct iphdr *iph)
+static inline struct ipq *ip_find(struct iphdr *iph)
{
+ __u16 id = iph->id;
+ __u32 saddr = iph->saddr;
+ __u32 daddr = iph->daddr;
+ __u8 protocol = iph->protocol;
+ unsigned int hash = ipqhashfn(id, saddr, daddr, protocol);
struct ipq *qp;
- struct ipq *qplast;
-
- cli();
- qplast = NULL;
- for(qp = ipqueue; qp != NULL; qplast = qp, qp = qp->next)
- {
- if (iph->id== qp->iph->id && iph->saddr == qp->iph->saddr &&
- iph->daddr == qp->iph->daddr && iph->protocol == qp->iph->protocol)
- {
- del_timer(&qp->timer); /* So it doesn't vanish on us. The timer will be reset anyway */
- sti();
- return(qp);
+
+ start_bh_atomic();
+ for(qp = ipq_hash[hash]; qp; qp = qp->next) {
+ if(qp->iph->id == id &&
+ qp->iph->saddr == saddr &&
+ qp->iph->daddr == daddr &&
+ qp->iph->protocol == protocol) {
+ del_timer(&qp->timer);
+ break;
}
}
- sti();
- return(NULL);
+ end_bh_atomic();
+ return qp;
}
-
-/*
- * Remove an entry from the "incomplete datagrams" queue, either
- * because we completed, reassembled and processed it, or because
- * it timed out.
+/* Remove an entry from the "incomplete datagrams" queue, either
+ * because we completed, reassembled and processed it, or because
+ * it timed out.
*/
-
static void ip_free(struct ipq *qp)
{
struct ipfrag *fp;
- struct ipfrag *xp;
-
- /*
- * Stop the timer for this entry.
- */
+ /* Stop the timer for this entry. */
del_timer(&qp->timer);
/* Remove this entry from the "incomplete datagrams" queue. */
- cli();
- if (qp->prev == NULL)
- {
- ipqueue = qp->next;
- if (ipqueue != NULL)
- ipqueue->prev = NULL;
- }
- else
- {
- qp->prev->next = qp->next;
- if (qp->next != NULL)
- qp->next->prev = qp->prev;
- }
+ start_bh_atomic();
+ if(qp->next)
+ qp->next->pprev = qp->pprev;
+ *qp->pprev = qp->next;
+ end_bh_atomic();
/* Release all fragment data. */
-
fp = qp->fragments;
- while (fp != NULL)
- {
- xp = fp->next;
+ while (fp) {
+ struct ipfrag *xp = fp->next;
+
frag_kfree_skb(fp->skb,FREE_READ);
frag_kfree_s(fp, sizeof(struct ipfrag));
fp = xp;
@@ -187,83 +183,65 @@ static void ip_free(struct ipq *qp)
/* Finally, release the queue descriptor itself. */
frag_kfree_s(qp, sizeof(struct ipq));
- sti();
}
-
-/*
- * Oops- a fragment queue timed out. Kill it and send an ICMP reply.
- */
-
+/* Oops, a fragment queue timed out. Kill it and send an ICMP reply. */
static void ip_expire(unsigned long arg)
{
- struct ipq *qp;
-
- qp = (struct ipq *)arg;
-
- /*
- * Send an ICMP "Fragment Reassembly Timeout" message.
- */
+ struct ipq *qp = (struct ipq *) arg;
+ /* Send an ICMP "Fragment Reassembly Timeout" message. */
ip_statistics.IpReasmTimeout++;
ip_statistics.IpReasmFails++;
- /* This if is always true... shrug */
- if(qp->fragments!=NULL)
- icmp_send(qp->fragments->skb,ICMP_TIME_EXCEEDED,
- ICMP_EXC_FRAGTIME, 0);
+ icmp_send(qp->fragments->skb,ICMP_TIME_EXCEEDED, ICMP_EXC_FRAGTIME, 0);
- /*
- * Nuke the fragment queue.
- */
+ /* Nuke the fragment queue. */
ip_free(qp);
}
-/*
- * Memory limiting on fragments. Evictor trashes the oldest
- * fragment queue until we are back under the low threshold
+/* Memory limiting on fragments. Evictor trashes the oldest
+ * fragment queue until we are back under the low threshold.
*/
-
static void ip_evictor(void)
{
- while(atomic_read(&ip_frag_mem)>IPFRAG_LOW_THRESH)
- {
- if(!ipqueue)
+ while(atomic_read(&ip_frag_mem)>sysctl_ipfrag_low_thresh) {
+ int i;
+
+ /* FIXME: Make LRU queue of frag heads. -DaveM */
+ for(i = 0; i < IPQ_HASHSZ; i++)
+ if(ipq_hash[i])
+ break;
+ if(i >= IPQ_HASHSZ)
panic("ip_evictor: memcount");
- ip_free(ipqueue);
+ ip_free(ipq_hash[i]);
}
}
-/*
- * Add an entry to the 'ipq' queue for a newly received IP datagram.
- * We will (hopefully :-) receive all other fragments of this datagram
- * in time, so we just create a queue for this datagram, in which we
- * will insert the received fragments at their respective positions.
+/* Add an entry to the 'ipq' queue for a newly received IP datagram.
+ * We will (hopefully :-) receive all other fragments of this datagram
+ * in time, so we just create a queue for this datagram, in which we
+ * will insert the received fragments at their respective positions.
*/
-
static struct ipq *ip_create(struct sk_buff *skb, struct iphdr *iph)
{
struct ipq *qp;
+ unsigned int hash;
int ihlen;
qp = (struct ipq *) frag_kmalloc(sizeof(struct ipq), GFP_ATOMIC);
- if (qp == NULL)
- {
+ if (qp == NULL) {
NETDEBUG(printk(KERN_ERR "IP: create: no memory left !\n"));
return(NULL);
}
- memset(qp, 0, sizeof(struct ipq));
-
- /*
- * Allocate memory for the IP header (plus 8 octets for ICMP).
- */
+ /* Allocate memory for the IP header (plus 8 octets for ICMP). */
ihlen = iph->ihl * 4;
+
qp->iph = (struct iphdr *) frag_kmalloc(64 + 8, GFP_ATOMIC);
- if (qp->iph == NULL)
- {
+ if (qp->iph == NULL) {
NETDEBUG(printk(KERN_ERR "IP: create: no memory left !\n"));
frag_kfree_s(qp, sizeof(struct ipq));
- return(NULL);
+ return NULL;
}
memcpy(qp->iph, iph, ihlen + 8);
@@ -279,21 +257,19 @@ static struct ipq *ip_create(struct sk_buff *skb, struct iphdr *iph)
add_timer(&qp->timer);
/* Add this entry to the queue. */
- qp->prev = NULL;
- cli();
- qp->next = ipqueue;
- if (qp->next != NULL)
- qp->next->prev = qp;
- ipqueue = qp;
- sti();
- return(qp);
-}
+ hash = ipqhashfn(iph->id, iph->saddr, iph->daddr, iph->protocol);
+ start_bh_atomic();
+ if((qp->next = ipq_hash[hash]) != NULL)
+ qp->next->pprev = &qp->next;
+ ipq_hash[hash] = qp;
+ qp->pprev = &ipq_hash[hash];
+ end_bh_atomic();
-/*
- * See if a fragment queue is complete.
- */
+ return qp;
+}
+/* See if a fragment queue is complete. */
static int ip_done(struct ipq *qp)
{
struct ipfrag *fp;
@@ -301,13 +277,12 @@ static int ip_done(struct ipq *qp)
/* Only possible if we received the final fragment. */
if (qp->len == 0)
- return(0);
+ return 0;
/* Check all fragment offsets to see if they connect. */
fp = qp->fragments;
offset = 0;
- while (fp != NULL)
- {
+ while (fp) {
if (fp->offset > offset)
return(0); /* fragment(s) missing */
offset = fp->end;
@@ -315,18 +290,15 @@ static int ip_done(struct ipq *qp)
}
/* All fragments are present. */
- return(1);
+ return 1;
}
-
-/*
- * Build a new IP datagram from all its fragments.
+/* Build a new IP datagram from all its fragments.
*
- * FIXME: We copy here because we lack an effective way of handling lists
- * of bits on input. Until the new skb data handling is in I'm not going
- * to touch this with a bargepole.
+ * FIXME: We copy here because we lack an effective way of handling lists
+ * of bits on input. Until the new skb data handling is in I'm not going
+ * to touch this with a bargepole.
*/
-
static struct sk_buff *ip_glue(struct ipq *qp)
{
struct sk_buff *skb;
@@ -335,25 +307,23 @@ static struct sk_buff *ip_glue(struct ipq *qp)
unsigned char *ptr;
int count, len;
- /*
- * Allocate a new buffer for the datagram.
- */
+ /* Allocate a new buffer for the datagram. */
len = qp->ihlen + qp->len;
- if(len>65535)
- {
- printk(KERN_INFO "Oversized IP packet from %s.\n", in_ntoa(qp->iph->saddr));
+ if(len>65535) {
+ printk(KERN_INFO "Oversized IP packet from %s.\n",
+ in_ntoa(qp->iph->saddr));
ip_statistics.IpReasmFails++;
ip_free(qp);
return NULL;
}
- if ((skb = dev_alloc_skb(len)) == NULL)
- {
+ if ((skb = dev_alloc_skb(len)) == NULL) {
ip_statistics.IpReasmFails++;
- NETDEBUG(printk(KERN_ERR "IP: queue_glue: no memory for gluing queue %p\n", qp));
+ NETDEBUG(printk(KERN_ERR "IP: queue_glue: no memory for gluing "
+ "queue %p\n", qp));
ip_free(qp);
- return(NULL);
+ return NULL;
}
/* Fill in the basic details. */
@@ -368,11 +338,10 @@ static struct sk_buff *ip_glue(struct ipq *qp)
/* Copy the data portions of all fragments into the new buffer. */
fp = qp->fragments;
- while(fp != NULL)
- {
- if(count+fp->len > skb->len)
- {
- NETDEBUG(printk(KERN_ERR "Invalid fragment list: Fragment over size.\n"));
+ while(fp) {
+ if(count+fp->len > skb->len) {
+ NETDEBUG(printk(KERN_ERR "Invalid fragment list: "
+ "Fragment over size.\n"));
ip_free(qp);
kfree_skb(skb,FREE_WRITE);
ip_statistics.IpReasmFails++;
@@ -396,14 +365,10 @@ static struct sk_buff *ip_glue(struct ipq *qp)
iph->tot_len = htons((iph->ihl * 4) + count);
ip_statistics.IpReasmOKs++;
- return(skb);
+ return skb;
}
-
-/*
- * Process an incoming IP datagram fragment.
- */
-
+/* Process an incoming IP datagram fragment. */
struct sk_buff *ip_defrag(struct sk_buff *skb)
{
struct iphdr *iph = skb->nh.iph;
@@ -417,45 +382,37 @@ struct sk_buff *ip_defrag(struct sk_buff *skb)
ip_statistics.IpReasmReqds++;
- /*
- * Start by cleaning up the memory
- */
-
- if(atomic_read(&ip_frag_mem)>IPFRAG_HIGH_THRESH)
+ /* Start by cleaning up the memory. */
+ if(atomic_read(&ip_frag_mem)>sysctl_ipfrag_high_thresh)
ip_evictor();
- /*
- * Find the entry of this IP datagram in the "incomplete datagrams" queue.
- */
-
+
+ /* Find the entry of this IP datagram in the "incomplete datagrams" queue. */
qp = ip_find(iph);
/* Is this a non-fragmented datagram? */
offset = ntohs(iph->frag_off);
flags = offset & ~IP_OFFSET;
offset &= IP_OFFSET;
- if (((flags & IP_MF) == 0) && (offset == 0))
- {
- if (qp != NULL)
- ip_free(qp); /* Fragmented frame replaced by full unfragmented copy */
- return(skb);
+ if (((flags & IP_MF) == 0) && (offset == 0)) {
+ if (qp != NULL) {
+ /* Fragmented frame replaced by full unfragmented copy. */
+ ip_free(qp);
+ }
+ return skb;
}
offset <<= 3; /* offset is in 8-byte chunks */
ihl = iph->ihl * 4;
- /*
- * If the queue already existed, keep restarting its timer as long
+ /* If the queue already existed, keep restarting its timer as long
* as we still are receiving fragments. Otherwise, create a fresh
* queue entry.
*/
-
- if (qp != NULL)
- {
+ if (qp) {
/* ANK. If the first fragment is received,
* we should remember the correct IP header (with options)
*/
- if (offset == 0)
- {
+ if (offset == 0) {
qp->ihlen = ihl;
memcpy(qp->iph, iph, ihl+8);
}
@@ -464,84 +421,59 @@ struct sk_buff *ip_defrag(struct sk_buff *skb)
qp->timer.data = (unsigned long) qp; /* pointer to queue */
qp->timer.function = ip_expire; /* expire function */
add_timer(&qp->timer);
- }
- else
- {
- /*
- * If we failed to create it, then discard the frame
- */
- if ((qp = ip_create(skb, iph)) == NULL)
- {
+ } else {
+ /* If we failed to create it, then discard the frame. */
+ if ((qp = ip_create(skb, iph)) == NULL) {
kfree_skb(skb, FREE_READ);
ip_statistics.IpReasmFails++;
return NULL;
}
}
- /*
- * Attempt to construct an oversize packet.
- */
-
- if(ntohs(iph->tot_len)+(int)offset>65535)
- {
- printk(KERN_INFO "Oversized packet received from %s\n",in_ntoa(iph->saddr));
+ /* Attempt to construct an oversize packet. */
+ if(ntohs(iph->tot_len)+(int)offset>65535) {
+ printk(KERN_INFO "Oversized packet received from %s\n",
+ in_ntoa(iph->saddr));
frag_kfree_skb(skb, FREE_READ);
ip_statistics.IpReasmFails++;
return NULL;
}
- /*
- * Determine the position of this fragment.
- */
-
+ /* Determine the position of this fragment. */
end = offset + ntohs(iph->tot_len) - ihl;
- /*
- * Point into the IP datagram 'data' part.
- */
-
+ /* Point into the IP datagram 'data' part. */
ptr = skb->data + ihl;
- /*
- * Is this the final fragment?
- */
-
+ /* Is this the final fragment? */
if ((flags & IP_MF) == 0)
qp->len = end;
- /*
- * Find out which fragments are in front and at the back of us
- * in the chain of fragments so far. We must know where to put
- * this fragment, right?
+ /* Find out which fragments are in front and at the back of us
+ * in the chain of fragments so far. We must know where to put
+ * this fragment, right?
*/
-
prev = NULL;
- for(next = qp->fragments; next != NULL; next = next->next)
- {
- if (next->offset > offset)
+ for(next = qp->fragments; next != NULL; next = next->next) {
+ if (next->offset >= offset)
break; /* bingo! */
prev = next;
}
- /*
- * We found where to put this one.
- * Check for overlap with preceding fragment, and, if needed,
- * align things so that any overlaps are eliminated.
+ /* We found where to put this one. Check for overlap with
+ * preceding fragment, and, if needed, align things so that
+ * any overlaps are eliminated.
*/
- if (prev != NULL && offset < prev->end)
- {
+ if (prev != NULL && offset < prev->end) {
i = prev->end - offset;
offset += i; /* ptr into datagram */
ptr += i; /* ptr into fragment data */
}
- /*
- * Look for overlap with succeeding segments.
+ /* Look for overlap with succeeding segments.
* If we can merge fragments, do it.
*/
-
- for(tmp=next; tmp != NULL; tmp = tfp)
- {
+ for(tmp=next; tmp != NULL; tmp = tfp) {
tfp = tmp->next;
if (tmp->offset >= end)
break; /* no overlaps at all */
@@ -550,12 +482,11 @@ struct sk_buff *ip_defrag(struct sk_buff *skb)
tmp->len -= i; /* so reduce size of */
tmp->offset += i; /* next fragment */
tmp->ptr += i;
- /*
- * If we get a frag size of <= 0, remove it and the packet
- * that it goes with.
+
+ /* If we get a frag size of <= 0, remove it and the packet
+ * that it goes with.
*/
- if (tmp->len <= 0)
- {
+ if (tmp->len <= 0) {
if (tmp->prev != NULL)
tmp->prev->next = tmp->next;
else
@@ -564,26 +495,20 @@ struct sk_buff *ip_defrag(struct sk_buff *skb)
if (tmp->next != NULL)
tmp->next->prev = tmp->prev;
- next=tfp; /* We have killed the original next frame */
+ /* We have killed the original next frame. */
+ next = tfp;
frag_kfree_skb(tmp->skb,FREE_READ);
frag_kfree_s(tmp, sizeof(struct ipfrag));
}
}
- /*
- * Insert this fragment in the chain of fragments.
- */
-
+ /* Insert this fragment in the chain of fragments. */
tfp = NULL;
tfp = ip_frag_create(offset, end, skb, ptr);
- /*
- * No memory to save the fragment - so throw the lot
- */
-
- if (!tfp)
- {
+ /* No memory to save the fragment - so throw the lot. */
+ if (!tfp) {
frag_kfree_skb(skb, FREE_READ);
return NULL;
}
@@ -597,16 +522,14 @@ struct sk_buff *ip_defrag(struct sk_buff *skb)
if (next != NULL)
next->prev = tfp;
- /*
- * OK, so we inserted this new fragment into the chain.
- * Check if we now have a full IP datagram which we can
- * bump up to the IP layer...
+ /* OK, so we inserted this new fragment into the chain.
+ * Check if we now have a full IP datagram which we can
+ * bump up to the IP layer...
*/
-
- if (ip_done(qp))
- {
- skb2 = ip_glue(qp); /* glue together the fragments */
+ if (ip_done(qp)) {
+ /* Glue together the fragments. */
+ skb2 = ip_glue(qp);
return(skb2);
}
- return(NULL);
+ return NULL;
}
diff --git a/net/ipv4/ip_fw.c b/net/ipv4/ip_fw.c
index e516a2baa..ea9fe48b0 100644
--- a/net/ipv4/ip_fw.c
+++ b/net/ipv4/ip_fw.c
@@ -107,6 +107,7 @@
#include <net/netlink.h>
#include <linux/firewall.h>
#include <linux/ip_fw.h>
+#include <linux/init.h>
#ifdef CONFIG_IP_MASQUERADE
#include <net/ip_masq.h>
@@ -1298,7 +1299,7 @@ static struct proc_dir_entry proc_net_ipfwfwd = {
#endif
-void ip_fw_init(void)
+__initfunc(void ip_fw_init(void))
{
#ifdef CONFIG_PROC_FS
#ifdef CONFIG_IP_ACCT
diff --git a/net/ipv4/ip_masq.c b/net/ipv4/ip_masq.c
index c5976614e..2d2fd3717 100644
--- a/net/ipv4/ip_masq.c
+++ b/net/ipv4/ip_masq.c
@@ -31,6 +31,7 @@
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/inet.h>
+#include <linux/init.h>
#include <net/protocol.h>
#include <net/icmp.h>
#include <net/tcp.h>
@@ -1010,7 +1011,7 @@ static struct proc_dir_entry proc_net_ipmsqhst = {
/*
* Initialize ip masquerading
*/
-int ip_masq_init(void)
+__initfunc(int ip_masq_init(void))
{
#ifdef CONFIG_PROC_FS
proc_net_register(&proc_net_ipmsqhst);
diff --git a/net/ipv4/ip_masq_app.c b/net/ipv4/ip_masq_app.c
index 456888bc1..f7449e0ba 100644
--- a/net/ipv4/ip_masq_app.c
+++ b/net/ipv4/ip_masq_app.c
@@ -30,6 +30,7 @@
#include <linux/skbuff.h>
#include <linux/in.h>
#include <linux/ip.h>
+#include <linux/init.h>
#include <net/protocol.h>
#include <net/tcp.h>
#include <net/udp.h>
@@ -482,7 +483,7 @@ static struct proc_dir_entry proc_net_ip_masq_app = {
* Initialization routine
*/
-int ip_masq_app_init(void)
+__initfunc(int ip_masq_app_init(void))
{
#ifdef CONFIG_PROC_FS
proc_net_register(&proc_net_ip_masq_app);
diff --git a/net/ipv4/ip_masq_ftp.c b/net/ipv4/ip_masq_ftp.c
index cc2481746..4d5568d0a 100644
--- a/net/ipv4/ip_masq_ftp.c
+++ b/net/ipv4/ip_masq_ftp.c
@@ -28,6 +28,7 @@
#include <linux/skbuff.h>
#include <linux/in.h>
#include <linux/ip.h>
+#include <linux/init.h>
#include <net/protocol.h>
#include <net/tcp.h>
#include <net/ip_masq.h>
@@ -187,7 +188,7 @@ struct ip_masq_app ip_masq_ftp = {
* ip_masq_ftp initialization
*/
-int ip_masq_ftp_init(void)
+__initfunc(int ip_masq_ftp_init(void))
{
return register_ip_masq_app(&ip_masq_ftp, IPPROTO_TCP, 21);
}
diff --git a/net/ipv4/ip_masq_irc.c b/net/ipv4/ip_masq_irc.c
index e0b94f0d6..a1be56f81 100644
--- a/net/ipv4/ip_masq_irc.c
+++ b/net/ipv4/ip_masq_irc.c
@@ -29,6 +29,7 @@
#include <linux/skbuff.h>
#include <linux/in.h>
#include <linux/ip.h>
+#include <linux/init.h>
#include <net/protocol.h>
#include <net/tcp.h>
#include <net/ip_masq.h>
@@ -238,7 +239,7 @@ struct ip_masq_app ip_masq_irc = {
* ip_masq_irc initialization
*/
-int ip_masq_irc_init(void)
+__initfunc(int ip_masq_irc_init(void))
{
return register_ip_masq_app(&ip_masq_irc, IPPROTO_TCP, 6667);
}
diff --git a/net/ipv4/ip_masq_quake.c b/net/ipv4/ip_masq_quake.c
index 3614f0cf5..08a062bc7 100644
--- a/net/ipv4/ip_masq_quake.c
+++ b/net/ipv4/ip_masq_quake.c
@@ -28,6 +28,7 @@
#include <linux/skbuff.h>
#include <linux/in.h>
#include <linux/ip.h>
+#include <linux/init.h>
#include <net/protocol.h>
#include <net/udp.h>
#include <net/ip_masq.h>
@@ -279,7 +280,7 @@ struct ip_masq_app ip_masq_quakenew = {
* ip_masq_quake initialization
*/
-int ip_masq_quake_init(void)
+__initfunc(int ip_masq_quake_init(void))
{
return (register_ip_masq_app(&ip_masq_quake, IPPROTO_UDP, 26000) +
register_ip_masq_app(&ip_masq_quakenew, IPPROTO_UDP, 27000));
diff --git a/net/ipv4/ip_masq_raudio.c b/net/ipv4/ip_masq_raudio.c
index 85bba590e..52f439102 100644
--- a/net/ipv4/ip_masq_raudio.c
+++ b/net/ipv4/ip_masq_raudio.c
@@ -2,7 +2,7 @@
* IP_MASQ_RAUDIO - Real Audio masquerading module
*
*
- * Version: @(#)$Id: ip_masq_raudio.c,v 1.5 1997/04/03 08:52:02 davem Exp $
+ * Version: @(#)$Id: ip_masq_raudio.c,v 1.6 1997/04/29 09:38:26 mj Exp $
*
* Author: Nigel Metheringham
* [strongly based on ftp module by Juan Jose Ciarlante & Wouter Gadeyne]
@@ -45,6 +45,7 @@
#include <linux/skbuff.h>
#include <linux/in.h>
#include <linux/ip.h>
+#include <linux/init.h>
#include <net/protocol.h>
#include <net/tcp.h>
#include <net/ip_masq.h>
@@ -200,7 +201,7 @@ struct ip_masq_app ip_masq_raudio = {
* ip_masq_raudio initialization
*/
-int ip_masq_raudio_init(void)
+__initfunc(int ip_masq_raudio_init(void))
{
return register_ip_masq_app(&ip_masq_raudio, IPPROTO_TCP, 7070);
}
diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c
index 2c7974506..80baf8364 100644
--- a/net/ipv4/ip_options.c
+++ b/net/ipv4/ip_options.c
@@ -505,7 +505,7 @@ int ip_options_get(struct ip_options **optp, unsigned char *data, int optlen, in
opt->is_data = 1;
opt->is_setbyuser = 1;
if (optlen && ip_options_compile(opt, NULL)) {
- kfree_s(opt, sizeof(struct options) + optlen);
+ kfree_s(opt, sizeof(struct ip_options) + optlen);
return -EINVAL;
}
*optp = opt;
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index 41e60de61..6558b56e4 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -27,6 +27,8 @@
* (in case if packet not accepted by
* output firewall rules)
* Alexey Kuznetsov: use new route cache
+ * Andi Kleen: Fix broken PMTU recovery and remove
+ * some redundant tests.
*/
#include <asm/uaccess.h>
@@ -47,6 +49,7 @@
#include <linux/etherdevice.h>
#include <linux/proc_fs.h>
#include <linux/stat.h>
+#include <linux/init.h>
#include <net/snmp.h>
#include <net/ip.h>
@@ -126,9 +129,8 @@ int ip_build_pkt(struct sk_buff *skb, struct sock *sk, u32 saddr, u32 daddr,
iph->ihl = 5;
iph->tos = sk->ip_tos;
iph->frag_off = 0;
- if (sk->ip_pmtudisc == IP_PMTUDISC_DONT ||
- (sk->ip_pmtudisc == IP_PMTUDISC_WANT &&
- rt->rt_flags&RTF_NOPMTUDISC))
+ if (sk->ip_pmtudisc == IP_PMTUDISC_WANT &&
+ !(rt->rt_flags & RTF_NOPMTUDISC))
iph->frag_off |= htons(IP_DF);
iph->ttl = sk->ip_ttl;
iph->daddr = rt->rt_dst;
@@ -207,9 +209,8 @@ int ip_build_header(struct sk_buff *skb, struct sock *sk)
iph->ihl = 5;
iph->tos = sk->ip_tos;
iph->frag_off = 0;
- if (sk->ip_pmtudisc == IP_PMTUDISC_DONT ||
- (sk->ip_pmtudisc == IP_PMTUDISC_WANT &&
- rt->rt_flags&RTF_NOPMTUDISC))
+ if (sk->ip_pmtudisc == IP_PMTUDISC_WANT &&
+ !(rt->rt_flags & RTF_NOPMTUDISC))
iph->frag_off |= htons(IP_DF);
iph->ttl = sk->ip_ttl;
iph->daddr = rt->rt_dst;
@@ -480,8 +481,7 @@ int ip_build_xmit(struct sock *sk,
#endif
if (sk->ip_pmtudisc == IP_PMTUDISC_DONT ||
- (sk->ip_pmtudisc == IP_PMTUDISC_WANT &&
- rt->rt_flags&RTF_NOPMTUDISC))
+ rt->rt_flags&RTF_NOPMTUDISC)
df = 0;
@@ -1036,7 +1036,7 @@ static struct proc_dir_entry proc_net_igmp = {
* IP registers the packet type and then calls the subprotocol initialisers
*/
-void ip_init(void)
+__initfunc(void ip_init(void))
{
dev_add_pack(&ip_packet_type);
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index 1689159ed..8c2463d04 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -126,26 +126,24 @@ int ip_cmsg_send(struct msghdr *msg, struct ipcm_cookie *ipc, struct device **de
for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
if (cmsg->cmsg_level != SOL_IP)
continue;
- switch (cmsg->cmsg_type)
- {
+ switch (cmsg->cmsg_type) {
case IP_LOCALADDR:
- if (cmsg->cmsg_len < sizeof(struct in_addr)+sizeof(*cmsg))
+ if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct in_addr)))
return -EINVAL;
- memcpy(&ipc->addr, cmsg->cmsg_data, 4);
+ memcpy(&ipc->addr, CMSG_DATA(cmsg), sizeof(struct in_addr));
break;
case IP_RETOPTS:
- err = cmsg->cmsg_len - sizeof(*cmsg);
- err = ip_options_get(&ipc->opt, cmsg->cmsg_data,
- err < 40 ? err : 40, 0);
+ err = cmsg->cmsg_len - CMSG_ALIGN(sizeof(struct cmsghdr));
+ err = ip_options_get(&ipc->opt, CMSG_DATA(cmsg), err < 40 ? err : 40, 0);
if (err)
return err;
break;
case IP_TXINFO:
{
struct in_pktinfo *info;
- if (cmsg->cmsg_len < sizeof(*info)+sizeof(*cmsg))
+ if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct in_pktinfo)))
return -EINVAL;
- info = (struct in_pktinfo*)cmsg->cmsg_data;
+ info = (struct in_pktinfo *)CMSG_DATA(cmsg);
if (info->ipi_ifindex && !devp)
return -EINVAL;
if ((*devp = dev_get_by_index(info->ipi_ifindex)) == NULL)
@@ -212,7 +210,7 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int opt
sk->opt = opt;
sti();
if (old_opt)
- kfree_s(old_opt, sizeof(struct optlen) + old_opt->optlen);
+ kfree_s(old_opt, sizeof(struct ip_options) + old_opt->optlen);
return 0;
}
case IP_RXINFO:
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index f76c5b52d..1a38c5275 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -47,6 +47,7 @@
#include <linux/netdevice.h>
#include <linux/proc_fs.h>
#include <linux/mroute.h>
+#include <linux/init.h>
#include <net/ip.h>
#include <net/protocol.h>
#include <linux/skbuff.h>
@@ -1065,7 +1066,7 @@ static struct proc_dir_entry proc_net_ipmr_mfc = {
* Setup for IP multicast routing
*/
-void ip_mr_init(void)
+__initfunc(void ip_mr_init(void))
{
printk(KERN_INFO "Linux IP multicast router 0.06.\n");
register_netdevice_notifier(&ip_mr_notifier);
diff --git a/net/ipv4/rarp.c b/net/ipv4/rarp.c
index fb9e2a738..e0323bb85 100644
--- a/net/ipv4/rarp.c
+++ b/net/ipv4/rarp.c
@@ -45,6 +45,7 @@
#include <linux/if_arp.h>
#include <linux/in.h>
#include <linux/config.h>
+#include <linux/init.h>
#include <asm/system.h>
#include <asm/uaccess.h>
@@ -553,8 +554,8 @@ struct proc_dir_entry proc_net_rarp = {
rarp_get_info
};
-void
-rarp_init(void)
+__initfunc(void
+rarp_init(void))
{
proc_net_register(&proc_net_rarp);
rarp_ioctl_hook = rarp_ioctl;
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 5ba6467d9..4a4c5321c 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -69,6 +69,7 @@
#include <linux/netdevice.h>
#include <linux/if_arp.h>
#include <linux/proc_fs.h>
+#include <linux/init.h>
#include <net/ip.h>
#include <net/protocol.h>
#include <net/route.h>
@@ -1379,7 +1380,7 @@ void ip_rt_multicast_event(struct device *dev)
rt_cache_flush(0);
}
-void ip_rt_init()
+__initfunc(void ip_rt_init(void))
{
ip_fib_init();
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index 84ba6578b..18a8d2bf8 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -35,22 +35,27 @@ extern int sysctl_arp_check_interval;
extern int sysctl_arp_confirm_interval;
extern int sysctl_arp_confirm_timeout;
+/* From ip_fragment.c */
+extern int sysctl_ipfrag_low_thresh;
+extern int sysctl_ipfrag_high_thresh;
+
extern int sysctl_tcp_cong_avoidance;
extern int sysctl_tcp_hoe_retransmits;
extern int sysctl_tcp_sack;
extern int sysctl_tcp_tsack;
extern int sysctl_tcp_timestamps;
extern int sysctl_tcp_window_scaling;
+extern int sysctl_syn_retries;
extern int tcp_sysctl_congavoid(ctl_table *ctl, int write, struct file * filp,
void *buffer, size_t *lenp);
-struct ipv4_config ipv4_config = { 1, 1, 1, 1, };
+struct ipv4_config ipv4_config = { 1, 1, 1, 0, };
#ifdef CONFIG_SYSCTL
struct ipv4_config ipv4_def_router_config = { 0, 1, 1, 1, 1, 1, 1, };
-struct ipv4_config ipv4_def_host_config = { 1, 1, 1, 1, };
+struct ipv4_config ipv4_def_host_config = { 1, 1, 1, 0, };
int ipv4_sysctl_forwarding(ctl_table *ctl, int write, struct file * filp,
void *buffer, size_t *lenp)
@@ -144,6 +149,12 @@ ctl_table ipv4_table[] = {
{NET_IPV4_RFC1620_REDIRECTS, "ip_rfc1620_redirects",
&ipv4_config.rfc1620_redirects, sizeof(int), 0644, NULL,
&proc_dointvec},
+ {NET_TCP_SYN_RETRIES, "tcp_syn_retries",
+ &sysctl_syn_retries, sizeof(int), 0644, NULL, &proc_dointvec},
+ {NET_IPFRAG_HIGH_THRESH, "ipfrag_high_thresh",
+ &sysctl_ipfrag_high_thresh, sizeof(int), 0644, NULL, &proc_dointvec},
+ {NET_IPFRAG_LOW_THRESH, "ipfrag_low_thresh",
+ &sysctl_ipfrag_low_thresh, sizeof(int), 0644, NULL, &proc_dointvec},
{0}
};
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 420db4777..000813b94 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -5,7 +5,7 @@
*
* Implementation of the Transmission Control Protocol(TCP).
*
- * Version: $Id: tcp.c,v 1.61 1997/04/22 02:53:10 davem Exp $
+ * Version: $Id: tcp.c,v 1.65 1997/05/06 09:31:43 davem Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -424,6 +424,7 @@
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/poll.h>
+#include <linux/init.h>
#include <net/icmp.h>
#include <net/tcp.h>
@@ -849,7 +850,6 @@ int tcp_do_sendmsg(struct sock *sk, int iovlen, struct iovec *iov, int flags)
tcp_size = skb->tail -
((unsigned char *)(skb->h.th) + tp->tcp_header_len);
- /* printk("extending buffer\n"); */
/* This window_seq test is somewhat dangerous
* If the remote does SWS avoidance we should
* queue the best we can if not we should in
@@ -1100,6 +1100,9 @@ static void cleanup_rbuf(struct sock *sk)
struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
__u32 rcv_wnd;
+ /* FIXME: double check this rule, then check against
+ * other use of similar rules. Abtract if possible.
+ */
rcv_wnd = tp->rcv_wnd - (tp->rcv_nxt - tp->rcv_wup);
if ((rcv_wnd < sk->mss) && (sock_rspace(sk) > rcv_wnd))
@@ -1357,7 +1360,10 @@ static int tcp_close_state(struct sock *sk, int dead)
case TCP_CLOSE:
case TCP_LISTEN:
break;
- case TCP_LAST_ACK: /* Could have shutdown() then close() */
+ case TCP_LAST_ACK: /* Could have shutdown() then close()
+ * (but don't do send_fin again!) */
+ ns=TCP_LAST_ACK;
+ break;
case TCP_CLOSE_WAIT: /* They have FIN'd us. We send our FIN and
wait only for the ACK */
ns=TCP_LAST_ACK;
@@ -1655,11 +1661,11 @@ void tcp_set_keepalive(struct sock *sk, int val)
tcp_dec_slow_timer(TCP_SLT_KEEPALIVE);
}
-void tcp_init(void)
+__initfunc(void tcp_init(void))
{
tcp_openreq_cachep = kmem_cache_create("tcp_open_request",
sizeof(struct open_request),
- sizeof(long)*8, SLAB_HWCACHE_ALIGN,
+ 0, SLAB_HWCACHE_ALIGN,
NULL, NULL);
if(!tcp_openreq_cachep)
panic("tcp_init: Cannot alloc open_request cache.");
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index ab2b1ef82..3ab1dee42 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -5,7 +5,7 @@
*
* Implementation of the Transmission Control Protocol(TCP).
*
- * Version: $Id: tcp_input.c,v 1.50 1997/04/22 02:53:12 davem Exp $
+ * Version: $Id: tcp_input.c,v 1.51 1997/04/27 19:24:40 schenk Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -321,8 +321,10 @@ void tcp_parse_options(struct tcphdr *th, struct tcp_opt *tp)
break;
case TCPOPT_WINDOW:
if(opsize==TCPOLEN_WINDOW && th->syn)
- if (sysctl_tcp_window_scaling)
+ if (sysctl_tcp_window_scaling) {
+ tp->wscale_ok = 1;
tp->snd_wscale = *(__u8 *)ptr;
+ }
break;
case TCPOPT_SACK_PERM:
if(opsize==TCPOLEN_SACK_PERM && th->syn)
@@ -816,7 +818,7 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th,
*/
if (before(tp->snd_wl1, ack_seq) ||
(tp->snd_wl1 == ack_seq && !after(tp->snd_wl2, ack))) {
- unsigned long nwin = ntohs(th->window);
+ unsigned long nwin = ntohs(th->window) << tp->snd_wscale;
if ((tp->snd_wl2 != ack) || (nwin > tp->snd_wnd)) {
flag |= FLAG_WIN_UPDATE;
@@ -1464,17 +1466,21 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
if(tp->af_specific->conn_request(sk, skb, opt, isn) < 0)
return 1;
- /* Now we have several options: In theory there is
- * nothing else in the frame. KA9Q has an option to
- * send data with the syn, BSD accepts data with the
- * syn up to the [to be] advertised window and
- * Solaris 2.1 gives you a protocol error. For now
- * we just ignore it, that fits the spec precisely
- * and avoids incompatibilities. It would be nice in
- * future to drop through and process the data.
+ /* Now we have several options: In theory there is
+ * nothing else in the frame. KA9Q has an option to
+ * send data with the syn, BSD accepts data with the
+ * syn up to the [to be] advertised window and
+ * Solaris 2.1 gives you a protocol error. For now
+ * we just ignore it, that fits the spec precisely
+ * and avoids incompatibilities. It would be nice in
+ * future to drop through and process the data.
*
- * Now that TTCP is starting to be used we ought to
- * queue this data.
+ * Now that TTCP is starting to be used we ought to
+ * queue this data.
+ * But, this leaves one open to an easy denial of
+ * service attack, and SYN cookies can't defend
+ * against this problem. So, we drop the data
+ * in the interest of security over speed.
*/
return 0;
}
@@ -1514,10 +1520,9 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
* move to established.
*/
tp->rcv_nxt = skb->seq+1;
- tp->rcv_wnd = 0;
tp->rcv_wup = skb->seq+1;
- tp->snd_wnd = htons(th->window);
+ tp->snd_wnd = htons(th->window) << tp->snd_wscale;
tp->snd_wl1 = skb->seq;
tp->snd_wl2 = skb->ack_seq;
@@ -1526,6 +1531,10 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
tcp_set_state(sk, TCP_ESTABLISHED);
tcp_parse_options(th,tp);
/* FIXME: need to make room for SACK still */
+ if (tp->wscale_ok == 0) {
+ tp->snd_wscale = tp->rcv_wscale = 0;
+ tp->window_clamp = min(tp->window_clamp,65535);
+ }
if (tp->tstamp_ok) {
tp->tcp_header_len = sizeof(struct tcphdr) + 12; /* FIXME: Define constant! */
sk->dummy_th.doff += 3; /* reserve space of options */
@@ -1695,7 +1704,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
sk->state_change(sk);
tp->snd_una = skb->ack_seq;
- tp->snd_wnd = htons(th->window);
+ tp->snd_wnd = htons(th->window) << tp->snd_wscale;
tp->snd_wl1 = skb->seq;
tp->snd_wl2 = skb->ack_seq;
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index f4528f552..c4d12a54f 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -5,7 +5,7 @@
*
* Implementation of the Transmission Control Protocol(TCP).
*
- * Version: $Id: tcp_ipv4.c,v 1.39 1997/04/22 02:53:14 davem Exp $
+ * Version: $Id: tcp_ipv4.c,v 1.43 1997/05/06 09:31:44 davem Exp $
*
* IPv4 specific functions
*
@@ -465,7 +465,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
struct sk_buff *buff;
struct sk_buff *skb1;
int tmp;
- struct tcphdr *t1;
+ struct tcphdr *th;
struct rtable *rt;
struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
struct sockaddr_in *usin = (struct sockaddr_in *) uaddr;
@@ -546,20 +546,17 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
return(-ENETUNREACH);
}
- t1 = (struct tcphdr *) skb_put(buff,sizeof(struct tcphdr));
- buff->h.th = t1;
+ th = (struct tcphdr *) skb_put(buff,sizeof(struct tcphdr));
+ buff->h.th = th;
- memcpy(t1,(void *)&(sk->dummy_th), sizeof(*t1));
+ memcpy(th,(void *)&(sk->dummy_th), sizeof(*th));
buff->seq = sk->write_seq++;
- t1->seq = htonl(buff->seq);
+ th->seq = htonl(buff->seq);
tp->snd_nxt = sk->write_seq;
buff->end_seq = sk->write_seq;
- t1->ack = 0;
- t1->window = htons(512);
- t1->syn = 1;
+ th->ack = 0;
+ th->syn = 1;
- /* Use 512 or whatever user asked for. */
- tp->window_clamp = rt->u.dst.window;
sk->mtu = rt->u.dst.pmtu;
if ((sk->ip_pmtudisc == IP_PMTUDISC_DONT ||
@@ -577,13 +574,26 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
sk->mss = (sk->mtu - sizeof(struct iphdr) -
sizeof(struct tcphdr));
+ if (sk->mss < 1) {
+ printk(KERN_DEBUG "intial sk->mss below 1\n");
+ sk->mss = 1; /* Sanity limit */
+ }
+
+ tp->window_clamp = rt->u.dst.window;
+ tcp_select_initial_window(sock_rspace(sk)/2,sk->mss,
+ &tp->rcv_wnd,
+ &tp->window_clamp,
+ sysctl_tcp_window_scaling,
+ &tp->rcv_wscale);
+ th->window = htons(tp->rcv_wnd);
+
tmp = tcp_syn_build_options(buff, sk->mss, sysctl_tcp_sack,
sysctl_tcp_timestamps,
- sysctl_tcp_window_scaling?tp->rcv_wscale:0);
+ sysctl_tcp_window_scaling,tp->rcv_wscale);
buff->csum = 0;
- t1->doff = (sizeof(*t1)+ tmp)>>2;
+ th->doff = (sizeof(*th)+ tmp)>>2;
- tcp_v4_send_check(sk, t1, sizeof(struct tcphdr) + tmp, buff);
+ tcp_v4_send_check(sk, th, sizeof(struct tcphdr) + tmp, buff);
tcp_set_state(sk,TCP_SYN_SENT);
@@ -803,7 +813,6 @@ int tcp_chkaddr(struct sk_buff *skb)
static void tcp_v4_send_synack(struct sock *sk, struct open_request *req)
{
- struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
struct sk_buff * skb;
struct tcphdr *th;
int tmp;
@@ -829,6 +838,11 @@ static void tcp_v4_send_synack(struct sock *sk, struct open_request *req)
*/
req->mss = min(mss, req->mss);
+ if (req->mss < 1) {
+ printk(KERN_DEBUG "initial req->mss below 1\n");
+ req->mss = 1;
+ }
+
/* Yuck, make this header setup more efficient... -DaveM */
memset(th, 0, sizeof(struct tcphdr));
th->syn = 1;
@@ -839,7 +853,16 @@ static void tcp_v4_send_synack(struct sock *sk, struct open_request *req)
skb->end_seq = skb->seq + 1;
th->seq = ntohl(skb->seq);
th->ack_seq = htonl(req->rcv_isn + 1);
- th->window = ntohs(tp->rcv_wnd);
+ if (req->rcv_wnd == 0) {
+ /* Set this up on the first call only */
+ req->window_clamp = skb->dst->window;
+ tcp_select_initial_window(sock_rspace(sk)/2,req->mss,
+ &req->rcv_wnd,
+ &req->window_clamp,
+ req->wscale_ok,
+ &req->rcv_wscale);
+ }
+ th->window = htons(req->rcv_wnd);
/* XXX Partial csum of 4 byte quantity is itself! -DaveM
* Yes, but it's a bit harder to special case now. It's
@@ -850,7 +873,7 @@ static void tcp_v4_send_synack(struct sock *sk, struct open_request *req)
*/
tmp = tcp_syn_build_options(skb, req->mss, req->sack_ok, req->tstamp_ok,
- (req->snd_wscale)?tp->rcv_wscale:0);
+ req->wscale_ok,req->rcv_wscale);
skb->csum = 0;
th->doff = (sizeof(*th) + tmp)>>2;
th->check = tcp_v4_check(th, sizeof(*th) + tmp,
@@ -865,7 +888,7 @@ static void tcp_v4_or_free(struct open_request *req)
{
if(!req->sk && req->af.v4_req.opt)
kfree_s(req->af.v4_req.opt,
- sizeof(struct options) + req->af.v4_req.opt->optlen);
+ sizeof(struct ip_options) + req->af.v4_req.opt->optlen);
}
static struct or_calltable or_ipv4 = {
@@ -881,7 +904,7 @@ static int tcp_v4_syn_filter(struct sock *sk, struct sk_buff *skb, __u32 saddr)
int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb, void *ptr, __u32 isn)
{
struct ip_options *opt = (struct ip_options *) ptr;
- struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+ struct tcp_opt tp;
struct open_request *req;
struct tcphdr *th = skb->h.th;
__u32 saddr = skb->nh.iph->saddr;
@@ -913,19 +936,20 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb, void *ptr, __u32 i
sk->ack_backlog++;
+ req->rcv_wnd = 0; /* So that tcp_send_synack() knows! */
+
req->rcv_isn = skb->seq;
req->snt_isn = isn;
- tp->tstamp_ok = tp->sack_ok = tp->snd_wscale = 0;
- tcp_parse_options(th,tp);
- if (tp->saw_tstamp) {
- tp->ts_recent = tp->rcv_tsval;
- tp->ts_recent_stamp = jiffies;
- }
- req->mss = tp->in_mss;
- req->tstamp_ok = tp->tstamp_ok;
- req->sack_ok = tp->sack_ok;
- req->snd_wscale = tp->snd_wscale;
- req->ts_recent = tp->ts_recent;
+ tp.tstamp_ok = tp.sack_ok = tp.wscale_ok = tp.snd_wscale = 0;
+ tp.in_mss = 536;
+ tcp_parse_options(th,&tp);
+ if (tp.saw_tstamp)
+ req->ts_recent = tp.rcv_tsval;
+ req->mss = tp.in_mss;
+ req->tstamp_ok = tp.tstamp_ok;
+ req->sack_ok = tp.sack_ok;
+ req->snd_wscale = tp.snd_wscale;
+ req->wscale_ok = tp.wscale_ok;
req->rmt_port = th->source;
req->af.v4_req.loc_addr = daddr;
req->af.v4_req.rmt_addr = saddr;
@@ -1004,8 +1028,6 @@ struct sock * tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
atomic_set(&newsk->rmem_alloc, 0);
newsk->localroute = sk->localroute;
- newsk->max_unacked = MAX_WINDOW - TCP_WINDOW_DIFF;
-
newsk->err = 0;
newsk->shutdown = 0;
newsk->ack_backlog = 0;
@@ -1060,7 +1082,6 @@ struct sock * tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
newsk->dst_cache = &rt->u.dst;
- newtp->window_clamp = rt->u.dst.window;
snd_mss = rt->u.dst.pmtu;
/* FIXME: is mtu really the same as snd_mss? */
@@ -1072,10 +1093,19 @@ struct sock * tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
newtp->sack_ok = req->sack_ok;
newtp->tstamp_ok = req->tstamp_ok;
- newtp->snd_wscale = req->snd_wscale;
- newtp->ts_recent = req->ts_recent;
- newtp->ts_recent_stamp = jiffies;
+ newtp->window_clamp = req->window_clamp;
+ newtp->rcv_wnd = req->rcv_wnd;
+ newtp->wscale_ok = req->wscale_ok;
+ if (newtp->wscale_ok) {
+ newtp->snd_wscale = req->snd_wscale;
+ newtp->rcv_wscale = req->rcv_wscale;
+ } else {
+ newtp->snd_wscale = newtp->rcv_wscale = 0;
+ newtp->window_clamp = min(newtp->window_clamp,65535);
+ }
if (newtp->tstamp_ok) {
+ newtp->ts_recent = req->ts_recent;
+ newtp->ts_recent_stamp = jiffies;
newtp->tcp_header_len = sizeof(struct tcphdr) + 12; /* FIXME: define constant! */
newsk->dummy_th.doff += 3;
} else {
@@ -1219,9 +1249,8 @@ int tcp_v4_rcv(struct sk_buff *skb, unsigned short len)
case CHECKSUM_HW:
if (tcp_v4_check(th,len,saddr,daddr,skb->csum)) {
struct iphdr * iph = skb->nh.iph;
- printk(KERN_DEBUG "TCPv4 bad checksum from %08x:%04x to %08x:%04x, ack = %u, seq = %u, len=%d/%d/%d\n",
+ printk(KERN_DEBUG "TCPv4 bad checksum from %08x:%04x to %08x:%04x, len=%d/%d/%d\n",
saddr, ntohs(th->source), daddr,
- ntohl(th->ack_seq), ntohl(th->seq),
ntohs(th->dest), len, skb->len, ntohs(iph->tot_len));
goto discard_it;
}
@@ -1346,10 +1375,12 @@ static int tcp_v4_init_sock(struct sock *sk)
tp->ato = 0;
tp->iat = (HZ/5) << 3;
- tp->rcv_wnd = 8192;
+ /* FIXME: tie this to sk->rcvbuf? (May be unnecessary) */
+ /* tp->rcv_wnd = 8192; */
tp->tstamp_ok = 0;
tp->sack_ok = 0;
- tp->in_mss = 0;
+ tp->wscale_ok = 0;
+ tp->in_mss = 536;
tp->snd_wscale = 0;
tp->sacks = 0;
tp->saw_tstamp = 0;
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 7f157abe2..bdc79525f 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -5,7 +5,7 @@
*
* Implementation of the Transmission Control Protocol(TCP).
*
- * Version: $Id: tcp_output.c,v 1.42 1997/04/22 01:06:33 davem Exp $
+ * Version: $Id: tcp_output.c,v 1.43 1997/04/27 19:24:43 schenk Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -404,14 +404,115 @@ void tcp_write_xmit(struct sock *sk)
-/*
- * This function returns the amount that we can raise the
- * usable window based on the following constraints
+/* This function returns the amount that we can raise the
+ * usable window based on the following constraints
*
- * 1. The window can never be shrunk once it is offered (RFC 793)
- * 2. We limit memory per socket
+ * 1. The window can never be shrunk once it is offered (RFC 793)
+ * 2. We limit memory per socket
+ *
+ * RFC 1122:
+ * "the suggested [SWS] avoidance algoritm for the receiver is to keep
+ * RECV.NEXT + RCV.WIN fixed until:
+ * RCV.BUFF - RCV.USER - RCV.WINDOW >= min(1/2 RCV.BUFF, MSS)"
+ *
+ * i.e. don't raise the right edge of the window until you can raise
+ * it at least MSS bytes.
+ *
+ * Unfortunately, the recomended algorithm breaks header prediction,
+ * since header prediction assumes th->window stays fixed.
+ *
+ * Strictly speaking, keeping th->window fixed violates the receiver
+ * side SWS prevention criteria. The problem is that under this rule
+ * a stream of single byte packets will cause the right side of the
+ * window to always advance by a single byte.
+ *
+ * Of course, if the sender implements sender side SWS prevention
+ * then this will not be a problem.
+ *
+ * BSD seems to make the following compromise:
+ *
+ * If the free space is less than the 1/4 of the maximum
+ * space available and the free space is less than 1/2 mss,
+ * then set the window to 0.
+ * Otherwise, just prevent the window from shrinking
+ * and from being larger than the largest representable value.
+ *
+ * This prevents incremental opening of the window in the regime
+ * where TCP is limited by the speed of the reader side taking
+ * data out of the TCP receive queue. It does nothing about
+ * those cases where the window is constrained on the sender side
+ * because the pipeline is full.
+ *
+ * BSD also seems to "accidentally" limit itself to windows that are a
+ * multiple of MSS, at least until the free space gets quite small.
+ * This would appear to be a side effect of the mbuf implementation.
+ * Combining these two algorithms results in the observed behavior
+ * of having a fixed window size at almost all times.
+ *
+ * Below we obtain similar behavior by forcing the offered window to
+ * a multiple of the mss when it is feasible to do so.
+ *
+ * FIXME: In our current implementation the value returned by sock_rpsace(sk)
+ * is the total space we have allocated to the socket to store skbuf's.
+ * The current design assumes that up to half of that space will be
+ * taken by headers, and the remaining space will be available for TCP data.
+ * This should be accounted for correctly instead.
*/
+unsigned short tcp_select_window(struct sock *sk)
+{
+ struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
+ int mss = sk->mss;
+ long free_space = sock_rspace(sk)/2;
+ long window, cur_win;
+
+ if (tp->window_clamp) {
+ free_space = min(tp->window_clamp, free_space);
+ mss = min(tp->window_clamp, mss);
+ } else
+ printk(KERN_DEBUG "Clamp failure. Water leaking.\n");
+
+ if (mss < 1) {
+ mss = 1;
+ printk(KERN_DEBUG "tcp_select_window: mss fell to 0.\n");
+ }
+
+ /* compute the actual window i.e.
+ * old_window - received_bytes_on_that_win
+ */
+ cur_win = tp->rcv_wnd - (tp->rcv_nxt - tp->rcv_wup);
+ window = tp->rcv_wnd;
+
+ if (cur_win < 0) {
+ cur_win = 0;
+ printk(KERN_DEBUG "TSW: win < 0 w=%d 1=%u 2=%u\n",
+ tp->rcv_wnd, tp->rcv_nxt, tp->rcv_wup);
+ }
+
+ if (free_space < sk->rcvbuf/4 && free_space < mss/2)
+ window = 0;
+
+ /* Get the largest window that is a nice multiple of mss.
+ * Window clamp already applied above.
+ * If our current window offering is within 1 mss of the
+ * free space we just keep it. This prevents the divide
+ * and multiply from happening most of the time.
+ * We also don't do any window rounding when the free space
+ * is too small.
+ */
+ if (window < free_space - mss && free_space > mss)
+ window = (free_space/mss)*mss;
+ /* Never shrink the offered window */
+ if (window < cur_win)
+ window = cur_win;
+
+ tp->rcv_wnd = window;
+ tp->rcv_wup = tp->rcv_nxt;
+ return window >> tp->rcv_wscale; /* RFC1323 scaling applied */
+}
+
+#if 0
+/* Old algorithm for window selection */
unsigned short tcp_select_window(struct sock *sk)
{
struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
@@ -427,37 +528,31 @@ unsigned short tcp_select_window(struct sock *sk)
/* compute the actual window i.e.
* old_window - received_bytes_on_that_win
*/
- cur_win = tp->rcv_wup - (tp->rcv_nxt - tp->rcv_wnd);
+ cur_win = tp->rcv_wnd - (tp->rcv_nxt - tp->rcv_wup);
window = tp->rcv_wnd;
-
+
if (cur_win < 0) {
cur_win = 0;
printk(KERN_DEBUG "TSW: win < 0 w=%d 1=%u 2=%u\n",
tp->rcv_wnd, tp->rcv_nxt, tp->rcv_wup);
}
- /*
- * RFC 1122:
+ /* RFC 1122:
* "the suggested [SWS] avoidance algoritm for the receiver is to keep
* RECV.NEXT + RCV.WIN fixed until:
* RCV.BUFF - RCV.USER - RCV.WINDOW >= min(1/2 RCV.BUFF, MSS)"
*
- * i.e. don't raise the right edge of the window until you can't raise
- * it MSS bytes
+ * i.e. don't raise the right edge of the window until you can raise
+ * it at least MSS bytes.
*/
- /* It would be a good idea if it didn't break header prediction.
- * and BSD made the header predition standard...
- * It expects the same value in the header i.e. th->window to be
- * constant
- */
usable = free_space - cur_win;
if (usable < 0)
usable = 0;
if (window < usable) {
/* Window is not blocking the sender
- * and we have enought free space for it
+ * and we have enough free space for it
*/
if (cur_win > (sk->mss << 1))
goto out;
@@ -469,7 +564,7 @@ unsigned short tcp_select_window(struct sock *sk)
*/
window = max(usable, cur_win);
} else {
- if ((usable - window) >= mss)
+ while ((usable - window) >= mss)
window += mss;
}
out:
@@ -477,6 +572,7 @@ out:
tp->rcv_wup = tp->rcv_nxt;
return window;
}
+#endif
static int tcp_retrans_try_collapse(struct sock *sk, struct sk_buff *skb)
{
@@ -703,6 +799,11 @@ void tcp_send_fin(struct sock *sk)
}
}
+/* WARNING: This routine must only be called when we have already sent
+ * a SYN packet that crossed the incoming SYN that caused this routine
+ * to get called. If this assumption fails then the initial rcv_wnd
+ * and rcv_wscale values will not be correct.
+ */
int tcp_send_synack(struct sock *sk)
{
struct tcp_opt * tp = &(sk->tp_pinfo.af_tcp);
@@ -735,13 +836,16 @@ int tcp_send_synack(struct sock *sk)
skb->end_seq = skb->seq + 1 /* th->syn */ ;
th->seq = ntohl(skb->seq);
- th->window = ntohs(tp->rcv_wnd);
+ /* This is a resend of a previous SYN, now with an ACK.
+ * we must reuse the previously offered window.
+ */
+ th->window = htons(tp->rcv_wnd);
tp->last_ack_sent = th->ack_seq = htonl(tp->rcv_nxt);
tmp = tcp_syn_build_options(skb, sk->mss,
tp->sack_ok, tp->tstamp_ok,
- tp->snd_wscale?tp->rcv_wscale:0);
+ tp->wscale_ok,tp->rcv_wscale);
skb->csum = 0;
th->doff = (sizeof(*th) + tmp)>>2;
diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
index 365d3dac2..ce6c60feb 100644
--- a/net/ipv4/tcp_timer.c
+++ b/net/ipv4/tcp_timer.c
@@ -22,6 +22,8 @@
#include <net/tcp.h>
+int sysctl_syn_retries = TCP_SYN_RETRIES;
+
static void tcp_sltimer_handler(unsigned long);
static void tcp_syn_recv_timer(unsigned long);
static void tcp_keepalive(unsigned long data);
@@ -178,7 +180,7 @@ static int tcp_write_timeout(struct sock *sk)
}
/* Have we tried to SYN too many times (repent repent 8)) */
- if(tp->retransmits > TCP_SYN_RETRIES && sk->state==TCP_SYN_SENT) {
+ if(tp->retransmits > sysctl_syn_retries && sk->state==TCP_SYN_SENT) {
if(sk->err_soft)
sk->err=sk->err_soft;
else
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 9ca5f3045..ed84d5b0f 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -154,7 +154,7 @@ static int udp_v4_verify_bind(struct sock *sk, unsigned short snum)
return retval;
}
-static inline int udp_lport_inuse(int num)
+static inline int udp_lport_inuse(u16 num)
{
struct sock *sk = udp_hash[num & (UDP_HTABLE_SIZE - 1)];
@@ -168,36 +168,42 @@ static inline int udp_lport_inuse(int num)
/* Shared by v4/v6 tcp. */
unsigned short udp_good_socknum(void)
{
- static int start = 0;
- unsigned short base;
- int i, best = 0, size = 32767; /* a big num. */
int result;
-
- base = PROT_SOCK + (start & 1023) + 1;
+ static int start = 0;
+ int i, best, best_size_so_far;
SOCKHASH_LOCK();
- for(i = 0; i < UDP_HTABLE_SIZE; i++) {
- struct sock *sk = udp_hash[i];
- if(!sk) {
- start = (i + 1 + start) & 1023;
- result = i + base + 1;
+
+ /* Select initial not-so-random "best" */
+ best = PROT_SOCK + 1 + (start & 1023);
+ best_size_so_far = 32767; /* "big" num */
+ result = best;
+ for (i = 0; i < UDP_HTABLE_SIZE; i++, result++) {
+ struct sock *sk;
+ int size;
+
+ sk = udp_hash[result & (UDP_HTABLE_SIZE - 1)];
+
+ /* No clashes - take it */
+ if (!sk)
goto out;
- } else {
- int j = 0;
- do {
- if(++j >= size)
- goto next;
- } while((sk = sk->next));
- best = i;
- size = j;
- }
- next:
+
+ /* Is this one better than our best so far? */
+ size = 0;
+ do {
+ if(++size >= best_size_so_far)
+ goto next;
+ } while((sk = sk->next) != NULL);
+ best_size_so_far = size;
+ best = result;
+next:
}
- while(udp_lport_inuse(base + best + 1))
+ while (udp_lport_inuse(best))
best += UDP_HTABLE_SIZE;
- result = (best + base + 1);
+ result = best;
out:
+ start = result;
SOCKHASH_UNLOCK();
return result;
}
diff --git a/net/ipv4/utils.c b/net/ipv4/utils.c
index cbce01b68..4253c85db 100644
--- a/net/ipv4/utils.c
+++ b/net/ipv4/utils.c
@@ -46,7 +46,7 @@
* Display an IP address in readable format.
*/
-char *in_ntoa(unsigned long in)
+char *in_ntoa(__u32 in)
{
static char buff[18];
char *p;
@@ -62,7 +62,7 @@ char *in_ntoa(unsigned long in)
* Convert an ASCII string to binary IP.
*/
-unsigned long in_aton(const char *str)
+__u32 in_aton(const char *str)
{
unsigned long l;
unsigned int val;
diff --git a/net/ipv6/.cvsignore b/net/ipv6/.cvsignore
new file mode 100644
index 000000000..4671378ae
--- /dev/null
+++ b/net/ipv6/.cvsignore
@@ -0,0 +1 @@
+.depend
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 9173a7760..1639f916d 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -5,7 +5,7 @@
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: addrconf.c,v 1.18 1997/04/16 05:58:03 davem Exp $
+ * $Id: addrconf.c,v 1.20 1997/05/07 09:40:04 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -31,6 +31,7 @@
#include <linux/netdevice.h>
#include <linux/if_arp.h>
#include <linux/route.h>
+#include <linux/init.h>
#include <linux/proc_fs.h>
#include <net/sock.h>
@@ -1215,7 +1216,7 @@ void addrconf_verify(unsigned long foo)
* Init / cleanup code
*/
-void addrconf_init()
+__initfunc(void addrconf_init(void))
{
struct device *dev;
@@ -1273,6 +1274,7 @@ void addrconf_cleanup(void)
for (idev = inet6_dev_lst[i]; idev; ) {
struct inet6_dev *back;
+ addrconf_ifdown(idev->dev);
back = idev;
idev = idev->next;
kfree(back);
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 0f6bbf4de..1de20e358 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -7,7 +7,7 @@
*
* Adapted from linux/net/ipv4/af_inet.c
*
- * $Id: af_inet6.c,v 1.16 1997/03/18 18:24:26 davem Exp $
+ * $Id: af_inet6.c,v 1.18 1997/05/07 09:40:12 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -34,6 +34,7 @@
#include <linux/interrupt.h>
#include <linux/proc_fs.h>
#include <linux/stat.h>
+#include <linux/init.h>
#include <linux/inet.h>
#include <linux/netdevice.h>
@@ -457,13 +458,27 @@ static struct proc_dir_entry proc_net_sockstat6 = {
#endif /* CONFIG_PROC_FS */
#ifdef MODULE
+int ipv6_unload(void)
+{
+ return 0;
+}
+#endif
+
+#ifdef MODULE
int init_module(void)
#else
-void inet6_proto_init(struct net_proto *pro)
+__initfunc(void inet6_proto_init(struct net_proto *pro))
#endif
{
struct sk_buff *dummy_skb;
+#ifdef MODULE
+ if (!mod_member_present(&__this_module, can_unload))
+ return -EINVAL;
+
+ __this_module.can_unload = &ipv6_unload;
+#endif
+
printk(KERN_INFO "IPv6 v0.2 for NET3.037\n");
if (sizeof(struct ipv6_options) > sizeof(dummy_skb->cb))
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
index a898f6008..90f7b25d9 100644
--- a/net/ipv6/datagram.c
+++ b/net/ipv6/datagram.c
@@ -5,7 +5,7 @@
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: datagram.c,v 1.10 1997/04/14 05:39:42 davem Exp $
+ * $Id: datagram.c,v 1.12 1997/05/15 18:55:09 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -15,6 +15,9 @@
#include <linux/errno.h>
#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
#include <linux/socket.h>
#include <linux/sockios.h>
#include <linux/in6.h>
@@ -36,7 +39,7 @@ int datagram_recv_ctl(struct sock *sk, struct msghdr *msg, struct sk_buff *skb)
src_info.ipi6_ifindex = skb->dev->ifindex;
ipv6_addr_copy(&src_info.ipi6_addr, &skb->nh.ipv6h->daddr);
- put_cmsg(msg, SOL_IPV6, IPV6_RXINFO, sizeof(src_info), &src_info);
+ put_cmsg(msg, SOL_IPV6, IPV6_PKTINFO, sizeof(src_info), &src_info);
}
if (np->rxhlim) {
@@ -64,20 +67,18 @@ int datagram_send_ctl(struct msghdr *msg, struct device **src_dev,
for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
if (cmsg->cmsg_level != SOL_IPV6) {
- printk(KERN_DEBUG "cmsg_level %d\n", cmsg->cmsg_level);
+ printk(KERN_DEBUG "invalid cmsg_level %d\n", cmsg->cmsg_level);
continue;
}
switch (cmsg->cmsg_type) {
-
- case IPV6_TXINFO:
- if (cmsg->cmsg_len < (sizeof(struct cmsghdr) +
- sizeof(struct in6_pktinfo))) {
+ case IPV6_PKTINFO:
+ if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct in6_pktinfo))) {
err = -EINVAL;
goto exit_f;
}
- src_info = (struct in6_pktinfo *) cmsg->cmsg_data;
+ src_info = (struct in6_pktinfo *)CMSG_DATA(cmsg);
if (src_info->ipi6_ifindex) {
int index = src_info->ipi6_ifindex;
@@ -101,18 +102,13 @@ int datagram_send_ctl(struct msghdr *msg, struct device **src_dev,
break;
case IPV6_RXSRCRT:
-
- len = cmsg->cmsg_len;
-
- len -= sizeof(struct cmsghdr);
-
- /* validate option length */
- if (len < sizeof(struct ipv6_rt_hdr)) {
+ if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct ipv6_rt_hdr))) {
err = -EINVAL;
goto exit_f;
}
- rthdr = (struct ipv6_rt_hdr *) cmsg->cmsg_data;
+ len = cmsg->cmsg_len - sizeof(struct cmsghdr);
+ rthdr = (struct ipv6_rt_hdr *)CMSG_DATA(cmsg);
/*
* TYPE 0
@@ -139,21 +135,16 @@ int datagram_send_ctl(struct msghdr *msg, struct device **src_dev,
break;
case IPV6_HOPLIMIT:
-
- len = cmsg->cmsg_len;
- len -= sizeof(struct cmsghdr);
-
- if (len < sizeof(int)) {
+ if (cmsg->cmsg_len != CMSG_LEN(sizeof(int))) {
err = -EINVAL;
goto exit_f;
}
- *hlimit = *((int *) cmsg->cmsg_data);
+ *hlimit = *(int *)CMSG_DATA(cmsg);
break;
default:
- printk(KERN_DEBUG "invalid cmsg type: %d\n",
- cmsg->cmsg_type);
+ printk(KERN_DEBUG "invalid cmsg type: %d\n", cmsg->cmsg_type);
err = -EINVAL;
break;
};
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
index 37bd7f814..71ff84b4b 100644
--- a/net/ipv6/icmp.c
+++ b/net/ipv6/icmp.c
@@ -5,7 +5,7 @@
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: icmp.c,v 1.8 1997/03/18 18:24:30 davem Exp $
+ * $Id: icmp.c,v 1.9 1997/04/29 09:38:42 mj Exp $
*
* Based on net/ipv4/icmp.c
*
@@ -34,6 +34,7 @@
#include <linux/sockios.h>
#include <linux/net.h>
#include <linux/skbuff.h>
+#include <linux/init.h>
#include <linux/inet.h>
#include <linux/netdevice.h>
@@ -486,7 +487,7 @@ discard_it:
return 0;
}
-void icmpv6_init(struct net_proto_family *ops)
+__initfunc(void icmpv6_init(struct net_proto_family *ops))
{
struct sock *sk;
int err;
diff --git a/net/ipv6/ip6_fw.c b/net/ipv6/ip6_fw.c
index f6e7f8da4..5a47cc251 100644
--- a/net/ipv6/ip6_fw.c
+++ b/net/ipv6/ip6_fw.c
@@ -5,7 +5,7 @@
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: ip6_fw.c,v 1.4 1997/03/18 18:24:34 davem Exp $
+ * $Id: ip6_fw.c,v 1.5 1997/04/29 09:38:44 mj Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -22,6 +22,7 @@
#include <linux/netdevice.h>
#include <linux/in6.h>
#include <linux/udp.h>
+#include <linux/init.h>
#include <net/ipv6.h>
#include <net/ip6_route.h>
@@ -365,7 +366,7 @@ static void ip6_fw_destroy(struct flow_rule *rl)
#define ip6_fw_init module_init
#endif
-void ip6_fw_init(void)
+__initfunc(void ip6_fw_init(void))
{
netlink_attach(NETLINK_IP6_FW, ip6_fw_msgrcv);
}
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c
index c5e21417d..cf107efcd 100644
--- a/net/ipv6/ip6_input.c
+++ b/net/ipv6/ip6_input.c
@@ -6,7 +6,7 @@
* Pedro Roque <roque@di.fc.ul.pt>
* Ian P. Morris <I.P.Morris@soton.ac.uk>
*
- * $Id: ip6_input.c,v 1.4 1997/03/18 18:24:35 davem Exp $
+ * $Id: ip6_input.c,v 1.6 1997/05/11 16:06:52 davem Exp $
*
* Based in linux/net/ipv4/ip_input.c
*
@@ -133,7 +133,7 @@ static int ip6_parse_tlv(struct tlvtype_proc *procs, struct sk_buff *skb,
struct tlvtype_proc *curr;
while ((hdr=(struct ipv6_tlvtype *)skb->h.raw) != lastopt) {
- switch (hdr->type & 0x3F) {
+ switch (hdr->type) {
case 0: /* TLV encoded Pad1 */
skb->h.raw++;
break;
@@ -144,7 +144,7 @@ static int ip6_parse_tlv(struct tlvtype_proc *procs, struct sk_buff *skb,
default: /* Other TLV code so scan list */
for (curr=procs; curr->type != 255; curr++) {
- if (curr->type == (hdr->type & 0x3F)) {
+ if (curr->type == (hdr->type)) {
curr->func(skb, dev, nhptr, opt);
skb->h.raw += hdr->len+2;
break;
@@ -166,10 +166,12 @@ static int ipv6_dest_opt(struct sk_buff **skb_ptr, struct device *dev,
struct sk_buff *skb=*skb_ptr;
struct ipv6_destopt_hdr *hdr = (struct ipv6_destopt_hdr *) skb->h.raw;
int res = 0;
+ void *lastopt=skb->h.raw+hdr->hdrlen+sizeof(struct ipv6_destopt_hdr);
- if (ip6_parse_tlv(tlvprocdestopt_lst, skb, dev, nhptr, opt,
- skb->h.raw+hdr->hdrlen))
+ skb->h.raw += sizeof(struct ipv6_destopt_hdr);
+ if (ip6_parse_tlv(tlvprocdestopt_lst, skb, dev, nhptr, opt, lastopt))
res = hdr->nexthdr;
+ skb->h.raw+=hdr->hdrlen;
return res;
}
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index 88920bb73..64cfb00d5 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -7,7 +7,7 @@
*
* Based on linux/net/ipv4/ip_sockglue.c
*
- * $Id: ipv6_sockglue.c,v 1.11 1997/04/20 09:44:33 davem Exp $
+ * $Id: ipv6_sockglue.c,v 1.13 1997/05/15 18:55:10 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -31,12 +31,11 @@
#include <linux/in6.h>
#include <linux/netdevice.h>
#include <linux/if_arp.h>
-
+#include <linux/init.h>
#include <linux/sysctl.h>
#include <net/sock.h>
#include <net/snmp.h>
-
#include <net/ipv6.h>
#include <net/ndisc.h>
#include <net/protocol.h>
@@ -122,7 +121,7 @@ int ipv6_setsockopt(struct sock *sk, int level, int optname, char *optval,
}
break;
- case IPV6_RXINFO:
+ case IPV6_PKTINFO:
np->rxinfo = val;
retv = 0;
break;
@@ -239,7 +238,7 @@ extern void ipv6_sysctl_register(void);
extern void ipv6_sysctl_unregister(void);
#endif
-void ipv6_init(void)
+__initfunc(void ipv6_init(void))
{
dev_add_pack(&ipv6_packet_type);
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index 573f1f611..637f434d4 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -5,7 +5,7 @@
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: mcast.c,v 1.8 1997/04/12 04:32:48 davem Exp $
+ * $Id: mcast.c,v 1.10 1997/05/07 09:40:22 davem Exp $
*
* Based on linux/ipv4/igmp.c and linux/ipv4/ip_sockglue.c
*
@@ -27,6 +27,7 @@
#include <linux/netdevice.h>
#include <linux/if_arp.h>
#include <linux/route.h>
+#include <linux/init.h>
#include <net/sock.h>
#include <net/snmp.h>
@@ -186,7 +187,8 @@ int ipv6_dev_mc_inc(struct device *dev, struct in6_addr *addr)
hash = ipv6_addr_hash(addr);
for (mc = inet6_mcast_lst[hash]; mc; mc = mc->next) {
- if (ipv6_addr_cmp(&mc->mca_addr, addr) == 0) {
+ if ((ipv6_addr_cmp(&mc->mca_addr, addr) == 0) &&
+ (mc->dev->ifindex == dev->ifindex)) {
atomic_inc(&mc->mca_users);
return 0;
}
@@ -495,7 +497,7 @@ void igmp6_timer_handler(unsigned long data)
ma->mca_flags &= ~MAF_TIMER_RUNNING;
}
-void igmp6_init(struct net_proto_family *ops)
+__initfunc(void igmp6_init(struct net_proto_family *ops))
{
struct sock *sk;
int err;
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 3a1704f37..83b5cf3bc 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -6,7 +6,7 @@
* Pedro Roque <roque@di.fc.ul.pt>
* Mike Shaver <shaver@ingenia.com>
*
- * $Id: ndisc.c,v 1.14 1997/04/12 04:32:51 davem Exp $
+ * $Id: ndisc.c,v 1.15 1997/04/29 09:38:48 mj Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -43,6 +43,7 @@
#include <linux/net.h>
#include <linux/in6.h>
#include <linux/route.h>
+#include <linux/init.h>
#include <linux/if_arp.h>
#include <linux/ipv6.h>
@@ -1647,7 +1648,7 @@ struct proc_dir_entry ndisc_proc_entry =
};
#endif /* CONFIG_PROC_FS */
-void ndisc_init(struct net_proto_family *ops)
+__initfunc(void ndisc_init(struct net_proto_family *ops))
{
struct sock *sk;
int err;
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index d04464e26..b8e6ac4a5 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -5,7 +5,7 @@
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: route.c,v 1.11 1997/04/16 05:58:05 davem Exp $
+ * $Id: route.c,v 1.12 1997/04/29 09:38:50 mj Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -22,6 +22,7 @@
#include <linux/route.h>
#include <linux/netdevice.h>
#include <linux/in6.h>
+#include <linux/init.h>
#ifdef CONFIG_PROC_FS
#include <linux/proc_fs.h>
@@ -1573,7 +1574,7 @@ static struct proc_dir_entry proc_rt6_tree = {
};
#endif /* CONFIG_PROC_FS */
-void ip6_route_init(void)
+__initfunc(void ip6_route_init(void))
{
#ifdef CONFIG_PROC_FS
proc_net_register(&proc_rt6_info);
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index 4b072889c..d818bc777 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -5,7 +5,7 @@
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: sit.c,v 1.13 1997/03/18 18:24:50 davem Exp $
+ * $Id: sit.c,v 1.14 1997/04/29 09:38:52 mj Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -23,6 +23,7 @@
#include <linux/netdevice.h>
#include <linux/if_arp.h>
#include <linux/icmp.h>
+#include <linux/init.h>
#include <net/sock.h>
#include <net/snmp.h>
@@ -243,7 +244,7 @@ static int sit_close(struct device *dev)
return 0;
}
-int sit_init(void)
+__initfunc(int sit_init(void))
{
int i;
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 5151013a7..3c61f7b50 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -5,7 +5,7 @@
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: tcp_ipv6.c,v 1.27 1997/04/22 02:53:20 davem Exp $
+ * $Id: tcp_ipv6.c,v 1.31 1997/04/29 21:51:23 davem Exp $
*
* Based on:
* linux/net/ipv4/tcp.c
@@ -27,6 +27,7 @@
#include <linux/in.h>
#include <linux/in6.h>
#include <linux/netdevice.h>
+#include <linux/init.h>
#include <linux/ipv6.h>
#include <linux/icmpv6.h>
@@ -432,21 +433,32 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
tp->snd_nxt = sk->write_seq;
buff->end_seq = sk->write_seq;
th->ack = 0;
- th->window = 2;
th->syn = 1;
- tp->window_clamp = 0;
sk->mtu = dst->pmtu;
sk->mss = sk->mtu - sizeof(struct ipv6hdr) - sizeof(struct tcphdr);
+ if (sk->mss < 1) {
+ printk(KERN_DEBUG "intial ipv6 sk->mss below 1\n");
+ sk->mss = 1; /* Sanity limit */
+ }
+
+ tp->window_clamp = 0; /* FIXME: shouldn't ipv6 dst cache have this? */
+ tcp_select_initial_window(sock_rspace(sk)/2,sk->mss,
+ &tp->rcv_wnd,
+ &tp->window_clamp,
+ sysctl_tcp_window_scaling,
+ &tp->rcv_wscale);
+ th->window = htons(tp->rcv_wnd);
+
/*
* Put in the TCP options to say MTU.
*/
tmp = tcp_syn_build_options(buff, sk->mss, sysctl_tcp_sack,
sysctl_tcp_timestamps,
- sysctl_tcp_window_scaling?tp->rcv_wscale:0);
+ sysctl_tcp_window_scaling,tp->rcv_wscale);
th->doff = sizeof(*th)/4 + (tmp>>2);
buff->csum = 0;
tcp_v6_send_check(sk, th, sizeof(struct tcphdr) + tmp, buff);
@@ -586,9 +598,11 @@ void tcp_v6_err(int type, int code, unsigned char *header, __u32 info,
}
+/* FIXME: this is substantially similar to the ipv4 code.
+ * Can some kind of merge be done? -- erics
+ */
static void tcp_v6_send_synack(struct sock *sk, struct open_request *req)
{
- struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
struct sk_buff * skb;
struct tcphdr *th;
struct dst_entry *dst;
@@ -630,11 +644,32 @@ static void tcp_v6_send_synack(struct sock *sk, struct open_request *req)
th->seq = ntohl(skb->seq);
th->ack_seq = htonl(req->rcv_isn + 1);
th->doff = sizeof(*th)/4 + 1;
-
- th->window = ntohs(tp->rcv_wnd);
- tmp = tcp_syn_build_options(skb, sk->mss, req->sack_ok, req->tstamp_ok,
- (req->snd_wscale)?tp->rcv_wscale:0);
+ /* Don't offer more than they did.
+ * This way we don't have to memorize who said what.
+ * FIXME: the selection of initial mss here doesn't quite
+ * match what happens under IPV4. Figure out the right thing to do.
+ */
+ req->mss = min(sk->mss, req->mss);
+
+ if (req->mss < 1) {
+ printk(KERN_DEBUG "initial req->mss below 1\n");
+ req->mss = 1;
+ }
+
+ if (req->rcv_wnd == 0) {
+ /* Set this up on the first call only */
+ req->window_clamp = 0; /* FIXME: should be in dst cache */
+ tcp_select_initial_window(sock_rspace(sk)/2,req->mss,
+ &req->rcv_wnd,
+ &req->window_clamp,
+ req->wscale_ok,
+ &req->rcv_wscale);
+ }
+ th->window = htons(req->rcv_wnd);
+
+ tmp = tcp_syn_build_options(skb, req->mss, req->sack_ok, req->tstamp_ok,
+ req->snd_wscale,req->rcv_wscale);
th->doff = sizeof(*th)/4 + (tmp>>2);
th->check = tcp_v6_check(th, sizeof(*th) + tmp,
&req->af.v6_req.loc_addr, &req->af.v6_req.rmt_addr,
@@ -656,10 +691,13 @@ static struct or_calltable or_ipv6 = {
tcp_v6_or_free
};
+/* FIXME: this is substantially similar to the ipv4 code.
+ * Can some kind of merge be done? -- erics
+ */
static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb, void *ptr,
__u32 isn)
{
- struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
+ struct tcp_opt tp;
struct open_request *req;
__u16 req_mss;
@@ -691,14 +729,20 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb, void *ptr,
sk->ack_backlog++;
+ req->rcv_wnd = 0; /* So that tcp_send_synack() knows! */
+
req->rcv_isn = skb->seq;
req->snt_isn = isn;
-
- tcp_parse_options(skb->h.th,tp);
- req_mss = tp->in_mss;
- if (!req_mss)
- req_mss = 536;
- req->mss = req_mss;
+ tp.tstamp_ok = tp.sack_ok = tp.wscale_ok = tp.snd_wscale = 0;
+ tp.in_mss = 536;
+ tcp_parse_options(skb->h.th,&tp);
+ if (tp.saw_tstamp)
+ req->ts_recent = tp.rcv_tsval;
+ req->mss = tp.in_mss;
+ req->tstamp_ok = tp.tstamp_ok;
+ req->sack_ok = tp.sack_ok;
+ req->snd_wscale = tp.snd_wscale;
+ req->wscale_ok = tp.wscale_ok;
req->rmt_port = skb->h.th->source;
ipv6_addr_copy(&req->af.v6_req.rmt_addr, &skb->nh.ipv6h->saddr);
ipv6_addr_copy(&req->af.v6_req.loc_addr, &skb->nh.ipv6h->daddr);
@@ -876,6 +920,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
newtp->sack_ok = req->sack_ok;
newtp->tstamp_ok = req->tstamp_ok;
newtp->snd_wscale = req->snd_wscale;
+ newtp->wscale_ok = req->wscale_ok;
newtp->ts_recent = req->ts_recent;
if (newtp->tstamp_ok) {
newtp->tcp_header_len = sizeof(struct tcphdr) + 12; /* FIXME: define the contant. */
@@ -1305,8 +1350,11 @@ static int tcp_v6_init_sock(struct sock *sk)
tp->ato = 0;
tp->iat = (HZ/5) << 3;
-
- tp->rcv_wnd = 8192;
+
+ /* FIXME: right thing? */
+ tp->rcv_wnd = 0;
+ tp->in_mss = 536;
+ /* tp->rcv_wnd = 8192; */
/* start with only sending one packet at a time. */
tp->snd_cwnd = 1;
@@ -1320,7 +1368,7 @@ static int tcp_v6_init_sock(struct sock *sk)
sk->max_ack_backlog = SOMAXCONN;
sk->mtu = 576;
- sk->mss = 516;
+ sk->mss = 536;
sk->dummy_th.doff = sizeof(sk->dummy_th)/4;
@@ -1416,7 +1464,7 @@ static struct inet6_protocol tcpv6_protocol =
"TCPv6" /* name */
};
-void tcpv6_init(void)
+__initfunc(void tcpv6_init(void))
{
/* register inet6 protocol */
inet6_add_protocol(&tcpv6_protocol);
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 1f0fb8ce5..f18f5a6f8 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -7,7 +7,7 @@
*
* Based on linux/ipv4/udp.c
*
- * $Id: udp.c,v 1.16 1997/04/11 22:22:57 davem Exp $
+ * $Id: udp.c,v 1.17 1997/04/29 09:38:55 mj Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -26,6 +26,7 @@
#include <linux/if_arp.h>
#include <linux/ipv6.h>
#include <linux/icmpv6.h>
+#include <linux/init.h>
#include <net/sock.h>
#include <net/snmp.h>
@@ -770,7 +771,7 @@ struct proto udpv6_prot = {
0 /* highestinuse */
};
-void udpv6_init(void)
+__initfunc(void udpv6_init(void))
{
inet6_add_protocol(&udpv6_protocol);
}
diff --git a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c
index 5b131e4a9..cfb47bb42 100644
--- a/net/ipx/af_ipx.c
+++ b/net/ipx/af_ipx.c
@@ -91,6 +91,7 @@
#include <linux/proc_fs.h>
#include <linux/stat.h>
#include <linux/firewall.h>
+#include <linux/init.h>
#ifdef MODULE
static void ipx_proto_finito(void);
@@ -2434,7 +2435,7 @@ ipx_proto_init(struct net_proto *pro)
* sockets be closed from user space.
*/
-static void ipx_proto_finito(void)
+__initfunc(static void ipx_proto_finito(void))
{ ipx_interface *ifc;
while (ipx_interfaces) {
diff --git a/net/lapb/.cvsignore b/net/lapb/.cvsignore
new file mode 100644
index 000000000..4671378ae
--- /dev/null
+++ b/net/lapb/.cvsignore
@@ -0,0 +1 @@
+.depend
diff --git a/net/lapb/lapb_iface.c b/net/lapb/lapb_iface.c
index d5b586e04..f28f8fb8d 100644
--- a/net/lapb/lapb_iface.c
+++ b/net/lapb/lapb_iface.c
@@ -39,6 +39,7 @@
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/stat.h>
+#include <linux/init.h>
#include <net/lapb.h>
static lapb_cb *volatile lapb_list = NULL;
@@ -397,7 +398,7 @@ EXPORT_SYMBOL(lapb_disconnect_request);
EXPORT_SYMBOL(lapb_data_request);
EXPORT_SYMBOL(lapb_data_received);
-void lapb_proto_init(struct net_proto *pro)
+__initfunc(void lapb_proto_init(struct net_proto *pro))
{
printk(KERN_INFO "LAPB for Linux. Version 0.01 for Linux NET3.038 (Linux 2.1)\n");
}
diff --git a/net/netbeui/af_netbeui.c b/net/netbeui/af_netbeui.c
index e6683d00f..9b1444997 100644
--- a/net/netbeui/af_netbeui.c
+++ b/net/netbeui/af_netbeui.c
@@ -31,6 +31,7 @@
#include <linux/proc_fs.h>
#include <linux/stat.h>
#include <linux/firewall.h>
+#include <linux/init.h>
#undef NETBEUI_DEBUG
@@ -620,7 +621,7 @@ static struct proc_dir_entry proc_netbeui = {
/* Called by proto.c on kernel start up */
-void netbeui_proto_init(struct net_proto *pro)
+__initfunc(void netbeui_proto_init(struct net_proto *pro))
{
(void) sock_register(netbeui_proto_ops.family, &netbeui_proto_ops);
if ((nb_dl = register_8022_client(nb_8022_id, netbeui_rcv)) == NULL)
diff --git a/net/netlink.c b/net/netlink.c
index 8c3b0aecc..539ec4295 100644
--- a/net/netlink.c
+++ b/net/netlink.c
@@ -23,6 +23,7 @@
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/skbuff.h>
+#include <linux/init.h>
#include <net/netlink.h>
@@ -443,7 +444,7 @@ void nlmsg_transmit(struct nlmsg_ctl *ctl)
}
-int init_netlink(void)
+__initfunc(int init_netlink(void))
{
int ct;
diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c
index d66094134..c7383e228 100644
--- a/net/netrom/af_netrom.c
+++ b/net/netrom/af_netrom.c
@@ -64,6 +64,7 @@
#include <net/ip.h>
#include <net/arp.h>
#include <linux/if_arp.h>
+#include <linux/init.h>
int sysctl_netrom_default_path_quality = NR_DEFAULT_QUAL;
int sysctl_netrom_obsolescence_count_initialiser = NR_DEFAULT_OBS;
@@ -1361,7 +1362,7 @@ static struct device dev_nr[] = {
{"nr3", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, nr_init}
};
-void nr_proto_init(struct net_proto *pro)
+__initfunc(void nr_proto_init(struct net_proto *pro))
{
int i;
diff --git a/net/netrom/sysctl_net_netrom.c b/net/netrom/sysctl_net_netrom.c
index 2502885a3..c6a415ee6 100644
--- a/net/netrom/sysctl_net_netrom.c
+++ b/net/netrom/sysctl_net_netrom.c
@@ -7,6 +7,7 @@
#include <linux/mm.h>
#include <linux/sysctl.h>
+#include <linux/init.h>
#include <net/ax25.h>
#include <net/netrom.h>
@@ -78,7 +79,7 @@ static ctl_table nr_root_table[] = {
{0}
};
-void nr_register_sysctl(void)
+__initfunc(void nr_register_sysctl(void))
{
nr_table_header = register_sysctl_table(nr_root_table, 1);
}
diff --git a/net/netsyms.c b/net/netsyms.c
index 34946a5b7..118841c32 100644
--- a/net/netsyms.c
+++ b/net/netsyms.c
@@ -73,9 +73,6 @@ extern void destroy_8023_client(struct datalink_proto *);
#include <net/sock.h>
#endif
-extern char *skb_push_errstr;
-extern char *skb_put_errstr;
-
/* Skbuff symbols. */
EXPORT_SYMBOL(skb_push_errstr);
EXPORT_SYMBOL(skb_put_errstr);
@@ -200,6 +197,10 @@ EXPORT_SYMBOL(csum_partial_copy_fromiovecend);
EXPORT_SYMBOL(__release_sock);
EXPORT_SYMBOL(net_timer);
/* UDP/TCP exported functions for TCPv6 */
+EXPORT_SYMBOL(sysctl_tcp_sack);
+EXPORT_SYMBOL(sysctl_tcp_timestamps);
+EXPORT_SYMBOL(sysctl_tcp_window_scaling);
+EXPORT_SYMBOL(sock_rspace);
EXPORT_SYMBOL(udp_ioctl);
EXPORT_SYMBOL(udp_connect);
EXPORT_SYMBOL(udp_sendmsg);
diff --git a/net/rose/.cvsignore b/net/rose/.cvsignore
new file mode 100644
index 000000000..4671378ae
--- /dev/null
+++ b/net/rose/.cvsignore
@@ -0,0 +1 @@
+.depend
diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c
index f173dedaf..f3309ade9 100644
--- a/net/rose/af_rose.c
+++ b/net/rose/af_rose.c
@@ -52,6 +52,7 @@
#include <net/ip.h>
#include <net/arp.h>
#include <linux/if_arp.h>
+#include <linux/init.h>
int sysctl_rose_restart_request_timeout = ROSE_DEFAULT_T0;
int sysctl_rose_call_request_timeout = ROSE_DEFAULT_T1;
@@ -1381,7 +1382,7 @@ static struct device dev_rose[] = {
{"rose5", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, rose_init}
};
-void rose_proto_init(struct net_proto *pro)
+__initfunc(void rose_proto_init(struct net_proto *pro))
{
int i;
diff --git a/net/rose/sysctl_net_rose.c b/net/rose/sysctl_net_rose.c
index c899a1837..8cd49695f 100644
--- a/net/rose/sysctl_net_rose.c
+++ b/net/rose/sysctl_net_rose.c
@@ -7,6 +7,7 @@
#include <linux/mm.h>
#include <linux/sysctl.h>
+#include <linux/init.h>
#include <net/ax25.h>
#include <net/rose.h>
@@ -58,7 +59,7 @@ static ctl_table rose_root_table[] = {
{0}
};
-void rose_register_sysctl(void)
+__initfunc(void rose_register_sysctl(void))
{
rose_table_header = register_sysctl_table(rose_root_table, 1);
}
diff --git a/net/socket.c b/net/socket.c
index 2e53ed446..482255255 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -39,6 +39,8 @@
* for sockets. May have errors at the
* moment.
* Kevin Buhr : Fixed the dumb errors in the above.
+ * Andi Kleen : Some small cleanups, optimizations,
+ * and fixed a copy_from_user() bug.
*
*
* This program is free software; you can redistribute it and/or
@@ -71,6 +73,7 @@
#include <linux/proc_fs.h>
#include <linux/firewall.h>
#include <linux/wanrouter.h>
+#include <linux/init.h>
#if defined(CONFIG_KERNELD) && defined(CONFIG_NET)
#include <linux/kerneld.h>
@@ -179,7 +182,7 @@ int move_addr_to_user(void *kaddr, int klen, void *uaddr, int *ulen)
* "fromlen shall refer to the value before truncation.."
* 1003.1g
*/
- return put_user(klen, ulen);
+ return __put_user(klen, ulen);
}
/*
@@ -207,7 +210,6 @@ static int get_fd(struct inode *inode)
file->f_op = &socket_file_ops;
file->f_mode = 3;
file->f_flags = O_RDWR;
- file->f_count = 1;
file->f_inode = inode;
if (inode)
inode->i_count++;
@@ -365,6 +367,7 @@ static long sock_read(struct inode *inode, struct file *file,
if (size==0) /* Match SYS5 behaviour */
return 0;
+ /* FIXME: I think this can be removed now. */
if ((err=verify_area(VERIFY_WRITE,ubuf,size))<0)
return err;
msg.msg_name=NULL;
@@ -398,7 +401,8 @@ static long sock_write(struct inode *inode, struct file *file,
if(size==0) /* Match SYS5 behaviour */
return 0;
-
+
+ /* FIXME: I think this can be removed now */
if ((err=verify_area(VERIFY_READ,ubuf,size))<0)
return err;
@@ -797,7 +801,6 @@ asmlinkage int sys_accept(int fd, struct sockaddr *upeer_sockaddr, int *upeer_ad
{
if (!(newsock = sock_alloc()))
{
- printk(KERN_WARNING "accept: no more sockets\n");
err=-EMFILE;
goto out;
}
@@ -1130,6 +1133,7 @@ asmlinkage int sys_sendmsg(int fd, struct msghdr *msg, unsigned flags)
struct msghdr msg_sys;
int err= -EINVAL;
int total_len;
+ unsigned char *ctl_buf = ctl;
lock_kernel();
@@ -1149,22 +1153,26 @@ asmlinkage int sys_sendmsg(int fd, struct msghdr *msg, unsigned flags)
if (msg_sys.msg_controllen)
{
- if (msg_sys.msg_controllen > sizeof(ctl))
+ /* XXX We just limit the buffer and assume that the
+ * skbuff accounting stops it from going too far.
+ * I hope this is correct.
+ */
+ if (msg_sys.msg_controllen > sizeof(ctl) &&
+ msg_sys.msg_controllen <= 256)
{
- char *tmp = kmalloc(msg_sys.msg_controllen, GFP_KERNEL);
- if (tmp == NULL)
+ ctl_buf = kmalloc(msg_sys.msg_controllen, GFP_KERNEL);
+ if (ctl_buf == NULL)
{
err = -ENOBUFS;
goto failed2;
}
- err = copy_from_user(tmp, msg_sys.msg_control, msg_sys.msg_controllen);
- msg_sys.msg_control = tmp;
- } else {
- err = copy_from_user(ctl, msg_sys.msg_control, msg_sys.msg_controllen);
- msg_sys.msg_control = ctl;
}
- if (err)
+ if (copy_from_user(ctl_buf, msg_sys.msg_control,
+ msg_sys.msg_controllen)) {
+ err = -EFAULT;
goto failed;
+ }
+ msg_sys.msg_control = ctl_buf;
}
msg_sys.msg_flags = flags;
if (current->files->fd[fd]->f_flags & O_NONBLOCK)
@@ -1177,8 +1185,8 @@ asmlinkage int sys_sendmsg(int fd, struct msghdr *msg, unsigned flags)
}
failed:
- if (msg_sys.msg_controllen && msg_sys.msg_control != ctl)
- kfree(msg_sys.msg_control);
+ if (ctl_buf != ctl)
+ kfree_s(ctl_buf, msg_sys.msg_controllen);
failed2:
if (msg_sys.msg_iov != iov)
kfree(msg_sys.msg_iov);
@@ -1240,7 +1248,6 @@ asmlinkage int sys_recvmsg(int fd, struct msghdr *msg, unsigned int flags)
if (current->files->fd[fd]->f_flags&O_NONBLOCK)
flags |= MSG_DONTWAIT;
-
if ((sock = sockfd_lookup(fd, &err))!=NULL)
{
err=sock_recvmsg(sock, &msg_sys, total_len, flags);
@@ -1253,9 +1260,12 @@ asmlinkage int sys_recvmsg(int fd, struct msghdr *msg, unsigned int flags)
if (uaddr != NULL && err>=0)
err = move_addr_to_user(addr, msg_sys.msg_namelen, uaddr, uaddr_len);
- if (err>=0 && (put_user(msg_sys.msg_flags, &msg->msg_flags) ||
- put_user((unsigned long)msg_sys.msg_control-cmsg_ptr, &msg->msg_controllen)))
- err = -EFAULT;
+ if (err>=0) {
+ err = __put_user(msg_sys.msg_flags, &msg->msg_flags);
+ if (!err)
+ err = __put_user((unsigned long)msg_sys.msg_control-cmsg_ptr,
+ &msg->msg_controllen);
+ }
out:
unlock_kernel();
if(err<0)
@@ -1280,33 +1290,33 @@ int sock_fcntl(struct file *filp, unsigned int cmd, unsigned long arg)
return(-EINVAL);
}
+/* Argument list sizes for sys_socketcall */
+#define AL(x) ((x) * sizeof(unsigned long))
+static unsigned char nargs[18]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3),
+ AL(3),AL(3),AL(4),AL(4),AL(4),AL(6),
+ AL(6),AL(2),AL(5),AL(5),AL(3),AL(3)};
+#undef AL
/*
* System call vectors.
*
* Argument checking cleaned up. Saved 20% in size.
+ * This function doesn't need to set the kernel lock because
+ * it is set by the callees.
*/
asmlinkage int sys_socketcall(int call, unsigned long *args)
{
- unsigned char nargs[18]={0,3,3,3,2,3,3,3,
- 4,4,4,6,6,2,5,5,3,3};
unsigned long a[6];
unsigned long a0,a1;
- int err = -EINVAL;
-
- lock_kernel();
+ int err;
+
if(call<1||call>SYS_RECVMSG)
- goto out;
- err = -EFAULT;
+ return -EINVAL;
- /*
- * Ideally we want to precompute the maths, but unsigned long
- * isnt a fixed size....
- */
-
- if ((copy_from_user(a, args, nargs[call] * sizeof(unsigned long))))
- goto out;
+ /* copy_from_user should be SMP safe. */
+ if (copy_from_user(a, args, nargs[call]))
+ return -EFAULT;
a0=a[0];
a1=a[1];
@@ -1370,12 +1380,9 @@ asmlinkage int sys_socketcall(int call, unsigned long *args)
err = -EINVAL;
break;
}
-out:
- unlock_kernel();
return err;
}
-
/*
* This function is called by a protocol handler that wants to
* advertise its address family, and have it linked into the
@@ -1400,7 +1407,7 @@ int sock_unregister(int family)
return 0;
}
-void proto_init(void)
+__initfunc(void proto_init(void))
{
extern struct net_proto protocols[]; /* Network protocols */
struct net_proto *pro;
@@ -1417,7 +1424,7 @@ void proto_init(void)
extern void sk_init(void);
-void sock_init(void)
+__initfunc(void sock_init(void))
{
int i;
diff --git a/net/sunrpc/.cvsignore b/net/sunrpc/.cvsignore
new file mode 100644
index 000000000..4671378ae
--- /dev/null
+++ b/net/sunrpc/.cvsignore
@@ -0,0 +1 @@
+.depend
diff --git a/net/sunrpc/pmap_clnt.c b/net/sunrpc/pmap_clnt.c
index cb1a641e7..4a05efd9c 100644
--- a/net/sunrpc/pmap_clnt.c
+++ b/net/sunrpc/pmap_clnt.c
@@ -79,6 +79,8 @@ bailout:
}
#ifdef CONFIG_ROOT_NFS
+char *in_ntoa(__u32 in);
+
int
rpc_getport_external(struct sockaddr_in *sin, __u32 prog, __u32 vers, int prot)
{
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 7c4d4679d..80d91481e 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -81,6 +81,7 @@
#include <net/af_unix.h>
#include <linux/proc_fs.h>
#include <net/scm.h>
+#include <linux/init.h>
#include <asm/checksum.h>
@@ -1459,7 +1460,7 @@ struct net_proto_family unix_family_ops = {
unix_create
};
-void unix_proto_init(struct net_proto *pro)
+__initfunc(void unix_proto_init(struct net_proto *pro))
{
struct sk_buff *dummy_skb;
struct proc_dir_entry *ent;
diff --git a/net/wanrouter/.cvsignore b/net/wanrouter/.cvsignore
new file mode 100644
index 000000000..4671378ae
--- /dev/null
+++ b/net/wanrouter/.cvsignore
@@ -0,0 +1 @@
+.depend
diff --git a/net/wanrouter/wanmain.c b/net/wanrouter/wanmain.c
index 948bf81fa..4c0042082 100644
--- a/net/wanrouter/wanmain.c
+++ b/net/wanrouter/wanmain.c
@@ -34,6 +34,7 @@
#include <asm/byteorder.h> /* htons(), etc. */
#include <asm/uaccess.h> /* copy_to/from_user */
#include <linux/wanrouter.h> /* WAN router API definitions */
+#include <linux/init.h> /* __initfunc et al. */
/****** Defines and Macros **************************************************/
@@ -130,7 +131,7 @@ void cleanup_module (void)
#else
-void wanrouter_init(void)
+__initfunc(void wanrouter_init(void))
{
int err = wanrouter_proc_init();
if (err) printk(KERN_ERR
diff --git a/net/wanrouter/wanproc.c b/net/wanrouter/wanproc.c
index ce7140db0..de207d319 100644
--- a/net/wanrouter/wanproc.c
+++ b/net/wanrouter/wanproc.c
@@ -23,6 +23,7 @@
#include <linux/malloc.h> /* kmalloc(), kfree() */
#include <linux/mm.h> /* verify_area(), etc. */
#include <linux/string.h> /* inline mem*, str* functions */
+#include <linux/init.h> /* __initfunc et al. */
#include <asm/segment.h> /* kernel <-> user copy */
#include <asm/byteorder.h> /* htons(), etc. */
#include <asm/uaccess.h> /* copy_to_user */
@@ -271,7 +272,7 @@ static struct proc_dir_entry proc_router_stat =
* Initialize router proc interface.
*/
-int wanrouter_proc_init (void)
+__initfunc(int wanrouter_proc_init (void))
{
int err = proc_register(&proc_net, &proc_router);
diff --git a/net/x25/.cvsignore b/net/x25/.cvsignore
new file mode 100644
index 000000000..4671378ae
--- /dev/null
+++ b/net/x25/.cvsignore
@@ -0,0 +1 @@
+.depend
diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c
index 971ae497d..63a616e89 100644
--- a/net/x25/af_x25.c
+++ b/net/x25/af_x25.c
@@ -45,6 +45,7 @@
#include <linux/notifier.h>
#include <linux/proc_fs.h>
#include <linux/if_arp.h>
+#include <linux/init.h>
#include <net/x25.h>
int sysctl_x25_restart_request_timeout = X25_DEFAULT_T20;
@@ -1283,7 +1284,7 @@ static struct proc_dir_entry proc_net_x25_routes = {
};
#endif
-void x25_proto_init(struct net_proto *pro)
+__initfunc(void x25_proto_init(struct net_proto *pro))
{
sock_register(&x25_family_ops);
diff --git a/net/x25/sysctl_net_x25.c b/net/x25/sysctl_net_x25.c
index 892d817d7..8454ac9d9 100644
--- a/net/x25/sysctl_net_x25.c
+++ b/net/x25/sysctl_net_x25.c
@@ -10,6 +10,7 @@
#include <linux/skbuff.h>
#include <linux/socket.h>
#include <linux/netdevice.h>
+#include <linux/init.h>
#include <net/x25.h>
static int min_timer[] = {1 * X25_SLOWHZ};
@@ -46,7 +47,7 @@ static ctl_table x25_root_table[] = {
{0}
};
-void x25_register_sysctl(void)
+__initfunc(void x25_register_sysctl(void))
{
x25_table_header = register_sysctl_table(x25_root_table, 1);
}
diff --git a/scripts/mkdep.c b/scripts/mkdep.c
index d8ecde881..4afbd7381 100644
--- a/scripts/mkdep.c
+++ b/scripts/mkdep.c
@@ -6,6 +6,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
+#include <errno.h>
#include <sys/fcntl.h>
#include <sys/mman.h>
@@ -256,7 +257,7 @@ static void do_depend(void)
}
mapsize = st.st_size + 2*sizeof(unsigned long);
mapsize = (mapsize+pagesizem1) & ~pagesizem1;
- map = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, fd, 0);
+ map = mmap(NULL, mapsize, PROT_READ, MAP_AUTOGROW | MAP_PRIVATE, fd, 0);
if (-1 == (long)map) {
perror("mkdep: mmap");
close(fd);