From 8624512aa908741ba2795200133eae0d7f4557ea Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 2 Mar 2000 02:36:47 +0000 Subject: Merge with 2.3.48. --- CREDITS | 38 +- Documentation/Changes | 22 +- Documentation/Configure.help | 303 +- Documentation/IRQ-affinity.txt | 37 + Documentation/fb/matroxfb.txt | 31 +- Documentation/floppy.txt | 222 ++ Documentation/ide.txt | 2 +- Documentation/ioctl-number.txt | 3 +- Documentation/m68k/README.buddha | 210 ++ Documentation/networking/8139too.txt | 194 + Documentation/networking/fore200e.txt | 55 + Documentation/networking/tulip.txt | 244 +- Documentation/networking/wavelan.txt | 114 +- Documentation/parport-lowlevel.txt | 1490 ++++++++ Documentation/pci.txt | 2 + Documentation/pm.txt | 151 + Documentation/vm/balance | 14 +- MAINTAINERS | 17 +- Makefile | 2 +- arch/alpha/config.in | 5 + arch/alpha/kernel/alpha_ksyms.c | 6 + arch/alpha/kernel/core_tsunami.c | 35 +- arch/alpha/kernel/irq.c | 68 +- arch/alpha/kernel/pci_iommu.c | 53 +- arch/alpha/kernel/process.c | 109 +- arch/alpha/kernel/proto.h | 3 +- arch/alpha/kernel/semaphore.c | 4 +- arch/alpha/kernel/setup.c | 4 + arch/alpha/kernel/smp.c | 41 +- arch/alpha/kernel/sys_cabriolet.c | 26 +- arch/alpha/kernel/sys_dp264.c | 124 +- arch/alpha/kernel/sys_sio.c | 2 +- arch/alpha/kernel/time.c | 1 - arch/alpha/kernel/traps.c | 4 +- arch/alpha/vmlinux.lds | 1 - arch/arm/kernel/armksyms.c | 1 - arch/arm/mm/consistent.c | 6 - arch/i386/defconfig | 3 + arch/i386/kernel/acpi.c | 37 +- arch/i386/kernel/apm.c | 14 +- arch/i386/kernel/entry.S | 2 + arch/i386/kernel/i386_ksyms.c | 4 +- arch/i386/kernel/i8259.c | 36 +- arch/i386/kernel/io_apic.c | 102 +- arch/i386/kernel/irq.c | 419 ++- arch/i386/kernel/microcode.c | 46 +- arch/i386/kernel/mpparse.c | 29 +- arch/i386/kernel/mtrr.c | 9 +- arch/i386/kernel/process.c | 9 +- arch/i386/kernel/semaphore.c | 5 +- arch/i386/kernel/setup.c | 17 +- arch/i386/kernel/traps.c | 5 +- arch/i386/mm/init.c | 4 - arch/ia64/ia32/binfmt_elf32.c | 2 + arch/ia64/ia32/ia32_entry.S | 2 +- arch/ia64/ia32/sys_ia32.c | 21 +- arch/ia64/kdb/kdbsupport.c | 27 +- arch/ia64/kernel/irq.c | 3 + arch/ia64/kernel/irq_internal.c | 2 +- arch/ia64/kernel/ivt.S | 2 +- arch/ia64/kernel/process.c | 8 + arch/ia64/kernel/time.c | 20 +- arch/ia64/kernel/traps.c | 116 +- arch/ia64/kernel/unaligned.c | 47 +- arch/ia64/lib/copy_user.S | 440 ++- arch/mips/defconfig | 4 +- arch/mips/kernel/irixelf.c | 21 +- arch/mips/kernel/irq.c | 20 +- arch/mips/kernel/mips_ksyms.c | 4 +- arch/mips/kernel/proc.c | 5 + arch/mips/kernel/setup.c | 4 +- arch/mips/sgi/kernel/indy_int.c | 20 +- arch/mips64/defconfig | 1 + arch/mips64/defconfig-ip22 | 1 + arch/mips64/defconfig-ip27 | 1 + arch/mips64/kernel/proc.c | 7 +- arch/mips64/kernel/setup.c | 4 +- arch/mips64/sgi-ip22/ip22-int.c | 20 +- arch/mips64/sgi-ip27/ip27-irq.c | 22 +- arch/ppc/chrpboot/main.c | 20 +- arch/ppc/chrpboot/piggyback.c | 3 +- arch/ppc/coffboot/piggyback.c | 3 +- arch/ppc/config.in | 7 +- arch/ppc/configs/common_defconfig | 26 +- arch/ppc/defconfig | 26 +- arch/ppc/kernel/Makefile | 20 +- arch/ppc/kernel/apus_setup.c | 159 +- arch/ppc/kernel/entry.S | 4 +- arch/ppc/kernel/hashtable.S | 80 +- arch/ppc/kernel/head.S | 7 +- arch/ppc/kernel/irq.c | 3 - arch/ppc/kernel/misc.S | 11 +- arch/ppc/kernel/mk_defs.c | 1 + arch/ppc/kernel/pmac_pic.c | 24 +- arch/ppc/kernel/ppc_htab.c | 9 +- arch/ppc/kernel/ppc_ksyms.c | 17 +- arch/ppc/kernel/process.c | 2 +- arch/ppc/kernel/prom.c | 1 - arch/ppc/kernel/setup.c | 60 +- arch/ppc/kernel/smp.c | 3 + arch/ppc/mm/init.c | 86 +- arch/ppc/mm/mem_pieces.c | 2 +- arch/ppc/xmon/xmon.c | 46 +- arch/sparc/boot/Makefile | 14 +- arch/sparc/kernel/ioport.c | 40 +- arch/sparc/kernel/irq.c | 7 +- arch/sparc/kernel/setup.c | 6 +- arch/sparc/kernel/sparc_ksyms.c | 4 +- arch/sparc/lib/locks.S | 21 +- arch/sparc/mm/init.c | 4 +- arch/sparc64/defconfig | 6 +- arch/sparc64/kernel/irq.c | 7 +- arch/sparc64/kernel/setup.c | 6 +- arch/sparc64/kernel/signal32.c | 4 +- arch/sparc64/kernel/sparc64_ksyms.c | 3 +- arch/sparc64/lib/VIScsum.S | 693 ++-- arch/sparc64/lib/VIScsumcopy.S | 1176 +++--- arch/sparc64/lib/VIScsumcopyusr.S | 1162 +++--- drivers/Makefile | 5 + drivers/atm/Config.in | 25 + drivers/atm/Makefile | 52 + drivers/atm/atmdev_init.c | 6 + drivers/atm/eni.c | 125 +- drivers/atm/eni.h | 4 + drivers/atm/fore200e.c | 2973 +++++++++++++++ drivers/atm/fore200e.h | 952 +++++ drivers/atm/fore200e_firmware_copyright | 31 + drivers/atm/fore200e_mkfirm.c | 155 + drivers/atm/iphase.c | 6 +- drivers/atm/pca200e.data | 850 +++++ drivers/atm/pca200e_ecd.data | 906 +++++ drivers/atm/sba200e_ecd.data | 928 +++++ drivers/atm/zatm.c | 11 +- drivers/block/Config.in | 45 +- drivers/block/Makefile | 8 +- drivers/block/README.buddha | 210 -- drivers/block/README.fd | 222 -- drivers/block/README.lvm | 8 - drivers/block/README.md | 4 - drivers/block/aec6210.c | 64 +- drivers/block/ali14xx.c | 12 +- drivers/block/alim15x3.c | 21 +- drivers/block/amd7409.c | 220 +- drivers/block/buddha.c | 10 +- drivers/block/cmd640.c | 20 +- drivers/block/cmd64x.c | 278 +- drivers/block/cs5530.c | 174 +- drivers/block/cy82c693.c | 5 +- drivers/block/dtc2278.c | 4 +- drivers/block/falconide.c | 4 +- drivers/block/gayle.c | 4 +- drivers/block/hpt34x.c | 87 +- drivers/block/hpt366.c | 84 +- drivers/block/ht6560b.c | 359 +- drivers/block/ide-cd.h | 8 +- drivers/block/ide-disk.c | 2 +- drivers/block/ide-dma.c | 21 +- drivers/block/ide-features.c | 199 +- drivers/block/ide-floppy.c | 9 +- drivers/block/ide-pci.c | 54 +- drivers/block/ide-probe.c | 108 +- drivers/block/ide-proc.c | 93 +- drivers/block/ide-tape.c | 191 +- drivers/block/ide.c | 171 +- drivers/block/ide_modes.h | 5 +- drivers/block/linear.c | 8 +- drivers/block/ll_rw_blk.c | 95 +- drivers/block/lvm.c | 13 +- drivers/block/macide.c | 6 +- drivers/block/md.c | 102 +- drivers/block/ns87415.c | 2 +- drivers/block/opti621.c | 2 +- drivers/block/pdc202xx.c | 76 +- drivers/block/pdc4030.c | 2 +- drivers/block/pdc4030.h | 2 +- drivers/block/piix.c | 169 +- drivers/block/qd6580.c | 4 +- drivers/block/raid0.c | 25 +- drivers/block/rapide.c | 6 +- drivers/block/rz1000.c | 2 +- drivers/block/sis5513.c | 11 +- drivers/block/sl82c105.c | 2 +- drivers/block/trm290.c | 2 +- drivers/block/umc8672.c | 6 +- drivers/block/via82cxxx.c | 23 +- drivers/char/Config.in | 3 +- drivers/char/Makefile | 15 +- drivers/char/agp/agpgart_be.c | 2 - drivers/char/ds1620.c | 436 +++ drivers/char/efirtc.c | 2 + drivers/char/h8.c | 74 +- drivers/char/h8.h | 6 +- drivers/char/lp.c | 4 +- drivers/char/mem.c | 12 +- drivers/char/nwbutton.c | 276 ++ drivers/char/nwbutton.h | 48 + drivers/char/nwflash.c | 708 ++++ drivers/char/raw.c | 7 +- drivers/char/rtc.c | 8 +- drivers/char/wdt285.c | 204 ++ drivers/char/wdt977.c | 204 ++ drivers/i2c/i2c-core.c | 6 +- drivers/isdn/avmb1/b1dma.c | 7 +- drivers/isdn/avmb1/capi.c | 5 +- drivers/isdn/divert/divert_procfs.c | 6 +- drivers/isdn/eicon/eicon_idi.c | 57 +- drivers/isdn/eicon/eicon_isa.c | 11 +- drivers/isdn/eicon/eicon_mod.c | 14 +- drivers/isdn/hisax/avm_pci.c | 11 +- drivers/isdn/hisax/config.c | 9 +- drivers/isdn/hisax/diva.c | 9 +- drivers/isdn/hisax/elsa_ser.c | 8 +- drivers/isdn/hisax/hfc_2bds0.c | 21 +- drivers/isdn/hisax/hfc_2bs0.c | 13 +- drivers/isdn/hisax/hfc_pci.c | 17 +- drivers/isdn/hisax/hfc_sx.c | 20 +- drivers/isdn/hisax/hisax.h | 8 +- drivers/isdn/hisax/hscx.c | 7 +- drivers/isdn/hisax/hscx_irq.c | 7 +- drivers/isdn/hisax/isac.c | 11 +- drivers/isdn/hisax/isar.c | 9 +- drivers/isdn/hisax/jade.c | 7 +- drivers/isdn/hisax/jade_irq.c | 7 +- drivers/isdn/hisax/l3dss1.c | 12 +- drivers/isdn/hisax/md5sums.asc | 24 +- drivers/isdn/hisax/netjet.c | 11 +- drivers/isdn/hisax/w6692.c | 17 +- drivers/isdn/hysdn/hysdn_procconf.c | 6 +- drivers/isdn/hysdn/hysdn_procfs.c | 23 +- drivers/isdn/hysdn/hysdn_proclog.c | 6 +- drivers/isdn/isdn_common.c | 28 +- drivers/isdn/isdn_net.c | 28 +- drivers/isdn/isdn_tty.c | 164 +- drivers/isdn/isdn_tty.h | 36 +- drivers/isdn/sc/debug.h | 2 +- drivers/net/3c505.c | 3 +- drivers/net/8139too.c | 475 +-- drivers/net/Config.in | 4 +- drivers/net/Makefile | 12 +- drivers/net/eepro100.c | 74 +- drivers/net/hamradio/6pack.c | 4 +- drivers/net/irda/nsc-ircc.c | 49 +- drivers/net/irda/smc-ircc.c | 15 +- drivers/net/pcmcia/3c589_cs.c | 3 +- drivers/net/sk_g16.c | 2 +- drivers/net/tokenring/olympic.c | 9 +- drivers/net/tulip.c | 3159 ---------------- drivers/net/tulip/21142.c | 235 ++ drivers/net/tulip/Makefile | 14 + drivers/net/tulip/eeprom.c | 270 ++ drivers/net/tulip/interrupt.c | 337 ++ drivers/net/tulip/media.c | 403 ++ drivers/net/tulip/pnic.c | 146 + drivers/net/tulip/timer.c | 208 ++ drivers/net/tulip/tulip.h | 342 ++ drivers/net/tulip/tulip_core.c | 1391 +++++++ drivers/net/wan/cosa.c | 70 +- drivers/net/wan/syncppp.c | 17 +- drivers/net/wavelan.c | 244 +- drivers/net/wavelan.p.h | 59 +- drivers/parport/daisy.c | 32 +- drivers/parport/parport_pc.c | 190 +- drivers/parport/probe.c | 11 +- drivers/parport/share.c | 14 +- drivers/pci/pci.ids | 2 + drivers/pci/proc.c | 6 +- drivers/pcmcia/i82365.c | 35 - drivers/pcmcia/yenta.c | 70 +- drivers/pnp/isapnp_proc.c | 14 +- drivers/scsi/3w-xxxx.c | 10 +- drivers/scsi/ChangeLog.sym53c8xx | 14 + drivers/scsi/Config.in | 16 +- drivers/scsi/eata_dma_proc.c | 2 +- drivers/scsi/pci2000.c | 3 - drivers/scsi/pci2000.h | 74 +- drivers/scsi/pci2220i.c | 3 - drivers/scsi/pci2220i.h | 74 +- drivers/scsi/qla1280.c | 23 +- drivers/scsi/qlogicfc.c | 355 +- drivers/scsi/qlogicfc.h | 2 +- drivers/scsi/sr_ioctl.c | 4 +- drivers/scsi/sun3_scsi.c | 6 +- drivers/scsi/sym53c8xx.c | 794 ++-- drivers/sound/Makefile | 4 +- drivers/sound/README.CONFIG | 75 - drivers/sound/ac97_codec.c | 3 +- drivers/sound/ac97_codec.h | 161 - drivers/sound/ad1816.c | 4 - drivers/sound/ad1848.c | 26 +- drivers/sound/adlib_card.c | 2 +- drivers/sound/audio.c | 4 - drivers/sound/cs4232.c | 8 +- drivers/sound/dev_table.c | 12 - drivers/sound/dev_table.h | 32 +- drivers/sound/dmabuf.c | 4 - drivers/sound/es1371.c | 38 +- drivers/sound/finetune.h | 32 - drivers/sound/gus_card.c | 16 +- drivers/sound/gus_midi.c | 8 - drivers/sound/gus_vol.c | 3 - drivers/sound/gus_wave.c | 9 - drivers/sound/ics2101.c | 3 - drivers/sound/legacy.h | 50 - drivers/sound/lowlevel/Config.in | 9 + drivers/sound/mad16.c | 21 +- drivers/sound/maui.c | 14 +- drivers/sound/midi_synth.c | 9 - drivers/sound/midibuf.c | 4 - drivers/sound/mpu401.c | 16 +- drivers/sound/opl3.c | 4 +- drivers/sound/opl3sa.c | 16 +- drivers/sound/opl3sa2.c | 15 - drivers/sound/pas2_card.c | 17 +- drivers/sound/pas2_midi.c | 7 - drivers/sound/pas2_mixer.c | 4 - drivers/sound/pas2_pcm.c | 6 - drivers/sound/pss.c | 22 +- drivers/sound/sb.h | 3 - drivers/sound/sb_audio.c | 4 - drivers/sound/sb_card.c | 203 +- drivers/sound/sb_common.c | 40 - drivers/sound/sb_midi.c | 6 - drivers/sound/sb_mixer.c | 24 - drivers/sound/sb_mixer.h | 6 - drivers/sound/sequencer.c | 11 +- drivers/sound/sequencer_syms.c | 1 - drivers/sound/sgalaxy.c | 5 +- drivers/sound/softoss.c | 5 +- drivers/sound/softoss_rs.c | 3 - drivers/sound/sound_config.h | 1 - drivers/sound/sound_timer.c | 4 - drivers/sound/soundcard.c | 66 +- drivers/sound/sscape.c | 10 +- drivers/sound/sys_timer.c | 4 - drivers/sound/trident.c | 4 +- drivers/sound/trix.c | 26 +- drivers/sound/uart401.c | 8 +- drivers/sound/uart6850.c | 7 +- drivers/sound/v_midi.c | 6 +- drivers/sound/vidc.c | 522 ++- drivers/sound/vidc.h | 11 +- drivers/sound/vidc_audio.c | 314 -- drivers/sound/vidc_fill.S | 18 +- drivers/sound/vidc_mixer.c | 151 - drivers/sound/vidc_synth.c | 91 - drivers/sound/waveartist.c | 2 - drivers/sound/wavfront.c | 4 +- drivers/usb/acm.c | 20 +- drivers/usb/devio.c | 6 +- drivers/usb/evdev.c | 14 +- drivers/usb/ftdi_sio.h | 380 ++ drivers/usb/graphire.c | 18 +- drivers/usb/hid.c | 25 +- drivers/usb/inode.c | 40 +- drivers/usb/input.c | 33 - drivers/usb/joydev.c | 38 +- drivers/usb/keybdev.c | 20 +- drivers/usb/mousedev.c | 15 +- drivers/usb/printer.c | 17 +- drivers/usb/scanner.c | 12 +- drivers/usb/usb-core.c | 16 - drivers/usb/usb-ohci.c | 12 +- drivers/usb/usb-serial.c | 590 ++- drivers/usb/usb-serial.h | 64 +- drivers/usb/usb-storage-debug.h | 1 + drivers/usb/usbkbd.c | 18 +- drivers/usb/usbmouse.c | 17 +- drivers/usb/wmforce.c | 18 +- drivers/video/Config.in | 4 + drivers/video/Makefile | 21 +- drivers/video/aty128fb.c | 134 +- drivers/video/atyfb.c | 63 +- drivers/video/matrox/Makefile | 60 + drivers/video/matrox/i2c-matroxfb.c | 348 ++ drivers/video/matrox/matroxfb_DAC1064.c | 924 +++++ drivers/video/matrox/matroxfb_DAC1064.h | 147 + drivers/video/matrox/matroxfb_Ti3026.c | 862 +++++ drivers/video/matrox/matroxfb_Ti3026.h | 13 + drivers/video/matrox/matroxfb_accel.c | 1212 ++++++ drivers/video/matrox/matroxfb_accel.h | 12 + drivers/video/matrox/matroxfb_base.c | 2544 +++++++++++++ drivers/video/matrox/matroxfb_base.h | 825 +++++ drivers/video/matrox/matroxfb_crtc2.c | 788 ++++ drivers/video/matrox/matroxfb_crtc2.h | 44 + drivers/video/matrox/matroxfb_maven.c | 1040 ++++++ drivers/video/matrox/matroxfb_maven.h | 23 + drivers/video/matrox/matroxfb_misc.c | 660 ++++ drivers/video/matrox/matroxfb_misc.h | 21 + drivers/video/matroxfb.c | 6107 ------------------------------- drivers/video/vgacon.c | 7 + drivers/zorro/proc.c | 6 +- fs/Config.in | 2 +- fs/adfs/adfs.h | 2 + fs/adfs/dir.c | 15 +- fs/adfs/file.c | 5 +- fs/adfs/inode.c | 17 +- fs/adfs/super.c | 15 +- fs/affs/dir.c | 30 +- fs/affs/file.c | 39 +- fs/affs/inode.c | 16 +- fs/affs/namei.c | 8 +- fs/affs/super.c | 17 +- fs/affs/symlink.c | 6 + fs/attr.c | 4 +- fs/autofs/autofs_i.h | 2 + fs/autofs/dir.c | 7 +- fs/autofs/inode.c | 18 +- fs/autofs/root.c | 16 +- fs/autofs4/autofs_i.h | 2 + fs/autofs4/inode.c | 7 +- fs/autofs4/root.c | 38 +- fs/bad_inode.c | 30 +- fs/bfs/dir.c | 19 +- fs/bfs/file.c | 3 +- fs/bfs/inode.c | 11 +- fs/binfmt_elf.c | 10 +- fs/binfmt_em86.c | 5 +- fs/block_dev.c | 6 +- fs/buffer.c | 43 +- fs/coda/cnode.c | 17 +- fs/coda/dir.c | 28 +- fs/coda/file.c | 20 +- fs/coda/inode.c | 19 +- fs/coda/pioctl.c | 17 +- fs/cramfs/inode.c | 35 +- fs/devfs/base.c | 26 +- fs/devices.c | 11 +- fs/devpts/devpts_i.h | 2 +- fs/devpts/inode.c | 16 +- fs/devpts/root.c | 7 +- fs/efs/dir.c | 7 +- fs/efs/file.c | 9 - fs/efs/inode.c | 14 +- fs/efs/super.c | 12 +- fs/exec.c | 8 +- fs/ext2/dir.c | 28 +- fs/ext2/file.c | 3 +- fs/ext2/ialloc.c | 1 - fs/ext2/inode.c | 12 +- fs/ext2/namei.c | 35 +- fs/ext2/super.c | 17 +- fs/fat/dir.c | 8 +- fs/fat/fatfs_syms.c | 3 - fs/fat/file.c | 17 +- fs/fat/inode.c | 18 +- fs/fcntl.c | 4 +- fs/fifo.c | 6 +- fs/file_table.c | 4 +- fs/hfs/dir.c | 13 - fs/hfs/dir_cap.c | 32 +- fs/hfs/dir_dbl.c | 21 +- fs/hfs/dir_nat.c | 36 +- fs/hfs/file.c | 17 +- fs/hfs/file_cap.c | 32 +- fs/hfs/file_hdr.c | 22 +- fs/hfs/inode.c | 46 +- fs/hfs/super.c | 15 +- fs/hpfs/dir.c | 5 - fs/hpfs/hpfs_fn.h | 1 - fs/hpfs/inode.c | 57 +- fs/hpfs/super.c | 20 +- fs/inode.c | 5 +- fs/isofs/Makefile | 2 +- fs/isofs/dir.c | 7 +- fs/isofs/file.c | 31 - fs/isofs/inode.c | 29 +- fs/minix/bitmap.c | 1 - fs/minix/dir.c | 28 +- fs/minix/file.c | 15 +- fs/minix/inode.c | 30 +- fs/minix/namei.c | 35 +- fs/msdos/namei.c | 17 +- fs/ncpfs/dir.c | 36 +- fs/ncpfs/file.c | 18 +- fs/ncpfs/inode.c | 23 +- fs/nfs/dir.c | 37 +- fs/nfs/file.c | 19 +- fs/nfs/inode.c | 30 +- fs/nfs/symlink.c | 2 + fs/nfs/write.c | 20 +- fs/nfsd/nfsfh.c | 2 +- fs/nfsd/vfs.c | 7 +- fs/ntfs/fs.c | 46 +- fs/open.c | 2 +- fs/openpromfs/inode.c | 54 +- fs/partitions/check.c | 6 +- fs/partitions/msdos.c | 4 +- fs/pipe.c | 7 +- fs/proc/base.c | 77 +- fs/proc/generic.c | 30 +- fs/proc/inode.c | 26 +- fs/proc/kcore.c | 8 +- fs/proc/kmsg.c | 6 +- fs/proc/proc_misc.c | 45 +- fs/proc/root.c | 15 +- fs/qnx4/dir.c | 18 +- fs/qnx4/file.c | 3 +- fs/qnx4/inode.c | 9 +- fs/read_write.c | 10 + fs/romfs/inode.c | 77 +- fs/smbfs/dir.c | 34 +- fs/smbfs/file.c | 44 +- fs/smbfs/inode.c | 29 +- fs/smbfs/sock.c | 60 +- fs/sysv/dir.c | 28 +- fs/sysv/file.c | 11 +- fs/sysv/ialloc.c | 1 - fs/sysv/inode.c | 33 +- fs/sysv/namei.c | 38 +- fs/udf/dir.c | 30 +- fs/udf/file.c | 3 +- fs/udf/ialloc.c | 1 - fs/udf/inode.c | 2 + fs/udf/namei.c | 36 +- fs/udf/super.c | 24 +- fs/udf/udfdecl.h | 11 +- fs/ufs/Makefile | 2 +- fs/ufs/acl.c | 68 - fs/ufs/dir.c | 21 +- fs/ufs/file.c | 3 +- fs/ufs/ialloc.c | 1 - fs/ufs/inode.c | 8 +- fs/ufs/namei.c | 32 +- fs/ufs/super.c | 19 +- fs/umsdos/check.c | 1 - fs/umsdos/dir.c | 35 +- fs/umsdos/inode.c | 36 +- fs/umsdos/rdir.c | 21 +- fs/vfat/namei.c | 17 +- include/asm-alpha/atomic.h | 8 +- include/asm-alpha/bitops.h | 12 +- include/asm-alpha/parport.h | 2 + include/asm-alpha/pci.h | 19 +- include/asm-alpha/semaphore-helper.h | 4 +- include/asm-alpha/semaphore.h | 16 +- include/asm-alpha/spinlock.h | 8 +- include/asm-alpha/system.h | 36 +- include/asm-arm/arch-arc/io.h | 2 +- include/asm-arm/arch-cl7500/io.h | 2 +- include/asm-arm/arch-ebsa110/io.h | 2 +- include/asm-arm/arch-ebsa285/io.h | 4 +- include/asm-arm/arch-nexuspci/io.h | 2 +- include/asm-arm/arch-rpc/io.h | 2 +- include/asm-arm/arch-sa1100/io.h | 4 +- include/asm-arm/parport.h | 2 + include/asm-i386/atomic.h | 11 + include/asm-i386/hardirq.h | 32 +- include/asm-i386/hw_irq.h | 10 +- include/asm-i386/mpspec.h | 3 +- include/asm-i386/parport.h | 22 +- include/asm-i386/pgtable.h | 1 + include/asm-i386/smp.h | 2 + include/asm-i386/softirq.h | 8 +- include/asm-ia64/offsets.h | 6 +- include/asm-ia64/page.h | 5 +- include/asm-ia64/pgalloc.h | 21 +- include/asm-ia64/pgtable.h | 14 +- include/asm-ia64/processor.h | 36 +- include/asm-ia64/siginfo.h | 21 +- include/asm-mips/hardirq.h | 19 +- include/asm-mips/hw_irq.h | 5 + include/asm-mips/parport.h | 22 +- include/asm-mips/pgtable.h | 3 +- include/asm-mips/softirq.h | 10 +- include/asm-mips64/hardirq.h | 15 +- include/asm-mips64/hw_irq.h | 5 + include/asm-mips64/parport.h | 22 +- include/asm-mips64/pgtable.h | 3 +- include/asm-mips64/softirq.h | 10 +- include/asm-ppc/hw_irq.h | 21 +- include/asm-ppc/io.h | 98 +- include/asm-ppc/irq.h | 56 +- include/asm-ppc/pci.h | 3 +- include/asm-ppc/processor.h | 11 +- include/asm-ppc/system.h | 1 + include/asm-ppc/types.h | 9 +- include/asm-ppc/vga.h | 4 +- include/asm-sparc/termbits.h | 5 +- include/asm-sparc64/io.h | 24 +- include/asm-sparc64/siginfo.h | 2 +- include/asm-sparc64/termbits.h | 5 +- include/linux/ac97_codec.h | 159 + include/linux/affs_fs.h | 4 +- include/linux/bfs_fs.h | 2 + include/linux/blkdev.h | 5 +- include/linux/coda_linux.h | 1 + include/linux/dlists.h | 108 - include/linux/efs_fs.h | 2 +- include/linux/ext2_fs.h | 15 +- include/linux/fb.h | 19 + include/linux/fs.h | 15 +- include/linux/hdreg.h | 66 +- include/linux/hfs_fs.h | 16 +- include/linux/ide.h | 14 +- include/linux/irq.h | 34 +- include/linux/isdn.h | 27 +- include/linux/iso_fs.h | 2 +- include/linux/list.h | 3 + include/linux/lists.h | 62 - include/linux/matroxfb.h | 32 + include/linux/minix_fs.h | 13 +- include/linux/mm.h | 3 +- include/linux/mmzone.h | 5 +- include/linux/msdos_fs.h | 1 + include/linux/ncp_fs.h | 2 + include/linux/netdevice.h | 49 +- include/linux/nfs_fs.h | 3 + include/linux/pci.h | 1 + include/linux/pci_ids.h | 8 +- include/linux/pm.h | 15 +- include/linux/prctl.h | 6 + include/linux/proc_fs.h | 12 +- include/linux/qnx4_fs.h | 2 + include/linux/raid/md_k.h | 4 +- include/linux/smb_fs.h | 2 + include/linux/sysctl.h | 6 +- include/linux/sysv_fs.h | 14 +- include/linux/timer.h | 1 - include/linux/ufs_fs.h | 15 +- include/linux/umsdos_fs.h | 3 + include/linux/wait.h | 1 + include/net/atmclip.h | 7 +- init/main.c | 1 - ipc/shm.c | 409 ++- ipc/util.c | 5 + kernel/exit.c | 11 +- kernel/ksyms.c | 4 + kernel/pm.c | 39 +- kernel/sched.c | 11 +- kernel/sys.c | 19 +- kernel/sysctl.c | 59 +- mm/bootmem.c | 2 +- mm/filemap.c | 34 +- mm/memory.c | 30 +- mm/page_alloc.c | 26 +- mm/vmscan.c | 21 +- net/atm/clip.c | 67 +- net/atm/lec.c | 255 +- net/atm/mpoa_proc.c | 9 +- net/atm/proc.c | 13 +- net/atm/raw.c | 4 +- net/bridge/br_device.c | 8 +- net/bridge/br_fdb.c | 9 +- net/bridge/br_forward.c | 2 +- net/bridge/br_if.c | 2 +- net/bridge/br_input.c | 63 +- net/bridge/br_ioctl.c | 2 +- net/bridge/br_notify.c | 2 +- net/bridge/br_stp.c | 2 +- net/bridge/br_stp_bpdu.c | 2 +- net/bridge/br_stp_if.c | 2 +- net/bridge/br_stp_timer.c | 2 +- net/core/dev.c | 41 +- net/decnet/af_decnet.c | 3 +- net/ipv4/af_inet.c | 7 +- net/ipv4/igmp.c | 11 +- net/ipv4/ipconfig.c | 2 +- net/ipv4/tcp_output.c | 2 +- net/irda/ircomm/ircomm_tty.c | 5 +- net/netsyms.c | 3 - net/packet/af_packet.c | 4 +- net/sched/sch_atm.c | 67 +- net/sched/sch_cbq.c | 2 +- net/sched/sch_dsmark.c | 8 +- net/wanrouter/wanproc.c | 46 +- 665 files changed, 36638 insertions(+), 19372 deletions(-) create mode 100644 Documentation/IRQ-affinity.txt create mode 100644 Documentation/floppy.txt create mode 100644 Documentation/m68k/README.buddha create mode 100644 Documentation/networking/8139too.txt create mode 100644 Documentation/networking/fore200e.txt create mode 100644 Documentation/parport-lowlevel.txt create mode 100644 drivers/atm/fore200e.c create mode 100644 drivers/atm/fore200e.h create mode 100644 drivers/atm/fore200e_firmware_copyright create mode 100644 drivers/atm/fore200e_mkfirm.c create mode 100644 drivers/atm/pca200e.data create mode 100644 drivers/atm/pca200e_ecd.data create mode 100644 drivers/atm/sba200e_ecd.data delete mode 100644 drivers/block/README.buddha delete mode 100644 drivers/block/README.fd delete mode 100644 drivers/block/README.lvm delete mode 100644 drivers/block/README.md create mode 100644 drivers/char/ds1620.c create mode 100644 drivers/char/nwbutton.c create mode 100644 drivers/char/nwbutton.h create mode 100644 drivers/char/nwflash.c create mode 100644 drivers/char/wdt285.c create mode 100644 drivers/char/wdt977.c delete mode 100644 drivers/net/tulip.c create mode 100644 drivers/net/tulip/21142.c create mode 100644 drivers/net/tulip/Makefile create mode 100644 drivers/net/tulip/eeprom.c create mode 100644 drivers/net/tulip/interrupt.c create mode 100644 drivers/net/tulip/media.c create mode 100644 drivers/net/tulip/pnic.c create mode 100644 drivers/net/tulip/timer.c create mode 100644 drivers/net/tulip/tulip.h create mode 100644 drivers/net/tulip/tulip_core.c delete mode 100644 drivers/sound/README.CONFIG delete mode 100644 drivers/sound/ac97_codec.h delete mode 100644 drivers/sound/finetune.h delete mode 100644 drivers/sound/legacy.h delete mode 100644 drivers/sound/vidc_audio.c delete mode 100644 drivers/sound/vidc_mixer.c delete mode 100644 drivers/sound/vidc_synth.c create mode 100644 drivers/usb/ftdi_sio.h create mode 100644 drivers/video/matrox/Makefile create mode 100644 drivers/video/matrox/i2c-matroxfb.c create mode 100644 drivers/video/matrox/matroxfb_DAC1064.c create mode 100644 drivers/video/matrox/matroxfb_DAC1064.h create mode 100644 drivers/video/matrox/matroxfb_Ti3026.c create mode 100644 drivers/video/matrox/matroxfb_Ti3026.h create mode 100644 drivers/video/matrox/matroxfb_accel.c create mode 100644 drivers/video/matrox/matroxfb_accel.h create mode 100644 drivers/video/matrox/matroxfb_base.c create mode 100644 drivers/video/matrox/matroxfb_base.h create mode 100644 drivers/video/matrox/matroxfb_crtc2.c create mode 100644 drivers/video/matrox/matroxfb_crtc2.h create mode 100644 drivers/video/matrox/matroxfb_maven.c create mode 100644 drivers/video/matrox/matroxfb_maven.h create mode 100644 drivers/video/matrox/matroxfb_misc.c create mode 100644 drivers/video/matrox/matroxfb_misc.h delete mode 100644 drivers/video/matroxfb.c delete mode 100644 fs/isofs/file.c delete mode 100644 fs/ufs/acl.c create mode 100644 include/asm-mips/hw_irq.h create mode 100644 include/asm-mips64/hw_irq.h create mode 100644 include/linux/ac97_codec.h delete mode 100644 include/linux/dlists.h delete mode 100644 include/linux/lists.h create mode 100644 include/linux/matroxfb.h diff --git a/CREDITS b/CREDITS index a816e6127..7192442b9 100644 --- a/CREDITS +++ b/CREDITS @@ -1511,15 +1511,17 @@ S: Santa Clara, CA 95052 S: USA N: Martin Mares -E: mj@atrey.karlin.mff.cuni.cz +E: mj@suse.cz +E: mj@ucw.cz W: http://atrey.karlin.mff.cuni.cz/~mj/ D: BIOS video mode handling code D: MOXA C-218 serial board driver D: Network autoconfiguration +D: PCI subsystem D: Random kernel hacking S: Kankovskeho 1241 S: 182 00 Praha 8 -S: Czech Republic +S: Czech Republic N: John A. Martin E: jam@acm.org @@ -2023,6 +2025,14 @@ S: 301/222 City Walk S: Canberra ACT 2601 S: Australia +N: Sampo Saaristo +E: sambo@cs.tut.fi +D: Co-author of Multi-Protocol Over ATM (MPOA) +S: Tampere University of Technology / Telecom lab +S: Hermiankatu 12C +S: FIN-33720 Tampere +S: Finland + N: Thomas Sailer E: sailer@ife.ee.ethz.ch E: HB9JNX@HB9W.CHE.EU (packet radio) @@ -2405,6 +2415,14 @@ S: 27 Spencer Drive S: Nashua, New Hampshire 03062 S: USA +N: Heikki Vatiainen +E: hessu@cs.tut.fi +D: Co-author of Multi-Protocol Over ATM (MPOA), some LANE hacks +S: Tampere University of Technology / Telecom lab +S: Hermiankatu 12C +S: FIN-33720 Tampere +S: Finland + N: Andrew Veliath E: andrewtv@usa.net D: Turtle Beach MultiSound sound driver @@ -2431,6 +2449,14 @@ S: Kruislaan 419 S: 1098 VA Amsterdam S: The Netherlands +N: Peter Shaobo Wang +E: pwang@mmdcorp.com +W: http://www.mmdcorp.com/pw/linux +D: Driver for Interphase ATM (i)Chip SAR adapter card family (x575, x525, x531). +S: 1513 Brewster Dr. +S: Carrollton, TX 75010 +S: USA + N: Tim Waugh E: tim@cyberelk.demon.co.uk D: Co-architect of the parallel-port sharing system @@ -2471,6 +2497,14 @@ S: UC Berkeley S: Berkeley, CA 94720-1776 S: USA +N: Bill Wendling +E: wendling@ganymede.isdn.uiuc.edu +W: http://www.ncsa.uiuc.edu/~wendling/ +D: Various random hacks. Mostly on poll/select logic. +S: 605 E. Springfield Ave. +S: Champaign, IL 61820 +S: USA + N: Mike Westall D: IBM Turboways 25 ATM Device Driver E: westall@cs.clemson.edu diff --git a/Documentation/Changes b/Documentation/Changes index f07a1876f..ea01182b0 100644 --- a/Documentation/Changes +++ b/Documentation/Changes @@ -33,7 +33,7 @@ pour la traduction fran Also, don't forget http://www.linuxhq.com/ for all your Linux kernel needs. -Last updated: March 16, 1999 +Last updated: Feb 21, 2000 Current Author: Chris Ricker (kaboom@gatech.edu or chris.ricker@m.cc.utah.edu). Current Minimal Requirements @@ -512,6 +512,12 @@ recomented. Older isdn4k-utils versions don't support EXTRAVERSION into kernel version string. +Logical Volume Manager +====================== +Since 2.3.47 the kernel contains the Logical Volume Manager aka LVM. To use it, +you need to install the LVM tools. More information can be found at the home page +of the LVM project at http://linux.msede.com/lvm/. + Where to get the files ********************** @@ -751,9 +757,9 @@ http://www.cs.kuleuven.ac.be/~geert/bin/fbset-2.0-pre-19981104.tar.gz PCI utils ========= -The 2.0 release: -ftp://atrey.karlin.mff.cuni.cz/pub/linux/pci/pciutils-2.0.tar.gz -ftp://metalab.unc.edu/pub/Linux/hardware/pciutils-2.0.tar.gz +The 2.1.5 release: +ftp://atrey.karlin.mff.cuni.cz/pub/linux/pci/pciutils-2.1.5.tar.gz +ftp://metalab.unc.edu/pub/Linux/hardware/pciutils-2.1.5.tar.gz Powertweak ========== @@ -795,9 +801,17 @@ ftp://ftp.gnu.org/gnu/patch/patch-2.5.tar.gz ISDN4Linux ========== + The v3.1beta7 release: ftp://ftp.isdn4linux.de/pub/isdn4linux/utils/testing/isdn4k-utils.v3.1beta7.tar.gz +Logical Volume Manager +====================== + +The 0.7 release: +ftp://linux.msede.com/lvm/v0.7/lvm_0.7.tar.gz + + Other Info ========== diff --git a/Documentation/Configure.help b/Documentation/Configure.help index 82bbd2b50..878b5abe0 100644 --- a/Documentation/Configure.help +++ b/Documentation/Configure.help @@ -323,27 +323,31 @@ CONFIG_BLK_DEV_NBD Enhanced IDE/MFM/RLL disk/cdrom/tape/floppy support CONFIG_BLK_DEV_IDE If you say Y here, you will use the full-featured IDE driver to - control up to eight IDE interfaces, each being able to serve a - "master" and a "slave" device, for a total of up to sixteen IDE + control up to ten ATA/IDE interfaces, each being able to serve a + "master" and a "slave" device, for a total of up to twenty ATA/IDE disk/cdrom/tape/floppy drives. People with SCSI-only systems - can say N here. + can say N or M here. Useful information about large (>540 MB) IDE disks, multiple - interfaces, what to do if IDE devices are not automatically - detected, sound card IDE ports, module support, and other topics, is - contained in Documentation/ide.txt. For detailed information about + interfaces, what to do if ATA/IDE devices are not automatically + detected, sound card ATA/IDE ports, module support, and other topics, is + contained in Documentation/ata-ide.txt. For detailed information about hard drives, consult the Disk-HOWTO and the Multi-Disk-HOWTO, available from http://www.linuxdoc.org/docs.html#howto . - To fine-tune IDE drive/interface parameters for improved + To fine-tune ATA/IDE drive/interface parameters for improved + performance, look for the hdparm package at + ftp://metalab.unc.edu/pub/Linux/kernel/patches/diskdrives/ . + + To fine-tune ATA/IDE drive/interface parameters for improved performance, look for the hdparm package at ftp://metalab.unc.edu/pub/Linux/kernel/patches/diskdrives/ . If you want to compile this driver as a module ( = code which can be inserted in and removed from the running kernel whenever you want), say M here and read Documentation/modules.txt and - Documentation/ide.txt. The module will be called ide.o. Do not - compile this driver as a module if your root file system (the one + Documentation/ide.txt. The module will be called ide-mod.o. Do not + compile this driver as a module if your root filesystem (the one containing the directory /) is located on an IDE device. If you have one or more IDE drives, say Y or M here. If your system @@ -557,13 +561,6 @@ CONFIG_BLK_DEV_RZ1000 People with SCSI-only systems should say N here. If unsure, say Y. -Cyrix CS5530 MediaGX chipset support -CONFIG_BLK_DEV_CS5530 - Include support for UDMA on the Cyrix MediaGX 5530 chipset. This - will automatically be detected and configured if found. - - It is safe to say Y to this question. - Generic PCI IDE chipset support CONFIG_BLK_DEV_IDEPCI Say Y here for PCI systems which use IDE drive(s). @@ -572,6 +569,15 @@ CONFIG_BLK_DEV_IDEPCI People with SCSI-only systems should say N here; if unsure say Y. +Support for sharing PCI IDE interrupts +CONFIG_IDEPCI_SHARE_IRQ + Some ATA/IDE chipsets have hardware support which allows for + sharing a single IRQ with other cards. To enable support for + this in the ATA/IDE driver, say Y here. + + It is safe to say Y to this question, in most cases. + If unsure, say N. + Generic PCI bus-master DMA support CONFIG_BLK_DEV_IDEDMA_PCI If your PCI system uses IDE drive(s) (as opposed to SCSI, say) and @@ -584,7 +590,7 @@ CONFIG_BLK_DEV_IDEDMA_PCI the latest version of the hdparm utility from ftp://metalab.unc.edu/pub/Linux/system/hardware/ . - Read the comments at the beginning of drivers/block/idedma.c and the + Read the comments at the beginning of drivers/block/ide-dma.c and the file Documentation/ide.txt for more information. It is safe to say Y to this question. @@ -614,7 +620,7 @@ CONFIG_BLK_DEV_OFFBOARD If you say Y here, and you actually want to reverse the device scan order as explained above, you also need to issue the kernel command - line option "pci=reverse". (Try "man bootparam" or see the + line option "ide=reverse". (Try "man bootparam" or see the documentation of your boot loader (lilo or loadlin) about how to pass options to the kernel at boot time. The lilo procedure is also explained in the SCSI-HOWTO, available from @@ -639,6 +645,23 @@ CONFIG_IDEDMA_PCI_AUTO It is normally safe to answer Y to this question unless your motherboard uses a VIA VP2 chipset, in which case you should say N. +Various ATA, Work(s) In Progress (EXPERIMENTAL) +CONFIG_IDEDMA_PCI_WIP + If you enable this you will be capable of using and testing + highly developmentail projects. + + It is SAFEST to say N to this question. + +3ware Hardware ATA-RAID support (EXPERIMENTAL) +CONFIG_BLK_DEV_3W_XXXX_RAID + 3ware is the only hardware ATA-Raid product in Linux to date. + This card is 2,4, or 8 channel master mode support only. + SCSI support required!!! + + http://www.3ware.com/ + + Please read the comments at the top of drivers/scsi/3w-xxxx.c + AEC6210 chipset support CONFIG_BLK_DEV_AEC6210 This driver adds up to 4 more EIDE devices sharing a single @@ -648,6 +671,12 @@ CONFIG_BLK_DEV_AEC6210 available". Please read the comments at the top of drivers/block/aec6210.c + If you say Y here, then say Y to "Use DMA by default when available" as well. + +AEC6210 Tuning support (WIP) +CONFIG_AEC6210_TUNING + Please read the comments at the top of drivers/block/aec6210.c + If unsure, say N. ALI M15x3 chipset support CONFIG_BLK_DEV_ALI15X3 @@ -655,9 +684,8 @@ CONFIG_BLK_DEV_ALI15X3 1535, 1535D onboard chipsets. It also tests for Simplex mode and enables normal dual channel support. - If you say Y here, you also need to say Y to "Use DMA by default - when available", above. Please read the comments at the top of drivers/block/alim15x3.c + If you say Y here, then say Y to "Use DMA by default when available" as well. If unsure, say N. @@ -665,10 +693,14 @@ AMD7409 chipset support (EXPERIMENTAL) CONFIG_BLK_DEV_AMD7409 This driver ensures (U)DMA support for AMD756 Viper chipset. - If you say Y here, you also need to say Y to "Use DMA by default - when available", above. Please read the comments at the top of drivers/block/amd7409.c + If you say Y here, then say Y to "Use DMA by default when available" as well. + If unsure, say N. +AMD Viper ATA-66 Override support (WIP) +CONFIG_AMD7409_OVERRIDE + This option auto-forces the ata66 flag. + This effect can be also invoked by calling "idex=ata66" If unsure, say N. CMD64X chipset support @@ -676,8 +708,8 @@ CONFIG_BLK_DEV_CMD64X Say Y here if you have an IDE controller which uses any of these chipsets, CMD643, CMD646, or CMD648. -CMD64X chipset RAID support (EXPERIMENTAL) (WIP) -CONFIG_BLK_DEV_CMD64X +CMD64X chipset RAID support (WIP) +CONFIG_CMD64X_RAID Work in progress for hardware raid ata-33/66..........rev 7 minimum. Say N for now. @@ -686,8 +718,14 @@ CONFIG_BLK_DEV_CY82C693 This driver adds detection and support for the CY82C693 chipset used on Digital's PC-Alpha 164SX boards. - If you say Y here, you need to say Y to "Use DMA by default - when available" as well. + If you say Y here, then say Y to "Use DMA by default when available" as well. + +Cyrix CS5530 MediaGX chipset support +CONFIG_BLK_DEV_CS5530 + Include support for UDMA on the Cyrix MediaGX 5530 chipset. This + will automatically be detected and configured if found. + + It is safe to say Y to this question. HPT34X chipset support CONFIG_BLK_DEV_HPT34X @@ -698,12 +736,13 @@ CONFIG_BLK_DEV_HPT34X chipset during the ide-probe at boot time. It is reported to support DVD II drives, by the manufacturer. -HPT34X DMA support (EXPERIMENTAL) -CONFIG_BLK_DEV_HPT34X_DMA - you need to say Y to "Use DMA by default when available" if you say - Y here. - +HPT34X AUTODMA support (WIP) +CONFIG_HPT34X_AUTODMA + This is a dangerous thing to attempt currently! Please read the comments at the top of drivers/block/hpt34x.c + If you say Y here, then say Y to "Use DMA by default when available" as well. + + If unsure, say N. HPT366 chipset support CONFIG_BLK_DEV_HPT366 @@ -716,13 +755,14 @@ CONFIG_BLK_DEV_HPT366 manufacturer. Please read the comments at the top of drivers/block/hpt366.c + If you say Y here, then say Y to "Use DMA by default when available" as well. -HPT366 Fast Interrupt support (EXPERIMENTAL) (WIP) -CONFIG_HPT366_FAST_IRQ_PREDICTION +HPT366 Fast Interrupts (WIP) +CONFIG_HPT366_FIP If unsure, say N. -HPT366 mode three unsupported (EXPERIMENTAL) (WIP) +HPT366 mode three unsupported (WIP) CONFIG_HPT366_MODE3 This is an undocumented mode that the HA366 can default to in many cases. If unsure, say N. @@ -748,11 +788,11 @@ CONFIG_BLK_DEV_PIIX Please read the comments at the top of drivers/block/piix.c - Should also include "PIIXn Tuning support" CONFIG_BLK_DEV_PIIX_TUNING + Should also include "PIIXn Tuning support" CONFIG_PIIX_TUNING If unsure, say Y. PIIXn Tuning support -CONFIG_BLK_DEV_PIIX_TUNING +CONFIG_PIIX_TUNING This driver extension adds DMA mode setting and tuning for all PIIX IDE controllers by Intel. Since the BIOS can sometimes improperly set up the device/adapter combination and speed limits, it has @@ -784,15 +824,13 @@ CONFIG_BLK_DEV_PDC202XX boot-time for max-speed. Note tested limits are UDMA-2. Ultra66 BIOS 1.11 or newer required. - If you say Y here, you need to say Y to "Use DMA by default when - available" as well. - + If you say Y here, then say Y to "Use DMA by default when available" as well. Please read the comments at the top of drivers/block/pdc202xx.c If unsure, say N. Special UDMA Feature -CONFIG_PDC202XX_FORCE_BURST_BIT +CONFIG_PDC202XX_BURST For PDC20246 and PDC20262 Ultra DMA chipsets. Designed originally for PDC20246/Ultra33 that has BIOS setup failures when using 3 or more cards. @@ -801,8 +839,8 @@ CONFIG_PDC202XX_FORCE_BURST_BIT If unsure, say N. -Special Mode Feature (EXPERIMENTAL) -CONFIG_PDC202XX_FORCE_MASTER_MODE +Special Mode Feature (WIP) +CONFIG_PDC202XX_MASTER For PDC20246 and PDC20262 Ultra DMA chipsets. This is reserved for possible Hardware RAID 0,1 for the FastTrak Series. @@ -832,8 +870,7 @@ CONFIG_BLK_DEV_VIA82CXXX (while running a "cat") provided you enabled "proc" support. Please read the comments at the top of drivers/block/via82cxxx.c - If you say Y here, you also need to say Y to "Use DMA by default - when available", above. + If you say Y here, then say Y to "Use DMA by default when available" as well. If unsure, say N. @@ -908,16 +945,6 @@ CONFIG_BLK_DEV_UMC8672 See the files Documentation/ide.txt and drivers/block/umc8672.c for more info. -PS/2 ESDI hard disk support -CONFIG_BLK_DEV_PS2 - Say Y here if you have a PS/2 machine with a MCA bus and an ESDI - hard disk. - - If you want to compile the driver as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read Documentation/modules.txt. The module will be - called ps2esdi.o. - Amiga builtin Gayle IDE interface support CONFIG_BLK_DEV_GAYLE This is the IDE driver for the builtin IDE interface on some Amiga @@ -968,7 +995,14 @@ CONFIG_BLK_DEV_IDEDMA_PMAC Use DMA by default CONFIG_IDEDMA_PMAC_AUTO - No help for CONFIG_IDEDMA_PMAC_AUTO + Prior to kernel version 2.1.112, Linux used to automatically use + DMA for IDE drives and chipsets which support it. Due to concerns + about a couple of cases where buggy hardware may have caused damage, + the default is now to NOT use DMA automatically. To revert to the + previous behaviour, say Y to this question. + + If you suspect your hardware is at all flakey, say N here. + Do NOT email the IDE kernel people regarding this issue! Macintosh Quadra/Powerbook IDE interface support CONFIG_BLK_DEV_MAC_IDE @@ -981,9 +1015,16 @@ CONFIG_BLK_DEV_MAC_IDE devices (hard disks, CD-ROM drives, etc.) that are connected to the builtin IDE interface. +IDE card support +CONFIG_BLK_DEV_IDE_CARDS + On Acorn systems, say Y here if you wish to use an IDE interface + expansion card. If you do not or are unsure, say N to this. + ICS IDE interface support CONFIG_BLK_DEV_IDE_ICSIDE - No help for CONFIG_BLK_DEV_IDE_ICSIDE + On Acorn systems, say Y here if you wish to use the ICS IDE + interface card. This is not required for ICS partition support. + If you are unsure, say N to this. ICS DMA support CONFIG_BLK_DEV_IDEDMA_ICS @@ -991,7 +1032,14 @@ CONFIG_BLK_DEV_IDEDMA_ICS Use ICS DMA by default CONFIG_IDEDMA_ICS_AUTO - No help for CONFIG_IDEDMA_ICS_AUTO + Prior to kernel version 2.1.112, Linux used to automatically use + DMA for IDE drives and chipsets which support it. Due to concerns + about a couple of cases where buggy hardware may have caused damage, + the default is now to NOT use DMA automatically. To revert to the + previous behaviour, say Y to this question. + + If you suspect your hardware is at all flakey, say N here. + Do NOT email the IDE kernel people regarding this issue! RapIDE interface support CONFIG_BLK_DEV_IDE_RAPIDE @@ -1009,6 +1057,16 @@ CONFIG_BLK_DEV_XD It's pretty unlikely that you have one of these: say N. +PS/2 ESDI hard disk support +CONFIG_BLK_DEV_PS2 + Say Y here if you have a PS/2 machine with a MCA bus and an ESDI + hard disk. + + If you want to compile the driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called ps2esdi.o. + Mylex DAC960/DAC1100 PCI RAID Controller support CONFIG_BLK_DEV_DAC960 This driver adds support for the Mylex DAC960, AcceleRAID, and @@ -1599,7 +1657,7 @@ CONFIG_NETFILTER Chances are that you should say Y here if you compile a kernel which will run as a router and N for regular hosts. If unsure, say N. -SIN flood protection +SYN flood protection CONFIG_SYN_COOKIES Normal TCP/IP networking is open to an attack known as "SYN flooding". This denial-of-service attack prevents legitimate remote @@ -1982,7 +2040,7 @@ CONFIG_PNP Say Y here if you would like Linux to configure your Plug and Play devices. You should then also say Y to "ISA Plug and Play support", below. Alternatively, you can configure your PnP devices using the - user space utilities contained in the ISAPNP tools package. + user space utilities contained in the isapnptools package. This support is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -2540,6 +2598,52 @@ CONFIG_FB_MATROX_G100 you select "Advanced lowlevel driver options", you should check 8 bpp packed pixel, 16 bpp packed pixel, 24 bpp packed pixel and 32 bpp packed pixel. You can also use font widths different from 8. + + If you need support for G400 secondary head, you must first enable + I2C support and I2C bit-banging support in character devices section, + and then Matrox I2C support and G400 secondary head support here + in framebuffer section. + +Matrox I2C support +CONFIG_FB_MATROX_I2C + This drivers creates I2C buses which are needed for accessing + DDC (I2C) bus present on all Matroxes, I2C bus which interconnects + Matrox optional devices, like MGA-TVO on G200 and G400, and + secondary head DDC bus, present on G400 only. + + You can say Y or M here if you want to experiment with monitor + detection code. You must say Y or M here if you want to use either + second head of G400 or MGA-TVO on G200 or G400. + + If you compile it as module, it will create module named i2c-matroxfb.o. + +Matrox G400 second head support +CONFIG_FB_MATROX_MAVEN + Say Y or M here if you want to use secondary head on G400 or MGA-TVO + add-on on G200. Secondary head is not compatible with accelerated + XFree 3.3.x SVGA servers - secondary head output is blanked while you + are in X. With XFree 3.9.17 preview you can use both heads if you use + SVGA over fbdev or fbdev driver on first head and fbdev driver on + second head. + + If you compile it as module, two modules are created, matroxfb_crtc2.o + and matroxfb_maven.o. Matroxfb_maven is needed for both G200 and G400, + matroxfb_crtc2 is needed only by G400. You must also load i2c-matroxfb + to get it to run. + + Driver starts in monitor mode and you must use matroxset tool (available + at ftp://platan.vc.cvut.cz/pub/linux/matrox-latest) to switch it to PAL + or NTSC or to swap primary and secondary head outputs. Secondary head + driver also always start in 640x480 resolution, you must use fbset to + change it. + + Also do not forget that second head supports only 16 and 32 bpp packed + pixels, so it is good idea to compile them into kernel too. You can + use only some font widths, as driver uses generic painting procedures + (secondary head does not use acceleration engine). + + There is no need for enabling 'Matrox multihead support' if you have + only one Matrox card in the box. Matrox unified driver multihead support CONFIG_FB_MATROX_MULTIHEAD @@ -4226,6 +4330,82 @@ CONFIG_ATM_IA_DEBUG speed of the driver, and the size of your syslog files! When inactive, they will have only a modest impact on performance. +FORE Systems 200E-series +CONFIG_ATM_FORE200E + This is a driver for the FORE Systems 200E-series ATM adapter + cards. It simultaneously supports PCA-200E and SBA-200E models + on PCI and SBUS hosts. Say Y (or M to compile as a module + named fore_200e.o) here if you have one of these ATM adapters. + + See the file Documentation/networking/fore200e.txt for further + details. + +Enable PCA-200E card support on PCI-based hosts +CONFIG_ATM_FORE200E_PCA + Enable this if you want your PCA-200E cards to be probed. + +Use default PCA-200E firmware +CONFIG_ATM_FORE200E_PCA_DEFAULT_FW + Use the default PCA-200E firmware data shipped with the driver. + + Normal users do not have to deal with the firmware stuff, so + this feature is normally enabled. + +Pathname of user-supplied binary firmware +CONFIG_ATM_FORE200E_PCA_FW + This defines the pathname of an alternative PCA-200E binary + firmware image supplied by the user. This pathname may be + absolute or relative to the drivers/atm directory. + + The driver comes with an adequate firmware image, so normal users + do not have to supply an alternative one. They just enable the use + of the default firmware instead. + +Enable SBA-200E card support on SBUS-based hosts +CONFIG_ATM_FORE200E_SBA + Enable this if you want your SBA-200E cards to be probed. + +Use default SBA-200E firmware +CONFIG_ATM_FORE200E_SBA_DEFAULT_FW + Use the default SBA-200E firmware data shipped with the driver. + + Normal users do not have to deal with the firmware stuff, so + this feature is normally enabled. + +Pathname of user-supplied binary firmware +CONFIG_ATM_FORE200E_SBA_FW + This defines the pathname of an alternative SBA-200E binary + firmware image supplied by the user. This pathname may be + absolute or relative to the drivers/atm directory. + + The driver comes with an adequate firmware image, so normal users + do not have to supply an alternative one. They just enable the use + of the default firmware instead. + +Maximum number of tx retries +CONFIG_ATM_FORE200E_TX_RETRY + Specifies the number of times the driver attempts to transmit + a message before giving up, if the transmit queue of the ATM card + is transiently saturated. + + Saturation of the transmit queue may occur only under extreme + conditions, e.g. when a fast host continuously submits very small + frames (<64 bytes) or raw AAL0 cells (48 bytes) to the ATM adapter. + + Note that under common conditions, it is unlikely that you encounter + a saturation of the transmit queue, so the retry mechanism never + comes into play. + +Debugging level (0-3) +CONFIG_ATM_FORE200E_DEBUG + Specifies the level of debugging messages issued by the driver. + The verbosity of the driver increases with the value of this + parameter. + + When active, these messages can have a significant impact on + the performances of the driver, and the size of your syslog files! + Keep the debugging level to 0 during normal operations. + SCSI support? CONFIG_SCSI If you want to use a SCSI hard disk, SCSI tape drive, SCSI CDROM or @@ -7558,6 +7738,11 @@ CONFIG_EEPRO100 module, say M here and read Documentation/modules.txt as well as Documentation/networking/net-modules.txt. +EtherExpress PRO/100 support +CONFIG_EEPRO100_PM (EXPERIMENTAL) + If you want to play around with power management code + that has reported to lock up some machines, say Y here. + ICL EtherTeam 16i/32 support (EXPERIMENTAL) CONFIG_ETH16I If you have a network (Ethernet) card of this type, say Y and read diff --git a/Documentation/IRQ-affinity.txt b/Documentation/IRQ-affinity.txt new file mode 100644 index 000000000..7c582f494 --- /dev/null +++ b/Documentation/IRQ-affinity.txt @@ -0,0 +1,37 @@ + +SMP IRQ affinity, started by Ingo Molnar + + +/proc/irq/IRQ#/smp_affinity specifies which target CPUs are permitted +for a given IRQ source. It's a bitmask of allowed CPUs. It's not allowed +to turn off all CPUs, and if an IRQ controller does not support IRQ +affinity then the value will not change from the default 0xffffffff. + +Here is an example of restricting IRQ44 (eth1) to CPU0-3 then restricting +the IRQ to CPU4-8 (this is an 8-CPU SMP box): + +[root@moon 44]# cat smp_affinity +ffffffff +[root@moon 44]# echo 0f > smp_affinity +[root@moon 44]# cat smp_affinity +0000000f +[root@moon 44]# ping -f h +PING hell (195.4.7.3): 56 data bytes +... +--- hell ping statistics --- +6029 packets transmitted, 6027 packets received, 0% packet loss +round-trip min/avg/max = 0.1/0.1/0.4 ms +[root@moon 44]# cat /proc/interrupts | grep 44: + 44: 0 1785 1785 1783 1783 1 +1 0 IO-APIC-level eth1 +[root@moon 44]# echo f0 > smp_affinity +[root@moon 44]# ping -f h +PING hell (195.4.7.3): 56 data bytes +.. +--- hell ping statistics --- +2779 packets transmitted, 2777 packets received, 0% packet loss +round-trip min/avg/max = 0.1/0.5/585.4 ms +[root@moon 44]# cat /proc/interrupts | grep 44: + 44: 1068 1785 1785 1784 1784 1069 1070 1069 IO-APIC-level eth1 +[root@moon 44]# + diff --git a/Documentation/fb/matroxfb.txt b/Documentation/fb/matroxfb.txt index 6506273ea..d79f6694f 100644 --- a/Documentation/fb/matroxfb.txt +++ b/Documentation/fb/matroxfb.txt @@ -105,7 +105,7 @@ problem and not mine, but I'm not sure. Configuration ============= -You can pass kernel command line options to vesafb with +You can pass kernel command line options to matroxfb with `video=matrox:option1,option2:value2,option3' (multiple options should be separated by comma, values are separated from options by `:'). Accepted options: @@ -276,16 +276,16 @@ And following misfeatures: + color keying is not supported + feature connector of Mystique and Gx00 is set to VGA mode (it is disabled by BIOS) - + DCC (monitor detection) protocol is not implemented + + DDC (monitor detection) is supported through dualhead driver + some check for input values are not so strict how it should be (you can specify vslen=4000 and so on). + maybe more... And following features: + 4bpp is available only on Millennium I and Millennium II. It is hardware limitation. - + current fbset is not able to set 15bpp videomode: you must specify - depth==16 and green.length==5. fbset does not allow you to set - green.length. + + selection between 1:5:5:5 and 5:6:5 16bpp videomode is done by -rgba + option of fbset: "fbset -depth 16 -rgba 5,5,5" selects 1:5:5:5, anything + else selects 5:6:5 mode. + text mode uses 6 bit VGA palette instead of 8 bit (one of 262144 colors instead of one of 16M colors). It is due to hardware limitation of Millennium I/II and SVGALib compatibility. @@ -330,6 +330,27 @@ TEXT Millennium I G200 TEXT 3.29 1.50 + +Dualhead G400 +============= +Driver supports dualhead G400 with some limitations: + + secondary head shares videomemory with primary head. It is not problem + if you have 32MB of videoram, but if you have only 16MB, you may have + to think twice before choosing videomode (for example twice 1880x1440x32bpp + is not possible). + + due to hardware limitation, secondary head can use only 16 and 32bpp + videomodes. + + secondary head is not accelerated. There were bad problems with accelerated + XFree when secondary head used to use acceleration. + + secondary head always powerups in 640x480@60-32 videomode. You have to use + fbset to change this mode. + + secondary head always powerups in monitor mode. You have to use matroxset + to change it to TV mode. Also, you must select at least 525 lines for + NTSC output and 625 lines for PAL output. + + kernel is not fully multihead ready. So some things are impossible to do. + + if you compiled it as module, you must insert i2c-matroxfb, matroxfb_maven + and matroxfb_crtc2 into kernel. + * Yes, it is slower than Millennium I. -- diff --git a/Documentation/floppy.txt b/Documentation/floppy.txt new file mode 100644 index 000000000..7bd117ee8 --- /dev/null +++ b/Documentation/floppy.txt @@ -0,0 +1,222 @@ +This file describes the floppy driver. + +FAQ list: +========= + + A FAQ list may be found in the fdutils package (see below), and also +at http://fdutils.linux.lu/FAQ.html + + +LILO configuration options (Thinkpad users, read this) +====================================================== + + The floppy driver is configured using the 'floppy=' option in +lilo. This option can be typed at the boot prompt, or entered in the +lilo configuration file. + Example: If your kernel is called linux-2.2.13, type the following line +at the lilo boot prompt (if you have a thinkpad): + linux-2.2.13 floppy=thinkpad +You may also enter the following line in /etc/lilo.conf, in the description +of linux-2.2.13: + append = "floppy=thinkpad" + + Several floppy related options may be given, example: + linux-2.2.13 floppy=daring floppy=two_fdc + append = "floppy=daring floppy=two_fdc" + + If you give options both in the lilo config file and on the boot +prompt, the option strings of both places are concatenated, the boot +prompt options coming last. That's why there are also options to +restore the default behavior. + + If you use the floppy driver as a module, use the following syntax: + insmod floppy + +Example: + insmod floppy daring two_fdc + + Some versions of insmod are buggy in one way or another. If you have +any problems (options not being passed correctly, segfaults during +insmod), first check whether there is a more recent version. + + The floppy related options include: + + floppy=asus_pci + Sets the bit mask to allow only units 0 and 1. (default) + + floppy=daring + Tells the floppy driver that you have a well behaved floppy controller. + This allows more efficient and smoother operation, but may fail on + certain controllers. This may speed up certain operations. + + floppy=0,daring + Tells the floppy driver that your floppy controller should be used + with caution. + + floppy=one_fdc + Tells the floppy driver that you have only one floppy controller. + (default) + + floppy=two_fdc + floppy=
,two_fdc + Tells the floppy driver that you have two floppy controllers. + The second floppy controller is assumed to be at
. + This option is not needed if the second controller is at address + 0x370, and if you use the 'cmos' option. + + floppy=thinkpad + Tells the floppy driver that you have a Thinkpad. Thinkpads use an + inverted convention for the disk change line. + + floppy=0,thinkpad + Tells the floppy driver that you don't have a Thinkpad. + + floppy=omnibook + floppy=nodma + Tells the floppy driver not to use Dma for data transfers. + This is needed on HP Omnibooks, which don't have a workable + DMA channel for the floppy driver. This option is also useful + if you frequently get "Unable to allocate DMA memory" messages. + Indeed, dma memory needs to be continuous in physical memory, + and is thus harder to find, whereas non-dma buffers may be + allocated in virtual memory. However, I advise against this if + you have an FDC without a FIFO (8272A or 82072). 82072A and + later are OK. You also need at least a 486 to use nodma. + If you use nodma mode, I suggest you also set the FIFO + threshold to 10 or lower, in order to limit the number of data + transfer interrupts. + + If you have a FIFO-able FDC, the floppy driver automatically + falls back on non DMA mode if no DMA-able memory can be found. + If you want to avoid this, explicitely ask for 'yesdma'. + + floppy=yesdma + Tells the floppy driver that a workable DMA channel is available. + (default) + + floppy=nofifo + Disables the FIFO entirely. This is needed if you get "Bus + master arbitration error" messages from your Ethernet card (or + from other devices) while accessing the floppy. + + floppy=fifo + Enables the FIFO. (default) + + floppy=,fifo_depth + Sets the FIFO threshold. This is mostly relevant in DMA + mode. If this is higher, the floppy driver tolerates more + interrupt latency, but it triggers more interrupts (i.e. it + imposes more load on the rest of the system). If this is + lower, the interrupt latency should be lower too (faster + processor). The benefit of a lower threshold is less + interrupts. + To tune the fifo threshold, switch on over/underrun messages + using 'floppycontrol --messages'. Then access a floppy + disk. If you get a huge amount of "Over/Underrun - retrying" + messages, then the fifo threshold is too low. Try with a + higher value, until you only get an occasional Over/Underrun. + It is a good idea to compile the floppy driver as a module + when doing this tuning. Indeed, it allows to try different + fifo values without rebooting the machine for each test. Note + that you need to do 'floppycontrol --messages' every time you + re-insert the module. + Usually, tuning the fifo threshold should not be needed, as + the default (0xa) is reasonable. + + floppy=,,cmos + Sets the CMOS type of to . This is mandatory if + you have more than two floppy drives (only two can be + described in the physical CMOS), or if your BIOS uses + non-standard CMOS types. The CMOS types are: + 0 - Use the value of the physical CMOS + 1 - 5 1/4 DD + 2 - 5 1/4 HD + 3 - 3 1/2 DD + 4 - 3 1/2 HD + 5 - 3 1/2 ED + 6 - 3 1/2 ED + 16 - unknown or not installed + (Note: there are two valid types for ED drives. This is because 5 was + initially chosen to represent floppy *tapes*, and 6 for ED drives. + AMI ignored this, and used 5 for ED drives. That's why the floppy + driver handles both.) + + floppy=unexpected_interrupts + Print a warning message when an unexpected interrupt is received. + (default) + + floppy=no_unexpected_interrupts + floppy=L40SX + Don't print a message when an unexpected interrupt is received. This + is needed on IBM L40SX laptops in certain video modes. (There seems + to be an interaction between video and floppy. The unexpected + interrupts affect only performance, and can be safely ignored.) + + floppy=broken_dcl + Don't use the disk change line, but assume that the disk was + changed whenever the device node is reopened. Needed on some + boxes where the disk change line is broken or unsupported. + This should be regarded as a stopgap measure, indeed it makes + floppy operation less efficient due to unneeded cache + flushings, and slightly more unreliable. Please verify your + cable, connection and jumper settings if you have any DCL + problems. However, some older drives, and also some laptops + are known not to have a DCL. + + floppy=debug + Print debugging messages. + + floppy=messages + Print informational messages for some operations (disk change + notifications, warnings about over and underruns, and about + autodetection). + + floppy=silent_dcl_clear + Uses a less noisy way to clear the disk change line (which + doesn't involve seeks). Implied by 'daring' option. + + floppy=,irq + Sets the floppy IRQ to instead of 6. + + floppy=,dma + Sets the floppy DMA channel to instead of 2. + + floppy=slow + Use PS/2 stepping rate: + " PS/2 floppies have much slower step rates than regular floppies. + It's been recommended that take about 1/4 of the default speed + in some more extreme cases." + + + +Supporting utilities and additional documentation: +================================================== + + Additional parameters of the floppy driver can be configured at +runtime. Utilities which do this can be found in the fdutils package. +This package also contains a new version of mtools which allows to +access high capacity disks (up to 1992K on a high density 3 1/2 disk!). +It also contains additional documentation about the floppy driver. + +The latest version can be found at fdutils homepage: + http://fdutils.linux.lu + +The fdutils-5.3 release can be found at: + http://fdutils.linux.lu/fdutils-5.3.src.tar.gz + http://www.tux.org/pub/knaff/fdutils/fdutils-5.3.src.tar.gz + ftp://tsx-11.mit.edu/pub/linux/sources/sbin/fdutils-5.3.src.tar.gz + ftp://metalab.unc.edu/pub/Linux/utils/disk-management/fdutils-5.3.src.tar.gz + +Reporting problems about the floppy driver +========================================== + + If you have a question or a bug report about the floppy driver, mail +me at Alain.Knaff@poboxes.com . If you post to Usenet, preferably use +comp.os.linux.hardware. As the volume in these groups is rather high, +be sure to include the word "floppy" (or "FLOPPY") in the subject +line. If the reported problem happens when mounting floppy disks, be +sure to mention also the type of the filesystem in the subject line. + + Be sure to read the FAQ before mailing/posting any bug reports! + + Alain diff --git a/Documentation/ide.txt b/Documentation/ide.txt index 74e56b75f..7352528bd 100644 --- a/Documentation/ide.txt +++ b/Documentation/ide.txt @@ -38,7 +38,7 @@ NEW! - support for IDE ATAPI *floppy* drives - interface PIO timing & prefetch parameter support - experimental support for UMC 8672 interfaces - support for secondary interface on the FGI/Holtek HT-6560B VLB i/f - - use kernel command line option: ide0=ht6560 + - use kernel command line option: ide0=ht6560b - experimental support for various IDE chipsets - use appropriate kernel command line option from list below - support for drives with a stuck WRERR_STAT bit diff --git a/Documentation/ioctl-number.txt b/Documentation/ioctl-number.txt index c2a1b0025..29a11c3a8 100644 --- a/Documentation/ioctl-number.txt +++ b/Documentation/ioctl-number.txt @@ -128,7 +128,8 @@ Code Seq# Include File Comments 'm' all linux/soundcard.h conflict! 'm' all linux/synclink.h conflict! 'm' 00-1F net/irda/irmod.h conflict! -'n' all linux/ncp_fs.h +'n' 00-7F linux/ncp_fs.h +'n' E0-FF video/matrox.h matroxfb 'p' 00-3F linux/mc146818rtc.h 'p' 40-7F linux/nvram.h 'p' 80-9F user-space parport diff --git a/Documentation/m68k/README.buddha b/Documentation/m68k/README.buddha new file mode 100644 index 000000000..d3b7bc73f --- /dev/null +++ b/Documentation/m68k/README.buddha @@ -0,0 +1,210 @@ + +The Amiga Buddha and Catweasel IDE Driver (part of ide.c) was written by +Geert Uytterhoeven based on the following specifications: + +------------------------------------------------------------------------ + +Register map of the Buddha IDE controller and the +Buddha-part of the Catweasel Zorro-II version + +The Autoconfiguration has been implemented just as Commodore +described in their manuals, no tricks have been used (for +example leaving some address lines out of the equations...). +If you want to configure the board yourself (for example let +a Linux kernel configure the card), look at the Commodore +Docs. Reading the nibbles should give this information: + +Vendor number: 4626 ($1212) +product number: 0 (42 for Catweasel Z-II) +Serial number: 0 +Rom-vector: $1000 + +The card should be a Z-II board, size 64K, not for freemem +list, Rom-Vektor is valid, no second Autoconfig-board on the +same card, no space preferrence, supports "Shutup_forever". + +Setting the base address should be done in two steps, just +as the Amiga Kickstart does: The lower nibble of the 8-Bit +address is written to $4a, then the whole Byte is written to +$48, while it doesn't matter how often you're writing to $4a +as long as $48 is not touched. After $48 has been written, +the whole card disappears from $e8 and is mapped to the new +addrress just written. Make shure $4a is written befor $48, +otherwise your chance is only 1:16 to find the board :-). + +The local memory-map is even active when mapped to $e8: + +$0-$7e Autokonfig-space, see Z-II docs. + +$80-$7fd reserved + +$7fe Speed-select Register: Read & Write + (description see further down) + +$800-$8ff IDE-Select 0 (Port 0, Register set 0) + +$900-$9ff IDE-Select 1 (Port 0, Register set 1) + +$a00-$aff IDE-Select 2 (Port 1, Register set 0) + +$b00-$bff IDE-Select 3 (Port 1, Register set 1) + +$c00-$cff IDE-Select 4 (Port 2, Register set 0, + Catweasel only!) + +$d00-$dff IDE-Select 5 (Port 3, Register set 1, + Catweasel only!) + +$e00-$eff local expansion port, on Catweasel Z-II the + Catweasel registers are also mapped here. + Never touch, use multidisk.device! + +$f00 read only, Byte-access: Bit 7 shows the + level of the IRQ-line of IDE port 0. + +$f01-$f3f mirror of $f00 + +$f40 read only, Byte-access: Bit 7 shows the + level of the IRQ-line of IDE port 1. + +$f41-$f7f mirror of $f40 + +$f80 read only, Byte-access: Bit 7 shows the + level of the IRQ-line of IDE port 2. + (Catweasel only!) + +$f81-$fbf mirror of $f80 + +$fc0 write-only: Writing any value to this + register enables IRQs to be passed from the + IDE ports to the Zorro bus. This mechanism + has been implemented to be compatible with + harddisks that are either defective or have + a buggy firmware and pull the IRQ line up + while starting up. If interrupts would + always be passed to the bus, the computer + might not start up. Once enabled, this flag + can not be disabled again. The level of the + flag can not be determined by software + (what for? Write to me if it's necessary!). + +$fc1-$fff mirror of $fc0 + +$1000-$ffff Buddha-Rom with offset $1000 in the rom + chip. The addresses $0 to $fff of the rom + chip cannot be read. Rom is Byte-wide and + mapped to even addresses. + +The IDE ports issue an INT2. You can read the level of the +IRQ-lines of the IDE-ports by reading from the three (two +for Buddha-only) registers $f00, $f40 and $f80. This way +more than one I/O request can be handled and you can easily +determine what driver has to serve the INT2. Buddha and +Catweasel expansion boards can issue an INT6. A seperate +memory map is available for the I/O module and the sysop's +I/O module. + +The IDE ports are fed by the address lines A2 to A4, just as +the Amiga 1200 and Amiga 4000 IDE ports are. This way +existing drivers can be easily ported to Buddha. A move.l +polls two words out of the same address of IDE port since +every word is mirrored once. movem is not possible, but +it's not necessary either, because you can only speedup +68000 systems with this technique. A 68020 system with +fastmem is faster with move.l. + +If you're using the mirrored registers of the IDE-ports with +A6=1, the Buddha doesn't care about the speed that you have +selected in the speed register (see further down). With +A6=1 (for example $840 for port 0, register set 0), a 780ns +access is being made. These registers should be used for a +command access to the harddisk/CD-Rom, since command +accesses are Byte-wide and have to be made slower according +to the ATA-X3T9 manual. + +Now for the speed-register: The register is byte-wide, and +only the upper three bits are used (Bits 7 to 5). Bit 4 +must always be set to 1 to be compatible with later Buddha +versions (if I'll ever update this one). I presume that +I'll never use the lower four bits, but they have to be set +to 1 by definition. + The values in this table have to be shifted 5 bits to the +left and or'd with $1f (this sets the lower 5 bits). + +All the timings have in common: Select and IOR/IOW rise at +the same time. IOR and IOW have a propagation delay of +about 30ns to the clocks on the Zorro bus, that's why the +values are no multiple of 71. One clock-cycle is 71ns long +(exactly 70,5 at 14,18 Mhz on PAL systems). + +value 0 (Default after reset) + +497ns Select (7 clock cycles) , IOR/IOW after 172ns (2 clock cycles) +(same timing as the Amiga 1200 does on it's IDE port without +accelerator card) + +value 1 + +639ns Select (9 clock cycles), IOR/IOW after 243ns (3 clock cycles) + +value 2 + +781ns Select (11 clock cycles), IOR/IOW after 314ns (4 clock cycles) + +value 3 + +355ns Select (5 clock cycles), IOR/IOW after 101ns (1 clock cycle) + +value 4 + +355ns Select (5 clock cycles), IOR/IOW after 172ns (2 clock cycles) + +value 5 + +355ns Select (5 clock cycles), IOR/IOW after 243ns (3 clock cycles) + +value 6 + +1065ns Select (15 clock cycles), IOR/IOW after 314ns (4 clock cycles) + +value 7 + +355ns Select, (5 clock cycles), IOR/IOW after 101ns (1 clock cycle) + +When accessing IDE registers with A6=1 (for example $84x), +the timing will always be mode 0 8-bit compatible, no matter +what you have selected in the speed register: + +781ns select, IOR/IOW after 4 clock cycles (=314ns) aktive. + +All the timings with a very short select-signal (the 355ns +fast accesses) depend on the accelerator card used in the +system: Sometimes two more clock cycles are inserted by the +bus interface, making the whole access 497ns long. This +doesn't affect the reliability of the controller nor the +performance of the card, since this doesn't happen very +often. + +All the timings are calculated and only confirmed by +measurements that allowed me to count the clock cycles. If +the system is clocked by an oscillator other than 28,37516 +Mhz (for example the NTSC-frequency 28,63636 Mhz), each +clock cycle is shortened to a bit less than 70ns (not worth +mentioning). You could think of a small performance boost +by overclocking the system, but you would either need a +multisync monitor, or a graphics card, and your internal +diskdrive would go crazy, that's why you shouldn't tune your +Amiga this way. + +Giving you the possibility to write software that is +compatible with both the Buddha and the Catweasel Z-II, The +Buddha acts just like a Catweasel Z-II with no device +connected to the third IDE-port. The IRQ-register $f80 +always shows a "no IRQ here" on the Buddha, and accesses to +the third IDE port are going into data's Nirwana on the +Buddha. + + Jens Schönfeld february 19th, 1997 + updated may 27th, 1997 + eMail: sysop@nostlgic.tng.oche.de + diff --git a/Documentation/networking/8139too.txt b/Documentation/networking/8139too.txt new file mode 100644 index 000000000..6a75c7338 --- /dev/null +++ b/Documentation/networking/8139too.txt @@ -0,0 +1,194 @@ + + "8139too" Fast Ethernet driver for Linux + Improved support for RTL-8139 Fast Ethernet adapters + + Copyright 2000 Jeff Garzik + + + Architectures supported (all PCI platforms): + x86, Alpha AXP, PowerPC, Sparc64 + + + + +Disclaimer +---------- + +THIS DRIVER IS A DEVELOPMENT RELEASE FOR A DEVELOPMENT KERNEL. DO NOT +USE IN A PRODUCTION ENVIRONMENT. + +DO NOT CONTACT DONALD BECKER FOR SUPPORT OF THIS DRIVER, his driver is +completely different and maintained independently of the 8139too code base. + + + +Requirements +------------ +Kernel 2.3.41 or later. +A Fast Ethernet adapter containing an RTL8139-based chip. + + + +Introduction +------------ + +The "8139too" Fast Ethernet driver for Linux 2.4.0 is a substantial +modification of the experimental rtl8139 driver from Donald Becker, +some versions of which appeared in 2.2.x and 2.3.x kernels. The +RTL-8139 is a very low-cost Fast Ethernet chip, which makes it very +popular. + +The step from 2.2.x to 2.4.x kernels brings many new features to Linux +device drivers. Features for MMIO resources, a standard hot-plug API, +and other interfaces are now becoming requirements, as drivers move +off the x86 platform. With that in mind, I have begun updating the +RTL-8139 driver to current 2.3.x (2.4) kernel standards and APIs, and +fixing the problems that users have been encountering. + + + +Features of 8139too +------------------- +[note - this list intended for people familiar with kernel drivers] + +** 100% MMIO, for full speed operation. All users (so far) have +reported performance increases over their existing RTL drivers. + +** Multi-platform support: x86, Alpha, PPC, ... + +** Use proper SMP spinlocking, fixing SMP interrupt bugs, making the +driver portable to non-x86 SMP platforms in the process. + +** Use new PCI driver API for seamless, low-maintenance hot-plug support + +** Several bugs fixes from original rtl8139 1.08r (October 5, 1999), +including the very common "transmit timeout" problem. + +* Use new resource allocation API, required for hot-plug support +* Use new register read/write macros +* initcall support (module_init/exit) +* vastly improved debug tracing support +* code formatting in many places for readability +* use new init_etherdev() facilities + +...and probably some other less important changes which I forgot. + + + +Installation +------------ + +OPTION 1: Build inside kernel tree (into kernel image, or as module) + + (overwrite 8139too driver in kernel tree with different version) + 1) cp 8139too.c $my_source_tree/drivers/net/8139too.c + +OPTION 2: Build outside kernel tree + + Use the included Makefile. + + + +Tested Adapters +--------------- +AOpen ALN-325C +KTI KF-230TX +KTI KF-230TX/2 + +(please add your adapter model to this list) + + + +Status of Platform Support +-------------------------- + +(see errata below for details) + +x86: tested, stable +Alpha AXP: tested, stable +PowerPC: tested, unstable +Sparc64: not tested + + + +Special Thanks +-------------- +The following people contributed invaluable testing time, feedback +and/or patches during the development of this driver. Thanks to all +of them. + +Donald Becker, Alan Cox, Richard Stallman, Linus Torvalds - inspiration + +Alan Cox, Gerard Roudier - insight on posted MMIO writes + +Martin Mares - code review + +Tigran Aivazian - testing, code review, and a bug fix + +Chmouel Boudjnah, Alexander Dietrich, Oleg Drokin, +James Fidell, Taso Hatzi, Peter K - intrepid test team + +And thanks to every supporter free software. + + + +Known Bugs / Errata / To-Do +--------------------------- +The following issues are known, and are actively being pursued. Patches +to resolve these issues is welcome. If a problem occurs which is not in +the list, please report it. That's why we do beta releases, after all... + + + +1) Work with Donald to merge fixes and updates into his driver. + +2) 2.2.x COMPATIBILITY SUPPORT IS BROKEN. DO NOT USE IT. +It is included only for enterprising hackers willing to help fix it. + +3) PPC platform has stability problems. + +4) Sparc64 platform not tested at all. + +5) Identify and fix "rx wedge" when ping flooded. + +7) N-Way auto-negotiation is known to fail in some cases. This problem +also occurs in the rtl8139 driver in kernels 2.2.x/2.3.x. Solution: +Following technique in sunhme and sunbmac, use a kernel timer to +manually perform autonegotiation in case the network or card cannot do +it automatically. (patches welcome) + +8) Much improved command line / module parameter setup. (patches and +suggestions welcome) + +9) Better documentation. (patches welcome) + +10) User-mode (or maybe optional /proc) diagnostics program. + + + + +Change History +-------------- +Version 0.9.3.3.2 - Feb 22, 2000 - second public beta release + +* Begin integration of Daniel Kobras' MMIO flush patch (disabled for now) +* Softnet logic updates to fix bugs and improve performance +* Dynamic sizing of I/O resources (0x80 for older chips, 0xFF for newer ones) +* Remove bogus SiS entries from PCI probe table +* Add support for cards + "Delta Electronics 8139 10/100BaseTX" + "Addtron Technolgy 8139 10/100BaseTX" +* Fix major bug with rx ring buffer size (also present in rtl8139.c 1.08r) +* PCI DMA mapping by Dave Miller +* Complete rewrite of SMP locking logic +* Hotplug support +* Call rtl8139_hw_start from rtl8139_open, and remove duplicated code + from rtl8139_open +* Reset NWay registers to sane defaults on rtl8139_open/hw_start +* Miscellaneous code cleanup + +Version 0.7.0 - Feb 7, 2000 - first public beta release + + +[EOF] + diff --git a/Documentation/networking/fore200e.txt b/Documentation/networking/fore200e.txt new file mode 100644 index 000000000..13ee5327e --- /dev/null +++ b/Documentation/networking/fore200e.txt @@ -0,0 +1,55 @@ + +Fore PCA-200E/SBA-200E ATM NIC Firmware Copyright Notice +-------------------------------------------------------- + +Please read the fore200e_firmware_copyright file present +in the linux/drivers/atm directory for details and restrictions. + + +Firmware Updates +---------------- + +The FORE Systems 200E-series driver is shipped with firmware data being +uploaded to the ATM adapters at system boot time or at module loading time. +The supplied firmware images should work with all adapters. + +However, if you encounter problems (firmware doesn't start or the driver +is unable to read PROM data), you may consider trying another firmware +version. Alternative binary firmware images can be found somewhere on the +ForeThough CD-ROM supplied with your adapter by FORE Systems. + +You can also get the latest firmware images from FORE Systems at +http://www.fore.com. Register TACTics Online and go to +the 'software updates' pages. The firmware binaries are part of +the various ForeThough software distributions. + +Notice that different versions of the PCA-200E firmware exist, depending +on the endianess of the host architecture. The driver is shipped with +both little and big endian PCA firmware images. + +Name and location of the new firmware images can be set at kernel +configuration time. + + +Driver Rebuilding +----------------- + +1. Copy the new firmware binary files (with .bin, .bin1 or .bin2 suffix) + to some directory, such as linux/drivers/atm. + +2. Reconfigure your kernel to set the new firmware name and location. + Expected pathnames are absolute or relative to the drivers/atm directory. + +3. Delete the files drivers/atm/fore200e_pca_fw.[co] and/or fore200e_sba_fw.[co] + to ensure that the new firmware will be used when rebuilding the kernel or + the module. + +4. Rebuild and re-install your kernel or your module. + + +Feedback +-------- + +Feedback is welcome. Please send success stories/bug reports/ +patches/improvement/comments/flames to . + diff --git a/Documentation/networking/tulip.txt b/Documentation/networking/tulip.txt index 4a83d1bf2..ecef178b0 100644 --- a/Documentation/networking/tulip.txt +++ b/Documentation/networking/tulip.txt @@ -1,110 +1,144 @@ Tulip Ethernet Card Driver + Maintained by Jeff Garzik The Tulip driver is developed by Donald Becker and changed by -Takashi Manabe. This driver is designed to work with PCI Ethernet -cards which use the DECchip DC21x4x family. This driver hopefully -works with all of 1.2.x and 1.3.x kernels, but I tested only -with 1.2.13, 1.3.39, 1.3.49, 1.3.52, 1.3.57 and later. - -Hopefully, the de4x5.c driver will support all cards supported -by the tulip.c driver. However, the SMC's 9332dst card and some -cards do not work with the de4x5.c driver. So, if your card is -not a 9332dst, please try the de4x5.c driver first. - -Success List -============ - -+-------------------------------------+-----------+-------------+ -|vendor/card |chip |system | -+-------------------------------------+-----------+-------------+ -|SMC | | | -| EtherPower 10 PCI(8432T/8432BT) |21040/21041|Pentium | -+-------------------------------------+-----------+-------------+ -|SMC | | | -| EtherPower 10/100 PCI(9332DST) |21140 |Pentium/UDB | -+-------------------------------------+-----------+-------------+ -|DEC | | | -| EtherWorks 100/10 PCI(DE500-XA) |21140 |Pentium | -+-------------------------------------+-----------+-------------+ -|DEC | | | -| EtherWorks 10 PCI(DE450) |21041 |Pentium | -+-------------------------------------+-----------+-------------+ -|DEC | | | -| QSILVER's |21040 |UDB | -+-------------------------------------+-----------+-------------+ -|ZNYX | | | -| 312 etherarray |21040 |Pentium | -+-------------------------------------+-----------+-------------+ -|Allied Telesis | | | -| LA100PCI-T |21140 |Pentium/UDB | -+-------------------------------------+-----------+-------------+ -|Danpex ('Planet Japan' in Japan?) | | | -| EN-9400 |21040 |Pentium | -+-------------------------------------+-----------+-------------+ -|Cogent | | | -| EM110 |21140 |Pentium | -+-------------------------------------+-----------+-------------+ - -Pentium: PCI machine with Pentium CPU -UDB: Universal Desktop Box(aka Multia) with Alpha 21066 CPU - -Known bug(s) -============ -This driver's media detection is very simple and sometimes -it causes serious problem. The driver automatically switches -media when it causes timeout. If you want to specify or to fix -a media; - -- Modify TULIP_PORT in tulip.c, line 33. -- Uncomment the definition of TULIP_FIX_PORT in tulip.c, line 40. - -or - -- Use patched ifconfig command and specify 'link='. The patch - against ifconfig.c in net-tools-1.3.50-BETA6e is included in - this file. - -Thanks +Takashi Manabe and a cast of thousands. + + This driver is for the Digital "Tulip" Ethernet adapter interface. + It should work with most DEC 21*4*-based chips/ethercards, as well as + with work-alike chips from Lite-On (PNIC) and Macronix (MXIC) and ASIX. + + The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O + Center of Excellence in Space Data and Information Sciences + Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 + + Additional information available at + http://cesdis.gsfc.nasa.gov/linux/drivers/tulip.html + + Theory of Operation + +Board Compatibility +=================== + +This device driver is designed for the DECchip "Tulip", Digital's +single-chip ethernet controllers for PCI. Supported members of the family +are the 21040, 21041, 21140, 21140A, 21142, and 21143. Similar work-alike +chips from Lite-On, Macronics, ASIX, Compex and other listed below are also +supported. + +These chips are used on at least 140 unique PCI board designs. The great +number of chips and board designs supported is the reason for the +driver size and complexity. Almost of the increasing complexity is in the +board configuration and media selection code. There is very little +increasing in the operational critical path length. + +Board-specific settings +======================= + +PCI bus devices are configured by the system at boot time, so no jumpers +need to be set on the board. The system BIOS preferably should assign the +PCI INTA signal to an otherwise unused system IRQ line. + +Some boards have EEPROMs tables with default media entry. The factory default +is usually "autoselect". This should only be overridden when using +transceiver connections without link beat e.g. 10base2 or AUI, or (rarely!) +for forcing full-duplex when used with old link partners that do not do +autonegotiation. + +Driver operation +================ + +Ring buffers +------------ + +The Tulip can use either ring buffers or lists of Tx and Rx descriptors. +This driver uses statically allocated rings of Rx and Tx descriptors, set at +compile time by RX/TX_RING_SIZE. This version of the driver allocates skbuffs +for the Rx ring buffers at open() time and passes the skb->data field to the +Tulip as receive data buffers. When an incoming frame is less than +RX_COPYBREAK bytes long, a fresh skbuff is allocated and the frame is +copied to the new skbuff. When the incoming frame is larger, the skbuff is +passed directly up the protocol stack and replaced by a newly allocated +skbuff. + +The RX_COPYBREAK value is chosen to trade-off the memory wasted by +using a full-sized skbuff for small frames vs. the copying costs of larger +frames. For small frames the copying cost is negligible (esp. considering +that we are pre-loading the cache with immediately useful header +information). For large frames the copying cost is non-trivial, and the +larger copy might flush the cache of useful data. A subtle aspect of this +choice is that the Tulip only receives into longword aligned buffers, thus +the IP header at offset 14 isn't longword aligned for further processing. +Copied frames are put into the new skbuff at an offset of "+2", thus copying +has the beneficial effect of aligning the IP header and preloading the +cache. + +Synchronization +--------------- +The driver runs as two independent, single-threaded flows of control. One +is the send-packet routine, which enforces single-threaded use by the +dev->tbusy flag. The other thread is the interrupt handler, which is single +threaded by the hardware and other software. + +The send packet thread has partial control over the Tx ring and 'dev->tbusy' +flag. It sets the tbusy flag whenever it's queuing a Tx packet. If the next +queue slot is empty, it clears the tbusy flag when finished otherwise it sets +the 'tp->tx_full' flag. + +The interrupt handler has exclusive control over the Rx ring and records stats +from the Tx ring. (The Tx-done interrupt can't be selectively turned off, so +we can't avoid the interrupt overhead by having the Tx routine reap the Tx +stats.) After reaping the stats, it marks the queue entry as empty by setting +the 'base' to zero. Iff the 'tp->tx_full' flag is set, it clears both the +tx_full and tbusy flags. + +Notes +===== + +Thanks to Duke Kamstra of SMC for long ago providing an EtherPower board. +Greg LaPolla at Linksys provided PNIC and other Linksys boards. +Znyx provided a four-port card for testing. + +References +========== + +http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html +http://www.digital.com (search for current 21*4* datasheets and "21X4 SROM") +http://www.national.com/pf/DP/DP83840A.html +http://www.asix.com.tw/pmac.htm +http://www.admtek.com.tw/ + +Errata ====== -o becker@CESDIS.gsfc.nasa.gov (author of the tulip.c driver) -o davies@wanton.lkg.dec.com (author of the de4x5.c driver) - -o siekas@mailhost.tcs.tulane.edu - -o jheiss@calvin.caltech.edu (providing information about smc8432 card) -o goto@plathome.co.jp (lending me a DE450 card) -o ted@physics.ucsb.edu -o pmheuvel@xs4all.nl -o hjl@lucon.org (EN-9400) -o niles@axp745.gsfc.nasa.gov (ZNYX312) -o pkc@scs.carleton.ca (EM110) -o and testers... - ------------------------------------------------------------------------ -*** ifconfig.c-dist Wed Jan 17 07:25:36 1996 ---- ifconfig.c Tue Apr 9 15:24:25 1996 -*************** -*** 765,770 **** ---- 766,786 ---- - continue; - } - ifr.ifr_map.irq = atoi(*spp); -+ if (ioctl(skfd, SIOCSIFMAP, &ifr) < 0) { -+ fprintf(stderr, "SIOCSIFMAP: %s\n", strerror(errno)); -+ goterr = 1; -+ } -+ spp++; -+ continue; -+ } -+ -+ if (!strcmp(*spp, "link")) { -+ if (*++spp == NULL) usage(); -+ if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0) { -+ goterr = 1; -+ continue; -+ } -+ ifr.ifr_map.port = atoi(*spp); - if (ioctl(skfd, SIOCSIFMAP, &ifr) < 0) { - fprintf(stderr, "SIOCSIFMAP: %s\n", strerror(errno)); - goterr = 1; +The old DEC databooks were light on details. +The 21040 databook claims that CSR13, CSR14, and CSR15 should each be the last +register of the set CSR12-15 written. Hmmm, now how is that possible? + +The DEC SROM format is very badly designed not precisely defined, leading to +part of the media selection junkheap below. Some boards do not have EEPROM +media tables and need to be patched up. Worse, other boards use the DEC +design kit media table when it isn't correct for their board. + +We cannot use MII interrupts because there is no defined GPIO pin to attach +them. The MII transceiver status is polled using an kernel timer. + + +Source tree tour +---------------- +The following is a list of files comprising the Tulip ethernet driver in +drivers/net/tulip subdirectory. + +21142.c - 21142-specific h/w interaction +eeprom.c - EEPROM reading and parsing +interrupt.c - Interrupt handler +media.c - Media selection and MII support +pnic.c - PNIC-specific h/w interaction +timer.c - Main driver timer, and misc h/w timers +tulip.h - Private driver header +tulip_core.c - Driver core (a.k.a. where "everything else" goes) + + + +[EOF] + diff --git a/Documentation/networking/wavelan.txt b/Documentation/networking/wavelan.txt index a4a1f7921..82006e55d 100644 --- a/Documentation/networking/wavelan.txt +++ b/Documentation/networking/wavelan.txt @@ -1,41 +1,73 @@ -Sun Jul 2 01:38:33 EST 1995 - - As the date above certify, this ``readme'' is mostly -obsolete. Please read release notes and change list in -driver/net/wavelan.p.h, and consult my web page at : - http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Wavelan.html - - Jean - -1. At present the driver autoprobes for a WaveLAN card only at I/O address - 0x390. The version of the card that I use (NCR) supports four I/O addresses - (selectable via a pair of DIP switches). If you want the driver to - autoprobe a different subset of the four valid addresses then you will need - to edit .../drivers/net/wavelan.c (near line 714) and change the - initialisation of the `iobase[]' array. Normally, I use a LILO - configuration file directive to obviate the need for autoprobing entirely, - a course of action I heartily recommend. - -2. By default, the driver uses the Network ID (NWID) stored in the card's - Parameter Storage Area (PSA). However, the PSA NWID can be overridden by a - value passed explicitly as the third numeric argument to LILO's "ether=" - directive, either at the LILO prompt at boot time or within LILO's - configuration file. - For example, the following line from such a LILO configuration file would - auto-configure the IRQ value, set the I/O base to 0x390 and set the NWID to - 0x4321, all on a WaveLAN card labelled "eth0": - - .. - append ="ether=0,0x390,0x4321,eth0" - .. - -3. The driver uses the IRQ stored in the card's PSA. - To change this you will need to use the configuration/setup software that - accompanies each WaveLAN device. Yes, the driver should use the value passed - in via LILO and it will, just as soon as I can work out why that part of the - code doesn't work :-(. - -4. If you encounter any problems send me some email. - -Good luck, -Bruce Janson (bruce@cs.usyd.edu.au) + The Wavelan drivers saga + ------------------------ + + By Jean Tourrilhes + + The Wavelan is a Radio network adapter designed by +Lucent. Under this generic name is hidden quite a variety of hardware, +and many Linux driver to support it. + The get the full story on Wireless LANs, please consult : + http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/ + +"wavelan" driver (old ISA Wavelan) +---------------- + o Config : Network device -> Wireless LAN -> AT&T WaveLAN + o Location : .../drivers/net/wavelan* + o in-line doc : .../drivers/net/wavelan.p.h + o on-line doc : + http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Wavelan.html + + This is the driver for the ISA version of the first generation +of the Wavelan, now discontinued. The device is 2 Mb/s, composed of a +Intel 82586 controler and a Lucent Modem, and is NOT 802.11 compliant. + The driver has been tested with the following hardware : + o Wavelan ISA 915 MHz (full length ISA card) + o Wavelan ISA 915 MHz 2.0 (half length ISA card) + o Wavelan ISA 2.4 GHz (full length ISA card, fixed frequency) + o Wavelan ISA 2.4 GHz 2.0 (half length ISA card, frequency selectable) + o Above cards with the optional DES encryption feature + +"wavelan_cs" driver (old Pcmcia Wavelan) +------------------- + o Config : Network device -> PCMCIA network -> + Pcmcia Wireless LAN -> AT&T/Lucent WaveLAN + o Location : .../drivers/net/pcmcia/wavelan* + o in-line doc : .../drivers/net/pcmcia/wavelan_cs.h + o on-line doc : + http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Wavelan.html + + This is the driver for the PCMCIA version of the first +generation of the Wavelan, now discontinued. The device is 2 Mb/s, +composed of a Intel 82593 controler (totally different from the 82586) +and a Lucent Modem, and NOT 802.11 compatible. + The driver has been tested with the following hardware : + o Wavelan Pcmcia 915 MHz 2.0 (Pcmcia card + separate + modem/antenna block) + o Wavelan Pcmcia 2.4 GHz 2.0 (Pcmcia card + separate + modem/antenna block) + +"wvlan_cs" driver (Wavelan IEEE, GPL) +----------------- + o Config : Not yet in kernel + o Location : Pcmcia package 3.1.10+ + o on-line doc : http://www.fasta.fh-dortmund.de/users/andy/wvlan/ + + This is the driver for the current generation of Wavelan IEEE, +which is 802.11 compatible. Depending on version, it is 2 Mb/s or 11 +Mb/s, with or without encryption, all implemented in Lucent specific +DSP (the Hermes). + This is a GPL full source PCMCIA driver (ISA is just a Pcmcia +card with ISA-Pcmcia bridge). + +"wavelan2_cs" driver (Wavelan IEEE, binary) +-------------------- + o Config : Not yet in kernel + o Location : ftp://sourceforge.org/pcmcia/contrib/ + + This driver support exactly the same hardware as the previous +driver, the main difference is that it is based on a binary library +and supported by Lucent. + + I hope it clears the confusion ;-) + + Jean diff --git a/Documentation/parport-lowlevel.txt b/Documentation/parport-lowlevel.txt new file mode 100644 index 000000000..1d40008a1 --- /dev/null +++ b/Documentation/parport-lowlevel.txt @@ -0,0 +1,1490 @@ +PARPORT interface documentation +------------------------------- + +Time-stamp: <2000-02-24 13:30:20 twaugh> + +Described here are the following functions: + +Global functions: + parport_register_driver + parport_unregister_driver + parport_enumerate + parport_register_device + parport_unregister_device + parport_claim + parport_claim_or_block + parport_release + parport_yield + parport_yield_blocking + parport_wait_peripheral + parport_poll_peripheral + parport_wait_event + parport_negotiate + parport_read + parport_write + parport_open + parport_close + parport_device_id + parport_device_num + parport_device_coords + parport_find_class + parport_find_device + parport_set_timeout + +Port functions (can be overridden by low-level drivers): + SPP: + port->ops->read_data + port->ops->write_data + port->ops->read_status + port->ops->read_control + port->ops->write_control + port->ops->frob_control + port->ops->enable_irq + port->ops->disable_irq + port->ops->data_forward + port->ops->data_reverse + + EPP: + port->ops->epp_write_data + port->ops->epp_read_data + port->ops->epp_write_addr + port->ops->epp_read_addr + + ECP: + port->ops->ecp_write_data + port->ops->ecp_read_data + port->ops->ecp_write_addr + + Other: + port->ops->nibble_read_data + port->ops->byte_read_data + port->ops->compat_write_data + +The parport subsystem comprises 'parport' (the core port-sharing +code), and a variety of low-level drivers that actually do the port +accesses. Each low-level driver handles a particular style of port +(PC, Amiga, and so on). + +The parport interface to the device driver author can be broken down +into global functions and port functions. + +The global functions are mostly for communicating between the device +driver and the parport subsystem: acquiring a list of available ports, +claiming a port for exclusive use, and so on. They also include +'generic' functions for doing standard things that will work on any +IEEE 1284-capable architecture. + +The port functions are provided by the low-level drivers, although the +core parport module provides generic 'defaults' for some routines. +The port functions can be split into three groups: SPP, EPP, and ECP. + +SPP (Standard Parallel Port) functions modify so-called 'SPP' +registers: data, status, and control. The hardware may not actually +have registers exactly like that, but the PC does and this interface is +modelled after common PC implementations. Other low-level drivers may +be able to emulate most of the functionality. + +EPP (Enhanced Parallel Port) functions are provided for reading and +writing in IEEE 1284 EPP mode, and ECP (Extended Capabilities Port) +functions are used for IEEE 1284 ECP mode. (What about BECP? Does +anyone care?) + +Hardware assistance for EPP and/or ECP transfers may or may not be +available, and if it is available it may or may not be used. If +hardware is not used, the transfer will be software-driven. In order +to cope with peripherals that only tenuously support IEEE 1284, a +low-level driver specific function is provided, for altering 'fudge +factors'. + +GLOBAL FUNCTIONS +---------------- + +parport_register_driver - register a device driver with parport +----------------------- + +SYNOPSIS + +#include + +struct parport_driver { + const char *name; + void (*attach) (struct parport *); + void (*detach) (struct parport *); + struct parport_driver *next; +}; +int parport_register_driver (struct parport_driver *driver); + +DESCRIPTION + +In order to be notified about parallel ports when they are detected, +parport_register_driver should be called. Your driver will +immediately be notified of all ports that have already been detected, +and of each new port as low-level drivers are loaded. + +A 'struct parport_driver' contains the textual name of your driver, +a pointer to a function to handle new ports, and a pointer to a +function to handle ports going away due to a low-level driver +unloading. Ports will only be detached if they are not being used +(i.e. there are no devices registered on them). + +The visible parts of the 'struct parport *' argument given to +attach/detach are: + +struct parport +{ + struct parport *next; /* next parport in list */ + const char *name; /* port's name */ + unsigned int modes; /* bitfield of hardware modes */ + struct parport_device_info probe_info; + /* IEEE1284 info */ + int number; /* parport index */ + struct parport_operations *ops; + ... +}; + +There are other members of the structure, but they should not be +touched. + +The 'modes' member summarises the capabilities of the underlying +hardware. It consists of flags which may be bitwise-ored together: + + PARPORT_MODE_PCSPP IBM PC registers are available, + i.e. functions that act on data, + control and status registers are + probably writing directly to the + hardware. + PARPORT_MODE_TRISTATE The data drivers may be turned off. + This allows the data lines to be used + for reverse (peripheral to host) + transfers. + PARPORT_MODE_COMPAT The hardware can assist with + compatibility-mode (printer) + transfers, i.e. compat_write_block. + PARPORT_MODE_EPP The hardware can assist with EPP + transfers. + PARPORT_MODE_ECP The hardware can assist with ECP + transfers. + PARPORT_MODE_DMA The hardware can use DMA, so you might + want to pass ISA DMA-able memory + (i.e. memory allocated using the + GFP_DMA flag with kmalloc) to the + low-level driver in order to take + advantage of it. + +There may be other flags in 'modes' as well. + +The contents of 'modes' is advisory only. For example, if the +hardware is capable of DMA, and PARPORT_MODE_DMA is in 'modes', it +doesn't necessarily mean that DMA will always be used when possible. +Similarly, hardware that is capable of assisting ECP transfers won't +necessarily be used. + +RETURN VALUE + +Zero on success, otherwise an error code. + +ERRORS + +None. (Can it fail? Why return int?) + +EXAMPLE + +static void lp_attach (struct parport *port) +{ + ... + private = kmalloc (...); + dev[count++] = parport_register_device (...); + ... +} + +static void lp_detach (struct parport *port) +{ + ... +} + +static struct parport_driver lp_driver = { + "lp", + lp_attach, + lp_detach, + NULL /* always put NULL here */ +}; + +int lp_init (void) +{ + ... + if (parport_register_driver (&lp_driver)) { + /* Failed; nothing we can do. */ + return -EIO; + } + ... +} + +SEE ALSO + +parport_unregister_driver, parport_register_device, parport_enumerate + +parport_unregister_driver - tell parport to forget about this driver +------------------------- + +SYNOPSIS + +#include + +struct parport_driver { + const char *name; + void (*attach) (struct parport *); + void (*detach) (struct parport *); + struct parport_driver *next; +}; +void parport_unregister_driver (struct parport_driver *driver); + +DESCRIPTION + +This tells parport not to notify the device driver of new ports or of +ports going away. Registered devices belonging to that driver are NOT +unregistered: parport_unregister_device must be used for each one. + +EXAMPLE + +void cleanup_module (void) +{ + ... + /* Stop notifications. */ + parport_unregister_driver (&lp_driver); + + /* Unregister devices. */ + for (i = 0; i < NUM_DEVS; i++) + parport_unregister_device (dev[i]); + ... +} + +SEE ALSO + +parport_register_driver, parport_enumerate + +parport_enumerate - retrieve a list of parallel ports (DEPRECATED) +----------------- + +SYNOPSIS + +#include + +struct parport *parport_enumerate (void); + +DESCRIPTION + +Retrieve the first of a list of valid parallel ports for this machine. +Successive parallel ports can be found using the 'struct parport +*next' element of the 'struct parport *' that is returned. If 'next' +is NULL, there are no more parallel ports in the list. The number of +ports in the list will not exceed PARPORT_MAX. + +RETURN VALUE + +A 'struct parport *' describing a valid parallel port for the machine, +or NULL if there are none. + +ERRORS + +This function can return NULL to indicate that there are no parallel +ports to use. + +EXAMPLE + +int detect_device (void) +{ + struct parport *port; + + for (port = parport_enumerate (); + port != NULL; + port = port->next) { + /* Try to detect a device on the port... */ + ... + } + } + + ... +} + +NOTES + +parport_enumerate is deprecated; parport_register_driver should be +used instead. + +SEE ALSO + +parport_register_driver, parport_unregister_driver + +parport_register_device - register to use a port +----------------------- + +SYNOPSIS + +#include + +typedef int (*preempt_func) (void *handle); +typedef void (*wakeup_func) (void *handle); +typedef int (*irq_func) (int irq, void *handle, struct pt_regs *); + +struct pardevice *parport_register_device(struct parport *port, + const char *name, + preempt_func preempt, + wakeup_func wakeup, + irq_func irq, + int flags, + void *handle); + +DESCRIPTION + +Use this function to register your device driver on a parallel port +('port'). Once you have done that, you will be able to use +parport_claim and parport_release in order to use the port. + +This function will register three callbacks into your driver: +'preempt', 'wakeup' and 'irq'. Each of these may be NULL in order to +indicate that you do not want a callback. + +When the 'preempt' function is called, it is because another driver +wishes to use the parallel port. The 'preempt' function should return +non-zero if the parallel port cannot be released yet -- if zero is +returned, the port is lost to another driver and the port must be +re-claimed before use. + +The 'wakeup' function is called once another driver has released the +port and no other driver has yet claimed it. You can claim the +parallel port from within the 'wakeup' function (in which case the +claim is guaranteed to succeed), or choose not to if you don't need it +now. + +If an interrupt occurs on the parallel port your driver has claimed, +the 'irq' function will be called. (Write something about shared +interrupts here.) + +The 'handle' is a pointer to driver-specific data, and is passed to +the callback functions. + +'flags' may be a bitwise combination of the following flags: + + Flag Meaning + PARPORT_DEV_EXCL The device cannot share the parallel port at all. + Use this only when absolutely necessary. + +The typedefs are not actually defined -- they are only shown in order +to make the function prototype more readable. + +The visible parts of the returned 'struct pardevice' are: + +struct pardevice { + struct parport *port; /* Associated port */ + void *private; /* Device driver's 'handle' */ + ... +}; + +RETURN VALUE + +A 'struct pardevice *': a handle to the registered parallel port +device that can be used for parport_claim, parport_release, etc. + +ERRORS + +A return value of NULL indicates that there was a problem registering +a device on that port. + +EXAMPLE + +static int preempt (void *handle) +{ + if (busy_right_now) + return 1; + + must_reclaim_port = 1; + return 0; +} + +static void wakeup (void *handle) +{ + struct toaster *private = handle; + struct pardevice *dev = private->dev; + if (!dev) return; /* avoid races */ + + if (want_port) + parport_claim (dev); +} + +static int toaster_detect (struct toaster *private, struct parport *port) +{ + private->dev = parport_register_device (port, "toaster", preempt, + wakeup, NULL, 0, + private); + if (!private->dev) + /* Couldn't register with parport. */ + return -EIO; + + must_reclaim_port = 0; + busy_right_now = 1; + parport_claim_or_block (private->dev); + ... + /* Don't need the port while the toaster warms up. */ + busy_right_now = 0; + ... + busy_right_now = 1; + if (must_reclaim_port) { + parport_claim_or_block (private->dev); + must_reclaim_port = 0; + } + ... +} + +SEE ALSO + +parport_unregister_device, parport_claim + +parport_unregister_device - finish using a port +------------------------- + +SYNPOPSIS + +#include + +void parport_unregister_device (struct pardevice *dev); + +DESCRIPTION + +This function is the opposite of parport_register_device. After using +parport_unregister_device, 'dev' is no longer a valid device handle. + +You should not unregister a device that is currently claimed, although +if you do it will be released automatically. + +EXAMPLE + + ... + kfree (dev->private); /* before we lose the pointer */ + parport_unregister_device (dev); + ... + +SEE ALSO + +parport_unregister_driver + +parport_claim, parport_claim_or_block - claim the parallel port for a device +------------------------------------- + +SYNOPSIS + +#include + +int parport_claim (struct pardevice *dev); +int parport_claim_or_block (struct pardevice *dev); + +DESCRIPTION + +These functions attempt to gain control of the parallel port on which +'dev' is registered. 'parport_claim' does not block, but +'parport_claim_or_block' may do. (Put something here about blocking +interruptibly or non-interruptibly.) + +You should not try to claim a port that you have already claimed. + +RETURN VALUE + +A return value of zero indicates that the port was successfully +claimed, and the caller now has possession of the parallel port. + +If 'parport_claim_or_block' blocks before returning successfully, the +return value is positive. + +ERRORS + + -EAGAIN The port is unavailable at the moment, but another attempt + to claim it may succeed. + +SEE ALSO + +parport_release + +parport_release - release the parallel port +--------------- + +SYNOPSIS + +#include + +void parport_release (struct pardevice *dev); + +DESCRIPTION + +Once a parallel port device has been claimed, it can be released using +'parport_release'. It cannot fail, but you should not release a +device that you do not have possession of. + +EXAMPLE + +static size_t write (struct pardevice *dev, const void *buf, + size_t len) +{ + ... + written = dev->port->ops->write_ecp_data (dev->port, buf, + len); + parport_release (dev); + ... +} + + +SEE ALSO + +change_mode, parport_claim, parport_claim_or_block, parport_yield + +parport_yield, parport_yield_blocking - temporarily release a parallel port +------------------------------------- + +SYNOPSIS + +#include + +int parport_yield (struct pardevice *dev) +int parport_yield_blocking (struct pardevice *dev); + +DESCRIPTION + +When a driver has control of a parallel port, it may allow another +driver to temporarily 'borrow' it. 'parport_yield' does not block; +'parport_yield_blocking' may do. + +RETURN VALUE + +A return value of zero indicates that the caller still owns the port +and the call did not block. + +A positive return value from 'parport_yield_blocking' indicates that +the caller still owns the port and the call blocked. + +A return value of -EAGAIN indicates that the caller no longer owns the +port, and it must be re-claimed before use. + +ERRORS + + -EAGAIN Ownership of the parallel port was given away. + +SEE ALSO + +parport_release + +parport_wait_peripheral - wait for status lines, up to 35ms +----------------------- + +SYNOPSIS + +#include + +int parport_wait_peripheral (struct parport *port, + unsigned char mask, + unsigned char val); + +DESCRIPTION + +Wait for the status lines in mask to match the values in val. + +RETURN VALUE + + -EINTR a signal is pending + 0 the status lines in mask have values in val + 1 timed out while waiting (35ms elapsed) + +SEE ALSO + +parport_poll_peripheral + +parport_poll_peripheral - wait for status lines, in usec +----------------------- + +SYNOPSIS + +#include + +int parport_poll_peripheral (struct parport *port, + unsigned char mask, + unsigned char val, + int usec); + +DESCRIPTION + +Wait for the status lines in mask to match the values in val. + +RETURN VALUE + + -EINTR a signal is pending + 0 the status lines in mask have values in val + 1 timed out while waiting (usec microseconds have elapsed) + +SEE ALSO + +parport_wait_peripheral + +parport_wait_event - wait for an event on a port +------------------ + +SYNOPSIS + +#include + +int parport_wait_event (struct parport *port, signed long timeout) + +DESCRIPTION + +Wait for an event (e.g. interrupt) on a port. The timeout is in +jiffies. + +RETURN VALUE + + 0 success + <0 error (exit as soon as possible) + >0 timed out + +parport_negotiate - perform IEEE 1284 negotiation +----------------- + +SYNOPSIS + +#include + +int parport_negotiate (struct parport *, int mode); + +DESCRIPTION + +Perform IEEE 1284 negotiation. + +RETURN VALUE + + 0 handshake OK; IEEE 1284 peripheral and mode available + -1 handshake failed; peripheral not compliant (or none present) + 1 handshake OK; IEEE 1284 peripheral present but mode not + available + +SEE ALSO + +parport_read, parport_write + +parport_read - read data from device +------------ + +SYNOPSIS + +#include + +ssize_t parport_read (struct parport *, void *buf, size_t len); + +DESCRIPTION + +Read data from device in current IEEE 1284 transfer mode. This only +works for modes that support reverse data transfer. + +RETURN VALUE + +If negative, an error code; otherwise the number of bytes transferred. + +SEE ALSO + +parport_write, parport_negotiate + +parport_write - write data to device +------------- + +SYNOPSIS + +#include + +ssize_t parport_write (struct parport *, const void *buf, size_t len); + +DESCRIPTION + +Write data to device in current IEEE 1284 transfer mode. This only +works for modes that support forward data transfer. + +RETURN VALUE + +If negative, an error code; otherwise the number of bytes transferred. + +SEE ALSO + +parport_read, parport_negotiate + +parport_open - register device for particular device number +------------ + +SYNOPSIS + +#include + +struct pardevice *parport_open (int devnum, const char *name, + int (*pf) (void *), + void (*kf) (void *), + void (*irqf) (int, void *, + struct pt_regs *), + int flags, void *handle); + +DESCRIPTION + +This is like parport_register_device but takes a device number instead +of a pointer to a struct parport. + +RETURN VALUE + +See parport_register_device. If no device is associated with devnum, +NULL is returned. + +SEE ALSO + +parport_register_device, parport_device_num + +parport_close - unregister device for particular device number +------------- + +SYNOPSIS + +#include + +void parport_close (struct pardevice *dev); + +DESCRIPTION + +This is the equivalent of parport_unregister_device for parport_open. + +SEE ALSO + +parport_unregister_device, parport_open + +parport_device_id - obtain IEEE 1284 Device ID +----------------- + +SYNOPSIS + +#include + +ssize_t parport_device_id (int devnum, char *buffer, size_t len); + +DESCRIPTION + +Obtains the IEEE 1284 Device ID associated with a given device. + +RETURN VALUE + +If negative, an error code; otherwise, the number of bytes of buffer +that contain the device ID. The format of the device ID is as +follows: + +[length][ID] + +The first two bytes indicate the inclusive length of the entire Device +ID, and are in big-endian order. The ID is a sequence of pairs of the +form: + +key:value; + +NOTES + +Many devices have ill-formed IEEE 1284 Device IDs. + +SEE ALSO + +parport_find_class, parport_find_device, parport_device_num + +parport_device_num - convert device coordinates to device number +------------------ + +SYNOPSIS + +#include + +int parport_device_num (int parport, int mux, int daisy); + +DESCRIPTION + +Convert between device coordinates (port, multiplexor, daisy chain +address) and device number (zero-based). + +RETURN VALUE + +Device number, or -1 if no device at given coordinates. + +SEE ALSO + +parport_device_coords, parport_open, parport_device_id + +parport_device_coords - convert device number to device coordinates +------------------ + +SYNOPSIS + +#include + +int parport_device_coords (int devnum, int *parport, int *mux, + int *daisy); + +DESCRIPTION + +Convert between device number (zero-based) and device coordinates +(port, multiplexor, daisy chain address). + +RETURN VALUE + +Zero on success, in which case the coordinates are (*parport, *mux, +*daisy). + +SEE ALSO + +parport_device_num, parport_open, parport_device_id + +parport_find_class - find a device by its class +------------------ + +SYNOPSIS + +#include + +typedef enum { + PARPORT_CLASS_LEGACY = 0, /* Non-IEEE1284 device */ + PARPORT_CLASS_PRINTER, + PARPORT_CLASS_MODEM, + PARPORT_CLASS_NET, + PARPORT_CLASS_HDC, /* Hard disk controller */ + PARPORT_CLASS_PCMCIA, + PARPORT_CLASS_MEDIA, /* Multimedia device */ + PARPORT_CLASS_FDC, /* Floppy disk controller */ + PARPORT_CLASS_PORTS, + PARPORT_CLASS_SCANNER, + PARPORT_CLASS_DIGCAM, + PARPORT_CLASS_OTHER, /* Anything else */ + PARPORT_CLASS_UNSPEC, /* No CLS field in ID */ + PARPORT_CLASS_SCSIADAPTER +} parport_device_class; + +int parport_find_class (parport_device_class cls, int from); + +DESCRIPTION + +Find a device by class. The search starts from device number from+1. + +RETURN VALUE + +The device number of the next device in that class, or -1 if no such +device exists. + +NOTES + +Example usage: + +int devnum = -1; +while ((devnum = parport_find_class (PARPORT_CLASS_DIGCAM, devnum)) != -1) { + struct pardevice *dev = parport_open (devnum, ...); + ... +} + +SEE ALSO + +parport_find_device, parport_open, parport_device_id + +parport_find_device - find a device by its class +------------------ + +SYNOPSIS + +#include + +int parport_find_device (const char *mfg, const char *mdl, int from); + +DESCRIPTION + +Find a device by vendor and model. The search starts from device +number from+1. + +RETURN VALUE + +The device number of the next device matching the specifications, or +-1 if no such device exists. + +NOTES + +Example usage: + +int devnum = -1; +while ((devnum = parport_find_device ("IOMEGA", "ZIP+", devnum)) != -1) { + struct pardevice *dev = parport_open (devnum, ...); + ... +} + +SEE ALSO + +parport_find_class, parport_open, parport_device_id + +parport_set_timeout - set the inactivity timeout +------------------- + +SYNOPSIS + +#include + +long parport_set_timeout (struct pardevice *dev, long inactivity); + +DESCRIPTION + +Set the inactivity timeout, in jiffies, for a registered device. The +previous timeout is returned. + +RETURN VALUE + +The previous timeout, in jiffies. + +NOTES + +Some of the port->ops functions for a parport may take time, owing to +delays at the peripheral. After the peripheral has not responded for +'inactivity' jiffies, a timeout will occur and the blocking function +will return. + +A timeout of 0 jiffies is a special case: the function must do as much +as it can without blocking or leaving the hardware in an unknown +state. If port operations are performed from within an interrupt +handler, for instance, a timeout of 0 jiffies should be used. + +Once set for a registered device, the timeout will remain at the set +value until set again. + +SEE ALSO + +port->ops->xxx_read/write_yyy + +PORT FUNCTIONS +-------------- + +The functions in the port->ops structure (struct parport_operations) +are provided by the low-level driver responsible for that port. + +port->ops->read_data - read the data register +-------------------- + +SYNOPSIS + +#include + +struct parport_operations { + ... + unsigned char (*read_data) (struct parport *port); + ... +}; + +DESCRIPTION + +If port->modes contains the PARPORT_MODE_TRISTATE flag and the +PARPORT_CONTROL_DIRECTION bit in the control register is set, this +returns the value on the data pins. If port->modes contains the +PARPORT_MODE_TRISTATE flag and the PARPORT_CONTROL_DIRECTION bit is +not set, the return value _may_ be the last value written to the data +register. Otherwise the return value is undefined. + +SEE ALSO + +write_data, read_status, write_control + +port->ops->write_data - write the data register +--------------------- + +SYNOPSIS + +#include + +struct parport_operations { + ... + void (*write_data) (struct parport *port, unsigned char d); + ... +}; + +DESCRIPTION + +Writes to the data register. May have side-effects (a STROBE pulse, +for instance). + +SEE ALSO + +read_data, read_status, write_control + +port->ops->read_status - read the status register +---------------------- + +SYNOPSIS + +#include + +struct parport_operations { + ... + unsigned char (*read_status) (struct parport *port); + ... +}; + +DESCRIPTION + +Reads from the status register. This is a bitmask: + +- PARPORT_STATUS_ERROR (printer fault, "nFault") +- PARPORT_STATUS_SELECT (on-line, "Select") +- PARPORT_STATUS_PAPEROUT (no paper, "PError") +- PARPORT_STATUS_ACK (handshake, "nAck") +- PARPORT_STATUS_BUSY (busy, "Busy") + +There may be other bits set. + +SEE ALSO + +read_data, write_data, write_control + +port->ops->read_control - read the control register +----------------------- + +SYNOPSIS + +#include + +struct parport_operations { + ... + unsigned char (*read_control) (struct parport *port); + ... +}; + +DESCRIPTION + +Returns the last value written to the control register (either from +write_control or frob_control). No port access is performed. + +SEE ALSO + +read_data, write_data, read_status, write_control + +port->ops->write_control - write the control register +------------------------ + +SYNOPSIS + +#include + +struct parport_operations { + ... + void (*write_status) (struct parport *port, unsigned char s); + ... +}; + +DESCRIPTION + +Writes to the control register. This is a bitmask: + _______ +- PARPORT_CONTROL_STROBE (nStrobe) + _______ +- PARPORT_CONTROL_AUTOFD (nAutoFd) + _____ +- PARPORT_CONTROL_INIT (nInit) + _________ +- PARPORT_CONTROL_SELECT (nSelectIn) + +SEE ALSO + +read_data, write_data, read_status, frob_control + +port->ops->frob_control - write control register bits +----------------------- + +SYNOPSIS + +#include + +struct parport_operations { + ... + void (*frob_control) (struct parport *port, + unsigned char mask, + unsigned char val); + ... +}; + +DESCRIPTION + +This is equivalent to reading from the control register, masking out +the bits in mask, exclusive-or'ing with the bits in val, and writing +the result to the control register. + +As some ports don't allow reads from the control port, a software copy +of its contents is maintained, so frob_control is in fact only one +port access. + +SEE ALSO + +read_data, write_data, read_status, write_control + +port->ops->enable_irq - enable interrupt generation +--------------------- + +SYNOPSIS + +#include + +struct parport_operations { + ... + void (*enable_irq) (struct parport *port); + ... +}; + +DESCRIPTION + +The parallel port hardware is instructed to generate interrupts at +appropriate moments, although those moments are +architecture-specific. For the PC architecture, interrupts are +commonly generated on the rising edge of nAck. + +SEE ALSO + +disable_irq + +port->ops->disable_irq - disable interrupt generation +---------------------- + +SYNOPSIS + +#include + +struct parport_operations { + ... + void (*disable_irq) (struct parport *port); + ... +}; + +DESCRIPTION + +The parallel port hardware is instructed not to generate interrupts. +The interrupt itself is not masked. + +SEE ALSO + +enable_irq + +port->ops->data_forward - enable data drivers +----------------------- + +SYNOPSIS + +#include + +struct parport_operations { + ... + void (*data_forward) (struct parport *port); + ... +}; + +DESCRIPTION + +Enables the data line drivers, for 8-bit host-to-peripheral +communications. + +SEE ALSO + +data_reverse + +port->ops->data_reverse - tristate the buffer +----------------------- + +SYNOPSIS + +#include + +struct parport_operations { + ... + void (*data_reverse) (struct parport *port); + ... +}; + +DESCRIPTION + +Places the data bus in a high impedance state, if port->modes has the +PARPORT_MODE_TRISTATE bit set. + +SEE ALSO + +data_forward + +port->ops->epp_write_data - write EPP data +------------------------- + +SYNOPSIS + +#include + +struct parport_operations { + ... + size_t (*epp_write_data) (struct parport *port, const void *buf, + size_t len, int flags); + ... +}; + +DESCRIPTION + +Writes data in EPP mode, and returns the number of bytes written. + +The 'flags' parameter may be one or more of the following, +bitwise-or'ed together: + +PARPORT_EPP_FAST Use fast transfers. Some chips provide 16-bit and + 32-bit registers. However, if a transfer + times out, the return value may be unreliable. + +SEE ALSO + +epp_read_data, epp_write_addr, epp_read_addr + +port->ops->epp_read_data - read EPP data +------------------------ + +SYNOPSIS + +#include + +struct parport_operations { + ... + size_t (*epp_read_data) (struct parport *port, void *buf, + size_t len, int flags); + ... +}; + +DESCRIPTION + +Reads data in EPP mode, and returns the number of bytes read. + +The 'flags' parameter may be one or more of the following, +bitwise-or'ed together: + +PARPORT_EPP_FAST Use fast transfers. Some chips provide 16-bit and + 32-bit registers. However, if a transfer + times out, the return value may be unreliable. + +SEE ALSO + +epp_write_data, epp_write_addr, epp_read_addr + +port->ops->epp_write_addr - write EPP address +------------------------- + +SYNOPSIS + +#include + +struct parport_operations { + ... + size_t (*epp_write_addr) (struct parport *port, + const void *buf, size_t len, int flags); + ... +}; + +DESCRIPTION + +Writes EPP addresses (8 bits each), and returns the number written. + +The 'flags' parameter may be one or more of the following, +bitwise-or'ed together: + +PARPORT_EPP_FAST Use fast transfers. Some chips provide 16-bit and + 32-bit registers. However, if a transfer + times out, the return value may be unreliable. + +(Does PARPORT_EPP_FAST make sense for this function?) + +SEE ALSO + +epp_write_data, epp_read_data, epp_read_addr + +port->ops->epp_read_addr - read EPP address +------------------------ + +SYNOPSIS + +#include + +struct parport_operations { + ... + size_t (*epp_read_addr) (struct parport *port, void *buf, + size_t len, int flags); + ... +}; + +DESCRIPTION + +Reads EPP addresses (8 bits each), and returns the number read. + +The 'flags' parameter may be one or more of the following, +bitwise-or'ed together: + +PARPORT_EPP_FAST Use fast transfers. Some chips provide 16-bit and + 32-bit registers. However, if a transfer + times out, the return value may be unreliable. + +(Does PARPORT_EPP_FAST make sense for this function?) + +SEE ALSO + +epp_write_data, epp_read_data, epp_write_addr + +port->ops->ecp_write_data - write a block of ECP data +------------------------- + +SYNOPSIS + +#include + +struct parport_operations { + ... + size_t (*ecp_write_data) (struct parport *port, + const void *buf, size_t len, int flags); + ... +}; + +DESCRIPTION + +Writes a block of ECP data. The 'flags' parameter is ignored. + +RETURN VALUE + +The number of bytes written. + +SEE ALSO + +ecp_read_data, ecp_write_addr + +port->ops->ecp_read_data - read a block of ECP data +------------------------ + +SYNOPSIS + +#include + +struct parport_operations { + ... + size_t (*ecp_read_data) (struct parport *port, + void *buf, size_t len, int flags); + ... +}; + +DESCRIPTION + +Reads a block of ECP data. The 'flags' parameter is ignored. + +RETURN VALUE + +The number of bytes read. NB. There may be more unread data in a +FIFO. Is there a way of stunning the FIFO to prevent this? + +SEE ALSO + +ecp_write_block, ecp_write_addr + +port->ops->ecp_write_addr - write a block of ECP addresses +------------------------- + +SYNOPSIS + +#include + +struct parport_operations { + ... + size_t (*ecp_write_addr) (struct parport *port, + const void *buf, size_t len, int flags); + ... +}; + +DESCRIPTION + +Writes a block of ECP addresses. The 'flags' parameter is ignored. + +RETURN VALUE + +The number of bytes written. + +NOTES + +This may use a FIFO, and if so shall not return until the FIFO is empty. + +SEE ALSO + +ecp_read_data, ecp_write_data + +port->ops->nibble_read_data - read a block of data in nibble mode +--------------------------- + +SYNOPSIS + +#include + +struct parport_operations { + ... + size_t (*nibble_read_data) (struct parport *port, + void *buf, size_t len, int flags); + ... +}; + +DESCRIPTION + +Reads a block of data in nibble mode. The 'flags' parameter is ignored. + +RETURN VALUE + +The number of whole bytes read. + +SEE ALSO + +byte_read_data, compat_write_data + +port->ops->byte_read_data - read a block of data in byte mode +------------------------- + +SYNOPSIS + +#include + +struct parport_operations { + ... + size_t (*byte_read_data) (struct parport *port, + void *buf, size_t len, int flags); + ... +}; + +DESCRIPTION + +Reads a block of data in byte mode. The 'flags' parameter is ignored. + +RETURN VALUE + +The number of bytes read. + +SEE ALSO + +nibble_read_data, compat_write_data + +port->ops->compat_write_data - write a block of data in compatibility mode +---------------------------- + +SYNOPSIS + +#include + +struct parport_operations { + ... + size_t (*compat_write_data) (struct parport *port, + const void *buf, size_t len, int flags); + ... +}; + +DESCRIPTION + +Writes a block of data in compatibility mode. The 'flags' parameter +is ignored. + +RETURN VALUE + +The number of bytes written. + +SEE ALSO + +nibble_read_data, byte_read_data diff --git a/Documentation/pci.txt b/Documentation/pci.txt index d1211c512..f09ece79a 100644 --- a/Documentation/pci.txt +++ b/Documentation/pci.txt @@ -174,6 +174,8 @@ pci_find_slot() Find pci_dev corresponding to given bus and pci_set_power_state() Set PCI Power Management state (0=D0 ... 3=D3) pci_find_capability() Find specified capability in device's capability list. +pci_module_init() Inline helper function for ensuring correct + pci_driver initialization and error handling. 7. Miscellaneous hints diff --git a/Documentation/pm.txt b/Documentation/pm.txt index eb7a819b6..1e78926cd 100644 --- a/Documentation/pm.txt +++ b/Documentation/pm.txt @@ -164,3 +164,154 @@ void pm_dev_idle(struct pm_dev *dev); * access the device hardware until a call to "pm_access" is made. */ typedef int (*pm_callback)(struct pm_dev *dev, pm_request_t rqst, void *data); + +Driver Details +-------------- +This is just a quick Q&A as a stopgap until a real driver writers' +power management guide is available. + +Q: When is a device suspended? + +Devices can be suspended based on direct user request (eg. laptop lid +closes), system power policy (eg. sleep after 30 minutes of console +inactivity), or device power policy (eg. power down device after 5 +minutes of inactivity) + +Q: Must a driver honor a suspend request? + +No, a driver can return -EBUSY from a suspend request and this +will stop the system from suspending. When a suspend request +fails, all suspended devices are resumed and the system continues +to run. Suspend can be retried at a later time. + +Q: Can the driver block suspend/resume requests? + +Yes, a driver can delay its return from a suspend or resume +request until the device is ready to handle requests. It +is advantageous to return as quickly as possible from a +request as suspend/resume are done serially. + +Q: What context is a suspend/resume initiated from? + +A suspend or resume is initiated from a kernel thread context. +It is safe to block, allocate memory, initiate requests +or anything else you can do within the kernel. + +Q: Will requests continue to arrive after a suspend? + +Possibly. It is the driver's responsibility to queue(*), +fail, or drop any requests that arrive after returning +success to a suspend request. It is important that the +driver not access its device until after it receives +a resume request as the device's bus may no longer +be active. + +(*) If a driver queues requests for processing after + resume be aware that the device, network, etc. + might be in a different state than at suspend time. + It's probably better to drop requests unless + the driver is a storage device. + +Q: Do I have to manage bus-specific power management registers + +No. It is the responsibility of the bus driver to manage +PCI, USB, etc. power management registers. The bus driver +or the power management subsystem will also enable any +wake-on functionality that the device has. + +Q: So, really, what do I need to do to support suspend/resume? + +You need to save any device context that would +be lost if the device was powered off and then restore +it at resume time. When ACPI is active, there are +three levels of device suspend states; D1, D2, and D3. +(The suspend state is passed as the "data" argument +to the device callback.) With D3, the device is powered +off and loses all context, D1 and D2 are shallower power +states and require less device context to be saved. To +play it safe, just save everything at suspend and restore +everything at resume. + +Q: Where do I store device context for suspend? + +Anywhere in memory, kmalloc a buffer or store it +in the device descriptor. You are guaranteed that the +contents of memory will be restored and accessible +before resume, even when the system suspends to disk. + +Q: What do I need to do for ACPI vs. APM vs. etc? + +Drivers need not be aware of the specific power management +technology that is active. They just need to be aware +of when the overlying power management system requests +that they suspend or resume. + +Q: What about device dependencies? + +When a driver registers a device, the power management +subsystem uses the information provided to build a +tree of device dependencies (eg. USB device X is on +USB controller Y which is on PCI bus Z) When power +management wants to suspend a device, it first sends +a suspend request to its driver, then the bus driver, +and so on up to the system bus. Device resumes +proceed in the opposite direction. + +Q: Who do I contact for additional information about + enabling power management for my specific driver/device? + +ACPI4Linux mailing list: acpi@phobos.fs.tum.de +Linux ACPI maintainer: andy_henroid@yahoo.com + +System Interface +---------------- +If you are providing new power management support to Linux (ie. +adding support for something like APM or ACPI), you should +communicate with drivers through the existing generic power +management interface. + +/* + * Send a request to a single device + * + * Parameters: + * dev - PM device previously returned from pm_register or pm_find + * rqst - request type + * data - data, if any, associated with the request + * + * Returns: 0 if the request is successful + * See "pm_callback" return for errors + * + * Details: Forward request to device callback and, if a suspend + * or resume request, update the pm_dev "state" field + * appropriately + */ +int pm_send(struct pm_dev *dev, pm_request_t rqst, void *data); + +/* + * Send a request to all devices + * + * Parameters: + * rqst - request type + * data - data, if any, associated with the request + * + * Returns: 0 if the request is successful + * See "pm_callback" return for errors + * + * Details: Walk list of registered devices and call pm_send + * for each until complete or an error is encountered. + * If an error is encountered for a suspend request, + * return all devices to the state they were in before + * the suspend request. + */ +int pm_send_all(pm_request_t rqst, void *data); + +/* + * Find a matching device + * + * Parameters: + * type - device type (PCI device, system device, or 0 to match all devices) + * from - previous match or NULL to start from the beginning + * + * Returns: Matching device or NULL if none found + */ +struct pm_dev *pm_find(pm_dev_t type, struct pm_dev *from); diff --git a/Documentation/vm/balance b/Documentation/vm/balance index 6202e4291..bd3d31bc4 100644 --- a/Documentation/vm/balance +++ b/Documentation/vm/balance @@ -68,12 +68,24 @@ primarily needed in a situation where balancing can not be done, probably because all allocation requests are coming from intr context and all process contexts are sleeping. For 2.3, kswapd does not really need to balance the highmem zone, since intr context does not request -highmem pages. A zone aware kswapd still needs to be implemented. +highmem pages. kswapd looks at the zone_wake_kswapd field in the zone +structure to decide whether a zone needs balancing. Page stealing from process memory and shm is done if stealing the page would alleviate memory pressure on any zone in the page's node that has fallen below its watermark. +pages_min/pages_low/pages_high/low_on_memory/zone_wake_kswapd: These are +per-zone fields, used to determine when a zone needs to be balanced. When +the number of pages falls below pages_min, the hysteric field low_on_memory +gets set. This stays set till the number of free pages becomes pages_high. +When low_on_memory is set, page allocation requests will try to free some +pages in the zone (providing GFP_WAIT is set in the request). Orthogonal +to this, is the decision to poke kswapd to free some zone pages. That +decision is not hysteresis based, and is done when the number of free +pages is below pages_low; in which case zone_wake_kswapd is also set. + + (Good) Ideas that I have heard: 1. Dynamic experience should influence balancing: number of failed requests for a zone can be tracked and fed into the balancing scheme (jalvo@mbay.net) diff --git a/MAINTAINERS b/MAINTAINERS index 7c0c56032..03d8e42ed 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -726,6 +726,12 @@ M: emoenke@gwdg.de L: linux-kernel@vger.rutgers.edu S: Maintained +NVIDIA (RIVA) FRAMEBUFFER DRIVER +P: Jeff Garzik +M: jgarzik@mandrakesoft.com +L: linux-nvidia@lists.surfsouth.com +S: Maintained + OLYMPIC NETWORK DRIVER P: Peter De Shrijver M: p2@ace.ulyssis.sutdent.kuleuven.ac.be @@ -778,7 +784,7 @@ PCI SUBSYSTEM P: Martin Mares M: mj@suse.cz L: linux-kernel@vger.rutgers.edu -S: Maintained +S: Supported PCMCIA SUBSYSTEM P: David Hinds @@ -986,7 +992,7 @@ S: Maintained SVGA HANDLING P: Martin Mares -M: mj@atrey.karlin.mff.cuni.cz +M: mj@suse.cz L: linux-video@atrey.karlin.mff.cuni.cz S: Maintained @@ -1021,6 +1027,12 @@ L: linux-tr@linuxtr.net W: http://www.auk.cx/tms380tr/ S: Maintained +TULIP NETWORK DRIVER +P: Jeff Garzik +M: jgarzik@mandrakesoft.com +L: linux-tulip@cesdis.gsfc.nasa.gov +S: Maintained + U14-34F SCSI DRIVER P: Dario Ballabio M: dario@milano.europe.dg.com @@ -1112,6 +1124,7 @@ S: Maintained VIA 82Cxxx AUDIO DRIVER P: Jeff Garzik M: jgarzik@mandrakesoft.com +L: linux-via@gtf.org S: Maintained VIDEO FOR LINUX diff --git a/Makefile b/Makefile index 66627d6a3..9c6e47960 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 3 -SUBLEVEL = 47 +SUBLEVEL = 48 EXTRAVERSION = ARCH = mips diff --git a/arch/alpha/config.in b/arch/alpha/config.in index 8e44bb0e2..1686fefbc 100644 --- a/arch/alpha/config.in +++ b/arch/alpha/config.in @@ -60,6 +60,7 @@ unset CONFIG_ALPHA_LCA CONFIG_ALPHA_APECS CONFIG_ALPHA_CIA unset CONFIG_ALPHA_T2 CONFIG_ALPHA_PYXIS CONFIG_ALPHA_POLARIS unset CONFIG_ALPHA_TSUNAMI CONFIG_ALPHA_MCPCIA unset CONFIG_ALPHA_IRONGATE +unset CONFIG_ALPHA_BROKEN_IRQ_MASK # Most of these machines have ISA slots; not exactly sure which don't, # and this doesn't activate hordes of code, so do it always. @@ -178,6 +179,10 @@ if [ "$CONFIG_ALPHA_XL" = "y" ] then define_bool CONFIG_ALPHA_AVANTI y fi +if [ "$CONFIG_ALPHA_GENERIC" = "y" -o "$CONFIG_ALPHA_PC164" = "y" ] +then + define_bool CONFIG_ALPHA_BROKEN_IRQ_MASK y +fi if [ "$CONFIG_ALPHA_SABLE" = "y" -o "$CONFIG_ALPHA_RAWHIDE" = "y" \ -o "$CONFIG_ALPHA_DP264" = "y" -o "$CONFIG_ALPHA_GENERIC" = "y" ] diff --git a/arch/alpha/kernel/alpha_ksyms.c b/arch/alpha/kernel/alpha_ksyms.c index 725dd4f51..25d9583dd 100644 --- a/arch/alpha/kernel/alpha_ksyms.c +++ b/arch/alpha/kernel/alpha_ksyms.c @@ -98,6 +98,8 @@ EXPORT_SYMBOL(__memset); EXPORT_SYMBOL(__memsetw); EXPORT_SYMBOL(__constant_c_memset); +EXPORT_SYMBOL(__direct_map_base); +EXPORT_SYMBOL(__direct_map_size); EXPORT_SYMBOL(pci_alloc_consistent); EXPORT_SYMBOL(pci_free_consistent); EXPORT_SYMBOL(pci_map_single); @@ -144,6 +146,10 @@ EXPORT_SYMBOL(alpha_fp_emul_imprecise); EXPORT_SYMBOL(alpha_fp_emul); #endif +#ifdef CONFIG_ALPHA_BROKEN_IRQ_MASK +EXPORT_SYMBOL(__min_ipl); +#endif + /* * The following are specially called from the uaccess assembly stubs. */ diff --git a/arch/alpha/kernel/core_tsunami.c b/arch/alpha/kernel/core_tsunami.c index 5fa112173..1452b6336 100644 --- a/arch/alpha/kernel/core_tsunami.c +++ b/arch/alpha/kernel/core_tsunami.c @@ -24,7 +24,6 @@ #include "proto.h" #include "pci_impl.h" -int TSUNAMI_bootcpu; static struct { @@ -210,17 +209,23 @@ void tsunami_pci_tbi(struct pci_controler *hose, dma_addr_t start, dma_addr_t end) { tsunami_pchip *pchip = hose->index ? TSUNAMI_pchip1 : TSUNAMI_pchip0; - - wmb(); + volatile unsigned long *csr; + unsigned long value; /* We can invalidate up to 8 tlb entries in a go. The flush matches against <31:16> in the pci address. */ + csr = &pchip->tlbia.csr; if (((start ^ end) & 0xffff0000) == 0) - pchip->tlbiv.csr = (start & 0xffff0000) >> 12; - else - pchip->tlbia.csr = 0; + csr = &pchip->tlbiv.csr; + /* For TBIA, it doesn't matter what value we write. For TBI, + it's the shifted tag bits. */ + value = (start & 0xffff0000) >> 12; + + wmb(); + *csr = value; mb(); + *csr; } #ifdef NXM_MACHINE_CHECKS_ON_TSUNAMI @@ -229,7 +234,7 @@ tsunami_probe_read(volatile unsigned long *vaddr) { long dont_care, probe_result; int cpu = smp_processor_id(); - int s = swpipl(6); /* Block everything but machine checks. */ + int s = swpipl(IPL_MCHECK - 1); mcheck_taken(cpu) = 0; mcheck_expected(cpu) = 1; @@ -338,9 +343,13 @@ tsunami_init_one_pchip(tsunami_pchip *pchip, int index) * because of an idiot-syncrasy of the CYPRESS chip. It may * respond to a PCI bus address in the last 1MB of the 4GB * address range. + * + * Note that the TLB lookup logic uses bitwise concatenation, + * not addition, so the required arena alignment is based on + * the size of the window. */ - hose->sg_isa = iommu_arena_new(0x00800000, 0x00800000, PAGE_SIZE); - hose->sg_pci = iommu_arena_new(0xc0000000, 0x08000000, PAGE_SIZE); + hose->sg_isa = iommu_arena_new(0x00800000, 0x00800000, 0x00800000>>10); + hose->sg_pci = iommu_arena_new(0xc0000000, 0x08000000, 0x08000000>>10); __direct_map_base = 0x40000000; __direct_map_size = 0x80000000; @@ -399,8 +408,6 @@ tsunami_init_arch(void) printk("%s: CSR_STR 0x%lx\n", FN, TSUNAMI_dchip->str.csr); printk("%s: CSR_DREV 0x%lx\n", FN, TSUNAMI_dchip->drev.csr); #endif - TSUNAMI_bootcpu = __hard_smp_processor_id(); - /* With multiple PCI busses, we play with I/O as physical addrs. */ ioport_resource.end = ~0UL; iomem_resource.end = ~0UL; @@ -444,12 +451,10 @@ tsunami_kill_arch(int mode) static inline void tsunami_pci_clr_err_1(tsunami_pchip *pchip) { - unsigned int jd; - - jd = pchip->perror.csr; + pchip->perror.csr; pchip->perror.csr = 0x040; mb(); - jd = pchip->perror.csr; + pchip->perror.csr; } static inline void diff --git a/arch/alpha/kernel/irq.c b/arch/alpha/kernel/irq.c index 3d593acf3..613a633ba 100644 --- a/arch/alpha/kernel/irq.c +++ b/arch/alpha/kernel/irq.c @@ -48,6 +48,12 @@ unsigned long __irq_attempt[NR_IRQS]; #define ACTUAL_NR_IRQS NR_IRQS #endif +/* Hack minimum IPL during interupt processing for broken hardware. */ + +#ifdef CONFIG_ALPHA_BROKEN_IRQ_MASK +int __min_ipl; +#endif + /* * Performance counter hook. A module can override this to * do something useful. @@ -283,30 +289,32 @@ handle_IRQ_event(unsigned int irq, struct pt_regs *regs, struct irqaction *action) { int status, cpu = smp_processor_id(); - unsigned long ipl; + int old_ipl, ipl; kstat.irqs[cpu][irq]++; irq_enter(cpu, irq); status = 1; /* Force the "do bottom halves" bit */ - ipl = rdps() & 7; + old_ipl = ipl = getipl(); do { - unsigned long newipl = (action->flags & SA_INTERRUPT ? 7 : 0); - if (newipl != ipl) { - swpipl(newipl); - ipl = newipl; + int new_ipl = IPL_MIN; + if (action->flags & SA_INTERRUPT) + new_ipl = IPL_MAX; + if (new_ipl != ipl) { + setipl(new_ipl); + ipl = new_ipl; } status |= action->flags; action->handler(irq, action->dev_id, regs); action = action->next; } while (action); + if (ipl != old_ipl) + setipl(old_ipl); + if (status & SA_SAMPLE_RANDOM) add_interrupt_randomness(irq); - if (ipl == 0) - __cli(); - irq_exit(cpu, irq); return status; @@ -325,7 +333,7 @@ disable_irq_nosync(unsigned int irq) spin_lock_irqsave(&irq_controller_lock, flags); if (!irq_desc[irq].depth++) { - irq_desc[irq].status |= IRQ_DISABLED; + irq_desc[irq].status |= IRQ_DISABLED | IRQ_MASKED; irq_desc[irq].handler->disable(irq); } spin_unlock_irqrestore(&irq_controller_lock, flags); @@ -356,14 +364,15 @@ enable_irq(unsigned int irq) switch (irq_desc[irq].depth) { case 1: { - unsigned int status = irq_desc[irq].status & ~IRQ_DISABLED; - irq_desc[irq].status = status; - if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) { - irq_desc[irq].status = status | IRQ_REPLAY; + unsigned int status = irq_desc[irq].status; + status &= ~(IRQ_DISABLED | IRQ_MASKED); + if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) { + status |= IRQ_REPLAY; /* ??? We can't re-send on (most?) alpha hw. hw_resend_irq(irq_desc[irq].handler,irq); */ } + irq_desc[irq].status = status; irq_desc[irq].handler->enable(irq); /* fall-through */ } @@ -425,7 +434,7 @@ setup_irq(unsigned int irq, struct irqaction * new) if (!shared) { irq_desc[irq].depth = 0; - irq_desc[irq].status &= ~IRQ_DISABLED; + irq_desc[irq].status &= ~(IRQ_DISABLED | IRQ_MASKED); irq_desc[irq].handler->startup(irq); } spin_unlock_irqrestore(&irq_controller_lock,flags); @@ -500,7 +509,7 @@ free_irq(unsigned int irq, void *dev_id) /* Found - now remove it from the list of entries. */ *pp = action->next; if (!irq_desc[irq].action) { - irq_desc[irq].status |= IRQ_DISABLED; + irq_desc[irq].status |= IRQ_DISABLED|IRQ_MASKED; irq_desc[irq].handler->shutdown(irq); } spin_unlock_irqrestore(&irq_controller_lock,flags); @@ -669,7 +678,7 @@ __global_cli(void) * Maximize ipl. If ipl was previously 0 and if this thread * is not in an irq, then take global_irq_lock. */ - if (swpipl(7) == 0 && !local_irq_count(cpu)) + if (swpipl(IPL_MAX) == IPL_MIN && !local_irq_count(cpu)) get_irqlock(cpu, where); } @@ -841,13 +850,25 @@ handle_irq(int irq, struct pt_regs * regs) desc = irq_desc + irq; spin_lock_irq(&irq_controller_lock); /* mask also the RTC */ desc->handler->ack(irq); + status = desc->status; + +#ifndef CONFIG_SMP + /* Look for broken irq masking. */ + if (status & IRQ_MASKED) { + static unsigned long last_printed; + if (time_after(jiffies, last_printed+HZ)) { + printk(KERN_CRIT "Mask didn't work for irq %d!\n", irq); + last_printed = jiffies; + } + } +#endif /* * REPLAY is when Linux resends an IRQ that was dropped earlier. * WAITING is used by probe to mark irqs that are being tested. */ - status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING); - status |= IRQ_PENDING; /* we _want_ to handle it */ + status &= ~(IRQ_REPLAY | IRQ_WAITING); + status |= IRQ_PENDING | IRQ_MASKED; /* we _want_ to handle it */ /* * If the IRQ is disabled for whatever reason, we cannot @@ -890,9 +911,12 @@ handle_irq(int irq, struct pt_regs * regs) desc->status &= ~IRQ_PENDING; spin_unlock(&irq_controller_lock); } - desc->status &= ~IRQ_INPROGRESS; - if (!(desc->status & IRQ_DISABLED)) + status = desc->status & ~IRQ_INPROGRESS; + if (!(status & IRQ_DISABLED)) { + status &= ~IRQ_MASKED; desc->handler->end(irq); + } + desc->status = status; spin_unlock(&irq_controller_lock); } @@ -1056,7 +1080,7 @@ do_entInt(unsigned long type, unsigned long vector, unsigned long la_ptr, #ifdef CONFIG_SMP cpu_data[smp_processor_id()].smp_local_irq_count++; smp_percpu_timer_interrupt(®s); - if (smp_processor_id() == smp_boot_cpuid) + if (smp_processor_id() == boot_cpuid) #endif handle_irq(RTC_IRQ, ®s); return; diff --git a/arch/alpha/kernel/pci_iommu.c b/arch/alpha/kernel/pci_iommu.c index 72ce8bcb6..f5a9bd990 100644 --- a/arch/alpha/kernel/pci_iommu.c +++ b/arch/alpha/kernel/pci_iommu.c @@ -133,6 +133,9 @@ pci_map_single(struct pci_dev *pdev, void *cpu_addr, long size, int direction) unsigned long paddr; dma_addr_t ret; + if (direction == PCI_DMA_NONE) + BUG(); + paddr = virt_to_phys(cpu_addr); /* First check to see if we can use the direct map window. */ @@ -186,12 +189,15 @@ pci_map_single(struct pci_dev *pdev, void *cpu_addr, long size, int direction) wrote there. */ void -pci_unmap_single(struct pci_dev *pdev, dma_addr_t dma_addr, long size, int direction) +pci_unmap_single(struct pci_dev *pdev, dma_addr_t dma_addr, long size, + int direction) { struct pci_controler *hose = pdev ? pdev->sysdata : pci_isa_hose; struct pci_iommu_arena *arena; long dma_ofs, npages; + if (direction == PCI_DMA_NONE) + BUG(); if (dma_addr >= __direct_map_base && dma_addr < __direct_map_base + __direct_map_size) { @@ -247,7 +253,8 @@ pci_alloc_consistent(struct pci_dev *pdev, long size, dma_addr_t *dma_addrp) } memset(cpu_addr, 0, size); - *dma_addrp = pci_map_single(pdev, cpu_addr, size, PCI_DMA_BIDIRECTIONAL); + *dma_addrp = pci_map_single(pdev, cpu_addr, size, + PCI_DMA_BIDIRECTIONAL); if (*dma_addrp == 0) { free_pages((unsigned long)cpu_addr, order); return NULL; @@ -424,13 +431,17 @@ sg_fill(struct scatterlist *leader, struct scatterlist *end, } int -pci_map_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents, int direction) +pci_map_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents, + int direction) { struct scatterlist *start, *end, *out; struct pci_controler *hose; struct pci_iommu_arena *arena; dma_addr_t max_dma; + if (direction == PCI_DMA_NONE) + BUG(); + /* Fast path single entry scatterlists. */ if (nents == 1) { sg->dma_length = sg->length; @@ -499,7 +510,8 @@ error: above. */ void -pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents, int direction) +pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents, + int direction) { struct pci_controler *hose; struct pci_iommu_arena *arena; @@ -507,6 +519,9 @@ pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents, int direct dma_addr_t max_dma; dma_addr_t fstart, fend; + if (direction == PCI_DMA_NONE) + BUG(); + if (! alpha_mv.mv_pci_tbi) return; @@ -555,3 +570,33 @@ pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents, int direct DBGA("pci_unmap_sg: %d entries\n", nents - (end - sg)); } + +/* Return whether the given PCI device DMA address mask can be + supported properly. */ + +int +pci_dma_supported(struct pci_dev *pdev, dma_addr_t mask) +{ + struct pci_controler *hose; + struct pci_iommu_arena *arena; + + /* If there exists a direct map, and the mask fits either + MAX_DMA_ADDRESS defined such that GFP_DMA does something + useful, or the total system memory as shifted by the + map base. */ + if (__direct_map_size != 0 + && (__direct_map_base + MAX_DMA_ADDRESS-IDENT_ADDR-1 <= mask + || __direct_map_base + (max_low_pfn<sysdata : pci_isa_hose; + arena = hose->sg_isa; + if (arena && arena->dma_base + arena->size <= mask) + return 1; + arena = hose->sg_pci; + if (arena && arena->dma_base + arena->size <= mask) + return 1; + + return 0; +} diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c index 31a818209..2e462550f 100644 --- a/arch/alpha/kernel/process.c +++ b/arch/alpha/kernel/process.c @@ -90,55 +90,82 @@ cpu_idle(void) } } + +struct halt_info { + int mode; + char *restart_cmd; +}; + static void -common_shutdown(int mode, char *restart_cmd) +common_shutdown_1(void *generic_ptr) { - /* The following currently only has any effect on SRM. We should - fix MILO to understand it. Should be pretty easy. Also we can - support RESTART2 via the ipc_buffer machinations pictured below, - which SRM ignores. */ + struct halt_info *how = (struct halt_info *)generic_ptr; + struct percpu_struct *cpup; + unsigned long *pflags, flags; + int cpuid = smp_processor_id(); - if (alpha_using_srm) { - struct percpu_struct *cpup; - unsigned long flags; - - cpup = (struct percpu_struct *) - ((unsigned long)hwrpb + hwrpb->processor_offset); - - flags = cpup->flags; - - /* Clear reason to "default"; clear "bootstrap in progress". */ - flags &= ~0x00ff0001UL; - - if (mode == LINUX_REBOOT_CMD_RESTART) { - if (!restart_cmd) { - flags |= 0x00020000UL; /* "cold bootstrap" */ - cpup->ipc_buffer[0] = 0; - } else { - flags |= 0x00030000UL; /* "warm bootstrap" */ - strncpy((char *)cpup->ipc_buffer, restart_cmd, - sizeof(cpup->ipc_buffer)); - } + /* No point in taking interrupts anymore. */ + __cli(); + + cpup = (struct percpu_struct *) + ((unsigned long)hwrpb + hwrpb->processor_offset + + hwrpb->processor_size * cpuid); + pflags = &cpup->flags; + flags = *pflags; + + /* Clear reason to "default"; clear "bootstrap in progress". */ + flags &= ~0x00ff0001UL; + +#ifdef __SMP__ + /* Secondaries halt here. */ + if (cpuid != boot_cpuid) { + flags |= 0x00040000UL; /* "remain halted" */ + *pflags = flags; + clear_bit(cpuid, &cpu_present_mask); + halt(); + } +#endif + + if (how->mode == LINUX_REBOOT_CMD_RESTART) { + if (!how->restart_cmd) { + flags |= 0x00020000UL; /* "cold bootstrap" */ } else { - flags |= 0x00040000UL; /* "remain halted" */ + /* For SRM, we could probably set environment + variables to get this to work. We'd have to + delay this until after srm_paging_stop unless + we ever got srm_fixup working. + + At the moment, SRM will use the last boot device, + but the file and flags will be the defaults, when + doing a "warm" bootstrap. */ + flags |= 0x00030000UL; /* "warm bootstrap" */ } - - cpup->flags = flags; - mb(); + } else { + flags |= 0x00040000UL; /* "remain halted" */ + } + *pflags = flags; - /* reset_for_srm(); */ - set_hae(srm_hae); +#ifdef __SMP__ + /* Wait for the secondaries to halt. */ + clear_bit(boot_cpuid, &cpu_present_mask); + while (cpu_present_mask) + barrier(); +#endif + /* If booted from SRM, reset some of the original environment. */ + if (alpha_using_srm) { #ifdef CONFIG_DUMMY_CONSOLE - /* This has the effect of reseting the VGA video origin. */ + /* This has the effect of resetting the VGA video origin. */ take_over_console(&dummy_con, 0, MAX_NR_CONSOLES-1, 1); #endif + /* reset_for_srm(); */ + set_hae(srm_hae); } if (alpha_mv.kill_arch) - alpha_mv.kill_arch(mode); + alpha_mv.kill_arch(how->mode); - if (!alpha_using_srm && mode != LINUX_REBOOT_CMD_RESTART) { + if (! alpha_using_srm && how->mode != LINUX_REBOOT_CMD_RESTART) { /* Unfortunately, since MILO doesn't currently understand the hwrpb bits above, we can't reliably halt the processor and keep it halted. So just loop. */ @@ -151,6 +178,18 @@ common_shutdown(int mode, char *restart_cmd) halt(); } +static void +common_shutdown(int mode, char *restart_cmd) +{ + struct halt_info args; + args.mode = mode; + args.restart_cmd = restart_cmd; +#ifdef __SMP__ + smp_call_function(common_shutdown_1, &args, 1, 0); +#endif + common_shutdown_1(&args); +} + void machine_restart(char *restart_cmd) { diff --git a/arch/alpha/kernel/proto.h b/arch/alpha/kernel/proto.h index dd63de4d2..a8859059b 100644 --- a/arch/alpha/kernel/proto.h +++ b/arch/alpha/kernel/proto.h @@ -74,13 +74,14 @@ extern void tsunami_pci_tbi(struct pci_controler *, dma_addr_t, dma_addr_t); /* setup.c */ extern unsigned long srm_hae; +extern int boot_cpuid; /* smp.c */ extern void setup_smp(void); extern int smp_info(char *buffer); extern void handle_ipi(struct pt_regs *); extern void smp_percpu_timer_interrupt(struct pt_regs *); -extern int smp_boot_cpuid; +extern unsigned long cpu_present_mask; /* bios32.c */ /* extern void reset_for_srm(void); */ diff --git a/arch/alpha/kernel/semaphore.c b/arch/alpha/kernel/semaphore.c index d4793ecb4..dc5209531 100644 --- a/arch/alpha/kernel/semaphore.c +++ b/arch/alpha/kernel/semaphore.c @@ -173,7 +173,7 @@ __down_read(struct rw_semaphore *sem, int count) " subl %0,1,%0\n" " stl_c %2,%1\n" " bne %2,2f\n" - ".section .text2,\"ax\"\n" + ".subsection 2\n" "2: br 1b\n" ".previous" : "=r"(count), "=m"(sem->count), "=r"(tmp) @@ -226,7 +226,7 @@ __down_write(struct rw_semaphore *sem, int count) " ldah %0,%3(%0)\n" " stl_c %2,%1\n" " bne %2,2f\n" - ".section .text2,\"ax\"\n" + ".subsection 2\n" "2: br 1b\n" ".previous" : "=r"(count), "=m"(sem->count), "=r"(tmp) diff --git a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c index 112976bcb..1311d939b 100644 --- a/arch/alpha/kernel/setup.c +++ b/arch/alpha/kernel/setup.c @@ -50,6 +50,9 @@ struct hwrpb_struct *hwrpb; unsigned long srm_hae; +/* Which processor we booted from. */ +int boot_cpuid; + #ifdef CONFIG_ALPHA_GENERIC struct alpha_machine_vector alpha_mv; int alpha_using_srm; @@ -351,6 +354,7 @@ setup_arch(char **cmdline_p) char *type_name, *var_name, *p; hwrpb = (struct hwrpb_struct*) __va(INIT_HWRPB->phys_addr); + boot_cpuid = hard_smp_processor_id(); /* * Locate the command line. diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c index e3ae30973..be1a6440e 100644 --- a/arch/alpha/kernel/smp.c +++ b/arch/alpha/kernel/smp.c @@ -62,11 +62,13 @@ spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED; /* Set to a secondary's cpuid when it comes online. */ static unsigned long smp_secondary_alive; -unsigned long cpu_present_mask; /* Which cpus ids came online. */ -static unsigned long __cpu_present_mask __initdata = 0; /* cpu reported in the hwrpb */ +/* Which cpus ids came online. */ +unsigned long cpu_present_mask; + +/* cpus reported in the hwrpb */ +static unsigned long hwrpb_cpu_present_mask __initdata = 0; static int max_cpus = -1; /* Command-line limitation. */ -int smp_boot_cpuid; /* Which processor we booted from. */ int smp_num_probed; /* Internal processor count */ int smp_num_cpus = 1; /* Number that came online. */ int smp_threads_ready; /* True once the per process idle is forked. */ @@ -486,10 +488,9 @@ setup_smp(void) struct percpu_struct *cpubase, *cpu; int i; - smp_boot_cpuid = hard_smp_processor_id(); - if (smp_boot_cpuid != 0) { + if (boot_cpuid != 0) { printk(KERN_WARNING "SMP: Booting off cpu %d instead of 0?\n", - smp_boot_cpuid); + boot_cpuid); } if (hwrpb->nr_processors > 1) { @@ -508,7 +509,7 @@ setup_smp(void) if ((cpu->flags & 0x1cc) == 0x1cc) { smp_num_probed++; /* Assume here that "whami" == index */ - __cpu_present_mask |= (1L << i); + hwrpb_cpu_present_mask |= (1L << i); cpu->pal_revision = boot_cpu_palrev; } @@ -519,12 +520,12 @@ setup_smp(void) } } else { smp_num_probed = 1; - __cpu_present_mask = (1L << smp_boot_cpuid); + hwrpb_cpu_present_mask = (1L << boot_cpuid); } - cpu_present_mask = 1L << smp_boot_cpuid; + cpu_present_mask = 1L << boot_cpuid; printk(KERN_INFO "SMP: %d CPUs probed -- cpu_present_mask = %lx\n", - smp_num_probed, __cpu_present_mask); + smp_num_probed, hwrpb_cpu_present_mask); } /* @@ -541,13 +542,13 @@ smp_boot_cpus(void) memset(__cpu_logical_map, -1, sizeof(__cpu_logical_map)); memset(ipi_data, 0, sizeof(ipi_data)); - __cpu_number_map[smp_boot_cpuid] = 0; - __cpu_logical_map[0] = smp_boot_cpuid; - current->processor = smp_boot_cpuid; + __cpu_number_map[boot_cpuid] = 0; + __cpu_logical_map[0] = boot_cpuid; + current->processor = boot_cpuid; - smp_store_cpu_info(smp_boot_cpuid); + smp_store_cpu_info(boot_cpuid); smp_tune_scheduling(); - smp_setup_percpu_timer(smp_boot_cpuid); + smp_setup_percpu_timer(boot_cpuid); init_idle(); @@ -565,10 +566,10 @@ smp_boot_cpus(void) cpu_count = 1; for (i = 0; i < NR_CPUS; i++) { - if (i == smp_boot_cpuid) + if (i == boot_cpuid) continue; - if (((__cpu_present_mask >> i) & 1) == 0) + if (((hwrpb_cpu_present_mask >> i) & 1) == 0) continue; if (smp_boot_one_cpu(i, cpu_count)) @@ -1023,7 +1024,7 @@ debug_spin_lock(spinlock_t * lock, const char *base_file, int line_no) " stl_c %0,%1\n" " beq %0,3f\n" "4: mb\n" - ".section .text2,\"ax\"\n" + ".subsection 2\n" "2: ldl %0,%1\n" " subq %2,1,%2\n" "3: blt %2,4b\n" @@ -1097,7 +1098,7 @@ void write_lock(rwlock_t * lock) " stl_c %1,%0\n" " beq %1,6f\n" "4: mb\n" - ".section .text2,\"ax\"\n" + ".subsection 2\n" "6: blt %3,4b # debug\n" " subl %3,1,%3 # debug\n" " ldl %1,%0\n" @@ -1140,7 +1141,7 @@ void read_lock(rwlock_t * lock) " stl_c %1,%0;" " beq %1,6f;" "4: mb\n" - ".section .text2,\"ax\"\n" + ".subsection 2\n" "6: ldl %1,%0;" " blt %2,4b # debug\n" " subl %2,1,%2 # debug\n" diff --git a/arch/alpha/kernel/sys_cabriolet.c b/arch/alpha/kernel/sys_cabriolet.c index 1432496d8..acea58d1e 100644 --- a/arch/alpha/kernel/sys_cabriolet.c +++ b/arch/alpha/kernel/sys_cabriolet.c @@ -126,6 +126,30 @@ cabriolet_init_irq(void) setup_irq(16+4, &isa_cascade_irqaction); } +#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_PC164) +static void +pc164_device_interrupt(unsigned long v, struct pt_regs *r) +{ + /* In theory, the PC164 has the same interrupt hardware as + the other Cabriolet based systems. However, something + got screwed up late in the development cycle which broke + the interrupt masking hardware. Repeat, it is not + possible to mask and ack interrupts. At all. + + In an attempt to work around this, while processing + interrupts, we do not allow the IPL to drop below what + it is currently. This prevents the possibility of + recursion. + + ??? Another option might be to force all PCI devices + to use edge triggered rather than level triggered + interrupts. That might be too invasive though. */ + + __min_ipl = getipl(); + cabriolet_device_interrupt(v, r); + __min_ipl = 0; +} +#endif /* * The EB66+ is very similar to the EB66 except that it does not have @@ -379,7 +403,7 @@ struct alpha_machine_vector pc164_mv __initmv = { min_mem_address: CIA_DEFAULT_MEM_BASE, nr_irqs: 35, - device_interrupt: cabriolet_device_interrupt, + device_interrupt: pc164_device_interrupt, init_arch: cia_init_arch, init_irq: cabriolet_init_irq, diff --git a/arch/alpha/kernel/sys_dp264.c b/arch/alpha/kernel/sys_dp264.c index fbebdd5a5..7414b8cc2 100644 --- a/arch/alpha/kernel/sys_dp264.c +++ b/arch/alpha/kernel/sys_dp264.c @@ -33,94 +33,80 @@ #include "machvec_impl.h" +/* Note mask bit is true for ENABLED irqs. */ static unsigned long cached_irq_mask; - -#define TSUNAMI_SET_IRQ_MASK(cpu, value) \ -do { \ - volatile unsigned long *csr; \ - csr = &TSUNAMI_cchip->dim##cpu##.csr; \ - *csr = (value); \ - mb(); \ - *csr; \ -} while(0) - -static inline void -do_flush_irq_mask(unsigned long value) -{ - switch (TSUNAMI_bootcpu) { - case 0: - TSUNAMI_SET_IRQ_MASK(0, value); - break; - case 1: - TSUNAMI_SET_IRQ_MASK(1, value); - break; - case 2: - TSUNAMI_SET_IRQ_MASK(2, value); - break; - case 3: - TSUNAMI_SET_IRQ_MASK(3, value); - break; - } -} - -#ifdef CONFIG_SMP -static inline void -do_flush_smp_irq_mask(unsigned long value) -{ - extern unsigned long cpu_present_mask; - unsigned long other_cpus = cpu_present_mask & ~(1L << TSUNAMI_bootcpu); - - if (other_cpus & 1) - TSUNAMI_SET_IRQ_MASK(0, value); - if (other_cpus & 2) - TSUNAMI_SET_IRQ_MASK(1, value); - if (other_cpus & 4) - TSUNAMI_SET_IRQ_MASK(2, value); - if (other_cpus & 8) - TSUNAMI_SET_IRQ_MASK(3, value); -} -#endif - static void -dp264_flush_irq_mask(unsigned long mask) +tsunami_update_irq_hw(unsigned long mask, unsigned long isa_enable) { - unsigned long value; + register tsunami_cchip *cchip = TSUNAMI_cchip; + register int bcpu = boot_cpuid; #ifdef CONFIG_SMP - do_flush_smp_irq_mask(mask); + register unsigned long cpm = cpu_present_mask; + volatile unsigned long *dim0, *dim1, *dim2, *dim3; + unsigned long mask0, mask1, mask2, mask3, maskB, dummy; + + mask0 = mask1 = mask2 = mask3 = mask; + maskB = mask | isa_enable; + if (bcpu == 0) mask0 = maskB; + if (bcpu == 1) mask1 = maskB; + if (bcpu == 2) mask2 = maskB; + if (bcpu == 3) mask3 = maskB; + + dim0 = &cchip->dim0.csr; + dim1 = &cchip->dim1.csr; + dim2 = &cchip->dim2.csr; + dim3 = &cchip->dim3.csr; + if ((cpm & 1) == 0) dim0 = &dummy; + if ((cpm & 2) == 0) dim1 = &dummy; + if ((cpm & 4) == 0) dim2 = &dummy; + if ((cpm & 8) == 0) dim3 = &dummy; + + *dim0 = mask0; + *dim1 = mask1; + *dim2 = mask2; + *dim3 = mask3; + mb(); + *dim0; + *dim1; + *dim2; + *dim3; +#else + volatile unsigned long *dimB = &cchip->dim1.csr; + if (bcpu == 0) dimB = &cchip->dim0.csr; + if (bcpu == 2) dimB = &cchip->dim2.csr; + if (bcpu == 3) dimB = &cchip->dim3.csr; + *dimB = mask | isa_enable; + mb(); + *dimB; #endif - - value = mask | (1UL << 55) | 0xffff; /* isa irqs always enabled */ - do_flush_irq_mask(value); } -static void -clipper_flush_irq_mask(unsigned long mask) +static inline void +dp264_update_irq_hw(unsigned long mask) { - unsigned long value; - - value = mask >> 16; -#ifdef CONFIG_SMP - do_flush_smp_irq_mask(value); -#endif + tsunami_update_irq_hw(mask, (1UL << 55) | 0xffff); +} - value = value | (1UL << 55); /* master ISA enable */ - do_flush_irq_mask(value); +static inline void +clipper_update_irq_hw(unsigned long mask) +{ + tsunami_update_irq_hw(mask, 1UL << 55); } static inline void dp264_enable_irq(unsigned int irq) { cached_irq_mask |= 1UL << irq; - dp264_flush_irq_mask(cached_irq_mask); + dp264_update_irq_hw(cached_irq_mask); } static void dp264_disable_irq(unsigned int irq) { cached_irq_mask &= ~(1UL << irq); - dp264_flush_irq_mask(cached_irq_mask); + dp264_update_irq_hw(cached_irq_mask); } static unsigned int @@ -134,14 +120,14 @@ static inline void clipper_enable_irq(unsigned int irq) { cached_irq_mask |= 1UL << irq; - clipper_flush_irq_mask(cached_irq_mask); + clipper_update_irq_hw(cached_irq_mask); } static void clipper_disable_irq(unsigned int irq) { cached_irq_mask &= ~(1UL << irq); - clipper_flush_irq_mask(cached_irq_mask); + clipper_update_irq_hw(cached_irq_mask); } static unsigned int @@ -271,7 +257,7 @@ dp264_init_irq(void) if (alpha_using_srm) alpha_mv.device_interrupt = dp264_srm_device_interrupt; - dp264_flush_irq_mask(0UL); + dp264_update_irq_hw(0UL); init_i8259a_irqs(); init_rtc_irq(); @@ -289,7 +275,7 @@ clipper_init_irq(void) if (alpha_using_srm) alpha_mv.device_interrupt = clipper_srm_device_interrupt; - clipper_flush_irq_mask(0UL); + clipper_update_irq_hw(0UL); init_i8259a_irqs(); init_rtc_irq(); diff --git a/arch/alpha/kernel/sys_sio.c b/arch/alpha/kernel/sys_sio.c index ccdcf3bdb..0230ec6d9 100644 --- a/arch/alpha/kernel/sys_sio.c +++ b/arch/alpha/kernel/sys_sio.c @@ -391,7 +391,7 @@ struct alpha_machine_vector xl_mv __initmv = { nr_irqs: 16, device_interrupt: isa_device_interrupt, - init_arch: lca_init_arch, + init_arch: apecs_init_arch, init_irq: sio_init_irq, init_rtc: common_init_rtc, init_pci: noname_init_pci, diff --git a/arch/alpha/kernel/time.c b/arch/alpha/kernel/time.c index 8211045e8..d7b5cee8c 100644 --- a/arch/alpha/kernel/time.c +++ b/arch/alpha/kernel/time.c @@ -22,7 +22,6 @@ * fixed algorithm in do_gettimeofday() for calculating the precise time * from processor cycle counter (now taking lost_ticks into account) */ -#include #include #include #include diff --git a/arch/alpha/kernel/traps.c b/arch/alpha/kernel/traps.c index 36b0cc43a..828044b24 100644 --- a/arch/alpha/kernel/traps.c +++ b/arch/alpha/kernel/traps.c @@ -215,8 +215,10 @@ do_entIF(unsigned long type, unsigned long a1, /* EV4 does not implement anything except normal rounding. Everything else will come here as an illegal instruction. Emulate them. */ - if (alpha_fp_emul(regs.pc - 4)) + if (alpha_fp_emul(regs.pc)) { + regs.pc += 4; return; + } } send_sig(SIGILL, current, 1); break; diff --git a/arch/alpha/vmlinux.lds b/arch/alpha/vmlinux.lds index 4b49a5369..4eaac4e42 100644 --- a/arch/alpha/vmlinux.lds +++ b/arch/alpha/vmlinux.lds @@ -5,7 +5,6 @@ SECTIONS . = 0xfffffc0000310000; _text = .; .text : { *(.text) } - .text2 : { *(.text2) } _etext = .; /* Exception table */ diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c index 63d4631a4..c445daeee 100644 --- a/arch/arm/kernel/armksyms.c +++ b/arch/arm/kernel/armksyms.c @@ -165,7 +165,6 @@ EXPORT_SYMBOL_NOVERS(strncmp); EXPORT_SYMBOL_NOVERS(strchr); EXPORT_SYMBOL_NOVERS(strlen); EXPORT_SYMBOL_NOVERS(strnlen); -EXPORT_SYMBOL_NOVERS(strspn); EXPORT_SYMBOL_NOVERS(strpbrk); EXPORT_SYMBOL_NOVERS(strtok); EXPORT_SYMBOL_NOVERS(strrchr); diff --git a/arch/arm/mm/consistent.c b/arch/arm/mm/consistent.c index 8673d6c1d..7101b2936 100644 --- a/arch/arm/mm/consistent.c +++ b/arch/arm/mm/consistent.c @@ -23,7 +23,6 @@ void *consistent_alloc(int gfp, size_t size, dma_addr_t *dma_handle) { int order; unsigned long page; - struct vm_struct *area; void *ret; if (in_interrupt()) @@ -40,15 +39,10 @@ void *consistent_alloc(int gfp, size_t size, dma_addr_t *dma_handle) *dma_handle = virt_to_bus((void *)page); - area = get_vm_area(size, VM_IOREMAP); /* maybe new type? */ - if (!area) - goto no_area; - ret = __ioremap(virt_to_phys((void *)page), PAGE_SIZE << order, 0); if (ret) return ret; -no_area: free_pages(page, order); no_page: BUG(); diff --git a/arch/i386/defconfig b/arch/i386/defconfig index 4ca545255..34b453c2c 100644 --- a/arch/i386/defconfig +++ b/arch/i386/defconfig @@ -109,10 +109,12 @@ CONFIG_BLK_DEV_CMD640=y # CONFIG_BLK_DEV_ISAPNP is not set CONFIG_BLK_DEV_RZ1000=y CONFIG_BLK_DEV_IDEPCI=y +CONFIG_IDEPCI_SHARE_IRQ=y # CONFIG_BLK_DEV_IDEDMA_PCI is not set # CONFIG_BLK_DEV_OFFBOARD is not set # CONFIG_BLK_DEV_AEC6210 is not set # CONFIG_BLK_DEV_CMD64X is not set +# CONFIG_BLK_DEV_CS5530 is not set # CONFIG_IDE_CHIPSETS is not set # CONFIG_BLK_CPQ_DA is not set @@ -393,6 +395,7 @@ CONFIG_PSMOUSE=y # CONFIG_WATCHDOG is not set # CONFIG_NVRAM is not set # CONFIG_RTC is not set +# CONFIG_EFI_RTC is not set # # Video For Linux diff --git a/arch/i386/kernel/acpi.c b/arch/i386/kernel/acpi.c index 9bdd111d1..6228805db 100644 --- a/arch/i386/kernel/acpi.c +++ b/arch/i386/kernel/acpi.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -379,13 +380,14 @@ static struct acpi_table *__init acpi_map_table(u32 addr) ioremap((unsigned long) addr, table_size); } - if (!table) { - /* ioremap is a pain, it returns NULL if the - * table starts within mapped physical memory. - * Hopefully, no table straddles a mapped/unmapped - * physical memory boundary, ugh + if (!table && addr < virt_to_phys(high_memory)) { + /* sometimes we see ACPI tables in low memory + * and not reserved by the memory map (E820) code, + * who is at fault for this? BIOS? */ - table = (struct acpi_table*) phys_to_virt(addr); + printk(KERN_ERR + "ACPI: unreserved table memory @ 0x%p!\n", + (void*) addr); } } return table; @@ -933,9 +935,9 @@ static int acpi_enter_dx(acpi_dstate_t state) int status = 0; if (state == ACPI_D0) - status = pm_send_request(PM_RESUME, (void*) state); + status = pm_send_all(PM_RESUME, (void*) state); else - status = pm_send_request(PM_SUSPEND, (void*) state); + status = pm_send_all(PM_SUSPEND, (void*) state); return status; } @@ -1333,10 +1335,7 @@ static int __init acpi_init(void) if (acpi_claim_ioports(acpi_facp)) { printk(KERN_ERR "ACPI: I/O port allocation failed\n"); - if (pci_driver_registered) - pci_unregister_driver(&acpi_driver); - acpi_destroy_tables(); - return -ENODEV; + goto err_out; } if (acpi_facp->sci_int @@ -1347,12 +1346,7 @@ static int __init acpi_init(void) acpi_facp)) { printk(KERN_ERR "ACPI: SCI (IRQ%d) allocation failed\n", acpi_facp->sci_int); - - if (pci_driver_registered) - pci_unregister_driver(&acpi_driver); - acpi_destroy_tables(); - - return -ENODEV; + goto err_out; } acpi_sysctl = register_sysctl_table(acpi_dir_table, 1); @@ -1379,6 +1373,13 @@ static int __init acpi_init(void) pm_idle = acpi_idle; return 0; + +err_out: + if (pci_driver_registered) + pci_unregister_driver(&acpi_driver); + acpi_destroy_tables(); + + return -ENODEV; } /* diff --git a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c index 4ec5e7993..3d403b93c 100644 --- a/arch/i386/kernel/apm.c +++ b/arch/i386/kernel/apm.c @@ -333,7 +333,7 @@ static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue); static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue); static struct apm_user * user_list = NULL; -static char driver_version[] = "1.12"; /* no spaces */ +static char driver_version[] = "1.13"; /* no spaces */ static char * apm_event_name[] = { "system standby", @@ -590,7 +590,11 @@ static void apm_cpu_idle(void) continue; if (hlt_counter) continue; - asm volatile("sti ; hlt" : : : "memory"); + asm volatile("cli" : : : "memory"); + if (!current->need_resched) + asm volatile("sti ; hlt" : : : "memory"); + else + asm volatile("sti" : : : "memory"); continue; } @@ -635,7 +639,7 @@ static void apm_power_off(void) */ #ifdef CONFIG_SMP /* Some bioses don't like being called from CPU != 0 */ - while (cpu_number_map[smp_processor_id()] != 0) { + while (cpu_number_map(smp_processor_id()) != 0) { kernel_thread(apm_magic, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD); schedule(); @@ -916,7 +920,7 @@ static int send_event(apm_event_t event, struct apm_user *sender) case APM_CRITICAL_SUSPEND: case APM_USER_SUSPEND: /* map all suspends to ACPI D3 */ - if (pm_send_request(PM_SUSPEND, (void *)3)) { + if (pm_send_all(PM_SUSPEND, (void *)3)) { if (apm_bios_info.version > 0x100) apm_set_power_state(APM_STATE_REJECT); return 0; @@ -925,7 +929,7 @@ static int send_event(apm_event_t event, struct apm_user *sender) case APM_NORMAL_RESUME: case APM_CRITICAL_RESUME: /* map all resumes to ACPI D0 */ - (void) pm_send_request(PM_RESUME, (void *)0); + (void) pm_send_all(PM_RESUME, (void *)0); break; } diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S index bcca244c1..0c3cae5d9 100644 --- a/arch/i386/kernel/entry.S +++ b/arch/i386/kernel/entry.S @@ -181,6 +181,8 @@ ret_from_fork: call SYMBOL_NAME(schedule_tail) addl $4, %esp GET_CURRENT(%ebx) + testb $0x20,flags(%ebx) # PF_TRACESYS + jne tracesys_exit jmp ret_from_sys_call /* diff --git a/arch/i386/kernel/i386_ksyms.c b/arch/i386/kernel/i386_ksyms.c index cad6ceb17..a3389c5f0 100644 --- a/arch/i386/kernel/i386_ksyms.c +++ b/arch/i386/kernel/i386_ksyms.c @@ -144,6 +144,4 @@ EXPORT_SYMBOL(screen_info); EXPORT_SYMBOL(get_wchan); - -EXPORT_SYMBOL(local_bh_count); -EXPORT_SYMBOL(local_irq_count); +EXPORT_SYMBOL(irq_stat); diff --git a/arch/i386/kernel/i8259.c b/arch/i386/kernel/i8259.c index d54f9b503..ec33f2269 100644 --- a/arch/i386/kernel/i8259.c +++ b/arch/i386/kernel/i8259.c @@ -127,11 +127,14 @@ void (*interrupt[NR_IRQS])(void) = { * moves to arch independent land */ -void enable_8259A_irq(unsigned int irq); -void disable_8259A_irq(unsigned int irq); +static spinlock_t i8259A_lock = SPIN_LOCK_UNLOCKED; + +static void end_8259A_irq (unsigned int irq) +{ + if (!(irq_desc[irq].status & IRQ_DISABLED)) + enable_8259A_irq(irq); +} -/* shutdown is same as "disable" */ -#define end_8259A_irq enable_8259A_irq #define shutdown_8259A_irq disable_8259A_irq void mask_and_ack_8259A(unsigned int); @@ -149,7 +152,8 @@ static struct hw_interrupt_type i8259A_irq_type = { enable_8259A_irq, disable_8259A_irq, mask_and_ack_8259A, - end_8259A_irq + end_8259A_irq, + NULL }; /* @@ -183,30 +187,45 @@ unsigned long io_apic_irqs = 0; void disable_8259A_irq(unsigned int irq) { unsigned int mask = 1 << irq; + unsigned long flags; + + spin_lock_irqsave(&i8259A_lock, flags); cached_irq_mask |= mask; if (irq & 8) outb(cached_A1,0xA1); else outb(cached_21,0x21); + spin_unlock_irqrestore(&i8259A_lock, flags); } void enable_8259A_irq(unsigned int irq) { unsigned int mask = ~(1 << irq); + unsigned long flags; + + spin_lock_irqsave(&i8259A_lock, flags); cached_irq_mask &= mask; if (irq & 8) outb(cached_A1,0xA1); else outb(cached_21,0x21); + spin_unlock_irqrestore(&i8259A_lock, flags); } int i8259A_irq_pending(unsigned int irq) { unsigned int mask = 1<> 8)); + ret = inb(0x20) & mask; + else + ret = inb(0xA0) & (mask >> 8); + spin_unlock_irqrestore(&i8259A_lock, flags); + + return ret; } void make_8259A_irq(unsigned int irq) @@ -247,7 +266,9 @@ static inline int i8259A_irq_real(unsigned int irq) void mask_and_ack_8259A(unsigned int irq) { unsigned int irqmask = 1 << irq; + unsigned long flags; + spin_lock_irqsave(&i8259A_lock, flags); /* * Lightweight spurious IRQ detection. We do not want * to overdo spurious IRQ handling - it's usually a sign @@ -278,6 +299,7 @@ handle_real_irq: outb(cached_21,0x21); outb(0x20,0x20); /* 'generic EOI' to master */ } + spin_unlock_irqrestore(&i8259A_lock, flags); return; spurious_8259A_irq: diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c index 75b2bfb9f..129a587f0 100644 --- a/arch/i386/kernel/io_apic.c +++ b/arch/i386/kernel/io_apic.c @@ -28,6 +28,8 @@ #include #include +static spinlock_t ioapic_lock = SPIN_LOCK_UNLOCKED; + /* * # of IO-APICs and # of IRQ routing registers */ @@ -87,9 +89,8 @@ static void add_pin_to_irq(unsigned int irq, int apic, int pin) entry->pin = pin; } -#define DO_ACTION(name,R,ACTION, FINAL) \ +#define __DO_ACTION(name,R,ACTION, FINAL) \ \ -static void name##_IO_APIC_irq(unsigned int irq) \ { \ int pin; \ struct irq_pin_list *entry = irq_2_pin + irq; \ @@ -109,8 +110,31 @@ static void name##_IO_APIC_irq(unsigned int irq) \ FINAL; \ } -DO_ACTION( mask, 0, |= 0x00010000, io_apic_sync(entry->apic))/* mask = 1 */ -DO_ACTION( unmask, 0, &= 0xfffeffff, ) /* mask = 0 */ +#define DO_ACTION(name,R,ACTION, FINAL) \ + \ +static void name##_IO_APIC_irq(unsigned int irq) \ +__DO_ACTION(name,R,ACTION, FINAL) + +DO_ACTION( __mask, 0, |= 0x00010000, io_apic_sync(entry->apic))/* mask = 1 */ +DO_ACTION( __unmask, 0, &= 0xfffeffff, ) /* mask = 0 */ + +static void mask_IO_APIC_irq (unsigned int irq) +{ + unsigned long flags; + + spin_lock_irqsave(&ioapic_lock, flags); + __mask_IO_APIC_irq(irq); + spin_unlock_irqrestore(&ioapic_lock, flags); +} + +static void unmask_IO_APIC_irq (unsigned int irq) +{ + unsigned long flags; + + spin_lock_irqsave(&ioapic_lock, flags); + __unmask_IO_APIC_irq(irq); + spin_unlock_irqrestore(&ioapic_lock, flags); +} void clear_IO_APIC_pin(unsigned int apic, unsigned int pin) { @@ -537,7 +561,7 @@ void __init setup_IO_APIC_irqs(void) entry.delivery_mode = dest_LowestPrio; entry.dest_mode = 1; /* logical delivery */ entry.mask = 0; /* enable IRQ */ - entry.dest.logical.logical_dest = APIC_ALL_CPUS; /* all CPUs */ + entry.dest.logical.logical_dest = APIC_ALL_CPUS; idx = find_irq_entry(apic,pin,mp_INT); if (idx == -1) { @@ -1026,16 +1050,16 @@ extern atomic_t nmi_counter[NR_CPUS]; static int __init nmi_irq_works(void) { - atomic_t tmp[NR_CPUS]; + irq_cpustat_t tmp[NR_CPUS]; int j, cpu; - memcpy(tmp, nmi_counter, sizeof(tmp)); + memcpy(tmp, irq_stat, sizeof(tmp)); sti(); mdelay(50); for (j = 0; j < smp_num_cpus; j++) { cpu = cpu_logical_map(j); - if (atomic_read(nmi_counter+cpu) - atomic_read(tmp+cpu) <= 3) { + if (atomic_read(&nmi_counter(cpu)) - atomic_read(&tmp[cpu].__nmi_counter) <= 3) { printk("CPU#%d NMI appears to be stuck.\n", cpu); return 0; } @@ -1055,14 +1079,9 @@ static int __init nmi_irq_works(void) * that was delayed but this is now handled in the device * independent code. */ -static void enable_edge_ioapic_irq(unsigned int irq) -{ - unmask_IO_APIC_irq(irq); -} +#define enable_edge_ioapic_irq unmask_IO_APIC_irq -static void disable_edge_ioapic_irq(unsigned int irq) -{ -} +static void disable_edge_ioapic_irq (unsigned int irq) { /* nothing */ } /* * Starting up a edge-triggered IO-APIC interrupt is @@ -1077,12 +1096,17 @@ static void disable_edge_ioapic_irq(unsigned int irq) static unsigned int startup_edge_ioapic_irq(unsigned int irq) { int was_pending = 0; + unsigned long flags; + + spin_lock_irqsave(&ioapic_lock, flags); if (irq < 16) { disable_8259A_irq(irq); if (i8259A_irq_pending(irq)) was_pending = 1; } - enable_edge_ioapic_irq(irq); + __unmask_IO_APIC_irq(irq); + spin_unlock_irqrestore(&ioapic_lock, flags); + return was_pending; } @@ -1093,14 +1117,15 @@ static unsigned int startup_edge_ioapic_irq(unsigned int irq) * interrupt for real. This prevents IRQ storms from unhandled * devices. */ -void static ack_edge_ioapic_irq(unsigned int irq) +static void ack_edge_ioapic_irq(unsigned int irq) { if ((irq_desc[irq].status & (IRQ_PENDING | IRQ_DISABLED)) == (IRQ_PENDING | IRQ_DISABLED)) mask_IO_APIC_irq(irq); ack_APIC_irq(); } -void static end_edge_ioapic_irq(unsigned int i){} + +static void end_edge_ioapic_irq (unsigned int i) { /* nothing */ } /* @@ -1108,23 +1133,46 @@ void static end_edge_ioapic_irq(unsigned int i){} * and shutting down and starting up the interrupt * is the same as enabling and disabling them -- except * with a startup need to return a "was pending" value. + * + * Level triggered interrupts are special because we + * do not touch any IO-APIC register while handling + * them. We ack the APIC in the end-IRQ handler, not + * in the start-IRQ-handler. Protection against reentrance + * from the same interrupt is still provided, both by the + * generic IRQ layer and by the fact that an unacked local + * APIC does not accept IRQs. */ -static unsigned int startup_level_ioapic_irq(unsigned int irq) +static unsigned int startup_level_ioapic_irq (unsigned int irq) { unmask_IO_APIC_irq(irq); + return 0; /* don't check for pending */ } #define shutdown_level_ioapic_irq mask_IO_APIC_irq #define enable_level_ioapic_irq unmask_IO_APIC_irq #define disable_level_ioapic_irq mask_IO_APIC_irq -#define end_level_ioapic_irq unmask_IO_APIC_irq -void static mask_and_ack_level_ioapic_irq(unsigned int i) + +static void end_level_ioapic_irq (unsigned int i) { - mask_IO_APIC_irq(i); ack_APIC_irq(); } +static void mask_and_ack_level_ioapic_irq (unsigned int i) { /* nothing */ } + +static void set_ioapic_affinity (unsigned int irq, unsigned int mask) +{ + unsigned long flags; + /* + * Only the first 8 bits are valid. + */ + mask = mask << 24; + + spin_lock_irqsave(&ioapic_lock, flags); + __DO_ACTION( target, 1, = mask, ) + spin_unlock_irqrestore(&ioapic_lock, flags); +} + /* * Level and edge triggered IO-APIC interrupts need different handling, * so we use two separate IRQ descriptors. Edge triggered IRQs can be @@ -1141,7 +1189,8 @@ static struct hw_interrupt_type ioapic_edge_irq_type = { enable_edge_ioapic_irq, disable_edge_ioapic_irq, ack_edge_ioapic_irq, - end_edge_ioapic_irq + end_edge_ioapic_irq, + set_ioapic_affinity, }; static struct hw_interrupt_type ioapic_level_irq_type = { @@ -1151,7 +1200,8 @@ static struct hw_interrupt_type ioapic_level_irq_type = { enable_level_ioapic_irq, disable_level_ioapic_irq, mask_and_ack_level_ioapic_irq, - end_level_ioapic_irq + end_level_ioapic_irq, + set_ioapic_affinity, }; static inline void init_IO_APIC_traps(void) @@ -1185,12 +1235,12 @@ static inline void init_IO_APIC_traps(void) } } -void static ack_lapic_irq (unsigned int irq) +static void ack_lapic_irq (unsigned int irq) { ack_APIC_irq(); } -void static end_lapic_irq (unsigned int i) { /* nothing */ } +static void end_lapic_irq (unsigned int i) { /* nothing */ } static struct hw_interrupt_type lapic_irq_type = { "local-APIC-edge", diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c index 9d4a81041..7054249e6 100644 --- a/arch/i386/kernel/irq.c +++ b/arch/i386/kernel/irq.c @@ -31,21 +31,20 @@ #include #include #include +#include +#include #include #include #include #include +#include #include #include #include #include -unsigned int local_bh_count[NR_CPUS]; -unsigned int local_irq_count[NR_CPUS]; - -extern atomic_t nmi_counter[NR_CPUS]; /* * Linux has a controller-independent x86 interrupt architecture. @@ -63,17 +62,15 @@ extern atomic_t nmi_counter[NR_CPUS]; * interrupt controllers, without having to do assembly magic. */ -/* - * Micro-access to controllers is serialized over the whole - * system. We never hold this lock when we call the actual - * IRQ handler. - */ -spinlock_t irq_controller_lock = SPIN_LOCK_UNLOCKED; +irq_cpustat_t irq_stat [NR_CPUS]; + /* * Controller mappings for all interrupt sources: */ irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = - { [0 ... NR_IRQS-1] = { 0, &no_irq_type, }}; + { [0 ... NR_IRQS-1] = { 0, &no_irq_type, NULL, 0, SPIN_LOCK_UNLOCKED}}; + +static void register_irq_proc (unsigned int irq); /* * Special irq handlers. @@ -164,7 +161,7 @@ int get_irq_list(char *buf) p += sprintf(p, "NMI: "); for (j = 0; j < smp_num_cpus; j++) p += sprintf(p, "%10u ", - atomic_read(nmi_counter+cpu_logical_map(j))); + atomic_read(&nmi_counter(cpu_logical_map(j)))); p += sprintf(p, "\n"); #if CONFIG_SMP p += sprintf(p, "LOC: "); @@ -186,7 +183,6 @@ int get_irq_list(char *buf) #ifdef CONFIG_SMP unsigned char global_irq_holder = NO_PROC_ID; unsigned volatile int global_irq_lock; -atomic_t global_irq_count; static void show(char * str) { @@ -196,9 +192,9 @@ static void show(char * str) printk("\n%s, CPU %d:\n", str, cpu); printk("irq: %d [%d %d]\n", - atomic_read(&global_irq_count), local_irq_count[0], local_irq_count[1]); + irqs_running(), local_irq_count(0), local_irq_count(1)); printk("bh: %d [%d %d]\n", - spin_is_locked(&global_bh_lock) ? 1 : 0, local_bh_count[0], local_bh_count[1]); + spin_is_locked(&global_bh_lock) ? 1 : 0, local_bh_count(0), local_bh_count(1)); stack = (unsigned long *) &stack; for (i = 40; i ; i--) { unsigned long x = *++stack; @@ -248,10 +244,9 @@ static inline void wait_on_irq(int cpu) * for bottom half handlers unless we're * already executing in one.. */ - if (!atomic_read(&global_irq_count)) { - if (local_bh_count[cpu] || !spin_is_locked(&global_bh_lock)) + if (!irqs_running()) + if (local_bh_count(cpu) || !spin_is_locked(&global_bh_lock)) break; - } /* Duh, we have to loop. Release the lock to avoid deadlocks */ clear_bit(0,&global_irq_lock); @@ -264,11 +259,11 @@ static inline void wait_on_irq(int cpu) __sti(); SYNC_OTHER_CORES(cpu); __cli(); - if (atomic_read(&global_irq_count)) + if (irqs_running()) continue; if (global_irq_lock) continue; - if (!local_bh_count[cpu] && spin_is_locked(&global_bh_lock)) + if (!local_bh_count(cpu) && spin_is_locked(&global_bh_lock)) continue; if (!test_and_set_bit(0,&global_irq_lock)) break; @@ -285,7 +280,7 @@ static inline void wait_on_irq(int cpu) */ void synchronize_irq(void) { - if (atomic_read(&global_irq_count)) { + if (irqs_running()) { /* Stupid approach */ cli(); sti(); @@ -338,7 +333,7 @@ void __global_cli(void) if (flags & (1 << EFLAGS_IF_SHIFT)) { int cpu = smp_processor_id(); __cli(); - if (!local_irq_count[cpu]) + if (!local_irq_count(cpu)) get_irqlock(cpu); } } @@ -347,7 +342,7 @@ void __global_sti(void) { int cpu = smp_processor_id(); - if (!local_irq_count[cpu]) + if (!local_irq_count(cpu)) release_irqlock(cpu); __sti(); } @@ -364,6 +359,7 @@ unsigned long __global_save_flags(void) int retval; int local_enabled; unsigned long flags; + int cpu = smp_processor_id(); __save_flags(flags); local_enabled = (flags >> EFLAGS_IF_SHIFT) & 1; @@ -371,10 +367,10 @@ unsigned long __global_save_flags(void) retval = 2 + local_enabled; /* check for global flags if we're not in an interrupt */ - if (!local_irq_count[smp_processor_id()]) { + if (!local_irq_count(cpu)) { if (local_enabled) retval = 1; - if (global_irq_holder == (unsigned char) smp_processor_id()) + if (global_irq_holder == cpu) retval = 0; } return retval; @@ -442,16 +438,17 @@ int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, struct irqaction * * hardware disable after having gotten the irq * controller lock. */ -void disable_irq_nosync(unsigned int irq) +void inline disable_irq_nosync(unsigned int irq) { + irq_desc_t *desc = irq_desc + irq; unsigned long flags; - spin_lock_irqsave(&irq_controller_lock, flags); - if (!irq_desc[irq].depth++) { - irq_desc[irq].status |= IRQ_DISABLED; - irq_desc[irq].handler->disable(irq); + spin_lock_irqsave(&desc->lock, flags); + if (!desc->depth++) { + desc->status |= IRQ_DISABLED; + desc->handler->disable(irq); } - spin_unlock_irqrestore(&irq_controller_lock, flags); + spin_unlock_irqrestore(&desc->lock, flags); } /* @@ -462,7 +459,7 @@ void disable_irq(unsigned int irq) { disable_irq_nosync(irq); - if (!local_irq_count[smp_processor_id()]) { + if (!local_irq_count(smp_processor_id())) { do { barrier(); } while (irq_desc[irq].status & IRQ_INPROGRESS); @@ -471,28 +468,29 @@ void disable_irq(unsigned int irq) void enable_irq(unsigned int irq) { + irq_desc_t *desc = irq_desc + irq; unsigned long flags; - spin_lock_irqsave(&irq_controller_lock, flags); - switch (irq_desc[irq].depth) { + spin_lock_irqsave(&desc->lock, flags); + switch (desc->depth) { case 1: { - unsigned int status = irq_desc[irq].status & ~IRQ_DISABLED; - irq_desc[irq].status = status; + unsigned int status = desc->status & ~IRQ_DISABLED; + desc->status = status; if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) { - irq_desc[irq].status = status | IRQ_REPLAY; - hw_resend_irq(irq_desc[irq].handler,irq); + desc->status = status | IRQ_REPLAY; + hw_resend_irq(desc->handler,irq); } - irq_desc[irq].handler->enable(irq); + desc->handler->enable(irq); /* fall-through */ } default: - irq_desc[irq].depth--; + desc->depth--; break; case 0: printk("enable_irq() unbalanced from %p\n", __builtin_return_address(0)); } - spin_unlock_irqrestore(&irq_controller_lock, flags); + spin_unlock_irqrestore(&desc->lock, flags); } /* @@ -514,13 +512,12 @@ asmlinkage unsigned int do_IRQ(struct pt_regs regs) */ int irq = regs.orig_eax & 0xff; /* high bits used in ret_from_ code */ int cpu = smp_processor_id(); - irq_desc_t *desc; + irq_desc_t *desc = irq_desc + irq; struct irqaction * action; unsigned int status; kstat.irqs[cpu][irq]++; - desc = irq_desc + irq; - spin_lock(&irq_controller_lock); + spin_lock(&desc->lock); desc->handler->ack(irq); /* REPLAY is when Linux resends an IRQ that was dropped earlier @@ -540,7 +537,6 @@ asmlinkage unsigned int do_IRQ(struct pt_regs regs) status |= IRQ_INPROGRESS; /* we are handling it */ } desc->status = status; - spin_unlock(&irq_controller_lock); /* * If there is no IRQ handler or it was disabled, exit early. @@ -549,7 +545,7 @@ asmlinkage unsigned int do_IRQ(struct pt_regs regs) will take care of it. */ if (!action) - return 1; + goto out; /* * Edge triggered interrupts need to remember @@ -562,20 +558,24 @@ asmlinkage unsigned int do_IRQ(struct pt_regs regs) * SMP environment. */ for (;;) { + spin_unlock(&desc->lock); handle_IRQ_event(irq, ®s, action); - spin_lock(&irq_controller_lock); + spin_lock(&desc->lock); if (!(desc->status & IRQ_PENDING)) break; desc->status &= ~IRQ_PENDING; - spin_unlock(&irq_controller_lock); } desc->status &= ~IRQ_INPROGRESS; - if (!(desc->status & IRQ_DISABLED)) - desc->handler->end(irq); - spin_unlock(&irq_controller_lock); +out: + /* + * The ->end() handler has to deal with interrupts which got + * disabled while the handler was running. + */ + desc->handler->end(irq); + spin_unlock(&desc->lock); - if (softirq_state[cpu].active&softirq_state[cpu].mask) + if (softirq_state[cpu].active & softirq_state[cpu].mask) do_softirq(); return 1; } @@ -627,14 +627,16 @@ int request_irq(unsigned int irq, void free_irq(unsigned int irq, void *dev_id) { + irq_desc_t *desc; struct irqaction **p; unsigned long flags; if (irq >= NR_IRQS) return; - spin_lock_irqsave(&irq_controller_lock,flags); - p = &irq_desc[irq].action; + desc = irq_desc + irq; + spin_lock_irqsave(&desc->lock,flags); + p = &desc->action; for (;;) { struct irqaction * action = *p; if (action) { @@ -645,22 +647,22 @@ void free_irq(unsigned int irq, void *dev_id) /* Found it - now remove it from the list of entries */ *pp = action->next; - if (!irq_desc[irq].action) { - irq_desc[irq].status |= IRQ_DISABLED; - irq_desc[irq].handler->shutdown(irq); + if (!desc->action) { + desc->status |= IRQ_DISABLED; + desc->handler->shutdown(irq); } - spin_unlock_irqrestore(&irq_controller_lock,flags); + spin_unlock_irqrestore(&desc->lock,flags); #ifdef CONFIG_SMP /* Wait to make sure it's not being used on another CPU */ - while (irq_desc[irq].status & IRQ_INPROGRESS) + while (desc->status & IRQ_INPROGRESS) barrier(); #endif kfree(action); return; } printk("Trying to free free IRQ%d\n",irq); - spin_unlock_irqrestore(&irq_controller_lock,flags); + spin_unlock_irqrestore(&desc->lock,flags); return; } } @@ -676,21 +678,43 @@ void free_irq(unsigned int irq, void *dev_id) unsigned long probe_irq_on(void) { unsigned int i; - unsigned long delay; + irq_desc_t *desc; unsigned long val; + unsigned long delay; + + /* + * something may have generated an irq long ago and we want to + * flush such a longstanding irq before considering it as spurious. + */ + for (i = NR_IRQS-1; i > 0; i--) { + desc = irq_desc + i; + + spin_lock_irq(&desc->lock); + if (!irq_desc[i].action) + irq_desc[i].handler->startup(i); + spin_unlock_irq(&desc->lock); + } + + /* Wait for longstanding interrupts to trigger. */ + for (delay = jiffies + HZ/50; time_after(delay, jiffies); ) + /* about 20ms delay */ synchronize_irq(); /* - * first, enable any unassigned irqs + * enable any unassigned irqs + * (we must startup again here because if a longstanding irq + * happened in the previous stage, it may have masked itself) */ - spin_lock_irq(&irq_controller_lock); for (i = NR_IRQS-1; i > 0; i--) { - if (!irq_desc[i].action) { - irq_desc[i].status |= IRQ_AUTODETECT | IRQ_WAITING; - if(irq_desc[i].handler->startup(i)) - irq_desc[i].status |= IRQ_PENDING; + desc = irq_desc + i; + + spin_lock_irq(&desc->lock); + if (!desc->action) { + desc->status |= IRQ_AUTODETECT | IRQ_WAITING; + if (desc->handler->startup(i)) + desc->status |= IRQ_PENDING; } + spin_unlock_irq(&desc->lock); } - spin_unlock_irq(&irq_controller_lock); /* * Wait for spurious interrupts to trigger @@ -702,24 +726,24 @@ unsigned long probe_irq_on(void) * Now filter out any obviously spurious interrupts */ val = 0; - spin_lock_irq(&irq_controller_lock); - for (i=0; ishutdown(i); - continue; + for (i = 0; i < NR_IRQS; i++) { + irq_desc_t *desc = irq_desc + i; + unsigned int status; + + spin_lock_irq(&desc->lock); + status = desc->status; + + if (status & IRQ_AUTODETECT) { + /* It triggered already - consider it spurious. */ + if (!(status & IRQ_WAITING)) { + desc->status = status & ~IRQ_AUTODETECT; + desc->handler->shutdown(i); + } else + if (i < 32) + val |= 1 << i; } - - if (i < 32) - val |= 1 << i; + spin_unlock_irq(&desc->lock); } - spin_unlock_irq(&irq_controller_lock); return val; } @@ -734,20 +758,22 @@ unsigned int probe_irq_mask(unsigned long val) unsigned int mask; mask = 0; - spin_lock_irq(&irq_controller_lock); for (i = 0; i < 16; i++) { - unsigned int status = irq_desc[i].status; + irq_desc_t *desc = irq_desc + i; + unsigned int status; - if (!(status & IRQ_AUTODETECT)) - continue; + spin_lock_irq(&desc->lock); + status = desc->status; - if (!(status & IRQ_WAITING)) - mask |= 1 << i; + if (status & IRQ_AUTODETECT) { + if (!(status & IRQ_WAITING)) + mask |= 1 << i; - irq_desc[i].status = status & ~IRQ_AUTODETECT; - irq_desc[i].handler->shutdown(i); + desc->status = status & ~IRQ_AUTODETECT; + desc->handler->shutdown(i); + } + spin_unlock_irq(&desc->lock); } - spin_unlock_irq(&irq_controller_lock); return mask & val; } @@ -762,22 +788,24 @@ int probe_irq_off(unsigned long val) nr_irqs = 0; irq_found = 0; - spin_lock_irq(&irq_controller_lock); - for (i=0; ilock); + status = desc->status; + + if (status & IRQ_AUTODETECT) { + if (!(status & IRQ_WAITING)) { + if (!nr_irqs) + irq_found = i; + nr_irqs++; + } + desc->status = status & ~IRQ_AUTODETECT; + desc->handler->shutdown(i); } - irq_desc[i].status = status & ~IRQ_AUTODETECT; - irq_desc[i].handler->shutdown(i); + spin_unlock_irq(&desc->lock); } - spin_unlock_irq(&irq_controller_lock); if (nr_irqs > 1) irq_found = -irq_found; @@ -788,8 +816,9 @@ int probe_irq_off(unsigned long val) int setup_irq(unsigned int irq, struct irqaction * new) { int shared = 0; - struct irqaction *old, **p; unsigned long flags; + struct irqaction *old, **p; + irq_desc_t *desc = irq_desc + irq; /* * Some drivers like serial.c use request_irq() heavily, @@ -811,12 +840,12 @@ int setup_irq(unsigned int irq, struct irqaction * new) /* * The following block of code has to be executed atomically */ - spin_lock_irqsave(&irq_controller_lock,flags); - p = &irq_desc[irq].action; + spin_lock_irqsave(&desc->lock,flags); + p = &desc->action; if ((old = *p) != NULL) { /* Can't share interrupts unless both agree to */ if (!(old->flags & new->flags & SA_SHIRQ)) { - spin_unlock_irqrestore(&irq_controller_lock,flags); + spin_unlock_irqrestore(&desc->lock,flags); return -EBUSY; } @@ -831,11 +860,171 @@ int setup_irq(unsigned int irq, struct irqaction * new) *p = new; if (!shared) { - irq_desc[irq].depth = 0; - irq_desc[irq].status &= ~IRQ_DISABLED; - irq_desc[irq].handler->startup(irq); + desc->depth = 0; + desc->status &= ~IRQ_DISABLED; + desc->handler->startup(irq); } - spin_unlock_irqrestore(&irq_controller_lock,flags); + spin_unlock_irqrestore(&desc->lock,flags); + + register_irq_proc(irq); return 0; } +static struct proc_dir_entry * root_irq_dir; +static struct proc_dir_entry * irq_dir [NR_IRQS]; +static struct proc_dir_entry * smp_affinity_entry [NR_IRQS]; + +unsigned int irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = 0xffffffff}; + +#define HEX_DIGITS 8 + +static int irq_affinity_read_proc (char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + if (count < HEX_DIGITS+1) + return -EINVAL; + return sprintf (page, "%08x\n", irq_affinity[(int)data]); +} + +static unsigned int parse_hex_value (const char *buffer, + unsigned long count, unsigned long *ret) +{ + unsigned char hexnum [HEX_DIGITS]; + unsigned long value; + int i; + + if (!count) + return -EINVAL; + if (count > HEX_DIGITS) + count = HEX_DIGITS; + if (copy_from_user(hexnum, buffer, count)) + return -EFAULT; + + /* + * Parse the first 8 characters as a hex string, any non-hex char + * is end-of-string. '00e1', 'e1', '00E1', 'E1' are all the same. + */ + value = 0; + + for (i = 0; i < count; i++) { + unsigned int c = hexnum[i]; + + switch (c) { + case '0' ... '9': c -= '0'; break; + case 'a' ... 'f': c -= 'a'-10; break; + case 'A' ... 'F': c -= 'A'-10; break; + default: + goto out; + } + value = (value << 4) | c; + } +out: + *ret = value; + return 0; +} + +static int irq_affinity_write_proc (struct file *file, const char *buffer, + unsigned long count, void *data) +{ + int irq = (int) data, full_count = count, err; + unsigned long new_value; + + if (!irq_desc[irq].handler->set_affinity) + return -EIO; + + err = parse_hex_value(buffer, count, &new_value); + +#if CONFIG_SMP + /* + * Do not allow disabling IRQs completely - it's a too easy + * way to make the system unusable accidentally :-) At least + * one online CPU still has to be targeted. + */ + if (!(new_value & cpu_online_map)) + return -EINVAL; +#endif + + irq_affinity[irq] = new_value; + irq_desc[irq].handler->set_affinity(irq, new_value); + + return full_count; +} + +static int prof_cpu_mask_read_proc (char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + unsigned long *mask = (unsigned long *) data; + if (count < HEX_DIGITS+1) + return -EINVAL; + return sprintf (page, "%08lx\n", *mask); +} + +static int prof_cpu_mask_write_proc (struct file *file, const char *buffer, + unsigned long count, void *data) +{ + unsigned long *mask = (unsigned long *) data, full_count = count, err; + unsigned long new_value; + + err = parse_hex_value(buffer, count, &new_value); + if (err) + return err; + + *mask = new_value; + return full_count; +} + +#define MAX_NAMELEN 10 + +static void register_irq_proc (unsigned int irq) +{ + struct proc_dir_entry *entry; + char name [MAX_NAMELEN]; + + if (!root_irq_dir || (irq_desc[irq].handler == &no_irq_type)) + return; + + memset(name, 0, MAX_NAMELEN); + sprintf(name, "%d", irq); + + /* create /proc/irq/1234 */ + irq_dir[irq] = proc_mkdir(name, root_irq_dir); + + /* create /proc/irq/1234/smp_affinity */ + entry = create_proc_entry("smp_affinity", 0700, irq_dir[irq]); + + entry->nlink = 1; + entry->data = (void *)irq; + entry->read_proc = irq_affinity_read_proc; + entry->write_proc = irq_affinity_write_proc; + + smp_affinity_entry[irq] = entry; +} + +unsigned long prof_cpu_mask = -1; + +void init_irq_proc (void) +{ + struct proc_dir_entry *entry; + int i; + + /* create /proc/irq */ + root_irq_dir = proc_mkdir("irq", 0); + + /* create /proc/irq/prof_cpu_mask */ + entry = create_proc_entry("prof_cpu_mask", 0700, root_irq_dir); + + entry->nlink = 1; + entry->data = (void *)&prof_cpu_mask; + entry->read_proc = prof_cpu_mask_read_proc; + entry->write_proc = prof_cpu_mask_write_proc; + + /* + * Create entries for all existing IRQs. + */ + for (i = 0; i < NR_IRQS; i++) { + if (irq_desc[i].handler == &no_irq_type) + continue; + register_irq_proc(i); + } +} + diff --git a/arch/i386/kernel/microcode.c b/arch/i386/kernel/microcode.c index 26b6525d8..84490b40b 100644 --- a/arch/i386/kernel/microcode.c +++ b/arch/i386/kernel/microcode.c @@ -20,6 +20,9 @@ * Initial release. * 1.01 18 February 2000, Tigran Aivazian * Added read() support + cleanups. + * 1.02 21 February 2000, Tigran Aivazian + * Added 'device trimming' support. open(O_WRONLY) zeroes + * and frees the saved copy of applied microcode. */ #include @@ -33,7 +36,7 @@ #include #include -#define MICROCODE_VERSION "1.01" +#define MICROCODE_VERSION "1.02" MODULE_DESCRIPTION("CPU (P6) microcode update driver"); MODULE_AUTHOR("Tigran Aivazian "); @@ -53,7 +56,7 @@ static void do_update_one(void *); /* * Bits in microcode_status. (31 bits of room for future expansion) */ -#define MICROCODE_IS_OPEN 0 /* set if /dev/microcode is in use */ +#define MICROCODE_IS_OPEN 0 /* set if device is in use */ static unsigned long microcode_status = 0; /* the actual array of microcode blocks, each 2048 bytes */ @@ -68,31 +71,16 @@ static struct file_operations microcode_fops = { release: microcode_release, }; -static struct inode_operations microcode_inops = { - default_file_ops: µcode_fops, -}; - static struct proc_dir_entry *proc_microcode; static int __init microcode_init(void) { - int size; - proc_microcode = create_proc_entry("microcode", S_IWUSR|S_IRUSR, proc_root_driver); if (!proc_microcode) { printk(KERN_ERR "microcode: can't create /proc/driver/microcode\n"); return -ENOMEM; } - proc_microcode->ops = µcode_inops; - size = smp_num_cpus * sizeof(struct microcode); - mc_applied = kmalloc(size, GFP_KERNEL); - if (!mc_applied) { - remove_proc_entry("microcode", proc_root_driver); - printk(KERN_ERR "microcode: can't allocate memory for saved microcode\n"); - return -ENOMEM; - } - memset(mc_applied, 0, size); /* so that reading from offsets corresponding to failed - update makes this obvious */ + proc_microcode->proc_fops = µcode_fops; printk(KERN_INFO "P6 Microcode Update Driver v%s registered\n", MICROCODE_VERSION); return 0; } @@ -100,7 +88,8 @@ static int __init microcode_init(void) static void __exit microcode_exit(void) { remove_proc_entry("microcode", proc_root_driver); - kfree(mc_applied); + if (mc_applied) + kfree(mc_applied); printk(KERN_INFO "P6 Microcode Update Driver v%s unregistered\n", MICROCODE_VERSION); } @@ -119,6 +108,15 @@ static int microcode_open(struct inode *inode, struct file *file) if (test_and_set_bit(MICROCODE_IS_OPEN, µcode_status)) return -EBUSY; + if ((file->f_flags & O_ACCMODE) == O_WRONLY) { + proc_microcode->size = 0; + if (mc_applied) { + memset(mc_applied, 0, smp_num_cpus * sizeof(struct microcode)); + kfree(mc_applied); + mc_applied = NULL; + } + } + MOD_INC_USE_COUNT; return 0; @@ -243,6 +241,16 @@ static ssize_t microcode_write(struct file *file, const char *buf, size_t len, l sizeof(struct microcode)); return -EINVAL; } + if (!mc_applied) { + int size = smp_num_cpus * sizeof(struct microcode); + mc_applied = kmalloc(size, GFP_KERNEL); + if (!mc_applied) { + printk(KERN_ERR "microcode: can't allocate memory for saved microcode\n"); + return -ENOMEM; + } + memset(mc_applied, 0, size); + } + lock_kernel(); microcode_num = len/sizeof(struct microcode); microcode = vmalloc(len); diff --git a/arch/i386/kernel/mpparse.c b/arch/i386/kernel/mpparse.c index 81685d2f5..030b31647 100644 --- a/arch/i386/kernel/mpparse.c +++ b/arch/i386/kernel/mpparse.c @@ -316,11 +316,14 @@ static int __init smp_read_mpc(struct mp_config_table *mpc) return num_processors; } +static struct intel_mp_floating *mpf_found; + /* * Scan the memory blocks for an SMP configuration block. */ -static int __init smp_get_mpf(struct intel_mp_floating *mpf) +void __init get_smp_config (void) { + struct intel_mp_floating *mpf = mpf_found; printk("Intel MultiProcessor Specification v1.%d\n", mpf->mpf_specification); if (mpf->mpf_feature2 & (1<<7)) { printk(" IMCR and PIC compatibility mode.\n"); @@ -329,7 +332,6 @@ static int __init smp_get_mpf(struct intel_mp_floating *mpf) printk(" Virtual Wire compatibility mode.\n"); pic_mode = 0; } - smp_found_config = 1; /* * default CPU id - if it's different in the mptable * then we change it before first using it. @@ -388,7 +390,7 @@ static int __init smp_get_mpf(struct intel_mp_floating *mpf) default: printk("???\nUnknown standard configuration %d\n", mpf->mpf_feature1); - return 1; + return; } if (mpf->mpf_feature1 > 4) { printk("Bus #1 is PCI\n"); @@ -412,10 +414,9 @@ static int __init smp_get_mpf(struct intel_mp_floating *mpf) /* * Only use the first configuration found. */ - return 1; } -static int __init smp_scan_config(unsigned long base, unsigned long length) +static int __init smp_scan_config (unsigned long base, unsigned long length) { unsigned long *bp = phys_to_virt(base); struct intel_mp_floating *mpf; @@ -432,9 +433,13 @@ static int __init smp_scan_config(unsigned long base, unsigned long length) ((mpf->mpf_specification == 1) || (mpf->mpf_specification == 4)) ) { - printk("found SMP MP-table at %08ld\n", + smp_found_config = 1; + printk("found SMP MP-table at %08lx\n", virt_to_phys(mpf)); - smp_get_mpf(mpf); + reserve_bootmem(virt_to_phys(mpf), PAGE_SIZE); + if (mpf->mpf_physptr) + reserve_bootmem(mpf->mpf_physptr, PAGE_SIZE); + mpf_found = mpf; return 1; } bp += 4; @@ -443,7 +448,7 @@ static int __init smp_scan_config(unsigned long base, unsigned long length) return 0; } -void __init init_intel_smp (void) +void __init find_intel_smp (void) { unsigned int address; @@ -488,7 +493,7 @@ void __init init_intel_smp (void) * sense, but it doesnt have a BIOS(-configuration table). * No problem for Linux. */ -void __init init_visws_smp(void) +void __init find_visws_smp(void) { smp_found_config = 1; @@ -505,13 +510,13 @@ void __init init_visws_smp(void) * - Intel MP Configuration Table * - or SGI Visual Workstation configuration */ -void __init init_smp_config (void) +void __init find_smp_config (void) { #ifdef CONFIG_X86_IO_APIC - init_intel_smp(); + find_intel_smp(); #endif #ifdef CONFIG_VISWS - init_visws_smp(); + find_visws_smp(); #endif } diff --git a/arch/i386/kernel/mtrr.c b/arch/i386/kernel/mtrr.c index a0a4ab851..cc9c7eafe 100644 --- a/arch/i386/kernel/mtrr.c +++ b/arch/i386/kernel/mtrr.c @@ -1507,11 +1507,6 @@ static struct file_operations mtrr_fops = # ifdef CONFIG_PROC_FS -static struct inode_operations proc_mtrr_inode_operations = -{ - &mtrr_fops, /* default property file-ops */ -}; - static struct proc_dir_entry *proc_root_mtrr; # endif /* CONFIG_PROC_FS */ @@ -1836,9 +1831,9 @@ int __init mtrr_init(void) #ifdef CONFIG_PROC_FS proc_root_mtrr = create_proc_entry ("mtrr", S_IWUSR | S_IRUGO, &proc_root); - proc_root_mtrr->ops = &proc_mtrr_inode_operations; + proc_root_mtrr->proc_fops = &mtrr_fops; #endif -#ifdev CONFIG_DEVFS_FS +#ifdef CONFIG_DEVFS_FS devfs_handle = devfs_register (NULL, "cpu/mtrr", 0, DEVFS_FL_DEFAULT, 0, 0, S_IFREG | S_IRUGO | S_IWUSR, 0, 0, &mtrr_fops, NULL); diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c index 0f61ca543..19f7022a4 100644 --- a/arch/i386/kernel/process.c +++ b/arch/i386/kernel/process.c @@ -74,8 +74,13 @@ void enable_hlt(void) */ static void default_idle(void) { - if (current_cpu_data.hlt_works_ok && !hlt_counter) - asm volatile("sti ; hlt" : : : "memory"); + if (current_cpu_data.hlt_works_ok && !hlt_counter) { + asm volatile("cli" : : : "memory"); + if (!current->need_resched) + asm volatile("sti ; hlt" : : : "memory"); + else + asm volatile("sti" : : : "memory"); + } } /* diff --git a/arch/i386/kernel/semaphore.c b/arch/i386/kernel/semaphore.c index c530eece0..febc592ae 100644 --- a/arch/i386/kernel/semaphore.c +++ b/arch/i386/kernel/semaphore.c @@ -150,8 +150,9 @@ int __down_interruptible(struct semaphore * sem) int __down_trylock(struct semaphore * sem) { int sleepers; + unsigned long flags; - spin_lock_irq(&semaphore_lock); + spin_lock_irqsave(&semaphore_lock, flags); sleepers = sem->sleepers + 1; sem->sleepers = 0; @@ -162,7 +163,7 @@ int __down_trylock(struct semaphore * sem) if (!atomic_add_negative(sleepers, &sem->count)) wake_up(&sem->wait); - spin_unlock_irq(&semaphore_lock); + spin_unlock_irqrestore(&semaphore_lock, flags); return 1; } diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c index cd2a3d8af..b5602ebec 100644 --- a/arch/i386/kernel/setup.c +++ b/arch/i386/kernel/setup.c @@ -119,7 +119,7 @@ extern int rd_image_start; /* starting block # of image */ #endif extern int root_mountflags; -extern int _text, _etext, _edata, _end; +extern char _text, _etext, _edata, _end; extern unsigned long cpu_hz; /* @@ -709,9 +709,20 @@ void __init setup_arch(char **cmdline_p) #ifdef CONFIG_X86_IO_APIC /* - * Save possible boot-time SMP configuration: + * Find and reserve possible boot-time SMP configuration: */ - init_smp_config(); + find_smp_config(); +#endif + paging_init(); +#ifdef CONFIG_X86_IO_APIC + /* + * get boot-time SMP configuration: + */ + if (smp_found_config) + get_smp_config(); +#endif +#ifdef CONFIG_X86_LOCAL_APIC + init_apic_mappings(); #endif #ifdef CONFIG_BLK_DEV_INITRD diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c index 07797e760..7400b628b 100644 --- a/arch/i386/kernel/traps.c +++ b/arch/i386/kernel/traps.c @@ -360,8 +360,6 @@ static void unknown_nmi_error(unsigned char reason, struct pt_regs * regs) printk("Do you have a strange power saving mode enabled?\n"); } -atomic_t nmi_counter[NR_CPUS]; - #if CONFIG_X86_IO_APIC int nmi_watchdog = 1; @@ -437,7 +435,8 @@ asmlinkage void do_nmi(struct pt_regs * regs, long error_code) { unsigned char reason = inb(0x61); - atomic_inc(nmi_counter+smp_processor_id()); + + atomic_inc(&nmi_counter(smp_processor_id())); if (!(reason & 0xc0)) { #if CONFIG_X86_IO_APIC /* diff --git a/arch/i386/mm/init.c b/arch/i386/mm/init.c index c3991b056..8b1324520 100644 --- a/arch/i386/mm/init.c +++ b/arch/i386/mm/init.c @@ -438,10 +438,6 @@ void __init paging_init(void) __flush_tlb_all(); -#ifdef CONFIG_X86_LOCAL_APIC - init_apic_mappings(); -#endif - #ifdef CONFIG_HIGHMEM kmap_init(); #endif diff --git a/arch/ia64/ia32/binfmt_elf32.c b/arch/ia64/ia32/binfmt_elf32.c index 685d85b20..af51038e5 100644 --- a/arch/ia64/ia32/binfmt_elf32.c +++ b/arch/ia64/ia32/binfmt_elf32.c @@ -82,6 +82,8 @@ void ia64_elf32_init(struct pt_regs *regs) /* Do all the IA-32 setup here */ + current->thread.map_base = 0x40000000; + /* CS descriptor */ __asm__("mov ar.csd = %0" : /* no outputs */ : "r" IA64_SEG_DESCRIPTOR(0L, 0xFFFFFL, 0xBL, 1L, diff --git a/arch/ia64/ia32/ia32_entry.S b/arch/ia64/ia32/ia32_entry.S index 82ba58129..bd7b0517b 100644 --- a/arch/ia64/ia32/ia32_entry.S +++ b/arch/ia64/ia32/ia32_entry.S @@ -75,7 +75,7 @@ ia32_syscall_table: data8 sys_unlink /* 10 */ data8 sys32_execve data8 sys_chdir - data8 sys_ni_syscall /* sys_time is not supported on ia64 */ + data8 sys32_time data8 sys_mknod data8 sys_chmod /* 15 */ data8 sys_lchown diff --git a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c index d61f1cfe5..8d4e4a8fd 100644 --- a/arch/ia64/ia32/sys_ia32.c +++ b/arch/ia64/ia32/sys_ia32.c @@ -278,7 +278,7 @@ do_mmap_fake(struct file *file, unsigned long addr, unsigned long len, if (!file) return -EINVAL; inode = file->f_dentry->d_inode; - if (!inode->i_op || !inode->i_op->default_file_ops) + if (!inode->i_fop) return -EINVAL; if (!file->f_op->read) return -EINVAL; @@ -1930,6 +1930,25 @@ out: return err; } +/* + * sys_time() can be implemented in user-level using + * sys_gettimeofday(). IA64 did this but i386 Linux did not + * so we have to implement this system call here. + */ +asmlinkage long sys32_time(int * tloc) +{ + int i; + + /* SMP: This is fairly trivial. We grab CURRENT_TIME and + stuff it to user space. No side effects */ + i = CURRENT_TIME; + if (tloc) { + if (put_user(i,tloc)) + i = -EFAULT; + } + return i; +} + #ifdef NOTYET /* UNTESTED FOR IA64 FROM HERE DOWN */ /* In order to reduce some races, while at the same time doing additional diff --git a/arch/ia64/kdb/kdbsupport.c b/arch/ia64/kdb/kdbsupport.c index 0b574ae6e..d074a01a3 100644 --- a/arch/ia64/kdb/kdbsupport.c +++ b/arch/ia64/kdb/kdbsupport.c @@ -28,9 +28,10 @@ #include #include -#include +#include #include #include +#include extern kdb_state_t kdb_state ; k_machreg_t dbregs[KDB_DBREGS]; @@ -44,6 +45,21 @@ kdb_setup (char *str) __setup("kdb", kdb_setup); +static int +kdb_ia64_itm (int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + int diag; + unsigned long val; + + diag = kdbgetularg(argv[1], &val); + if (diag) + return diag; + kdb_printf("new itm=%0xlx\n", val); + + ia64_set_itm(val); + return 0; +} + static int kdb_ia64_sir (int argc, const char **argv, const char **envp, struct pt_regs *regs) { @@ -53,15 +69,17 @@ kdb_ia64_sir (int argc, const char **argv, const char **envp, struct pt_regs *re asm ("mov %0=cr.tpr" : "=r"(tpr)); asm ("mov %0=cr.lrr0" : "=r"(lrr0)); asm ("mov %0=cr.lrr1" : "=r"(lrr1)); - printk ("lid=0x%lx, tpr=0x%lx, lrr0=0x%lx, llr1=0x%lx\n", lid, tpr, lrr0, lrr1); + printk("lid=0x%lx, tpr=0x%lx, lrr0=0x%lx, llr1=0x%lx\n", lid, tpr, lrr0, lrr1); asm ("mov %0=cr.itv" : "=r"(itv)); asm ("mov %0=cr.pmv" : "=r"(pmv)); asm ("mov %0=cr.cmcv" : "=r"(cmcv)); - printk ("itv=0x%lx, pmv=0x%lx, cmcv=0x%lx\n", itv, pmv, cmcv); + printk("itv=0x%lx, pmv=0x%lx, cmcv=0x%lx\n", itv, pmv, cmcv); - printk ("irr=0x%016lx,0x%016lx,0x%016lx,0x%016lx\n", + printk("irr=0x%016lx,0x%016lx,0x%016lx,0x%016lx\n", ia64_get_irr0(), ia64_get_irr1(), ia64_get_irr2(), ia64_get_irr3()); + + printk("itc=0x%016lx, itm=0x%016lx\n", ia64_get_itc(), ia64_get_itm()); return 0; } @@ -90,6 +108,7 @@ kdb_init (void) kdb_state.bkpt_handling_state = BKPTSTATE_NOT_HANDLED ; kdb_register("irr", kdb_ia64_sir, "", "Show interrupt registers", 0); + kdb_register("itm", kdb_ia64_itm, "", "Set new ITM value", 0); } /* diff --git a/arch/ia64/kernel/irq.c b/arch/ia64/kernel/irq.c index 5efe50164..6059e41c6 100644 --- a/arch/ia64/kernel/irq.c +++ b/arch/ia64/kernel/irq.c @@ -158,6 +158,9 @@ ia64_handle_irq (unsigned long irq, struct pt_regs *regs) unsigned long eoi_ptr; # ifdef CONFIG_USB + extern void reenable_usb (void); + extern void disable_usb (void); + if (usbfix) disable_usb(); # endif diff --git a/arch/ia64/kernel/irq_internal.c b/arch/ia64/kernel/irq_internal.c index 1ae904fe8..cc59e0c72 100644 --- a/arch/ia64/kernel/irq_internal.c +++ b/arch/ia64/kernel/irq_internal.c @@ -60,7 +60,7 @@ internal_noop (unsigned int irq) } struct hw_interrupt_type irq_type_ia64_internal = { - "IA64 internal", + "IA64-internal", (void (*)(unsigned long)) internal_noop, /* init */ internal_noop, /* startup */ internal_noop, /* shutdown */ diff --git a/arch/ia64/kernel/ivt.S b/arch/ia64/kernel/ivt.S index 4c3ac242a..b4592999f 100644 --- a/arch/ia64/kernel/ivt.S +++ b/arch/ia64/kernel/ivt.S @@ -1026,7 +1026,7 @@ dispatch_to_fault_handler: // 0x5000 Entry 20 (size 16 bundles) Page Not Present (10,22,49) mov r16=cr.ifa rsm psr.dt -#if 0 +#if 1 // If you disable this, you MUST re-enable to update_mmu_cache() code in pgtable.h mov r17=_PAGE_SIZE_4K<<2 ;; diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c index 5b6deb5f5..cc26b8760 100644 --- a/arch/ia64/kernel/process.c +++ b/arch/ia64/kernel/process.c @@ -97,6 +97,14 @@ cpu_idle (void *unused) check_pgt_cache(); if (pm_idle) (*pm_idle)(); +#ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC + if (ia64_get_itm() < ia64_get_itc()) { + extern void ia64_reset_itm(); + + printk("cpu_idle: ITM in past, resetting it...\n"); + ia64_reset_itm(); + } +#endif } } diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c index 7c5ace740..cfcff3063 100644 --- a/arch/ia64/kernel/time.c +++ b/arch/ia64/kernel/time.c @@ -21,6 +21,10 @@ #include #include #include +#ifdef CONFIG_KDB +# include +#endif + extern rwlock_t xtime_lock; extern volatile unsigned long lost_ticks; @@ -61,7 +65,7 @@ do_profile (unsigned long ip) * update to jiffy. The xtime_lock must be at least read-locked when * calling this routine. */ -static inline unsigned long +static /*inline*/ unsigned long gettimeoffset (void) { unsigned long now = ia64_get_itc(); @@ -186,6 +190,20 @@ timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) write_unlock(&xtime_lock); } +#ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC + +void +ia64_reset_itm (void) +{ + unsigned long flags; + + local_irq_save(flags); + timer_interrupt(0, 0, current); + local_irq_restore(flags); +} + +#endif /* CONFIG_ITANIUM_ASTEP_SPECIFIC */ + /* * Encapsulate access to the itm structure for SMP. */ diff --git a/arch/ia64/kernel/traps.c b/arch/ia64/kernel/traps.c index c242622ec..1f5106036 100644 --- a/arch/ia64/kernel/traps.c +++ b/arch/ia64/kernel/traps.c @@ -110,15 +110,75 @@ void ia64_bad_break (unsigned long break_num, struct pt_regs *regs) { siginfo_t siginfo; + int sig, code; - /* gdb uses a break number of 0xccccc for debug breakpoints: */ - if (break_num != 0xccccc) - die_if_kernel("Bad break", regs, break_num); + /* SIGILL, SIGFPE, SIGSEGV, and SIGBUS want these field initialized: */ + siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri); + siginfo.si_imm = break_num; - siginfo.si_signo = SIGTRAP; - siginfo.si_errno = break_num; /* XXX is it legal to abuse si_errno like this? */ - siginfo.si_code = TRAP_BRKPT; - send_sig_info(SIGTRAP, &siginfo, current); + switch (break_num) { + case 0: /* unknown error */ + sig = SIGILL; code = ILL_ILLOPC; + break; + + case 1: /* integer divide by zero */ + sig = SIGFPE; code = FPE_INTDIV; + break; + + case 2: /* integer overflow */ + sig = SIGFPE; code = FPE_INTOVF; + break; + + case 3: /* range check/bounds check */ + sig = SIGFPE; code = FPE_FLTSUB; + break; + + case 4: /* null pointer dereference */ + sig = SIGSEGV; code = SEGV_MAPERR; + break; + + case 5: /* misaligned data */ + sig = SIGSEGV; code = BUS_ADRALN; + break; + + case 6: /* decimal overflow */ + sig = SIGFPE; code = __FPE_DECOVF; + break; + + case 7: /* decimal divide by zero */ + sig = SIGFPE; code = __FPE_DECDIV; + break; + + case 8: /* packed decimal error */ + sig = SIGFPE; code = __FPE_DECERR; + break; + + case 9: /* invalid ASCII digit */ + sig = SIGFPE; code = __FPE_INVASC; + break; + + case 10: /* invalid decimal digit */ + sig = SIGFPE; code = __FPE_INVDEC; + break; + + case 11: /* paragraph stack overflow */ + sig = SIGSEGV; code = __SEGV_PSTKOVF; + break; + + default: + if (break_num < 0x40000 || break_num > 0x100000) + die_if_kernel("Bad break", regs, break_num); + + if (break_num < 0x80000) { + sig = SIGILL; code = __ILL_BREAK; + } else { + sig = SIGTRAP; code = TRAP_BRKPT; + } + } + siginfo.si_signo = sig; + siginfo.si_errno = 0; + siginfo.si_code = code; + send_sig_info(sig, &siginfo, current); } /* @@ -240,6 +300,7 @@ handle_fpu_swa (int fp_fault, struct pt_regs *regs, unsigned long isr) { long exception, bundle[2]; unsigned long fault_ip; + struct siginfo siginfo; static int fpu_swa_count = 0; static unsigned long last_time; @@ -265,21 +326,41 @@ handle_fpu_swa (int fp_fault, struct pt_regs *regs, unsigned long isr) ia64_increment_ip(regs); } else if (exception == -1) { printk("handle_fpu_swa: fp_emulate() returned -1\n"); - return -2; + return -1; } else { /* is next instruction a trap? */ if (exception & 2) { ia64_increment_ip(regs); } - return -1; + siginfo.si_signo = SIGFPE; + siginfo.si_errno = 0; + siginfo.si_code = 0; + siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri); + if (isr & 0x11) { + siginfo.si_code = FPE_FLTINV; + } else if (isr & 0x44) { + siginfo.si_code = FPE_FLTDIV; + } + send_sig_info(SIGFPE, &siginfo, current); } } else { if (exception == -1) { printk("handle_fpu_swa: fp_emulate() returned -1\n"); - return -2; + return -1; } else if (exception != 0) { /* raise exception */ - return -1; + siginfo.si_signo = SIGFPE; + siginfo.si_errno = 0; + siginfo.si_code = 0; + siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri); + if (isr & 0x880) { + siginfo.si_code = FPE_FLTOVF; + } else if (isr & 0x1100) { + siginfo.si_code = FPE_FLTUND; + } else if (isr & 0x2200) { + siginfo.si_code = FPE_FLTRES; + } + send_sig_info(SIGFPE, &siginfo, current); } } return 0; @@ -369,22 +450,19 @@ ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa, return; case 30: /* Unaligned fault */ - sprintf(buf, "Unaligned access in kernel mode---don't do this!"); + sprintf(buf, "Kernel unaligned trap accessing %016lx (ip=%016lx)!", + ifa, regs->cr_iip + ia64_psr(regs)->ri); break; case 32: /* fp fault */ case 33: /* fp trap */ - result = handle_fpu_swa((vector == 32) ? 1 : 0, regs, isr); + result = handle_fpu_swa((vector == 32) ? 1 : 0, regs, &isr); if (result < 0) { siginfo.si_signo = SIGFPE; siginfo.si_errno = 0; - siginfo.si_code = 0; /* XXX fix me */ + siginfo.si_code = FPE_FLTINV; siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri); - send_sig_info(SIGFPE, &siginfo, current); - if (result == -1) - send_sig_info(SIGFPE, &siginfo, current); - else - force_sig(SIGFPE, current); + force_sig(SIGFPE, current); } return; diff --git a/arch/ia64/kernel/unaligned.c b/arch/ia64/kernel/unaligned.c index 0bd213f6b..014adcf35 100644 --- a/arch/ia64/kernel/unaligned.c +++ b/arch/ia64/kernel/unaligned.c @@ -1384,30 +1384,33 @@ ia64_handle_unaligned(unsigned long ifa, struct pt_regs *regs) load_store_t *insn; int ret = -1; - /* - * We flag unaligned references while in kernel as - * errors: the kernel must be fixed. The switch code - * is in ivt.S at entry 30. - * - * So here we keep a simple sanity check. - */ - if ( !user_mode(regs) ) { - die_if_kernel("Unaligned reference while in kernel\n", regs, 30); - /* NOT_REACHED */ + if (current->thread.flags & IA64_THREAD_UAC_SIGBUS) { + struct siginfo si; + + si.si_signo = SIGBUS; + si.si_errno = 0; + si.si_code = BUS_ADRALN; + si.si_addr = (void *) ifa; + send_sig_info (SIGBUS, &si, current); + return; } - /* - * Make sure we log the unaligned access, so that user/sysadmin can notice it - * and eventually fix the program. - * - * We don't want to do that for every access so we pace it with jiffies. - */ - if ( unalign_count > 5 && jiffies - last_time > 5*HZ ) unalign_count = 0; - if ( ++unalign_count < 5 ) { - last_time = jiffies; - printk("%s(%d): unaligned trap accessing %016lx (ip=%016lx)\n", - current->comm, current->pid, ifa, regs->cr_iip + ipsr->ri); - + if (!(current->thread.flags & IA64_THREAD_UAC_NOPRINT)) { + /* + * Make sure we log the unaligned access, so that + * user/sysadmin can notice it and eventually fix the + * program. + * + * We don't want to do that for every access so we + * pace it with jiffies. + */ + if (unalign_count > 5 && jiffies - last_time > 5*HZ) + unalign_count = 0; + if (++unalign_count < 5) { + last_time = jiffies; + printk("%s(%d): unaligned trap accessing %016lx (ip=%016lx)\n", + current->comm, current->pid, ifa, regs->cr_iip + ipsr->ri); + } } DPRINT(("iip=%lx ifa=%lx isr=%lx\n", regs->cr_iip, ifa, regs->cr_ipsr)); diff --git a/arch/ia64/lib/copy_user.S b/arch/ia64/lib/copy_user.S index 03a540a80..58c92876f 100644 --- a/arch/ia64/lib/copy_user.S +++ b/arch/ia64/lib/copy_user.S @@ -1,71 +1,375 @@ -/* - * This routine copies a linear memory buffer across the user/kernel boundary. When - * reading a byte from the source causes a fault, the remainder of the destination - * buffer is zeroed out. Note that this can happen only when copying from user - * to kernel memory and we do this to absolutely guarantee that the - * kernel doesn't operate on random data. - * - * This file is derived from arch/alpha/lib/copy_user.S. - * - * Inputs: - * in0: address of destination buffer - * in1: address of source buffer - * in2: length of buffer in bytes - * Outputs: - * r8: number of bytes that didn't get copied due to a fault - * - * Copyright (C) 1999 Hewlett-Packard Co - * Copyright (C) 1998, 1999 David Mosberger-Tang - */ - -#define EXI(x...) \ -99: x; \ +// The label comes first because our store instruction contains a comma +// and confuse the preprocessor otherwise +// +#undef DEBUG +#ifdef DEBUG +#define EX(y,x...) \ +99: x +#else +#define EX(y,x...) \ .section __ex_table,"a"; \ - data4 @gprel(99b); \ - data4 .Lexit_in-99b; \ - .previous + data4 @gprel(99f); \ + data4 y-99f; \ + .previous; \ +99: x +#endif -#define EXO(x...) \ -99: x; \ - .section __ex_table,"a"; \ - data4 @gprel(99b); \ - data4 .Lexit_out-99b; \ - .previous - - .text - .psr abi64 - .psr lsb - .lsb - - .align 32 - .global __copy_user - .proc __copy_user +// +// Tuneable parameters +// +#define COPY_BREAK 16 // we do byte copy below (must be >=16) +#define PIPE_DEPTH 4 // pipe depth + +#define EPI p[PIPE_DEPTH-1] // PASTE(p,16+PIPE_DEPTH-1) + +// +// arguments +// +#define dst in0 +#define src in1 +#define len in2 + +// +// local registers +// +#define cnt r18 +#define len2 r19 +#define saved_lc r20 +#define saved_pr r21 +#define tmp r22 +#define val r23 +#define src1 r24 +#define dst1 r25 +#define src2 r26 +#define dst2 r27 +#define len1 r28 +#define enddst r29 +#define endsrc r30 +#define saved_pfs r31 + .text + .psr abi64 + .psr lsb + + .align 16 + .global __copy_user + .proc __copy_user __copy_user: - alloc r10=ar.pfs,3,0,0,0 - mov r9=ar.lc // save ar.lc - mov ar.lc=in2 // set ar.lc to length of buffer - br.sptk.few .Lentr - - // XXX braindead copy loop---this needs to be optimized -.Loop1: - EXI(ld1 r8=[in1],1) - ;; - EXO(st1 [in0]=r8,1) -.Lentr: br.cloop.dptk.few .Loop1 // repeat unless ar.lc--==0 - ;; // avoid RAW on ar.lc -.Lexit_out: - mov r8=ar.lc // return how many bytes we _didn't_ copy - mov ar.lc=r9 - br.ret.sptk.few rp - -.Lexit_in: - // clear the remainder of the buffer: - mov r8=ar.lc // return how many bytes we _didn't_ copy -.Loop2: - st1 [in0]=r0,1 // this cannot fault because we get here only on user->kernel copies - br.cloop.dptk.few .Loop2 - ;; // avoid RAW on ar.lc - mov ar.lc=r9 - br.ret.sptk.few rp - - .endp __copy_user + alloc saved_pfs=ar.pfs,3,((2*PIPE_DEPTH+7)&~7),0,((2*PIPE_DEPTH+7)&~7) + + .rotr val1[PIPE_DEPTH],val2[PIPE_DEPTH] + .rotp p[PIPE_DEPTH] + + adds len2=-1,len // br.ctop is repeat/until + mov ret0=r0 + + ;; // RAW of cfm when len=0 + cmp.eq p8,p0=r0,len // check for zero length + mov saved_lc=ar.lc // preserve ar.lc (slow) +(p8) br.ret.spnt.few rp // empty mempcy() + ;; + add enddst=dst,len // first byte after end of source + add endsrc=src,len // first byte after end of destination + mov saved_pr=pr // preserve predicates + + mov dst1=dst // copy because of rotation + mov ar.ec=PIPE_DEPTH + mov pr.rot=1<<16 // p16=true all others are false + + mov src1=src // copy because of rotation + mov ar.lc=len2 // initialize lc for small count + cmp.lt p10,p7=COPY_BREAK,len // if len > COPY_BREAK then long copy + + xor tmp=src,dst // same alignment test prepare +(p10) br.cond.dptk.few long_memcpy + ;; // RAW pr.rot/p16 ? + // + // Now we do the byte by byte loop with software pipeline + // + // p7 is necessarily false by now +1: + EX(failure_in_pipe1,(p16) ld1 val1[0]=[src1],1) + + EX(failure_out,(EPI) st1 [dst1]=val1[PIPE_DEPTH-1],1) + br.ctop.dptk.few 1b + ;; + mov ar.lc=saved_lc + mov pr=saved_pr,0xffffffffffff0000 + mov ar.pfs=saved_pfs // restore ar.ec + br.ret.sptk.few rp // end of short memcpy + + // + // Beginning of long mempcy (i.e. > 16 bytes) + // +long_memcpy: + tbit.nz p6,p7=src1,0 // odd alignement + and tmp=7,tmp + ;; + cmp.eq p10,p8=r0,tmp + mov len1=len // copy because of rotation +(p8) br.cond.dpnt.few 1b // XXX Fixme. memcpy_diff_align + ;; + // At this point we know we have more than 16 bytes to copy + // and also that both src and dest have the same alignment + // which may not be the one we want. So for now we must move + // forward slowly until we reach 16byte alignment: no need to + // worry about reaching the end of buffer. + // + EX(failure_in1,(p6) ld1 val1[0]=[src1],1) // 1-byte aligned +(p6) adds len1=-1,len1;; + tbit.nz p7,p0=src1,1 + ;; + EX(failure_in1,(p7) ld2 val1[1]=[src1],2) // 2-byte aligned +(p7) adds len1=-2,len1;; + tbit.nz p8,p0=src1,2 + ;; + // + // Stop bit not required after ld4 because if we fail on ld4 + // we have never executed the ld1, therefore st1 is not executed. + // + EX(failure_in1,(p8) ld4 val2[0]=[src1],4) // 4-byte aligned + EX(failure_out,(p6) st1 [dst1]=val1[0],1) + tbit.nz p9,p0=src1,3 + ;; + // + // Stop bit not required after ld8 because if we fail on ld8 + // we have never executed the ld2, therefore st2 is not executed. + // + EX(failure_in1,(p9) ld8 val2[1]=[src1],8) // 8-byte aligned + EX(failure_out,(p7) st2 [dst1]=val1[1],2) +(p8) adds len1=-4,len1 + ;; + EX(failure_out, (p8) st4 [dst1]=val2[0],4) +(p9) adds len1=-8,len1;; + shr.u cnt=len1,4 // number of 128-bit (2x64bit) words + ;; + EX(failure_out, (p9) st8 [dst1]=val2[1],8) + tbit.nz p6,p0=len1,3 + cmp.eq p7,p0=r0,cnt + adds tmp=-1,cnt // br.ctop is repeat/until +(p7) br.cond.dpnt.few .dotail // we have less than 16 bytes left + ;; + adds src2=8,src1 + adds dst2=8,dst1 + mov ar.lc=tmp + ;; + // + // 16bytes/iteration + // +2: + EX(failure_in3,(p16) ld8 val1[0]=[src1],16) +(p16) ld8 val2[0]=[src2],16 + + EX(failure_out, (EPI) st8 [dst1]=val1[PIPE_DEPTH-1],16) +(EPI) st8 [dst2]=val2[PIPE_DEPTH-1],16 + br.ctop.dptk.few 2b + ;; // RAW on src1 when fall through from loop + // + // Tail correction based on len only + // + // No matter where we come from (loop or test) the src1 pointer + // is 16 byte aligned AND we have less than 16 bytes to copy. + // +.dotail: + EX(failure_in1,(p6) ld8 val1[0]=[src1],8) // at least 8 bytes + tbit.nz p7,p0=len1,2 + ;; + EX(failure_in1,(p7) ld4 val1[1]=[src1],4) // at least 4 bytes + tbit.nz p8,p0=len1,1 + ;; + EX(failure_in1,(p8) ld2 val2[0]=[src1],2) // at least 2 bytes + tbit.nz p9,p0=len1,0 + ;; + EX(failure_out, (p6) st8 [dst1]=val1[0],8) + ;; + EX(failure_in1,(p9) ld1 val2[1]=[src1]) // only 1 byte left + mov ar.lc=saved_lc + ;; + EX(failure_out,(p7) st4 [dst1]=val1[1],4) + mov pr=saved_pr,0xffffffffffff0000 + ;; + EX(failure_out, (p8) st2 [dst1]=val2[0],2) + mov ar.pfs=saved_pfs + ;; + EX(failure_out, (p9) st1 [dst1]=val2[1]) + br.ret.dptk.few rp + + + + // + // Here we handle the case where the byte by byte copy fails + // on the load. + // Several factors make the zeroing of the rest of the buffer kind of + // tricky: + // - the pipeline: loads/stores are not in sync (pipeline) + // + // In the same loop iteration, the dst1 pointer does not directly + // reflect where the faulty load was. + // + // - pipeline effect + // When you get a fault on load, you may have valid data from + // previous loads not yet store in transit. Such data must be + // store normally before moving onto zeroing the rest. + // + // - single/multi dispersal independence. + // + // solution: + // - we don't disrupt the pipeline, i.e. data in transit in + // the software pipeline will be eventually move to memory. + // We simply replace the load with a simple mov and keep the + // pipeline going. We can't really do this inline because + // p16 is always reset to 1 when lc > 0. + // +failure_in_pipe1: + sub ret0=endsrc,src1 // number of bytes to zero, i.e. not copied +1: +(p16) mov val1[0]=r0 +(EPI) st1 [dst1]=val1[PIPE_DEPTH-1],1 + br.ctop.dptk.few 1b + ;; + mov pr=saved_pr,0xffffffffffff0000 + mov ar.lc=saved_lc + mov ar.pfs=saved_pfs + br.ret.dptk.few rp + + + // + // Here we handle the head & tail part when we check for alignment. + // The following code handles only the load failures. The + // main diffculty comes from the fact that loads/stores are + // scheduled. So when you fail on a load, the stores corresponding + // to previous successful loads must be executed. + // + // However some simplifications are possible given the way + // things work. + // + // 1) HEAD + // Theory of operation: + // + // Page A | Page B + // ---------|----- + // 1|8 x + // 1 2|8 x + // 4|8 x + // 1 4|8 x + // 2 4|8 x + // 1 2 4|8 x + // |1 + // |2 x + // |4 x + // + // page_size >= 4k (2^12). (x means 4, 2, 1) + // Here we suppose Page A exists and Page B does not. + // + // As we move towards eight byte alignment we may encounter faults. + // The numbers on each page show the size of the load (current alignment). + // + // Key point: + // - if you fail on 1, 2, 4 then you have never executed any smaller + // size loads, e.g. failing ld4 means no ld1 nor ld2 executed + // before. + // + // This allows us to simplify the cleanup code, because basically you + // only have to worry about "pending" stores in the case of a failing + // ld8(). Given the way the code is written today, this means only + // worry about st2, st4. There we can use the information encapsulated + // into the predicates. + // + // Other key point: + // - if you fail on the ld8 in the head, it means you went straight + // to it, i.e. 8byte alignment within an unexisting page. + // Again this comes from the fact that if you crossed just for the the ld8 then + // you are 8byte aligned but also 16byte align, therefore you would + // either go for the 16byte copy loop OR the ld8 in the tail part. + // The combination ld1, ld2, ld4, ld8 where you fail on ld8 is impossible + // because it would mean you had 15bytes to copy in which case you + // would have defaulted to the byte by byte copy. + // + // + // 2) TAIL + // Here we now we have less than 16 bytes AND we are either 8 or 16 byte + // aligned. + // + // Key point: + // This means that we either: + // - are right on a page boundary + // OR + // - are at more than 16 bytes from a page boundary with + // at most 15 bytes to copy: no chance of crossing. + // + // This allows us to assume that if we fail on a load we haven't possibly + // executed any of the previous (tail) ones, so we don't need to do + // any stores. For instance, if we fail on ld2, this means we had + // 2 or 3 bytes left to copy and we did not execute the ld8 nor ld4. + // + // This means that we are in a situation similar the a fault in the + // head part. That's nice! + // +failure_in1: +// sub ret0=enddst,dst1 // number of bytes to zero, i.e. not copied +// sub len=enddst,dst1,1 + sub ret0=endsrc,src1 // number of bytes to zero, i.e. not copied + sub len=endsrc,src1,1 + // + // we know that ret0 can never be zero at this point + // because we failed why trying to do a load, i.e. there is still + // some work to do. + // The failure_in1bis and length problem is taken care of at the + // calling side. + // + ;; +failure_in1bis: // from (failure_in3) + mov ar.lc=len // Continue with a stupid byte store. + ;; +5: + st1 [dst1]=r0,1 + br.cloop.dptk.few 5b + ;; +skip_loop: + mov pr=saved_pr,0xffffffffffff0000 + mov ar.lc=saved_lc + mov ar.pfs=saved_pfs + br.ret.dptk.few rp + + // + // Here we simply restart the loop but instead + // of doing loads we fill the pipeline with zeroes + // We can't simply store r0 because we may have valid + // data in transit in the pipeline. + // ar.lc and ar.ec are setup correctly at this point + // + // we MUST use src1/endsrc here and not dst1/enddst because + // of the pipeline effect. + // +failure_in3: + sub ret0=endsrc,src1 // number of bytes to zero, i.e. not copied + ;; +2: +(p16) mov val1[0]=r0 +(p16) mov val2[0]=r0 +(EPI) st8 [dst1]=val1[PIPE_DEPTH-1],16 +(EPI) st8 [dst2]=val2[PIPE_DEPTH-1],16 + br.ctop.dptk.few 2b + ;; + cmp.ne p6,p0=dst1,enddst // Do we need to finish the tail ? + sub len=enddst,dst1,1 // precompute len +(p6) br.cond.dptk.few failure_in1bis + ;; + mov pr=saved_pr,0xffffffffffff0000 + mov ar.lc=saved_lc + mov ar.pfs=saved_pfs + br.ret.dptk.few rp + + // + // handling of failures on stores: that's the easy part + // +failure_out: + sub ret0=enddst,dst1 + mov pr=saved_pr,0xffffffffffff0000 + mov ar.lc=saved_lc + + mov ar.pfs=saved_pfs + br.ret.dptk.few rp + + + .endp __copy_user + diff --git a/arch/mips/defconfig b/arch/mips/defconfig index 5516700c1..bec96e794 100644 --- a/arch/mips/defconfig +++ b/arch/mips/defconfig @@ -176,6 +176,8 @@ CONFIG_SCSI_CONSTANTS=y # SCSI low-level drivers # CONFIG_SCSI_SGIWD93=y +CONFIG_SCSI_SGIWD93=y +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set # CONFIG_SCSI_7000FASST is not set # CONFIG_SCSI_ACARD is not set # CONFIG_SCSI_AHA152X is not set @@ -210,7 +212,6 @@ CONFIG_SCSI_SGIWD93=y # CONFIG_SCSI_U14_34F is not set # CONFIG_SCSI_ULTRASTOR is not set # CONFIG_SCSI_DEBUG is not set -# CONFIG_BLK_DEV_3W_XXXX_RAID is not set # # I2O device support @@ -269,6 +270,7 @@ CONFIG_PSMOUSE=y # CONFIG_WATCHDOG is not set # CONFIG_NVRAM is not set # CONFIG_RTC is not set +# CONFIG_EFI_RTC is not set # # Video For Linux diff --git a/arch/mips/kernel/irixelf.c b/arch/mips/kernel/irixelf.c index b0225f750..41ea11b98 100644 --- a/arch/mips/kernel/irixelf.c +++ b/arch/mips/kernel/irixelf.c @@ -1,4 +1,4 @@ -/* $Id: irixelf.c,v 1.23 2000/01/29 01:41:59 ralf Exp $ +/* $Id: irixelf.c,v 1.24 2000/02/04 07:40:23 ralf Exp $ * * irixelf.c: Code to load IRIX ELF executables which conform to * the MIPS ABI. @@ -257,11 +257,11 @@ static unsigned int load_irix_interp(struct elfhdr * interp_elf_ex, #endif /* 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_dentry->d_inode->i_op || - !interpreter_dentry->d_inode->i_op->default_file_ops->mmap)) { + if ((interp_elf_ex->e_type != ET_EXEC && + interp_elf_ex->e_type != ET_DYN) || + !elf_check_arch(interp_elf_ex->e_machine) || + (!interpreter_dentry->d_inode->i_fop || + !interpreter_dentry->d_inode->i_fop->mmap)) { printk("IRIX interp has bad e_type %d\n", interp_elf_ex->e_type); return 0xffffffff; } @@ -410,9 +410,8 @@ static int verify_binary(struct elfhdr *ehp, struct linux_binprm *bprm) /* First of all, some simple consistency checks */ if((ehp->e_type != ET_EXEC && ehp->e_type != ET_DYN) || !elf_check_arch(ehp->e_machine) || - (!bprm->dentry->d_inode->i_op || - !bprm->dentry->d_inode->i_op->default_file_ops || - !bprm->dentry->d_inode->i_op->default_file_ops->mmap)) { + (!bprm->dentry->d_inode->i_fop || + !bprm->dentry->d_inode->i_fop->mmap)) { return -ENOEXEC; } @@ -877,8 +876,8 @@ static inline int do_load_irix_library(struct file *file) /* 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) || - (!dentry->d_inode->i_op || - !dentry->d_inode->i_op->default_file_ops->mmap)) + (!dentry->d_inode->i_fop || + !dentry->d_inode->i_fop->mmap)) return -ENOEXEC; /* Now read in all of the header information. */ diff --git a/arch/mips/kernel/irq.c b/arch/mips/kernel/irq.c index 4e3ba5ad9..239576e4e 100644 --- a/arch/mips/kernel/irq.c +++ b/arch/mips/kernel/irq.c @@ -1,4 +1,4 @@ -/* $Id: irq.c,v 1.19 2000/02/04 07:40:23 ralf Exp $ +/* $Id: irq.c,v 1.20 2000/02/23 00:41:00 ralf Exp $ * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive @@ -31,6 +31,24 @@ #include #include +/* + * Linux has a controller-independent x86 interrupt architecture. + * every controller has a 'controller-template', that is used + * by the main code to do the right thing. Each driver-visible + * interrupt source is transparently wired to the apropriate + * controller. Thus drivers need not be aware of the + * interrupt-controller. + * + * Various interrupt controllers we handle: 8259 PIC, SMP IO-APIC, + * PIIX4's internal 8259 PIC and SGI's Visual Workstation Cobalt (IO-)APIC. + * (IO-APICs assumed to be messaging to Pentium local-APICs) + * + * the code is designed to be easily extended with new/different + * interrupt controllers, without having to do assembly magic. + */ + +irq_cpustat_t irq_stat [NR_CPUS]; + /* * This contains the irq mask for both 8259A irq controllers, it's an * int so we can deal with the third PIC in some systems like the RM300. diff --git a/arch/mips/kernel/mips_ksyms.c b/arch/mips/kernel/mips_ksyms.c index f1c65805f..b8e1e6ec2 100644 --- a/arch/mips/kernel/mips_ksyms.c +++ b/arch/mips/kernel/mips_ksyms.c @@ -1,4 +1,4 @@ -/* $Id: mips_ksyms.c,v 1.24 2000/02/04 07:40:23 ralf Exp $ +/* $Id: mips_ksyms.c,v 1.25 2000/02/24 00:12:40 ralf Exp $ * * Export MIPS-specific functions needed for loadable modules. * @@ -56,8 +56,6 @@ EXPORT_SYMBOL_NOVERS(strtok); EXPORT_SYMBOL_NOVERS(strpbrk); EXPORT_SYMBOL(_clear_page); -EXPORT_SYMBOL(local_bh_count); -EXPORT_SYMBOL(local_irq_count); EXPORT_SYMBOL(enable_irq); EXPORT_SYMBOL(disable_irq); EXPORT_SYMBOL(kernel_thread); diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c index c2ee57b86..9bffcdc96 100644 --- a/arch/mips/kernel/proc.c +++ b/arch/mips/kernel/proc.c @@ -83,3 +83,8 @@ int get_cpuinfo(char *buffer) return len; } + +void init_irq_proc(void) +{ + /* Nothing, for now. */ +} diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index 43cf5ad74..f6209461f 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.21 2000/01/26 00:07:44 ralf Exp $ +/* $Id: setup.c,v 1.22 2000/01/27 01:05:23 ralf Exp $ * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive @@ -220,4 +220,6 @@ void __init setup_arch(char **cmdline_p) *memory_start_p = initrd_end; } #endif + + paging_init(); } diff --git a/arch/mips/sgi/kernel/indy_int.c b/arch/mips/sgi/kernel/indy_int.c index 916b0873a..cab112c29 100644 --- a/arch/mips/sgi/kernel/indy_int.c +++ b/arch/mips/sgi/kernel/indy_int.c @@ -1,4 +1,4 @@ -/* $Id: indy_int.c,v 1.16 1999/12/04 03:59:00 ralf Exp $ +/* $Id: indy_int.c,v 1.17 2000/02/04 07:40:23 ralf Exp $ * * indy_int.c: Routines for generic manipulation of the INT[23] ASIC * found on INDY workstations.. @@ -40,6 +40,24 @@ #include #include +/* + * Linux has a controller-independent x86 interrupt architecture. + * every controller has a 'controller-template', that is used + * by the main code to do the right thing. Each driver-visible + * interrupt source is transparently wired to the apropriate + * controller. Thus drivers need not be aware of the + * interrupt-controller. + * + * Various interrupt controllers we handle: 8259 PIC, SMP IO-APIC, + * PIIX4's internal 8259 PIC and SGI's Visual Workstation Cobalt (IO-)APIC. + * (IO-APICs assumed to be messaging to Pentium local-APICs) + * + * the code is designed to be easily extended with new/different + * interrupt controllers, without having to do assembly magic. + */ + +irq_cpustat_t irq_stat [NR_CPUS]; + /* #define DEBUG_SGINT */ struct sgi_int2_regs *sgi_i2regs; diff --git a/arch/mips64/defconfig b/arch/mips64/defconfig index 039ffd84f..c4f4ba27a 100644 --- a/arch/mips64/defconfig +++ b/arch/mips64/defconfig @@ -305,6 +305,7 @@ CONFIG_SERIAL_CONSOLE=y # CONFIG_WATCHDOG is not set # CONFIG_NVRAM is not set # CONFIG_RTC is not set +# CONFIG_EFI_RTC is not set # # Video For Linux diff --git a/arch/mips64/defconfig-ip22 b/arch/mips64/defconfig-ip22 index 9c6687735..b40469cfc 100644 --- a/arch/mips64/defconfig-ip22 +++ b/arch/mips64/defconfig-ip22 @@ -224,6 +224,7 @@ CONFIG_VT_CONSOLE=y # CONFIG_WATCHDOG is not set # CONFIG_NVRAM is not set # CONFIG_RTC is not set +# CONFIG_EFI_RTC is not set # # Video For Linux diff --git a/arch/mips64/defconfig-ip27 b/arch/mips64/defconfig-ip27 index 039ffd84f..c4f4ba27a 100644 --- a/arch/mips64/defconfig-ip27 +++ b/arch/mips64/defconfig-ip27 @@ -305,6 +305,7 @@ CONFIG_SERIAL_CONSOLE=y # CONFIG_WATCHDOG is not set # CONFIG_NVRAM is not set # CONFIG_RTC is not set +# CONFIG_EFI_RTC is not set # # Video For Linux diff --git a/arch/mips64/kernel/proc.c b/arch/mips64/kernel/proc.c index 6fba1b756..063ac5d88 100644 --- a/arch/mips64/kernel/proc.c +++ b/arch/mips64/kernel/proc.c @@ -1,4 +1,4 @@ -/* $Id: proc.c,v 1.1 1999/09/27 16:01:37 ralf Exp $ +/* $Id: proc.c,v 1.1 1999/09/28 22:25:51 ralf Exp $ * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive @@ -69,3 +69,8 @@ int get_cpuinfo(char *buffer) return len; } + +void init_irq_proc(void) +{ + /* Nothing, for now. */ +} diff --git a/arch/mips64/kernel/setup.c b/arch/mips64/kernel/setup.c index b42271b47..2a7d8a894 100644 --- a/arch/mips64/kernel/setup.c +++ b/arch/mips64/kernel/setup.c @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.6 2000/01/27 01:05:24 ralf Exp $ +/* $Id: setup.c,v 1.7 2000/02/04 07:40:24 ralf Exp $ * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive @@ -183,4 +183,6 @@ void __init setup_arch(char **cmdline_p) *memory_start_p = initrd_end; } #endif + + paging_init(); } diff --git a/arch/mips64/sgi-ip22/ip22-int.c b/arch/mips64/sgi-ip22/ip22-int.c index 420e47fc7..a26ad631d 100644 --- a/arch/mips64/sgi-ip22/ip22-int.c +++ b/arch/mips64/sgi-ip22/ip22-int.c @@ -1,4 +1,4 @@ -/* $Id: ip22-int.c,v 1.3 1999/12/04 03:59:01 ralf Exp $ +/* $Id: ip22-int.c,v 1.4 2000/02/04 07:40:24 ralf Exp $ * * indy_int.c: Routines for generic manipulation of the INT[23] ASIC * found on INDY workstations.. @@ -37,6 +37,24 @@ #include #include +/* + * Linux has a controller-independent x86 interrupt architecture. + * every controller has a 'controller-template', that is used + * by the main code to do the right thing. Each driver-visible + * interrupt source is transparently wired to the apropriate + * controller. Thus drivers need not be aware of the + * interrupt-controller. + * + * Various interrupt controllers we handle: 8259 PIC, SMP IO-APIC, + * PIIX4's internal 8259 PIC and SGI's Visual Workstation Cobalt (IO-)APIC. + * (IO-APICs assumed to be messaging to Pentium local-APICs) + * + * the code is designed to be easily extended with new/different + * interrupt controllers, without having to do assembly magic. + */ + +irq_cpustat_t irq_stat [NR_CPUS]; + struct sgi_int2_regs *sgi_i2regs; struct sgi_int3_regs *sgi_i3regs; struct sgi_ioc_ints *ioc_icontrol; diff --git a/arch/mips64/sgi-ip27/ip27-irq.c b/arch/mips64/sgi-ip27/ip27-irq.c index 7f5a36f97..c9e6fe150 100644 --- a/arch/mips64/sgi-ip27/ip27-irq.c +++ b/arch/mips64/sgi-ip27/ip27-irq.c @@ -1,4 +1,4 @@ -/* $Id: ip27-irq.c,v 1.5 2000/02/04 07:40:24 ralf Exp $ +/* $Id: ip27-irq.c,v 1.6 2000/02/10 05:58:56 dagum Exp $ * * ip27-irq.c: Highlevel interrupt handling for IP27 architecture. * @@ -35,6 +35,24 @@ #include #include +/* + * Linux has a controller-independent x86 interrupt architecture. + * every controller has a 'controller-template', that is used + * by the main code to do the right thing. Each driver-visible + * interrupt source is transparently wired to the apropriate + * controller. Thus drivers need not be aware of the + * interrupt-controller. + * + * Various interrupt controllers we handle: 8259 PIC, SMP IO-APIC, + * PIIX4's internal 8259 PIC and SGI's Visual Workstation Cobalt (IO-)APIC. + * (IO-APICs assumed to be messaging to Pentium local-APICs) + * + * the code is designed to be easily extended with new/different + * interrupt controllers, without having to do assembly magic. + */ + +irq_cpustat_t irq_stat [NR_CPUS]; + extern asmlinkage void ip27_irq(void); int (*irq_cannonicalize)(int irq); @@ -255,7 +273,7 @@ void irq_debug(void) printk("PI_INT_MASK0_A = 0x%x\n", LOCAL_HUB_L(PI_INT_MASK0_A)); } -int setup_irq(int irq, struct irqaction *new) +int setup_irq(unsigned int irq, struct irqaction *new) { int shared = 0; struct irqaction *old, **p; diff --git a/arch/ppc/chrpboot/main.c b/arch/ppc/chrpboot/main.c index d54a429a9..91bf4d8c4 100644 --- a/arch/ppc/chrpboot/main.c +++ b/arch/ppc/chrpboot/main.c @@ -10,7 +10,6 @@ #include "../coffboot/zlib.h" #include #include -#define __KERNEL__ #include extern void *finddevice(const char *); @@ -49,17 +48,8 @@ chrpboot(int a1, int a2, void *prom) printf("chrpboot starting: loaded at 0x%x\n\r", &_start); - if (initrd_len) { - initrd_size = initrd_len; - initrd_start = (RAM_END - initrd_size) & ~0xFFF; - a1 = initrd_start; - a2 = initrd_size; - printf("initial ramdisk moving 0x%x <- 0x%x (%x bytes)\n\r", initrd_start, - initrd_data,initrd_size); - memcpy((char *)initrd_start, initrd_data, initrd_size); - end_avail = (char *)initrd_start; - } else - end_avail = (char *) RAM_END; + end_avail = (char *) RAM_END; + im = image_data; len = image_len; dst = (void *) PROG_START; @@ -98,7 +88,7 @@ chrpboot(int a1, int a2, void *prom) rec = (struct bi_record *)((unsigned long)rec + rec->size); rec->tag = BI_SYSMAP; - rec->data[0] = sysmap_data; + rec->data[0] = (unsigned long)sysmap_data; rec->data[1] = sysmap_len; rec->size = sizeof(struct bi_record) + sizeof(unsigned long); rec = (struct bi_record *)((unsigned long)rec + rec->size); @@ -129,6 +119,10 @@ void *zalloc(void *x, unsigned items, unsigned size) void zfree(void *x, void *addr, unsigned nb) { + nb = (nb + 7) & -8; + if (addr == (avail_ram - nb)) { + avail_ram -= nb; + } } #define HEAD_CRC 2 diff --git a/arch/ppc/chrpboot/piggyback.c b/arch/ppc/chrpboot/piggyback.c index 172025802..304bc8f11 100644 --- a/arch/ppc/chrpboot/piggyback.c +++ b/arch/ppc/chrpboot/piggyback.c @@ -1,8 +1,9 @@ #include +#include extern long ce_exec_config[]; -main(int argc, char *argv[]) +int main(int argc, char *argv[]) { int i, cnt, pos, len; unsigned int cksum, val; diff --git a/arch/ppc/coffboot/piggyback.c b/arch/ppc/coffboot/piggyback.c index 172025802..304bc8f11 100644 --- a/arch/ppc/coffboot/piggyback.c +++ b/arch/ppc/coffboot/piggyback.c @@ -1,8 +1,9 @@ #include +#include extern long ce_exec_config[]; -main(int argc, char *argv[]) +int main(int argc, char *argv[]) { int i, cnt, pos, len; unsigned int cksum, val; diff --git a/arch/ppc/config.in b/arch/ppc/config.in index 8bb23afa2..7d0ab5fa0 100644 --- a/arch/ppc/config.in +++ b/arch/ppc/config.in @@ -47,12 +47,9 @@ if [ "$CONFIG_8xx" = "y" ]; then fi if [ "$CONFIG_6xx" = "y" ]; then choice 'Machine Type' \ - "PowerMac CONFIG_PMAC \ - PReP/MTX CONFIG_PREP \ - CHRP CONFIG_CHRP \ - PowerMac/PReP/CHRP CONFIG_ALL_PPC \ + "PowerMac/PReP/MTX/CHRP CONFIG_ALL_PPC \ Gemini CONFIG_GEMINI \ - APUS CONFIG_APUS" PowerMac + APUS CONFIG_APUS" PowerMac/PReP/MTX/CHRP fi if [ "$CONFIG_PPC64" = "y" ]; then diff --git a/arch/ppc/configs/common_defconfig b/arch/ppc/configs/common_defconfig index 17217702f..4ba96bde9 100644 --- a/arch/ppc/configs/common_defconfig +++ b/arch/ppc/configs/common_defconfig @@ -17,9 +17,6 @@ CONFIG_6xx=y # CONFIG_PPC64 is not set # CONFIG_82xx is not set # CONFIG_8xx is not set -# CONFIG_PMAC is not set -# CONFIG_PREP is not set -# CONFIG_CHRP is not set CONFIG_ALL_PPC=y # CONFIG_GEMINI is not set # CONFIG_APUS is not set @@ -286,30 +283,29 @@ CONFIG_GMAC=y # CONFIG_LANCE is not set # CONFIG_NET_VENDOR_SMC is not set # CONFIG_NET_VENDOR_RACAL is not set -# CONFIG_RTL8139 is not set -# CONFIG_DM9102 is not set # CONFIG_AT1700 is not set # CONFIG_DEPCA is not set # CONFIG_NET_ISA is not set -CONFIG_NET_EISA=y +CONFIG_NET_PCI=y CONFIG_PCNET32=y # CONFIG_ADAPTEC_STARFIRE is not set # CONFIG_AC3200 is not set # CONFIG_APRICOT is not set -# CONFIG_CS89x0 is not set CONFIG_DE4X5=y -# CONFIG_DEC_ELCP is not set +# CONFIG_TULIP is not set # CONFIG_DGRS is not set -# CONFIG_EEXPRESS_PRO100 is not set +# CONFIG_DM9102 is not set +# CONFIG_EEPRO100 is not set # CONFIG_LNE390 is not set # CONFIG_NE3210 is not set # CONFIG_NE2K_PCI is not set +# CONFIG_RTL8129 is not set +# CONFIG_8139TOO is not set # CONFIG_SIS900 is not set # CONFIG_TLAN is not set # CONFIG_VIA_RHINE is not set # CONFIG_ES3210 is not set # CONFIG_EPIC100 is not set -# CONFIG_ZNET is not set # CONFIG_NET_POCKET is not set # @@ -499,6 +495,7 @@ CONFIG_USB_OHCI=y # CONFIG_USB_DC2XX is not set # CONFIG_USB_STORAGE is not set # CONFIG_USB_DABUSB is not set +# CONFIG_USB_PLUSB is not set # # USB HID @@ -508,13 +505,15 @@ CONFIG_USB_KBD=y CONFIG_USB_MOUSE=y # CONFIG_USB_GRAPHIRE is not set # CONFIG_USB_WMFORCE is not set -# CONFIG_INPUT_KEYBDEV is not set -# CONFIG_INPUT_MOUSEDEV is not set +CONFIG_INPUT_KEYBDEV=y +CONFIG_INPUT_MOUSEDEV=y +# CONFIG_INPUT_MOUSEDEV_MIX is not set +# CONFIG_INPUT_MOUSEDEV_DIGITIZER is not set # CONFIG_INPUT_JOYDEV is not set # CONFIG_INPUT_EVDEV is not set # -# Filesystems +# File systems # # CONFIG_QUOTA is not set CONFIG_AUTOFS_FS=y @@ -535,6 +534,7 @@ CONFIG_ISO9660_FS=y # CONFIG_NTFS_FS is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set CONFIG_DEVPTS_FS=y # CONFIG_QNX4FS_FS is not set # CONFIG_ROMFS_FS is not set diff --git a/arch/ppc/defconfig b/arch/ppc/defconfig index 17217702f..4ba96bde9 100644 --- a/arch/ppc/defconfig +++ b/arch/ppc/defconfig @@ -17,9 +17,6 @@ CONFIG_6xx=y # CONFIG_PPC64 is not set # CONFIG_82xx is not set # CONFIG_8xx is not set -# CONFIG_PMAC is not set -# CONFIG_PREP is not set -# CONFIG_CHRP is not set CONFIG_ALL_PPC=y # CONFIG_GEMINI is not set # CONFIG_APUS is not set @@ -286,30 +283,29 @@ CONFIG_GMAC=y # CONFIG_LANCE is not set # CONFIG_NET_VENDOR_SMC is not set # CONFIG_NET_VENDOR_RACAL is not set -# CONFIG_RTL8139 is not set -# CONFIG_DM9102 is not set # CONFIG_AT1700 is not set # CONFIG_DEPCA is not set # CONFIG_NET_ISA is not set -CONFIG_NET_EISA=y +CONFIG_NET_PCI=y CONFIG_PCNET32=y # CONFIG_ADAPTEC_STARFIRE is not set # CONFIG_AC3200 is not set # CONFIG_APRICOT is not set -# CONFIG_CS89x0 is not set CONFIG_DE4X5=y -# CONFIG_DEC_ELCP is not set +# CONFIG_TULIP is not set # CONFIG_DGRS is not set -# CONFIG_EEXPRESS_PRO100 is not set +# CONFIG_DM9102 is not set +# CONFIG_EEPRO100 is not set # CONFIG_LNE390 is not set # CONFIG_NE3210 is not set # CONFIG_NE2K_PCI is not set +# CONFIG_RTL8129 is not set +# CONFIG_8139TOO is not set # CONFIG_SIS900 is not set # CONFIG_TLAN is not set # CONFIG_VIA_RHINE is not set # CONFIG_ES3210 is not set # CONFIG_EPIC100 is not set -# CONFIG_ZNET is not set # CONFIG_NET_POCKET is not set # @@ -499,6 +495,7 @@ CONFIG_USB_OHCI=y # CONFIG_USB_DC2XX is not set # CONFIG_USB_STORAGE is not set # CONFIG_USB_DABUSB is not set +# CONFIG_USB_PLUSB is not set # # USB HID @@ -508,13 +505,15 @@ CONFIG_USB_KBD=y CONFIG_USB_MOUSE=y # CONFIG_USB_GRAPHIRE is not set # CONFIG_USB_WMFORCE is not set -# CONFIG_INPUT_KEYBDEV is not set -# CONFIG_INPUT_MOUSEDEV is not set +CONFIG_INPUT_KEYBDEV=y +CONFIG_INPUT_MOUSEDEV=y +# CONFIG_INPUT_MOUSEDEV_MIX is not set +# CONFIG_INPUT_MOUSEDEV_DIGITIZER is not set # CONFIG_INPUT_JOYDEV is not set # CONFIG_INPUT_EVDEV is not set # -# Filesystems +# File systems # # CONFIG_QUOTA is not set CONFIG_AUTOFS_FS=y @@ -535,6 +534,7 @@ CONFIG_ISO9660_FS=y # CONFIG_NTFS_FS is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set CONFIG_DEVPTS_FS=y # CONFIG_QNX4FS_FS is not set # CONFIG_ROMFS_FS is not set diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile index ea7c7c6e7..0f7167622 100644 --- a/arch/ppc/kernel/Makefile +++ b/arch/ppc/kernel/Makefile @@ -88,24 +88,14 @@ endif ifeq ($(CONFIG_NVRAM),y) O_OBJS += pmac_nvram.o endif -ifeq ($(CONFIG_6xx),y) - O_OBJS += open_pic.o indirect_pci.o -endif -ifeq ($(CONFIG_PPC64),y) - O_OBJS += open_pic.o indirect_pci.o -endif ifeq ($(CONFIG_APUS),y) O_OBJS += apus_setup.o endif -ifeq ($(CONFIG_PMAC),y) - O_OBJS += pmac_pic.o pmac_setup.o pmac_time.o feature.o pmac_pci.o prom.o -endif -ifeq ($(CONFIG_CHRP),y) - O_OBJS += chrp_pci.o pmac_pci.o chrp_setup.o i8259.o \ - chrp_time.o pmac_time.o prom.o -endif -ifeq ($(CONFIG_PREP),y) - O_OBJS += prep_pci.o i8259.o prep_setup.o prep_nvram.o prep_time.o residual.o +ifeq ($(CONFIG_ALL_PPC),y) + O_OBJS += pmac_pic.o pmac_setup.o pmac_time.o feature.o pmac_pci.o prom.o \ + chrp_setup.o chrp_time.o chrp_pci.o open_pic.o indirect_pci.o \ + prep_pci.o i8259.o prep_nvram.o prep_time.o residual.o + OX_OBJS += prep_setup.o endif ifeq ($(CONFIG_GEMINI),y) O_OBJS += gemini_prom.o gemini_pci.o gemini_setup.o diff --git a/arch/ppc/kernel/apus_setup.c b/arch/ppc/kernel/apus_setup.c index 5f0c4b06e..a54efc6fd 100644 --- a/arch/ppc/kernel/apus_setup.c +++ b/arch/ppc/kernel/apus_setup.c @@ -10,7 +10,7 @@ * TODO: * This file needs a *really* good cleanup. Restructure and optimize. * Make sure it can be compiled for non-APUS configs. Begin to move - * Amiga specific stuff into linux/machine/amiga. + * Amiga specific stuff into mach/amiga. */ #include @@ -27,6 +27,10 @@ #include #endif +/* Needs INITSERIAL call in head.S! */ +#undef APUS_DEBUG + + #include #define T_CHAR (0x0000) /* char: don't touch */ #define T_SHORT (0x4000) /* short: 12 -> 21 */ @@ -60,37 +64,6 @@ static u_short driveid_types[] = { #define num_driveid_types (sizeof(driveid_types)/sizeof(*driveid_types)) -#if 0 /* Get rid of this crud */ -/* Get the IDE stuff from the 68k file */ -#define ide_init_hwif_ports m68k_ide_init_hwif_ports -#define ide_default_irq m68k_ide_default_irq -#undef ide_request_irq -#define ide_request_irq m68k_ide_request_irq -#undef ide_free_irq -#define ide_free_irq m68k_ide_free_irq -#define ide_default_io_base m68k_ide_default_io_base -#define ide_check_region m68k_ide_check_region -#define ide_request_region m68k_ide_request_region -#define ide_release_region m68k_ide_release_region -#define ide_fix_driveid m68k_ide_fix_driveid -#define ide_init_default_hwifs m68k_ide_init_default_hwifs -#define select_t m68k_select_t -//#include -#include -#undef ide_free_irq -#undef select_t -#undef ide_request_irq -#undef ide_init_default_hwifs -#undef ide_init_hwif_ports -#undef ide_default_irq -#undef ide_default_io_base -#undef ide_check_region -#undef ide_request_region -#undef ide_release_region -#undef ide_fix_driveid -/*-------------------------------------------*/ -#endif - #include #include #include @@ -763,6 +736,12 @@ void apus_ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port, #endif /****************************************************** IRQ stuff */ +__apus +static unsigned int apus_irq_cannonicalize(unsigned int irq) +{ + return irq; +} + __apus int apus_get_irq_list(char *buf) { @@ -922,6 +901,114 @@ static void apus_kbd_init_hw(void) } +/****************************************************** debugging */ + +/* some serial hardware definitions */ +#define SDR_OVRUN (1<<15) +#define SDR_RBF (1<<14) +#define SDR_TBE (1<<13) +#define SDR_TSRE (1<<12) + +#define AC_SETCLR (1<<15) +#define AC_UARTBRK (1<<11) + +#define SER_DTR (1<<7) +#define SER_RTS (1<<6) +#define SER_DCD (1<<5) +#define SER_CTS (1<<4) +#define SER_DSR (1<<3) + +static __inline__ void ser_RTSon(void) +{ + ciab.pra &= ~SER_RTS; /* active low */ +} + +__apus +int __debug_ser_out( unsigned char c ) +{ + custom.serdat = c | 0x100; + mb(); + while (!(custom.serdatr & 0x2000)) + barrier(); + return 1; +} + +__apus +unsigned char __debug_ser_in( void ) +{ + unsigned char c; + + /* XXX: is that ok?? derived from amiga_ser.c... */ + while( !(custom.intreqr & IF_RBF) ) + barrier(); + c = custom.serdatr; + /* clear the interrupt, so that another character can be read */ + custom.intreq = IF_RBF; + return c; +} + +__apus +int __debug_serinit( void ) +{ + unsigned long flags; + + save_flags (flags); + cli(); + + /* turn off Rx and Tx interrupts */ + custom.intena = IF_RBF | IF_TBE; + + /* clear any pending interrupt */ + custom.intreq = IF_RBF | IF_TBE; + + restore_flags (flags); + + /* + * set the appropriate directions for the modem control flags, + * and clear RTS and DTR + */ + ciab.ddra |= (SER_DTR | SER_RTS); /* outputs */ + ciab.ddra &= ~(SER_DCD | SER_CTS | SER_DSR); /* inputs */ + +#ifdef CONFIG_KGDB + /* turn Rx interrupts on for GDB */ + custom.intena = IF_SETCLR | IF_RBF; + ser_RTSon(); +#endif + + return 0; +} + +__apus +void __debug_print_hex(unsigned long x) +{ + int i; + char hexchars[] = "0123456789ABCDEF"; + + for (i = 0; i < 8; i++) { + __debug_ser_out(hexchars[(x >> 28) & 15]); + x <<= 4; + } + __debug_ser_out('\n'); + __debug_ser_out('\r'); +} + +__apus +void __debug_print_string(char* s) +{ + unsigned char c; + while((c = *s++)) + __debug_ser_out(c); + __debug_ser_out('\n'); + __debug_ser_out('\r'); +} + +__apus +static void apus_progress(char *s, unsigned short value) +{ + __debug_print_string(s); +} + /****************************************************** init */ /* The number of spurious interrupts */ @@ -970,7 +1057,7 @@ void apus_init_IRQ(void) int i; for ( i = 0 ; i < NR_IRQS ; i++ ) - irq_desc[i].ctl = &amiga_irqctrl; + irq_desc[i].handler = &amiga_irqctrl; for (i = 0; i < NUM_IRQ_NODES; i++) nodes[i].handler = NULL; @@ -1015,13 +1102,17 @@ void apus_init(unsigned long r3, unsigned long r4, unsigned long r5, ppc_md.setup_arch = apus_setup_arch; ppc_md.setup_residual = NULL; ppc_md.get_cpuinfo = apus_get_cpuinfo; - ppc_md.irq_cannonicalize = NULL; + ppc_md.irq_cannonicalize = apus_irq_cannonicalize; ppc_md.init_IRQ = apus_init_IRQ; ppc_md.get_irq = apus_get_irq; ppc_md.post_irq = apus_post_irq; #ifdef CONFIG_HEARTBEAT ppc_md.heartbeat = apus_heartbeat; ppc_md.heartbeat_count = 1; +#endif +#ifdef APUS_DEBUG + __debug_serinit(); + ppc_md.progress = apus_progress; #endif ppc_md.init = NULL; diff --git a/arch/ppc/kernel/entry.S b/arch/ppc/kernel/entry.S index 013812afc..cc647a58b 100644 --- a/arch/ppc/kernel/entry.S +++ b/arch/ppc/kernel/entry.S @@ -435,7 +435,7 @@ _GLOBAL(fake_interrupt) * here so it's easy to add arch-specific sections later. * -- Cort */ -#if defined(CONFIG_CHRP) || defined(CONFIG_PMAC) || defined(CONFIG_ALL_PPC) +#if defined(CONFIG_ALL_PPC) /* * On CHRP, the Run-Time Abstraction Services (RTAS) have to be * called with the MMU off. @@ -475,4 +475,4 @@ enter_rtas: mtspr SRR0,r8 mtspr SRR1,r9 rfi /* return to caller */ -#endif /* CONFIG_CHRP || CONFIG_PMAC || CONFIG_ALL_PPC */ +#endif /* CONFIG_ALL_PPC */ diff --git a/arch/ppc/kernel/hashtable.S b/arch/ppc/kernel/hashtable.S index c87385c53..5593ebe18 100644 --- a/arch/ppc/kernel/hashtable.S +++ b/arch/ppc/kernel/hashtable.S @@ -115,11 +115,6 @@ hash_page: stw r6,0(r2) /* update PTE (accessed/dirty bits) */ /* Convert linux-style PTE to low word of PPC-style PTE */ -#ifdef CONFIG_PPC64 - /* clear the high 32 bits just in case */ - clrldi r6,r6,32 - clrldi r4,r4,32 -#endif /* CONFIG_PPC64 */ rlwinm r4,r6,32-9,31,31 /* _PAGE_HWWRITE -> PP lsb */ rlwimi r6,r6,32-1,31,31 /* _PAGE_USER -> PP (both bits now) */ ori r4,r4,0xe04 /* clear out reserved bits */ @@ -151,10 +146,6 @@ hash_page: .globl hash_page_patch_A hash_page_patch_A: lis r4,Hash_base@h /* base address of hash table */ -#ifdef CONFIG_PPC64 - /* just in case */ - clrldi r4,r4,32 -#endif rlwimi r4,r5,32-1,26-Hash_bits,25 /* (VSID & hash_mask) << 6 */ rlwinm r0,r3,32-6,26-Hash_bits,25 /* (PI & hash_mask) << 6 */ xor r4,r4,r0 /* make primary hash */ @@ -169,43 +160,89 @@ hash_page_patch_A: /* Search the primary PTEG for a PTE whose 1st word matches r5 */ mtctr r2 addi r3,r4,-8 -1: lwzu r0,8(r3) /* get next PTE */ +1: +#ifdef CONFIG_PPC64 + lwzu r0,16(r3) /* get next PTE */ +#else + lwzu r0,8(r3) /* get next PTE */ +#endif cmp 0,r0,r5 bdnzf 2,1b /* loop while ctr != 0 && !cr0.eq */ beq+ found_slot /* Search the secondary PTEG for a matching PTE */ +#ifdef CONFIG_PPC64 + ori r5,r5,0x2 /* set H (secondary hash) bit */ +#else ori r5,r5,0x40 /* set H (secondary hash) bit */ +#endif .globl hash_page_patch_B hash_page_patch_B: xoris r3,r4,Hash_msk>>16 /* compute secondary hash */ xori r3,r3,0xffc0 +#ifdef CONFIG_PPC64 + addi r3,r3,-16 +#else addi r3,r3,-8 +#endif mtctr r2 -2: lwzu r0,8(r3) +2: +#ifdef CONFIG_PPC64 + lwzu r0,16(r3) +#else + lwzu r0,8(r3) +#endif cmp 0,r0,r5 bdnzf 2,2b beq+ found_slot +#ifdef CONFIG_PPC64 + xori r5,r5,0x2 /* clear H bit again */ +#else xori r5,r5,0x40 /* clear H bit again */ +#endif /* Search the primary PTEG for an empty slot */ 10: mtctr r2 +#ifdef CONFIG_PPC64 + addi r3,r4,-16 /* search primary PTEG */ +#else addi r3,r4,-8 /* search primary PTEG */ -1: lwzu r0,8(r3) /* get next PTE */ +#endif +1: +#ifdef CONFIG_PPC64 + lwzu r0,16(r3) /* get next PTE */ + andi. r0,r0,1 +#else + lwzu r0,8(r3) /* get next PTE */ rlwinm. r0,r0,0,0,0 /* only want to check valid bit */ +#endif bdnzf 2,1b /* loop while ctr != 0 && !cr0.eq */ beq+ found_empty /* Search the secondary PTEG for an empty slot */ +#ifdef CONFIG_PPC64 + ori r5,r5,0x2 /* set H (secondary hash) bit */ +#else ori r5,r5,0x40 /* set H (secondary hash) bit */ +#endif .globl hash_page_patch_C hash_page_patch_C: xoris r3,r4,Hash_msk>>16 /* compute secondary hash */ xori r3,r3,0xffc0 +#ifdef CONFIG_PPC64 + addi r3,r3,-16 +#else addi r3,r3,-8 +#endif mtctr r2 -2: lwzu r0,8(r3) +2: +#ifdef CONFIG_PPC64 + lwzu r0,16(r3) + andi. r0,r0,1 +#else + lwzu r0,8(r3) rlwinm. r0,r0,0,0,0 /* only want to check valid bit */ +#endif bdnzf 2,2b beq+ found_empty @@ -218,12 +255,21 @@ hash_page_patch_C: * advantage to putting the PTE in the primary PTEG, we always * put the PTE in the primary PTEG. */ +#ifdef CONFIG_PPC64 + xori r5,r5,0x2 /* clear H bit again */ +#else xori r5,r5,0x40 /* clear H bit again */ +#endif lis r3,next_slot@ha tophys(r3,r3) lwz r2,next_slot@l(r3) +#ifdef CONFIG_PPC64 + addi r2,r2,16 + andi. r2,r2,0x78 +#else addi r2,r2,8 andi. r2,r2,0x38 +#endif stw r2,next_slot@l(r3) add r3,r4,r2 11: @@ -237,9 +283,17 @@ hash_page_patch_C: #ifndef __SMP__ /* Store PTE in PTEG */ found_empty: +#ifdef CONFIG_PPC64 + std r5,0(r3) +#else stw r5,0(r3) +#endif found_slot: +#ifdef CONFIG_PPC64 + std r6,8(r3) +#else stw r6,4(r3) +#endif sync #else /* __SMP__ */ diff --git a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S index dd16b8c27..b6d44ecb3 100644 --- a/arch/ppc/kernel/head.S +++ b/arch/ppc/kernel/head.S @@ -1328,18 +1328,15 @@ load_up_mmu: /* Load the SDR1 register (hash table base & size) */ lis r6,_SDR1@ha tophys(r6,r6) -#ifdef CONFIG_PPC64 - ld r6,_SDR1@l(r6) + lwz r6,_SDR1@l(r6) mtspr SDR1,r6 +#ifdef CONFIG_PPC64 /* clear the v bit in the ASR so we can * behave as if we have segment registers * -- Cort */ clrldi r6,r6,63 mtasr r6 -#else - lwz r6,_SDR1@l(r6) - mtspr SDR1,r6 #endif /* CONFIG_PPC64 */ li r0,16 /* load up segment register values */ mtctr r0 /* for context 0 */ diff --git a/arch/ppc/kernel/irq.c b/arch/ppc/kernel/irq.c index fd77fbc36..ffac1871a 100644 --- a/arch/ppc/kernel/irq.c +++ b/arch/ppc/kernel/irq.c @@ -70,8 +70,6 @@ volatile unsigned char *chrp_int_ack_special; #define MAXCOUNT 10000000 -#define NR_MASK_WORDS ((NR_IRQS + 31) / 32) - irq_desc_t irq_desc[NR_IRQS]; int ppc_spurious_interrupts = 0; unsigned int local_bh_count[NR_CPUS]; @@ -81,7 +79,6 @@ unsigned int ppc_cached_irq_mask[NR_MASK_WORDS]; unsigned int ppc_lost_interrupts[NR_MASK_WORDS]; atomic_t ppc_n_lost_interrupts; - /* nasty hack for shared irq's since we need to do kmalloc calls but * can't very early in the boot when we need to do a request irq. * this needs to be removed. diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S index 50f63eeb4..8444bb4a0 100644 --- a/arch/ppc/kernel/misc.S +++ b/arch/ppc/kernel/misc.S @@ -241,12 +241,21 @@ _GLOBAL(__flush_page_to_ram) rlwinm r5,r5,16,16,31 cmpi 0,r5,1 beqlr /* for 601, do nothing */ + li r4,0x0FFF + andc r3,r3,r4 /* Get page base address */ li r4,4096/CACHE_LINE_SIZE /* Number of lines in a page */ mtctr r4 + mr r6,r3 0: dcbst 0,r3 /* Write line to ram */ addi r3,r3,CACHE_LINE_SIZE bdnz 0b sync + mtctr r4 +1: icbi 0,r6 + addi r6,r6,CACHE_LINE_SIZE + bdnz 1b + sync + isync blr /* @@ -270,7 +279,7 @@ _GLOBAL(__flush_icache_page) sync isync blr - + /* * Clear a page using the dcbz instruction, which doesn't cause any * memory traffic (except to write out any cache lines which get diff --git a/arch/ppc/kernel/mk_defs.c b/arch/ppc/kernel/mk_defs.c index 4f3c6834d..c381ea073 100644 --- a/arch/ppc/kernel/mk_defs.c +++ b/arch/ppc/kernel/mk_defs.c @@ -99,6 +99,7 @@ main(void) DEFINE(_CTR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, ctr)); DEFINE(_LINK, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, link)); DEFINE(_CCR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, ccr)); + DEFINE(_MQ, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, mq)); DEFINE(_XER, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, xer)); DEFINE(_DAR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dar)); DEFINE(_DSISR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dsisr)); diff --git a/arch/ppc/kernel/pmac_pic.c b/arch/ppc/kernel/pmac_pic.c index d13875c9f..b0276ca2c 100644 --- a/arch/ppc/kernel/pmac_pic.c +++ b/arch/ppc/kernel/pmac_pic.c @@ -39,6 +39,17 @@ extern int pmac_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn extern int pmac_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned short val); +/* + * Mark an irq as "lost". This is only used on the pmac + * since it can lose interrupts (see pmac_set_irq_mask). + * -- Cort + */ +void __pmac __no_use_set_lost(unsigned long irq_nr) +{ + if (!test_and_set_bit(irq_nr, ppc_lost_interrupts)) + atomic_inc(&ppc_n_lost_interrupts); +} + static void pmac_openpic_mask_irq(unsigned int irq_nr) { openpic_disable_irq(irq_nr); @@ -105,10 +116,8 @@ static void __pmac pmac_set_irq_mask(unsigned int irq_nr) */ if ((bit & ppc_cached_irq_mask[i]) && (ld_le32(&pmac_irq_hw[i]->level) & bit) - && !(ld_le32(&pmac_irq_hw[i]->flag) & bit)) { - if (!test_and_set_bit(irq_nr, ppc_lost_interrupts)) - atomic_inc(&ppc_n_lost_interrupts); - } + && !(ld_le32(&pmac_irq_hw[i]->flag) & bit)) + __set_lost((ulong)irq_nr); } static void __pmac pmac_mask_irq(unsigned int irq_nr) @@ -174,6 +183,8 @@ pmac_get_irq(struct pt_regs *regs) unsigned long bits = 0; #ifdef __SMP__ + void pmac_smp_message_recv(void); + /* IPI's are a hack on the powersurge -- Cort */ if ( smp_processor_id() != 0 ) { @@ -182,12 +193,12 @@ pmac_get_irq(struct pt_regs *regs) if (xmon_2nd) xmon(regs); #endif - smp_message_recv(); + pmac_smp_message_recv(); return -2; /* ignore, already handled */ } #endif /* __SMP__ */ - /* Yeah, I know, this could be a separate do_IRQ function */ + /* Yeah, I know, this could be a separate get_irq function */ if (has_openpic) { irq = openpic_irq(smp_processor_id()); @@ -376,6 +387,7 @@ pmac_pic_init(void) irqctrler = NULL; } + int_control.int_set_lost = __no_use_set_lost; /* * G3 powermacs and 1999 G3 PowerBooks have 64 interrupts, * 1998 G3 Series PowerBooks have 128, diff --git a/arch/ppc/kernel/ppc_htab.c b/arch/ppc/kernel/ppc_htab.c index 264a24d48..da46f3c1c 100644 --- a/arch/ppc/kernel/ppc_htab.c +++ b/arch/ppc/kernel/ppc_htab.c @@ -44,19 +44,12 @@ extern unsigned long htab_evicts; extern unsigned long pte_misses; extern unsigned long pte_errors; -static struct file_operations ppc_htab_operations = { +struct file_operations ppc_htab_operations = { llseek: ppc_htab_lseek, read: ppc_htab_read, write: ppc_htab_write, }; -/* - * proc files can do almost nothing.. - */ -struct inode_operations proc_ppc_htab_inode_operations = { - &ppc_htab_operations, /* default proc file-ops */ -}; - /* these will go into processor.h when I'm done debugging -- Cort */ #define MMCR0 952 #define MMCR0_PMC1_CYCLES (0x1<<7) diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c index 757715512..87c8d4082 100644 --- a/arch/ppc/kernel/ppc_ksyms.c +++ b/arch/ppc/kernel/ppc_ksyms.c @@ -34,6 +34,7 @@ #include #include #include +#include #ifdef __SMP__ #include #endif /* __SMP__ */ @@ -50,7 +51,6 @@ extern void AlignmentException(struct pt_regs *regs); extern void ProgramCheckException(struct pt_regs *regs); extern void SingleStepException(struct pt_regs *regs); extern int sys_sigreturn(struct pt_regs *regs); -extern atomic_t ppc_n_lost_interrupts; extern void do_lost_interrupts(unsigned long); extern int do_signal(sigset_t *, struct pt_regs *); @@ -69,6 +69,7 @@ EXPORT_SYMBOL(ProgramCheckException); EXPORT_SYMBOL(SingleStepException); EXPORT_SYMBOL(sys_sigreturn); EXPORT_SYMBOL(ppc_n_lost_interrupts); +EXPORT_SYMBOL(ppc_lost_interrupts); EXPORT_SYMBOL(do_lost_interrupts); EXPORT_SYMBOL(enable_irq); EXPORT_SYMBOL(disable_irq); @@ -88,7 +89,7 @@ EXPORT_SYMBOL(ISA_DMA_THRESHOLD); EXPORT_SYMBOL(DMA_MODE_READ); EXPORT_SYMBOL(DMA_MODE_WRITE); #ifndef CONFIG_8xx -#if defined(CONFIG_PREP) || defined(CONFIG_ALL_PPC) +#if defined(CONFIG_ALL_PPC) EXPORT_SYMBOL(_prep_type); EXPORT_SYMBOL(ucSystemType); #endif @@ -125,7 +126,6 @@ EXPORT_SYMBOL(strtok); EXPORT_SYMBOL(strstr); EXPORT_SYMBOL(strlen); EXPORT_SYMBOL(strnlen); -EXPORT_SYMBOL(strspn); EXPORT_SYMBOL(strcmp); EXPORT_SYMBOL(strncmp); @@ -227,7 +227,7 @@ EXPORT_SYMBOL(pmu_register_sleep_notifier); EXPORT_SYMBOL(pmu_unregister_sleep_notifier); EXPORT_SYMBOL(pmu_enable_irled); #endif CONFIG_PMAC_PBOOK -#if defined(CONFIG_PMAC) || defined(CONFIG_ALL_PPC) +#if defined(CONFIG_ALL_PPC) EXPORT_SYMBOL(find_devices); EXPORT_SYMBOL(find_type_devices); EXPORT_SYMBOL(find_compatible_devices); @@ -243,8 +243,8 @@ EXPORT_SYMBOL(pci_device_loc); EXPORT_SYMBOL(feature_set); EXPORT_SYMBOL(feature_clear); EXPORT_SYMBOL(feature_test); -#endif /* defined(CONFIG_PMAC) || defined(CONFIG_ALL_PPC) */ -#if defined(CONFIG_SCSI) && (defined(CONFIG_PMAC) || defined(CONFIG_ALL_PPC)) +#endif /* defined(CONFIG_ALL_PPC) */ +#if defined(CONFIG_SCSI) && defined(CONFIG_ALL_PPC) EXPORT_SYMBOL(note_scsi_host); #endif EXPORT_SYMBOL(kd_mksound); @@ -270,7 +270,6 @@ EXPORT_SYMBOL(screen_info); EXPORT_SYMBOL(int_control); EXPORT_SYMBOL(timer_interrupt_intercept); EXPORT_SYMBOL(timer_interrupt); -extern unsigned long do_IRQ_intercept; EXPORT_SYMBOL(do_IRQ_intercept); EXPORT_SYMBOL(irq_desc); void ppc_irq_dispatch_handler(struct pt_regs *, int); @@ -278,3 +277,7 @@ EXPORT_SYMBOL(ppc_irq_dispatch_handler); EXPORT_SYMBOL(decrementer_count); EXPORT_SYMBOL(get_wchan); EXPORT_SYMBOL(console_drivers); +#ifdef CONFIG_XMON +EXPORT_SYMBOL(xmon); +#endif +EXPORT_SYMBOL(down_read_failed); diff --git a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c index 41382b2d7..5c01d3c72 100644 --- a/arch/ppc/kernel/process.c +++ b/arch/ppc/kernel/process.c @@ -158,7 +158,7 @@ enable_kernel_altivec(void) if (current->thread.regs && (current->thread.regs->msr & MSR_VEC)) giveup_altivec(current); else - giveup_altivec(NULL): /* just enable AltiVec for kernel - force */ + giveup_altivec(NULL); /* just enable AltiVec for kernel - force */ #else giveup_altivec(last_task_used_altivec); #endif /* __SMP __ */ diff --git a/arch/ppc/kernel/prom.c b/arch/ppc/kernel/prom.c index b86e2a153..4ee638f62 100644 --- a/arch/ppc/kernel/prom.c +++ b/arch/ppc/kernel/prom.c @@ -604,7 +604,6 @@ prom_init(int r3, int r4, prom_entry pp) /* XXX: hack - don't start cpu 0, this cpu -- Cort */ if ( smp_chrp_cpu_nr++ == 0 ) continue; - RELOC(smp_ibm_chrp_hack) = 1; prom_print(RELOC("starting cpu ")); prom_print(path); *(unsigned long *)(0x4) = 0; diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c index 7502ad08e..5a57ba8a2 100644 --- a/arch/ppc/kernel/setup.c +++ b/arch/ppc/kernel/setup.c @@ -733,17 +733,13 @@ void ppc_generic_ide_fix_driveid(struct hd_driveid *id) id->eide_dma_time = __le16_to_cpu(id->eide_dma_time); id->eide_pio = __le16_to_cpu(id->eide_pio); id->eide_pio_iordy = __le16_to_cpu(id->eide_pio_iordy); - id->word69 = __le16_to_cpu(id->word69); - id->word70 = __le16_to_cpu(id->word70); - id->word71 = __le16_to_cpu(id->word71); - id->word72 = __le16_to_cpu(id->word72); - id->word73 = __le16_to_cpu(id->word73); - id->word74 = __le16_to_cpu(id->word74); + for (i=0; i<2 i++) + id->words69_70[i] = __le16_to_cpu(id->words69_70[i]); + for (i=0; i<4 i++) + id->words71_74[i] = __le16_to_cpu(id->words71_74[i]); id->queue_depth = __le16_to_cpu(id->queue_depth); - id->word76 = __le16_to_cpu(id->word76); - id->word77 = __le16_to_cpu(id->word77); - id->word78 = __le16_to_cpu(id->word78); - id->word79 = __le16_to_cpu(id->word79); + for (i=0; i<4 i++) + id->words76_79[i] = __le16_to_cpu(id->words76_79[i]); id->major_rev_num = __le16_to_cpu(id->major_rev_num); id->minor_rev_num = __le16_to_cpu(id->minor_rev_num); id->command_set_1 = __le16_to_cpu(id->command_set_1); @@ -758,40 +754,14 @@ void ppc_generic_ide_fix_driveid(struct hd_driveid *id) id->CurAPMvalues = __le16_to_cpu(id->CurAPMvalues); id->word92 = __le16_to_cpu(id->word92); id->hw_config = __le16_to_cpu(id->hw_config); - id->word94 = __le16_to_cpu(id->word94); - id->word95 = __le16_to_cpu(id->word95); - id->word96 = __le16_to_cpu(id->word96); - id->word97 = __le16_to_cpu(id->word97); - id->word98 = __le16_to_cpu(id->word98); - id->word99 = __le16_to_cpu(id->word99); - id->word100 = __le16_to_cpu(id->word100); - id->word101 = __le16_to_cpu(id->word101); - id->word102 = __le16_to_cpu(id->word102); - id->word103 = __le16_to_cpu(id->word103); - id->word104 = __le16_to_cpu(id->word104); - id->word105 = __le16_to_cpu(id->word105); - id->word106 = __le16_to_cpu(id->word106); - id->word107 = __le16_to_cpu(id->word107); - id->word108 = __le16_to_cpu(id->word108); - id->word109 = __le16_to_cpu(id->word109); - id->word110 = __le16_to_cpu(id->word110); - id->word111 = __le16_to_cpu(id->word111); - id->word112 = __le16_to_cpu(id->word112); - id->word113 = __le16_to_cpu(id->word113); - id->word114 = __le16_to_cpu(id->word114); - id->word115 = __le16_to_cpu(id->word115); - id->word116 = __le16_to_cpu(id->word116); - id->word117 = __le16_to_cpu(id->word117); - id->word118 = __le16_to_cpu(id->word118); - id->word119 = __le16_to_cpu(id->word119); - id->word120 = __le16_to_cpu(id->word120); - id->word121 = __le16_to_cpu(id->word121); - id->word122 = __le16_to_cpu(id->word122); - id->word123 = __le16_to_cpu(id->word123); - id->word124 = __le16_to_cpu(id->word124); - id->word125 = __le16_to_cpu(id->word125); - id->word126 = __le16_to_cpu(id->word126); + for (i=0; i<34; i++) + id->words94_125[i] = __le16_to_cpu(id->words94_125[i]); + id->last_lun = __le16_to_cpu(id->last_lun); id->word127 = __le16_to_cpu(id->word127); - for (i=0; i<127; i++) - id->reserved[i] = __le16_to_cpu(id->reserved[i]); + id->dlf = __le16_to_cpu(id->dlf); + id->csfo = __le16_to_cpu(id->csfo); + for (i=0; i<31; i++) + id->words130_159[i] = __le16_to_cpu(id->words130_159[i]); + for (i=0; i<97; i++) + id->words160_255[i] = __le16_to_cpu(id->words160_255[i]); } diff --git a/arch/ppc/kernel/smp.c b/arch/ppc/kernel/smp.c index 83dff9246..97543348b 100644 --- a/arch/ppc/kernel/smp.c +++ b/arch/ppc/kernel/smp.c @@ -12,6 +12,7 @@ * (troy@microux.com, hozer@drgw.net) */ +#include #include #include #include @@ -445,8 +446,10 @@ void __init smp_callin(void) */ if ( _machine & (_MACH_gemini|_MACH_chrp|_MACH_prep) ) do_openpic_setup_cpu(); +#ifdef CONFIG_GEMINI if ( _machine == _MACH_gemini ) gemini_init_l2(); +#endif while(!smp_commenced) barrier(); __sti(); diff --git a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c index 25d728fdd..2faccd042 100644 --- a/arch/ppc/mm/init.c +++ b/arch/ppc/mm/init.c @@ -115,11 +115,7 @@ extern struct task_struct *current_set[NR_CPUS]; PTE *Hash, *Hash_end; unsigned long Hash_size, Hash_mask; #if !defined(CONFIG_4xx) && !defined(CONFIG_8xx) -#ifdef CONFIG_PPC64 -unsigned long long _SDR1; -#else unsigned long _SDR1; -#endif static void hash_init(void); union ubat { /* BAT register values to be loaded */ @@ -423,10 +419,9 @@ __ioremap(unsigned long addr, unsigned long size, unsigned long flags) /* * Is it a candidate for a BAT mapping? */ - for (i = 0; i < size; i += PAGE_SIZE) map_page(v+i, p+i, flags); -out: +out: return (void *) (v + (addr & ~PAGE_MASK)); } @@ -593,7 +588,7 @@ mmu_context_overflow(void) #if !defined(CONFIG_4xx) && !defined(CONFIG_8xx) static void get_mem_prop(char *, struct mem_pieces *); -#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP) || defined(CONFIG_ALL_PPC) +#if defined(CONFIG_ALL_PPC) /* * Read in a property describing some pieces of memory. */ @@ -616,7 +611,7 @@ static void __init get_mem_prop(char *name, struct mem_pieces *mp) mem_pieces_sort(mp); mem_pieces_coalesce(mp); } -#endif /* CONFIG_PMAC || CONFIG_CHRP || CONFIG_ALL_PPC */ +#endif /* CONFIG_ALL_PPC */ /* * Set up one of the I/D BAT (block address translation) register pairs. @@ -921,10 +916,11 @@ void __init MMU_init(void) if ( ppc_md.progress ) ppc_md.progress("MMU:hash init", 0x300); hash_init(); #ifdef CONFIG_PPC64 - _SDR1 = 0; /* temporary hack to just use bats -- Cort */ -#else + _SDR1 = __pa(Hash) | (ffz(~Hash_size) - 7)-11; +#else _SDR1 = __pa(Hash) | (Hash_mask >> 10); -#endif +#endif + ioremap_base = 0xf8000000; if ( ppc_md.progress ) ppc_md.progress("MMU:mapin", 0x301); @@ -947,7 +943,7 @@ void __init MMU_init(void) setbat(0, 0xf8000000, 0xf8000000, 0x08000000, IO_PAGE); #ifdef CONFIG_PPC64 /* temporary hack to get working until page tables are stable -- Cort*/ - setbat(1, 0x80000000, 0xc0000000, 0x10000000, IO_PAGE); +/* setbat(1, 0x80000000, 0xc0000000, 0x10000000, IO_PAGE);*/ setbat(3, 0xd0000000, 0xd0000000, 0x10000000, IO_PAGE); #else setbat(1, 0x80000000, 0x80000000, 0x10000000, IO_PAGE); @@ -1118,7 +1114,7 @@ void __init paging_init(void) /* * All pages are DMA-able so we put them all in the DMA zone. */ - zones_size[0] = virt_to_phys(end_of_DRAM) >> PAGE_SHIFT; + zones_size[0] = ((unsigned long)end_of_DRAM - KERNELBASE) >> PAGE_SHIFT; for (i = 1; i < MAX_NR_ZONES; i++) zones_size[i] = 0; free_area_init(zones_size); @@ -1132,9 +1128,9 @@ void __init mem_init(void) int codepages = 0; int datapages = 0; int initpages = 0; -#if defined(CONFIG_CHRP) || defined(CONFIG_ALL_PPC) +#if defined(CONFIG_ALL_PPC) extern unsigned int rtas_data, rtas_size; -#endif /* defined(CONFIG_CHRP) || defined(CONFIG_ALL_PPC) */ +#endif /* defined(CONFIG_ALL_PPC) */ max_mapnr = max_low_pfn; high_memory = (void *) __va(max_low_pfn * PAGE_SIZE); num_physpages = max_mapnr; /* RAM is assumed contiguous */ @@ -1150,13 +1146,13 @@ void __init mem_init(void) } #endif /* CONFIG_BLK_DEV_INITRD */ -#if defined(CONFIG_CHRP) || defined(CONFIG_ALL_PPC) +#if defined(CONFIG_ALL_PPC) /* mark the RTAS pages as reserved */ if ( rtas_data ) for (addr = rtas_data; addr < PAGE_ALIGN(rtas_data+rtas_size) ; addr += PAGE_SIZE) SetPageReserved(mem_map + MAP_NR(addr)); -#endif /* defined(CONFIG_CHRP) || defined(CONFIG_ALL_PPC) */ +#endif /* defined(CONFIG_ALL_PPC) */ if ( sysmap_size ) for (addr = (unsigned long)sysmap; addr < PAGE_ALIGN((unsigned long)sysmap+sysmap_size) ; @@ -1178,13 +1174,14 @@ void __init mem_init(void) printk("Memory: %luk available (%dk kernel code, %dk data, %dk init) [%08x,%08lx]\n", (unsigned long)nr_free_pages()<< (PAGE_SHIFT-10), - codepages, datapages, initpages, + codepages<< (PAGE_SHIFT-10), datapages<< (PAGE_SHIFT-10), + initpages<< (PAGE_SHIFT-10), PAGE_OFFSET, (unsigned long) end_of_DRAM); mem_init_done = 1; } #if !defined(CONFIG_4xx) && !defined(CONFIG_8xx) -#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP) || defined(CONFIG_ALL_PPC) +#if defined(CONFIG_ALL_PPC) /* * On systems with Open Firmware, collect information about * physical RAM and which pieces are already in use. @@ -1195,9 +1192,13 @@ void __init mem_init(void) unsigned long __init *pmac_find_end_of_memory(void) { unsigned long a, total; - - /* max amount of RAM we allow -- Cort */ -#define RAM_LIMIT (768<<20) + unsigned long ram_limit = 0xf0000000 - KERNELBASE; + /* allow 0x08000000 for IO space */ + if ( _machine & (_MACH_prep|_MACH_Pmac) ) + ram_limit = 0xd8000000 - KERNELBASE; +#ifdef CONFIG_PPC64 + ram_limit = 64<<20; +#endif memory_node = find_devices("memory"); if (memory_node == NULL) { @@ -1222,16 +1223,8 @@ unsigned long __init *pmac_find_end_of_memory(void) a = phys_mem.regions[0].address; if (a != 0) panic("RAM doesn't start at physical address 0"); - /* - * XXX: - * Make sure ram mappings don't stomp on IO space - * This is a temporary hack to keep this from happening - * until we move the KERNELBASE and can allocate RAM up - * to our nearest IO area. - * -- Cort - */ - if (__max_memory == 0 || __max_memory > RAM_LIMIT) - __max_memory = RAM_LIMIT; + if (__max_memory == 0 || __max_memory > ram_limit) + __max_memory = ram_limit; if (phys_mem.regions[0].size >= __max_memory) { phys_mem.regions[0].size = __max_memory; phys_mem.n_regions = 1; @@ -1247,12 +1240,11 @@ unsigned long __init *pmac_find_end_of_memory(void) set_phys_avail(&phys_mem); -#undef RAM_LIMIT return __va(total); } -#endif /* CONFIG_PMAC || CONFIG_CHRP || CONFIG_ALL_PPC */ +#endif /* CONFIG_ALL_PPC */ -#if defined(CONFIG_PREP) || defined(CONFIG_ALL_PPC) +#if defined(CONFIG_ALL_PPC) /* * This finds the amount of physical ram and does necessary * setup for prep. This is pretty architecture specific so @@ -1279,7 +1271,7 @@ unsigned long __init *prep_find_end_of_memory(void) return (__va(total)); } -#endif /* defined(CONFIG_PREP) || defined(CONFIG_ALL_PPC) */ +#endif /* defined(CONFIG_ALL_PPC) */ #if defined(CONFIG_GEMINI) @@ -1389,16 +1381,12 @@ static void __init hash_init(void) * up to a maximum of 2MB. */ ramsize = (ulong)end_of_DRAM - KERNELBASE; -#ifdef CONFIG_PPC64 - Hash_mask = 0; - for (h = 256<<10; h < ramsize / 256 && h < 4<<20; h *= 2, Hash_mask++) - ; - Hash_size = h; - Hash_mask <<= 10; /* so setting _SDR1 works the same -- Cort */ -#else for (h = 64<<10; h < ramsize / 256 && h < 2<<20; h *= 2) ; Hash_size = h; +#ifdef CONFIG_PPC64 + Hash_mask = (h >> 7) - 1; +#else Hash_mask = (h >> 6) - 1; #endif @@ -1433,7 +1421,11 @@ static void __init hash_init(void) /* * Patch up the instructions in head.S:hash_page */ +#ifdef CONFIG_PPC64 + Hash_bits = ffz(~Hash_size) - 7; +#else Hash_bits = ffz(~Hash_size) - 6; +#endif hash_page_patch_A[0] = (hash_page_patch_A[0] & ~0xffff) | (__pa(Hash) >> 16); hash_page_patch_A[1] = (hash_page_patch_A[1] & ~0x7c0) @@ -1443,9 +1435,17 @@ static void __init hash_init(void) hash_page_patch_A[2] = (hash_page_patch_A[2] & ~0x7c0) | ((26 - Hash_bits) << 6); hash_page_patch_B[0] = (hash_page_patch_B[0] & ~0xffff) +#ifdef CONFIG_PPC64 + | (Hash_mask >> 11); +#else | (Hash_mask >> 10); +#endif hash_page_patch_C[0] = (hash_page_patch_C[0] & ~0xffff) +#ifdef CONFIG_PPC64 + | (Hash_mask >> 11); +#else | (Hash_mask >> 10); +#endif #if 0 /* see hash_page in head.S, note also patch_C ref below */ hash_page_patch_D[0] = (hash_page_patch_D[0] & ~0xffff) | (Hash_mask >> 10); diff --git a/arch/ppc/mm/mem_pieces.c b/arch/ppc/mm/mem_pieces.c index e695d5a0a..309a526f5 100644 --- a/arch/ppc/mm/mem_pieces.c +++ b/arch/ppc/mm/mem_pieces.c @@ -127,7 +127,7 @@ mem_pieces_print(struct mem_pieces *mp) printk("\n"); } -#if defined(CONFIG_PREP) || defined(CONFIG_APUS) || defined(CONFIG_ALL_PPC) +#if defined(CONFIG_APUS) || defined(CONFIG_ALL_PPC) /* * Add some memory to an array of pieces */ diff --git a/arch/ppc/xmon/xmon.c b/arch/ppc/xmon/xmon.c index a0da2f1b4..d18d74dfd 100644 --- a/arch/ppc/xmon/xmon.c +++ b/arch/ppc/xmon/xmon.c @@ -75,11 +75,14 @@ static void take_input(char *); static unsigned read_spr(int); static void write_spr(int, unsigned); static void super_regs(void); +static void print_sysmap(void); static void remove_bpts(void); static void insert_bpts(void); static struct bpt *at_breakpoint(unsigned pc); static void bpt_cmds(void); static void cacheflush(void); +static char *pretty_lookup_name(unsigned long addr); +static char *lookup_name(unsigned long addr); extern int print_insn_big_powerpc(FILE *, unsigned long, unsigned); extern void printf(const char *fmt, ...); @@ -101,6 +104,7 @@ Commands:\n\ mm move a block of memory\n\ ms set a block of memory\n\ md compare two blocks of memory\n\ + M print System.map\n\ r print registers\n\ S print special registers\n\ t print backtrace\n\ @@ -337,6 +341,8 @@ cmds(struct pt_regs *excp) else excprint(excp); break; + case 'M': + print_sysmap(); case 'S': super_regs(); break; @@ -514,8 +520,10 @@ getsp() void excprint(struct pt_regs *fp) { - printf("vector: %x at pc = %x, msr = %x, sp = %x [%x]\n", - fp->trap, fp->nip, fp->msr, fp->gpr[1], fp); + printf("vector: %x at pc = %x %s", + fp->trap, fp->nip,/* pretty_lookup_name(fp->nip)*/""); + printf(", msr = %x, sp = %x [%x]\n", + fp->msr, fp->gpr[1], fp); if (fp->trap == 0x300 || fp->trap == 0x600) printf("dar = %x, dsisr = %x\n", fp->dar, fp->dsisr); if (current) @@ -596,6 +604,14 @@ static unsigned int regno; extern char exc_prolog; extern char dec_exc; +void +print_sysmap(void) +{ + extern char *sysmap; + if ( sysmap ) + printf("System.map: \n%s", sysmap); +} + void super_regs() { @@ -1345,9 +1361,26 @@ char *str; lineptr = str; } +/* + * We use this array a lot here. We assume we don't have multiple + * instances of xmon running and that we don't use the return value of + * any functions other than printing them. + * -- Cort + */ char last[64]; -char * -lookup_addr(unsigned long addr) +static char *pretty_lookup_name(unsigned long addr) +{ + if ( lookup_name(addr) ) + { + sprintf(last, " (%s)", lookup_name(addr)); + return last; + } + else + return NULL; +} + + +static char *lookup_name(unsigned long addr) { extern char *sysmap; extern unsigned long sysmap_size; @@ -1357,10 +1390,6 @@ lookup_addr(unsigned long addr) if ( !sysmap || !sysmap_size ) return NULL; - /* adjust if addr is relative to kernelbase */ - if ( addr < PAGE_OFFSET ) - addr += PAGE_OFFSET; - cmp = simple_strtoul(c, &c, 8); strcpy( last, strsep( &c, "\n")); while ( c < (sysmap+sysmap_size) ) @@ -1372,3 +1401,4 @@ lookup_addr(unsigned long addr) } return last; } + diff --git a/arch/sparc/boot/Makefile b/arch/sparc/boot/Makefile index b0f7f63ea..a7a562549 100644 --- a/arch/sparc/boot/Makefile +++ b/arch/sparc/boot/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.9 1998/10/26 20:01:03 davem Exp $ +# $Id: Makefile,v 1.10 2000/02/23 08:17:46 jj Exp $ # Makefile for the Sparc boot stuff. # # Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -22,16 +22,20 @@ btfixupprep: btfixupprep.c clean: rm -f btfixupprep piggyback tftpboot.img btfix.o btfix.s -BTOBJS := $(HEAD) init/main.o init/version.o \ - $(CORE_FILES_NO_BTFIX) $(FILESYSTEMS) \ - $(NETWORKS) $(DRIVERS) +BTOBJS := $(HEAD) init/main.o init/version.o +BTLIBS := $(CORE_FILES_NO_BTFIX) $(FILESYSTEMS) \ + $(DRIVERS) $(NETWORKS) # I wanted to make this depend upon BTOBJS so that a parallel # build would work, but this fails because $(HEAD) cannot work # properly as it will cause head.o to be built with the implicit # rules not the ones in kernel/Makefile. Someone please fix. --DaveM vmlinux.o: dummy - $(LD) -r $(patsubst %,$(TOPDIR)/%,$(BTOBJS)) $(LIBS) -o vmlinux.o + $(LD) -r $(patsubst %,$(TOPDIR)/%,$(BTOBJS)) \ + --start-group \ + $(patsubst %,$(TOPDIR)/%,$(BTLIBS)) \ + $(LIBS) \ + --end-group -o vmlinux.o btfix.s: btfixupprep vmlinux.o $(OBJDUMP) -x vmlinux.o | ./btfixupprep > btfix.s diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c index 8c8903d26..f0dbea065 100644 --- a/arch/sparc/kernel/ioport.c +++ b/arch/sparc/kernel/ioport.c @@ -695,42 +695,6 @@ _sparc_io_get_info(char *buf, char **start, off_t fpos, int length, int *eof, return p-buf; } -static struct proc_dir_entry _sparc_iomap_proc_entry = { - 0, /* Inode number - dynamic */ - 6, /* Length of the file name */ - "io_map", /* The file name */ - S_IFREG | S_IRUGO, /* File mode */ - 1, /* Number of links */ - 0, 0, /* The uid and gid for the file */ - 0, /* The size of the file reported by ls. */ - NULL, /* struct inode_operations * ops */ - NULL, /* get_info: backward compatibility */ - NULL, /* owner */ - NULL, NULL, NULL, /* linkage */ - &sparc_iomap, - _sparc_io_get_info, /* The read function for this file */ - NULL, - /* and more stuff */ -}; - -static struct proc_dir_entry _sparc_dvma_proc_entry = { - 0, /* Inode number - dynamic */ - 8, /* Length of the file name */ - "dvma_map", /* The file name */ - S_IFREG | S_IRUGO, /* File mode */ - 1, /* Number of links */ - 0, 0, /* The uid and gid for the file */ - 0, /* The size of the file reported by ls. */ - NULL, /* struct inode_operations * ops */ - NULL, /* get_info: backward compatibility */ - NULL, /* owner */ - NULL, NULL, NULL, /* linkage */ - &_sparc_dvma, - _sparc_io_get_info, - NULL, - /* some more stuff */ -}; - #endif CONFIG_PROC_FS /* @@ -782,7 +746,7 @@ void ioport_init(void) }; #ifdef CONFIG_PROC_FS - proc_register(&proc_root, &_sparc_iomap_proc_entry); - proc_register(&proc_root, &_sparc_dvma_proc_entry); + create_proc_read_entry("io_map",0,0,_sparc_io_get_info,&sparc_iomap); + create_proc_read_entry("dvma_map",0,0,_sparc_io_get_info,&_sparc_dvma); #endif } diff --git a/arch/sparc/kernel/irq.c b/arch/sparc/kernel/irq.c index 471929a01..07aefa660 100644 --- a/arch/sparc/kernel/irq.c +++ b/arch/sparc/kernel/irq.c @@ -1,4 +1,4 @@ -/* $Id: irq.c,v 1.101 2000/02/09 11:15:03 davem Exp $ +/* $Id: irq.c,v 1.102 2000/02/25 05:44:35 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 @@ -713,3 +713,8 @@ void __init init_IRQ(void) } btfixup(); } + +void init_irq_proc(void) +{ + /* For now, nothing... */ +} diff --git a/arch/sparc/kernel/setup.c b/arch/sparc/kernel/setup.c index 50d682929..d4ac34932 100644 --- a/arch/sparc/kernel/setup.c +++ b/arch/sparc/kernel/setup.c @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.114 2000/01/29 01:08:57 anton Exp $ +/* $Id: setup.c,v 1.115 2000/02/26 04:24:31 davem Exp $ * linux/arch/sparc/kernel/setup.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -294,6 +294,8 @@ static struct console prom_console = { "PROM", prom_cons_write, 0, 0, 0, 0, 0, CON_PRINTBUFFER, 0, 0, 0 }; +extern void paging_init(void); + void __init setup_arch(char **cmdline_p) { int i; @@ -478,6 +480,8 @@ void __init setup_arch(char **cmdline_p) if (serial_console) conswitchp = NULL; + + paging_init(); } asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on) diff --git a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c index cdc1f0751..d4585d9d5 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.91 2000/02/18 20:23:24 davem Exp $ +/* $Id: sparc_ksyms.c,v 1.93 2000/02/26 11:02:45 anton Exp $ * arch/sparc/kernel/ksyms.c: Sparc specific ksyms support. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -92,7 +92,6 @@ __attribute__((section("__ksymtab"))) = \ /* used by various drivers */ EXPORT_SYMBOL(sparc_cpu_model); -EXPORT_SYMBOL_PRIVATE(_spinlock_waitfor); EXPORT_SYMBOL(kernel_thread); #ifdef SPIN_LOCK_DEBUG EXPORT_SYMBOL(_do_spin_lock); @@ -246,7 +245,6 @@ EXPORT_SYMBOL(strrchr); EXPORT_SYMBOL(strpbrk); EXPORT_SYMBOL(strtok); EXPORT_SYMBOL(strstr); -EXPORT_SYMBOL(strspn); /* Special internal versions of library functions. */ EXPORT_SYMBOL(__copy_1page); diff --git a/arch/sparc/lib/locks.S b/arch/sparc/lib/locks.S index 102541b18..e199f3813 100644 --- a/arch/sparc/lib/locks.S +++ b/arch/sparc/lib/locks.S @@ -1,4 +1,4 @@ -/* $Id: locks.S,v 1.15 1998/10/14 09:18:55 jj Exp $ +/* $Id: locks.S,v 1.16 2000/02/26 11:02:47 anton Exp $ * locks.S: SMP low-level lock primitives on Sparc. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -15,25 +15,6 @@ .text .align 4 - /* This is called when the initial acquisition attempt of a spin - * lock fails. The calling convention is weird, return address - * is in %o7 as usual but we agree with the caller to only touch - * and use %g2 as a temporary. We are passed a ptr to the lock - * itself in %g1, %g4 must be restored into %o7 when we return, - * and the caller wants us to return to him at three instructions - * previous to the call instruction which got us here. See how - * this is used in asm/spinlock.h if what I just said confuses - * you to no end. - */ - .globl ___spinlock_waitfor -___spinlock_waitfor: -1: orcc %g2, 0x0, %g0 - bne,a 1b - ldub [%g1], %g2 - ldstub [%g1], %g2 - jmpl %o7 - 12, %g0 - mov %g4, %o7 - /* Read/writer locks, as usual this is overly clever to make it * as fast as possible. */ diff --git a/arch/sparc/mm/init.c b/arch/sparc/mm/init.c index 6736dc9d3..3ac49a10b 100644 --- a/arch/sparc/mm/init.c +++ b/arch/sparc/mm/init.c @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.80 2000/02/09 21:11:06 davem Exp $ +/* $Id: init.c,v 1.81 2000/02/26 11:59:31 anton Exp $ * linux/arch/sparc/mm/init.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -40,7 +40,7 @@ unsigned long phys_base; struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS]; unsigned long sparc_unmapped_base; -struct pgtable_cache_struct pgt_quicklists; +struct pgtable_cache_struct pgt_quicklists = { 0, 0, 0, 0, SPIN_LOCK_UNLOCKED, SPIN_LOCK_UNLOCKED }; /* References to section boundaries */ extern char __init_begin, __init_end, _start, end, etext , edata; diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig index 917bb5e74..12e9432a7 100644 --- a/arch/sparc64/defconfig +++ b/arch/sparc64/defconfig @@ -273,9 +273,9 @@ CONFIG_SUNBMAC=m CONFIG_SUNQE=m CONFIG_DE4X5=m CONFIG_VORTEX=m -CONFIG_RTL8139=m +CONFIG_8139TOO=m CONFIG_NE2K_PCI=m -CONFIG_EEXPRESS_PRO100=m +CONFIG_EEPRO100=m CONFIG_ADAPTEC_STARFIRE=m # @@ -299,7 +299,7 @@ CONFIG_VIDEO_DEV=y # CONFIG_VIDEO_BT848 is not set # -# Filesystems +# File systems # # CONFIG_QUOTA is not set CONFIG_AUTOFS_FS=m diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c index cb659b655..ed9e49685 100644 --- a/arch/sparc64/kernel/irq.c +++ b/arch/sparc64/kernel/irq.c @@ -1,4 +1,4 @@ -/* $Id: irq.c,v 1.83 2000/02/11 06:57:17 jj Exp $ +/* $Id: irq.c,v 1.84 2000/02/25 05:44:41 davem Exp $ * irq.c: UltraSparc IRQ handling/init/registry. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -1156,3 +1156,8 @@ void __init init_IRQ(void) : "i" (PSTATE_IE) : "g1"); } + +void init_irq_proc(void) +{ + /* For now, nothing... */ +} diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c index 0f280f818..ed2e8bd81 100644 --- a/arch/sparc64/kernel/setup.c +++ b/arch/sparc64/kernel/setup.c @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.50 1999/12/01 10:44:45 davem Exp $ +/* $Id: setup.c,v 1.51 2000/02/26 04:24:32 davem Exp $ * linux/arch/sparc64/kernel/setup.c * * Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu) @@ -451,6 +451,8 @@ void register_prom_callbacks(void) "' linux-.soft2 to .soft2"); } +extern void paging_init(void); + void __init setup_arch(char **cmdline_p) { extern int serial_console; /* in console.c, of course */ @@ -587,6 +589,8 @@ void __init setup_arch(char **cmdline_p) #endif if (serial_console) conswitchp = NULL; + + paging_init(); } asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on) diff --git a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c index f226a8ae5..8df2116e7 100644 --- a/arch/sparc64/kernel/signal32.c +++ b/arch/sparc64/kernel/signal32.c @@ -1,4 +1,4 @@ -/* $Id: signal32.c,v 1.59 2000/01/21 11:38:52 jj Exp $ +/* $Id: signal32.c,v 1.60 2000/02/25 06:02:37 jj Exp $ * arch/sparc64/kernel/signal32.c * * Copyright (C) 1991, 1992 Linus Torvalds @@ -126,6 +126,8 @@ int copy_siginfo_to_user32(siginfo_t32 *to, siginfo_t *from) err |= __put_user(from->si_pid, &to->si_pid); err |= __put_user(from->si_uid, &to->si_uid); break; + case SIGURG: + case SIGIO: case SIGSEGV: case SIGILL: case SIGFPE: diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c index ff3843651..f798358ce 100644 --- a/arch/sparc64/kernel/sparc64_ksyms.c +++ b/arch/sparc64/kernel/sparc64_ksyms.c @@ -1,4 +1,4 @@ -/* $Id: sparc64_ksyms.c,v 1.74 2000/02/09 11:15:07 davem Exp $ +/* $Id: sparc64_ksyms.c,v 1.75 2000/02/21 15:50:08 davem Exp $ * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -261,7 +261,6 @@ EXPORT_SYMBOL(strrchr); EXPORT_SYMBOL(strpbrk); EXPORT_SYMBOL(strtok); EXPORT_SYMBOL(strstr); -EXPORT_SYMBOL(strspn); #ifdef CONFIG_SOLARIS_EMUL_MODULE EXPORT_SYMBOL(getname32); diff --git a/arch/sparc64/lib/VIScsum.S b/arch/sparc64/lib/VIScsum.S index aad5d941a..9f77c8cb4 100644 --- a/arch/sparc64/lib/VIScsum.S +++ b/arch/sparc64/lib/VIScsum.S @@ -1,14 +1,15 @@ -/* $Id: VIScsum.S,v 1.5 1999/07/30 09:35:36 davem Exp $ +/* $Id: VIScsum.S,v 1.6 2000/02/20 23:21:39 davem Exp $ * VIScsum.S: High bandwidth IP checksumming utilizing the UltraSparc * Visual Instruction Set. * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 2000 David S. Miller (davem@redhat.com) * * Based on older sparc32/sparc64 checksum.S, which is: * * Copyright(C) 1995 Linus Torvalds * Copyright(C) 1995 Miguel de Icaza - * Copyright(C) 1996,1997 David S. Miller + * Copyright(C) 1996, 1997 David S. Miller * derived from: * Linux/Alpha checksum c-code * Linux/ix86 inline checksum assembly @@ -38,290 +39,290 @@ * tricks are UltraLinux trade secrets :)) */ -#define START_THE_TRICK(fz,f0,f2,f4,f6,f8,f10) \ - fcmpgt32 %fz, %f0, %g1 /* FPM Group */; \ - fcmpgt32 %fz, %f2, %g2 /* FPM Group */; \ - fcmpgt32 %fz, %f4, %g3 /* FPM Group */; \ - fcmpgt32 %fz, %f6, %g5 /* FPM Group */; \ - inc %g1 /* IEU0 */; \ - fcmpgt32 %fz, %f8, %g7 /* FPM Group */; \ - srl %g1, 1, %g1 /* IEU0 */; \ - inc %g2 /* IEU1 */; \ - fcmpgt32 %fz, %f10, %o3 /* FPM Group */; \ - srl %g2, 1, %g2 /* IEU0 */; \ - add %o2, %g1, %o2 /* IEU1 */; \ - add %g3, 1, %g3 /* IEU0 Group */; \ - srl %g3, 1, %g3 /* IEU0 Group */; \ - add %o2, %g2, %o2 /* IEU1 */; \ - inc %g5 /* IEU0 Group */; \ - add %o2, %g3, %o2 /* IEU1 */; +#define START_THE_TRICK(fz,f0,f2,f4,f6,f8,f10) \ + fcmpgt32 %fz, %f0, %g1 /* FPM Group */; \ + fcmpgt32 %fz, %f2, %g2 /* FPM Group */; \ + fcmpgt32 %fz, %f4, %g3 /* FPM Group */; \ + inc %g1 /* IEU0 Group */; \ + fcmpgt32 %fz, %f6, %g5 /* FPM */; \ + srl %g1, 1, %g1 /* IEU0 Group */; \ + fcmpgt32 %fz, %f8, %g7 /* FPM */; \ + inc %g2 /* IEU0 Group */; \ + fcmpgt32 %fz, %f10, %o3 /* FPM */; \ + srl %g2, 1, %g2 /* IEU0 Group */; \ + inc %g3 /* IEU1 */; \ + srl %g3, 1, %g3 /* IEU0 Group */; \ + add %o2, %g1, %o2 /* IEU1 */; \ + add %o2, %g2, %o2 /* IEU0 Group */; \ + inc %g5 /* IEU1 */; \ + add %o2, %g3, %o2 /* IEU0 Group */; -#define DO_THE_TRICK(O12,O14,f0,f2,f4,f6,f8,f10,f12,f14,F0,F2,F4,F6,F8,F10,F12,F14) \ - fcmpgt32 %O12, %f12, %o4 /* FPM Group */; \ - srl %g5, 1, %g5 /* IEU0 */; \ - inc %g7 /* IEU1 */; \ - fpadd32 %F0, %f0, %F0 /* FPA */; \ - fcmpgt32 %O14, %f14, %o5 /* FPM Group */; \ - srl %g7, 1, %g7 /* IEU0 */; \ - add %o2, %g5, %o2 /* IEU1 */; \ - fpadd32 %F2, %f2, %F2 /* FPA */; \ - inc %o3 /* IEU0 Group */; \ - add %o2, %g7, %o2 /* IEU1 */; \ - fcmpgt32 %f0, %F0, %g1 /* FPM Group */; \ - srl %o3, 1, %o3 /* IEU0 */; \ - inc %o4 /* IEU1 */; \ - fpadd32 %F4, %f4, %F4 /* FPA */; \ - fcmpgt32 %f2, %F2, %g2 /* FPM Group */; \ - srl %o4, 1, %o4 /* IEU0 */; \ - add %o2, %o3, %o2 /* IEU1 */; \ - fpadd32 %F6, %f6, %F6 /* FPA */; \ - inc %o5 /* IEU0 Group */; \ - add %o2, %o4, %o2 /* IEU1 */; \ - fcmpgt32 %f4, %F4, %g3 /* FPM Group */; \ - srl %o5, 1, %o5 /* IEU0 */; \ - inc %g1 /* IEU1 */; \ - fpadd32 %F8, %f8, %F8 /* FPA */; \ - fcmpgt32 %f6, %F6, %g5 /* FPM Group */; \ - srl %g1, 1, %g1 /* IEU0 */; \ - add %o2, %o5, %o2 /* IEU1 */; \ - fpadd32 %F10, %f10, %F10 /* FPA */; \ - inc %g2 /* IEU0 Group */; \ - add %o2, %g1, %o2 /* IEU1 */; \ - fcmpgt32 %f8, %F8, %g7 /* FPM Group */; \ - srl %g2, 1, %g2 /* IEU0 */; \ - inc %g3 /* IEU1 */; \ - fpadd32 %F12, %f12, %F12 /* FPA */; \ - fcmpgt32 %f10, %F10, %o3 /* FPM Group */; \ - srl %g3, 1, %g3 /* IEU0 */; \ - add %o2, %g2, %o2 /* IEU1 */; \ - fpadd32 %F14, %f14, %F14 /* FPA */; \ - inc %g5 /* IEU0 Group */; \ - add %o2, %g3, %o2 /* IEU1 */; +#define DO_THE_TRICK(O12,O14,f0,f2,f4,f6,f8,f10,f12,f14,F0,F2,F4,F6,F8,F10,F12,F14) \ + srl %g5, 1, %g5 /* IEU0 Group */; \ + fpadd32 %F0, %f0, %F0 /* FPA */; \ + fcmpgt32 %O12, %f12, %o4 /* FPM */; \ + inc %g7 /* IEU0 Group */; \ + fpadd32 %F2, %f2, %F2 /* FPA */; \ + fcmpgt32 %O14, %f14, %o5 /* FPM */; \ + add %o2, %g5, %o2 /* IEU1 Group */; \ + fpadd32 %F4, %f4, %F4 /* FPA */; \ + fcmpgt32 %f0, %F0, %g1 /* FPM */; \ + srl %g7, 1, %g7 /* IEU0 Group */; \ + fpadd32 %F6, %f6, %F6 /* FPA */; \ + fcmpgt32 %f2, %F2, %g2 /* FPM */; \ + add %o2, %g7, %o2 /* IEU0 Group */; \ + fpadd32 %F8, %f8, %F8 /* FPA */; \ + fcmpgt32 %f4, %F4, %g3 /* FPM */; \ + inc %o3 /* IEU0 Group */; \ + fpadd32 %F10, %f10, %F10 /* FPA */; \ + fcmpgt32 %f6, %F6, %g5 /* FPM */; \ + srl %o3, 1, %o3 /* IEU0 Group */; \ + fpadd32 %F12, %f12, %F12 /* FPA */; \ + fcmpgt32 %f8, %F8, %g7 /* FPM */; \ + add %o2, %o3, %o2 /* IEU0 Group */; \ + fpadd32 %F14, %f14, %F14 /* FPA */; \ + fcmpgt32 %f10, %F10, %o3 /* FPM */; \ + inc %o4 /* IEU0 Group */; \ + inc %o5 /* IEU1 */; \ + srl %o4, 1, %o4 /* IEU0 Group */; \ + inc %g1 /* IEU1 */; \ + srl %o5, 1, %o5 /* IEU0 Group */; \ + add %o2, %o4, %o2 /* IEU1 */; \ + srl %g1, 1, %g1 /* IEU0 Group */; \ + add %o2, %o5, %o2 /* IEU1 */; \ + inc %g2 /* IEU0 Group */; \ + add %o2, %g1, %o2 /* IEU1 */; \ + srl %g2, 1, %g2 /* IEU0 Group */; \ + inc %g3 /* IEU1 */; \ + srl %g3, 1, %g3 /* IEU0 Group */; \ + add %o2, %g2, %o2 /* IEU1 */; \ + inc %g5 /* IEU0 Group */; \ + add %o2, %g3, %o2 /* IEU0 */; -#define END_THE_TRICK(O12,O14,f0,f2,f4,f6,f8,f10,f12,f14,S0,S1,S2,S3,T0,T1,U0,fz) \ - fcmpgt32 %O12, %f12, %o4 /* FPM Group */; \ - srl %g5, 1, %g5 /* IEU0 */; \ - inc %g7 /* IEU1 */; \ - fpadd32 %f2, %f0, %S0 /* FPA */; \ - fcmpgt32 %O14, %f14, %o5 /* FPM Group */; \ - srl %g7, 1, %g7 /* IEU0 */; \ - add %o2, %g5, %o2 /* IEU1 */; \ - fpadd32 %f6, %f4, %S1 /* FPA */; \ - inc %o3 /* IEU0 Group */; \ - add %o2, %g7, %o2 /* IEU1 */; \ - fcmpgt32 %f0, %S0, %g1 /* FPM Group */; \ - srl %o3, 1, %o3 /* IEU0 */; \ - inc %o4 /* IEU1 */; \ - fpadd32 %f10, %f8, %S2 /* FPA */; \ - fcmpgt32 %f4, %S1, %g2 /* FPM Group */; \ - srl %o4, 1, %o4 /* IEU0 */; \ - add %o2, %o3, %o2 /* IEU1 */; \ - fpadd32 %f14, %f12, %S3 /* FPA */; \ - inc %o5 /* IEU0 Group */; \ - add %o2, %o4, %o2 /* IEU1 */; \ - fzero %fz /* FPA */; \ - fcmpgt32 %f8, %S2, %g3 /* FPM Group */; \ - srl %o5, 1, %o5 /* IEU0 */; \ - inc %g1 /* IEU1 */; \ - fpadd32 %S0, %S1, %T0 /* FPA */; \ - fcmpgt32 %f12, %S3, %g5 /* FPM Group */; \ - srl %g1, 1, %g1 /* IEU0 */; \ - add %o2, %o5, %o2 /* IEU1 */; \ - fpadd32 %S2, %S3, %T1 /* FPA */; \ - inc %g2 /* IEU0 Group */; \ - add %o2, %g1, %o2 /* IEU1 */; \ - fcmpgt32 %S0, %T0, %g7 /* FPM Group */; \ - srl %g2, 1, %g2 /* IEU0 */; \ - inc %g3 /* IEU1 */; \ - fcmpgt32 %S2, %T1, %o3 /* FPM Group */; \ - srl %g3, 1, %g3 /* IEU0 */; \ - add %o2, %g2, %o2 /* IEU1 */; \ - inc %g5 /* IEU0 Group */; \ - add %o2, %g3, %o2 /* IEU1 */; \ - fcmpgt32 %fz, %f2, %o4 /* FPM Group */; \ - srl %g5, 1, %g5 /* IEU0 */; \ - inc %g7 /* IEU1 */; \ - fpadd32 %T0, %T1, %U0 /* FPA */; \ - fcmpgt32 %fz, %f6, %o5 /* FPM Group */; \ - srl %g7, 1, %g7 /* IEU0 */; \ - add %o2, %g5, %o2 /* IEU1 */; \ - inc %o3 /* IEU0 Group */; \ - add %o2, %g7, %o2 /* IEU1 */; \ - fcmpgt32 %fz, %f10, %g1 /* FPM Group */; \ - srl %o3, 1, %o3 /* IEU0 */; \ - inc %o4 /* IEU1 */; \ - fcmpgt32 %fz, %f14, %g2 /* FPM Group */; \ - srl %o4, 1, %o4 /* IEU0 */; \ - add %o2, %o3, %o2 /* IEU1 */; \ - std %U0, [%sp + STACKOFF] /* Store Group */; \ - inc %o5 /* IEU0 */; \ - sub %o2, %o4, %o2 /* IEU1 */; \ - fcmpgt32 %fz, %S1, %g3 /* FPM Group */; \ - srl %o5, 1, %o5 /* IEU0 */; \ - inc %g1 /* IEU1 */; \ - fcmpgt32 %fz, %S3, %g5 /* FPM Group */; \ - srl %g1, 1, %g1 /* IEU0 */; \ - sub %o2, %o5, %o2 /* IEU1 */; \ - ldx [%sp + STACKOFF], %o5 /* Load Group */; \ - inc %g2 /* IEU0 */; \ - sub %o2, %g1, %o2 /* IEU1 */; \ - fcmpgt32 %fz, %T1, %g7 /* FPM Group */; \ - srl %g2, 1, %g2 /* IEU0 */; \ - inc %g3 /* IEU1 */; \ - fcmpgt32 %T0, %U0, %o3 /* FPM Group */; \ - srl %g3, 1, %g3 /* IEU0 */; \ - sub %o2, %g2, %o2 /* IEU1 */; \ - inc %g5 /* IEU0 Group */; \ - sub %o2, %g3, %o2 /* IEU1 */; \ - fcmpgt32 %fz, %U0, %o4 /* FPM Group */; \ - srl %g5, 1, %g5 /* IEU0 */; \ - inc %g7 /* IEU1 */; \ - srl %g7, 1, %g7 /* IEU0 Group */; \ - sub %o2, %g5, %o2 /* IEU1 */; \ - inc %o3 /* IEU0 Group */; \ - sub %o2, %g7, %o2 /* IEU1 */; \ - srl %o3, 1, %o3 /* IEU0 Group */; \ - inc %o4 /* IEU1 */; \ - srl %o4, 1, %o4 /* IEU0 Group */; \ - add %o2, %o3, %o2 /* IEU1 */; \ - sub %o2, %o4, %o2 /* IEU0 Group */; \ - addcc %o2, %o5, %o2 /* IEU1 Group */; \ - bcs,a,pn %xcc, 33f /* CTI */; \ - add %o2, 1, %o2 /* IEU0 */; \ -33: /* That's it */; +#define END_THE_TRICK(O12,O14,f0,f2,f4,f6,f8,f10,f12,f14,S0,S1,S2,S3,T0,T1,U0,fz) \ + srl %g5, 1, %g5 /* IEU0 Group */; \ + fpadd32 %f2, %f0, %S0 /* FPA */; \ + fcmpgt32 %O12, %f12, %o4 /* FPM */; \ + inc %g7 /* IEU0 Group */; \ + fpadd32 %f6, %f4, %S1 /* FPA */; \ + fcmpgt32 %O14, %f14, %o5 /* FPM */; \ + srl %g7, 1, %g7 /* IEU0 Group */; \ + fpadd32 %f10, %f8, %S2 /* FPA */; \ + fcmpgt32 %f0, %S0, %g1 /* FPM */; \ + inc %o3 /* IEU0 Group */; \ + fpadd32 %f14, %f12, %S3 /* FPA */; \ + fcmpgt32 %f4, %S1, %g2 /* FPM */; \ + add %o2, %g5, %o2 /* IEU0 Group */; \ + fpadd32 %S0, %S1, %T0 /* FPA */; \ + fcmpgt32 %f8, %S2, %g3 /* FPM */; \ + add %o2, %g7, %o2 /* IEU0 Group */; \ + fzero %fz /* FPA */; \ + fcmpgt32 %f12, %S3, %g5 /* FPM */; \ + srl %o3, 1, %o3 /* IEU0 Group */; \ + fpadd32 %S2, %S3, %T1 /* FPA */; \ + fcmpgt32 %S0, %T0, %g7 /* FPM */; \ + add %o2, %o3, %o2 /* IEU0 Group */; \ + fpadd32 %T0, %T1, %U0 /* FPA */; \ + fcmpgt32 %S2, %T1, %o3 /* FPM */; \ + inc %o4 /* IEU0 Group */; \ + inc %o5 /* IEU1 */; \ + srl %o4, 1, %o4 /* IEU0 Group */; \ + inc %g1 /* IEU1 */; \ + add %o2, %o4, %o2 /* IEU0 Group */; \ + fcmpgt32 %fz, %f2, %o4 /* FPM */; \ + srl %o5, 1, %o5 /* IEU0 Group */; \ + inc %g2 /* IEU1 */; \ + add %o2, %o5, %o2 /* IEU0 Group */; \ + fcmpgt32 %fz, %f6, %o5 /* FPM */; \ + srl %g1, 1, %g1 /* IEU0 Group */; \ + inc %g3 /* IEU1 */; \ + add %o2, %g1, %o2 /* IEU0 Group */; \ + fcmpgt32 %fz, %f10, %g1 /* FPM */; \ + srl %g2, 1, %g2 /* IEU0 Group */; \ + inc %g5 /* IEU1 */; \ + add %o2, %g2, %o2 /* IEU0 Group */; \ + fcmpgt32 %fz, %f14, %g2 /* FPM */; \ + srl %g3, 1, %g3 /* IEU0 Group */; \ + inc %g7 /* IEU1 */; \ + add %o2, %g3, %o2 /* IEU0 Group */; \ + fcmpgt32 %fz, %S1, %g3 /* FPM */; \ + srl %g5, 1, %g5 /* IEU0 Group */; \ + inc %o3 /* IEU1 */; \ + add %o2, %g5, %o2 /* IEU0 Group */; \ + fcmpgt32 %fz, %S3, %g5 /* FPM */; \ + srl %g7, 1, %g7 /* IEU0 Group */; \ + inc %o4 /* IEU1 */; \ + add %o2, %g7, %o2 /* IEU0 Group */; \ + fcmpgt32 %fz, %T1, %g7 /* FPM */; \ + srl %o3, 1, %o3 /* IEU0 Group */; \ + inc %o5 /* IEU1 */; \ + add %o2, %o3, %o2 /* IEU0 Group */; \ + fcmpgt32 %T0, %U0, %o3 /* FPM */; \ + srl %o4, 1, %o4 /* IEU0 Group */; \ + inc %g1 /* IEU1 */; \ + sub %o2, %o4, %o2 /* IEU0 Group */; \ + fcmpgt32 %fz, %U0, %o4 /* FPM */; \ + srl %o5, 1, %o5 /* IEU0 Group */; \ + inc %g2 /* IEU1 */; \ + srl %g1, 1, %g1 /* IEU0 Group */; \ + sub %o2, %o5, %o2 /* IEU1 */; \ + std %U0, [%sp + STACKOFF] /* Store */; \ + srl %g2, 1, %g2 /* IEU0 Group */; \ + sub %o2, %g1, %o2 /* IEU1 */; \ + inc %g3 /* IEU0 Group */; \ + sub %o2, %g2, %o2 /* IEU1 */; \ + srl %g3, 1, %g3 /* IEU0 Group */; \ + inc %g5 /* IEU1 */; \ + srl %g5, 1, %g5 /* IEU0 Group */; \ + sub %o2, %g3, %o2 /* IEU1 */; \ + ldx [%sp + STACKOFF], %o5 /* Load Group */; \ + inc %g7 /* IEU0 */; \ + sub %o2, %g5, %o2 /* IEU1 */; \ + srl %g7, 1, %g7 /* IEU0 Group */; \ + inc %o3 /* IEU1 */; \ + srl %o3, 1, %o3 /* IEU0 Group */; \ + sub %o2, %g7, %o2 /* IEU1 */; \ + inc %o4 /* IEU0 Group */; \ + add %o2, %o3, %o2 /* IEU1 */; \ + srl %o4, 1, %o4 /* IEU0 Group */; \ + sub %o2, %o4, %o2 /* IEU0 Group */; \ + addcc %o2, %o5, %o2 /* IEU1 Group */; \ + bcs,a,pn %xcc, 33f /* CTI */; \ + add %o2, 1, %o2 /* IEU0 */; \ +33: /* That's it */; -#define CSUM_LASTCHUNK(offset) \ - ldx [%o0 - offset - 0x10], %g2; \ - ldx [%o0 - offset - 0x08], %g3; \ - addcc %g2, %o2, %o2; \ - bcs,a,pn %xcc, 31f; \ - add %o2, 1, %o2; \ -31: addcc %g3, %o2, %o2; \ - bcs,a,pn %xcc, 32f; \ - add %o2, 1, %o2; \ +#define CSUM_LASTCHUNK(offset) \ + ldx [%o0 - offset - 0x10], %g2; \ + ldx [%o0 - offset - 0x08], %g3; \ + addcc %g2, %o2, %o2; \ + bcs,a,pn %xcc, 31f; \ + add %o2, 1, %o2; \ +31: addcc %g3, %o2, %o2; \ + bcs,a,pn %xcc, 32f; \ + add %o2, 1, %o2; \ 32: .text .globl csum_partial .align 32 csum_partial: - andcc %o0, 7, %g0 /* IEU1 Group */ - be,pt %icc, 4f /* CTI */ - andcc %o0, 0x38, %g3 /* IEU1 */ - mov 1, %g5 /* IEU0 Group */ - cmp %o1, 6 /* IEU1 */ - bl,pn %icc, 21f /* CTI */ - andcc %o0, 2, %g0 /* IEU1 Group */ - be,pt %icc, 1f /* CTI */ - and %o0, 4, %g7 /* IEU0 */ - lduh [%o0], %g2 /* Load */ - sub %o1, 2, %o1 /* IEU0 Group */ - add %o0, 2, %o0 /* IEU1 */ - andcc %o0, 4, %g7 /* IEU1 Group */ - sll %g5, 16, %g5 /* IEU0 */ - sll %g2, 16, %g2 /* IEU0 Group */ - addcc %g2, %o2, %o2 /* IEU1 Group (regdep) */ - bcs,a,pn %icc, 1f /* CTI */ - add %o2, %g5, %o2 /* IEU0 */ -1: ld [%o0], %g2 /* Load */ - brz,a,pn %g7, 4f /* CTI+IEU1 Group */ - and %o0, 0x38, %g3 /* IEU0 */ - add %o0, 4, %o0 /* IEU0 Group */ - sub %o1, 4, %o1 /* IEU1 */ - addcc %g2, %o2, %o2 /* IEU1 Group */ - bcs,a,pn %icc, 1f /* CTI */ - add %o2, 1, %o2 /* IEU0 */ -1: and %o0, 0x38, %g3 /* IEU1 Group */ -4: srl %o2, 0, %o2 /* IEU0 Group */ - mov 0x40, %g1 /* IEU1 */ - brz,pn %g3, 3f /* CTI+IEU1 Group */ - sub %g1, %g3, %g1 /* IEU0 */ - cmp %o1, 56 /* IEU1 Group */ - blu,pn %icc, 20f /* CTI */ - andcc %o0, 8, %g0 /* IEU1 Group */ - be,pn %icc, 1f /* CTI */ - ldx [%o0], %g2 /* Load */ - add %o0, 8, %o0 /* IEU0 Group */ - sub %o1, 8, %o1 /* IEU1 */ - addcc %g2, %o2, %o2 /* IEU1 Group */ - bcs,a,pn %xcc, 1f /* CTI */ - add %o2, 1, %o2 /* IEU0 */ -1: andcc %g1, 0x10, %g0 /* IEU1 Group */ - be,pn %icc, 2f /* CTI */ - and %g1, 0x20, %g1 /* IEU0 */ - ldx [%o0], %g2 /* Load */ - ldx [%o0+8], %g3 /* Load Group */ - add %o0, 16, %o0 /* IEU0 */ - sub %o1, 16, %o1 /* IEU1 */ - addcc %g2, %o2, %o2 /* IEU1 Group */ - bcs,a,pn %xcc, 1f /* CTI */ - add %o2, 1, %o2 /* IEU0 */ -1: addcc %g3, %o2, %o2 /* IEU1 Group */ - bcs,a,pn %xcc, 2f /* CTI */ - add %o2, 1, %o2 /* IEU0 */ -2: brz,pn %g1, 3f /* CTI+IEU1 Group */ - ldx [%o0], %g2 /* Load */ - ldx [%o0+8], %g3 /* Load Group */ - ldx [%o0+16], %g5 /* Load Group */ - ldx [%o0+24], %g7 /* Load Group */ - add %o0, 32, %o0 /* IEU0 */ - sub %o1, 32, %o1 /* IEU1 */ - addcc %g2, %o2, %o2 /* IEU1 Group */ - bcs,a,pn %xcc, 1f /* CTI */ - add %o2, 1, %o2 /* IEU0 */ -1: addcc %g3, %o2, %o2 /* IEU1 Group */ - bcs,a,pn %xcc, 1f /* CTI */ - add %o2, 1, %o2 /* IEU0 */ -1: addcc %g5, %o2, %o2 /* IEU1 Group */ - bcs,a,pn %xcc, 1f /* CTI */ - add %o2, 1, %o2 /* IEU0 */ -1: addcc %g7, %o2, %o2 /* IEU1 Group */ - bcs,a,pn %xcc, 3f /* CTI */ - add %o2, 1, %o2 /* IEU0 */ -3: cmp %o1, 0xc0 /* IEU1 Group */ - blu,pn %icc, 20f /* CTI */ - sllx %o2, 32, %g5 /* IEU0 */ + andcc %o0, 7, %g0 /* IEU1 Group */ + be,pt %icc, 4f /* CTI */ + andcc %o0, 0x38, %g3 /* IEU1 */ + mov 1, %g5 /* IEU0 Group */ + cmp %o1, 6 /* IEU1 */ + bl,pn %icc, 21f /* CTI */ + andcc %o0, 2, %g0 /* IEU1 Group */ + be,pt %icc, 1f /* CTI */ + and %o0, 4, %g7 /* IEU0 */ + lduh [%o0], %g2 /* Load */ + sub %o1, 2, %o1 /* IEU0 Group */ + add %o0, 2, %o0 /* IEU1 */ + andcc %o0, 4, %g7 /* IEU1 Group */ + sll %g5, 16, %g5 /* IEU0 */ + sll %g2, 16, %g2 /* IEU0 Group */ + addcc %g2, %o2, %o2 /* IEU1 Group (regdep) */ + bcs,a,pn %icc, 1f /* CTI */ + add %o2, %g5, %o2 /* IEU0 */ +1: ld [%o0], %g2 /* Load */ + brz,a,pn %g7, 4f /* CTI+IEU1 Group */ + and %o0, 0x38, %g3 /* IEU0 */ + add %o0, 4, %o0 /* IEU0 Group */ + sub %o1, 4, %o1 /* IEU1 */ + addcc %g2, %o2, %o2 /* IEU1 Group */ + bcs,a,pn %icc, 1f /* CTI */ + add %o2, 1, %o2 /* IEU0 */ +1: and %o0, 0x38, %g3 /* IEU1 Group */ +4: srl %o2, 0, %o2 /* IEU0 Group */ + mov 0x40, %g1 /* IEU1 */ + brz,pn %g3, 3f /* CTI+IEU1 Group */ + sub %g1, %g3, %g1 /* IEU0 */ + cmp %o1, 56 /* IEU1 Group */ + blu,pn %icc, 20f /* CTI */ + andcc %o0, 8, %g0 /* IEU1 Group */ + be,pn %icc, 1f /* CTI */ + ldx [%o0], %g2 /* Load */ + add %o0, 8, %o0 /* IEU0 Group */ + sub %o1, 8, %o1 /* IEU1 */ + addcc %g2, %o2, %o2 /* IEU1 Group */ + bcs,a,pn %xcc, 1f /* CTI */ + add %o2, 1, %o2 /* IEU0 */ +1: andcc %g1, 0x10, %g0 /* IEU1 Group */ + be,pn %icc, 2f /* CTI */ + and %g1, 0x20, %g1 /* IEU0 */ + ldx [%o0], %g2 /* Load */ + ldx [%o0+8], %g3 /* Load Group */ + add %o0, 16, %o0 /* IEU0 */ + sub %o1, 16, %o1 /* IEU1 */ + addcc %g2, %o2, %o2 /* IEU1 Group */ + bcs,a,pn %xcc, 1f /* CTI */ + add %o2, 1, %o2 /* IEU0 */ +1: addcc %g3, %o2, %o2 /* IEU1 Group */ + bcs,a,pn %xcc, 2f /* CTI */ + add %o2, 1, %o2 /* IEU0 */ +2: brz,pn %g1, 3f /* CTI+IEU1 Group */ + ldx [%o0], %g2 /* Load */ + ldx [%o0+8], %g3 /* Load Group */ + ldx [%o0+16], %g5 /* Load Group */ + ldx [%o0+24], %g7 /* Load Group */ + add %o0, 32, %o0 /* IEU0 */ + sub %o1, 32, %o1 /* IEU1 */ + addcc %g2, %o2, %o2 /* IEU1 Group */ + bcs,a,pn %xcc, 1f /* CTI */ + add %o2, 1, %o2 /* IEU0 */ +1: addcc %g3, %o2, %o2 /* IEU1 Group */ + bcs,a,pn %xcc, 1f /* CTI */ + add %o2, 1, %o2 /* IEU0 */ +1: addcc %g5, %o2, %o2 /* IEU1 Group */ + bcs,a,pn %xcc, 1f /* CTI */ + add %o2, 1, %o2 /* IEU0 */ +1: addcc %g7, %o2, %o2 /* IEU1 Group */ + bcs,a,pn %xcc, 3f /* CTI */ + add %o2, 1, %o2 /* IEU0 */ +3: cmp %o1, 0xc0 /* IEU1 Group */ + blu,pn %icc, 20f /* CTI */ + sllx %o2, 32, %g5 /* IEU0 */ #ifdef __KERNEL__ VISEntry #endif - addcc %o2, %g5, %o2 /* IEU1 Group */ - sub %o1, 0xc0, %o1 /* IEU0 */ - wr %g0, ASI_BLK_P, %asi /* LSU Group */ - membar #StoreLoad /* LSU Group */ - srlx %o2, 32, %o2 /* IEU0 Group */ - bcs,a,pn %xcc, 1f /* CTI */ - add %o2, 1, %o2 /* IEU1 */ -1: andcc %o1, 0x80, %g0 /* IEU1 Group */ - bne,pn %icc, 7f /* CTI */ - andcc %o1, 0x40, %g0 /* IEU1 Group */ - be,pn %icc, 6f /* CTI */ - fzero %f12 /* FPA */ - fzero %f14 /* FPA Group */ + addcc %o2, %g5, %o2 /* IEU1 Group */ + sub %o1, 0xc0, %o1 /* IEU0 */ + wr %g0, ASI_BLK_P, %asi /* LSU Group */ + membar #StoreLoad /* LSU Group */ + srlx %o2, 32, %o2 /* IEU0 Group */ + bcs,a,pn %xcc, 1f /* CTI */ + add %o2, 1, %o2 /* IEU1 */ +1: andcc %o1, 0x80, %g0 /* IEU1 Group */ + bne,pn %icc, 7f /* CTI */ + andcc %o1, 0x40, %g0 /* IEU1 Group */ + be,pn %icc, 6f /* CTI */ + fzero %f12 /* FPA */ + fzero %f14 /* FPA Group */ ldda [%o0 + 0x000] %asi, %f16 ldda [%o0 + 0x040] %asi, %f32 ldda [%o0 + 0x080] %asi, %f48 START_THE_TRICK(f12,f16,f18,f20,f22,f24,f26) ba,a,pt %xcc, 3f -6: sub %o0, 0x40, %o0 /* IEU0 Group */ - fzero %f28 /* FPA */ - fzero %f30 /* FPA Group */ +6: sub %o0, 0x40, %o0 /* IEU0 Group */ + fzero %f28 /* FPA */ + fzero %f30 /* FPA Group */ ldda [%o0 + 0x040] %asi, %f32 ldda [%o0 + 0x080] %asi, %f48 ldda [%o0 + 0x0c0] %asi, %f0 START_THE_TRICK(f28,f32,f34,f36,f38,f40,f42) ba,a,pt %xcc, 4f -7: bne,pt %icc, 8f /* CTI */ - fzero %f44 /* FPA */ - add %o0, 0x40, %o0 /* IEU0 Group */ - fzero %f60 /* FPA */ - fzero %f62 /* FPA Group */ +7: bne,pt %icc, 8f /* CTI */ + fzero %f44 /* FPA */ + add %o0, 0x40, %o0 /* IEU0 Group */ + fzero %f60 /* FPA */ + fzero %f62 /* FPA Group */ ldda [%o0 - 0x040] %asi, %f0 ldda [%o0 + 0x000] %asi, %f16 ldda [%o0 + 0x040] %asi, %f32 START_THE_TRICK(f60,f0,f2,f4,f6,f8,f10) ba,a,pt %xcc, 2f -8: add %o0, 0x80, %o0 /* IEU0 Group */ - fzero %f46 /* FPA */ +8: add %o0, 0x80, %o0 /* IEU0 Group */ + fzero %f46 /* FPA */ ldda [%o0 - 0x080] %asi, %f48 ldda [%o0 - 0x040] %asi, %f0 ldda [%o0 + 0x000] %asi, %f16 @@ -333,36 +334,36 @@ csum_partial: 3: DO_THE_TRICK(f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46) ldda [%o0 + 0x0c0] %asi, %f0 4: DO_THE_TRICK(f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,f48,f50,f52,f54,f56,f58,f60,f62) - add %o0, 0x100, %o0 /* IEU0 Group */ - subcc %o1, 0x100, %o1 /* IEU1 */ - bgeu,a,pt %icc, 1b /* CTI */ + add %o0, 0x100, %o0 /* IEU0 Group */ + subcc %o1, 0x100, %o1 /* IEU1 */ + bgeu,a,pt %icc, 1b /* CTI */ ldda [%o0 + 0x000] %asi, %f16 - membar #Sync /* LSU Group */ + membar #Sync /* LSU Group */ DO_THE_TRICK(f44,f46,f48,f50,f52,f54,f56,f58,f60,f62,f0,f2,f4,f6,f8,f10,f12,f14) END_THE_TRICK(f60,f62,f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30) #ifdef __KERNEL__ ldub [%g6 + AOFF_task_thread + AOFF_thread_current_ds], %g7 #endif - and %o1, 0x3f, %o1 /* IEU0 Group */ + and %o1, 0x3f, %o1 /* IEU0 Group */ #ifdef __KERNEL__ VISExit wr %g7, %g0, %asi #endif -20: andcc %o1, 0xf0, %g1 /* IEU1 Group */ - be,pn %icc, 23f /* CTI */ - and %o1, 0xf, %o3 /* IEU0 */ +20: andcc %o1, 0xf0, %g1 /* IEU1 Group */ + be,pn %icc, 23f /* CTI */ + and %o1, 0xf, %o3 /* IEU0 */ #ifdef __KERNEL__ -22: sll %g1, 1, %o4 /* IEU0 Group */ - sethi %hi(23f), %g7 /* IEU1 */ - sub %g7, %o4, %g7 /* IEU0 Group */ - jmpl %g7 + %lo(23f), %g0 /* CTI Group brk forced */ - add %o0, %g1, %o0 /* IEU0 */ +22: sll %g1, 1, %o4 /* IEU0 Group */ + sethi %hi(23f), %g7 /* IEU1 */ + sub %g7, %o4, %g7 /* IEU0 Group */ + jmpl %g7 + %lo(23f), %g0 /* CTI Group brk forced*/ + add %o0, %g1, %o0 /* IEU0 */ #else -22: rd %pc, %g7 /* LSU Group+4bubbles */ - sll %g1, 1, %o4 /* IEU0 Group */ - sub %g7, %o4, %g7 /* IEU0 Group (regdep) */ - jmpl %g7 + (23f - 22b), %g0 /* CTI Group brk forced */ - add %o0, %g1, %o0 /* IEU0 */ +22: rd %pc, %g7 /* LSU Group+4bubbles */ + sll %g1, 1, %o4 /* IEU0 Group */ + sub %g7, %o4, %g7 /* IEU0 Group (regdep) */ + jmpl %g7 + (23f - 22b), %g0 /* CTI Group brk forced*/ + add %o0, %g1, %o0 /* IEU0 */ #endif CSUM_LASTCHUNK(0xe0) CSUM_LASTCHUNK(0xd0) @@ -379,72 +380,72 @@ csum_partial: CSUM_LASTCHUNK(0x20) CSUM_LASTCHUNK(0x10) CSUM_LASTCHUNK(0x00) -23: brnz,pn %o3, 26f /* CTI+IEU1 Group */ -24: sllx %o2, 32, %g1 /* IEU0 */ -25: addcc %o2, %g1, %o0 /* IEU1 Group */ - srlx %o0, 32, %o0 /* IEU0 Group (regdep) */ - bcs,a,pn %xcc, 1f /* CTI */ - add %o0, 1, %o0 /* IEU1 */ -1: retl /* CTI Group brk forced */ - srl %o0, 0, %o0 /* IEU0 */ -26: andcc %o1, 8, %g0 /* IEU1 Group */ - be,pn %icc, 1f /* CTI */ - ldx [%o0], %g3 /* Load */ - add %o0, 8, %o0 /* IEU0 Group */ - addcc %g3, %o2, %o2 /* IEU1 Group */ - bcs,a,pn %xcc, 1f /* CTI */ - add %o2, 1, %o2 /* IEU0 */ -1: andcc %o1, 4, %g0 /* IEU1 Group */ - be,a,pn %icc, 1f /* CTI */ - clr %g2 /* IEU0 */ - ld [%o0], %g2 /* Load */ - add %o0, 4, %o0 /* IEU0 Group */ - sllx %g2, 32, %g2 /* IEU0 Group */ -1: andcc %o1, 2, %g0 /* IEU1 */ - be,a,pn %icc, 1f /* CTI */ - clr %o4 /* IEU0 Group */ - lduh [%o0], %o4 /* Load */ - add %o0, 2, %o0 /* IEU1 */ - sll %o4, 16, %o4 /* IEU0 Group */ -1: andcc %o1, 1, %g0 /* IEU1 */ - be,a,pn %icc, 1f /* CTI */ - clr %o5 /* IEU0 Group */ - ldub [%o0], %o5 /* Load */ - sll %o5, 8, %o5 /* IEU0 Group */ -1: or %g2, %o4, %o4 /* IEU1 */ - or %o5, %o4, %o4 /* IEU0 Group (regdep) */ - addcc %o4, %o2, %o2 /* IEU1 Group (regdep) */ - bcs,a,pn %xcc, 1f /* CTI */ - add %o2, 1, %o2 /* IEU0 */ -1: ba,pt %xcc, 25b /* CTI Group */ - sllx %o2, 32, %g1 /* IEU0 */ -21: srl %o2, 0, %o2 /* IEU0 Group */ - cmp %o1, 0 /* IEU1 */ - be,pn %icc, 24b /* CTI */ - andcc %o1, 4, %g0 /* IEU1 Group */ - be,a,pn %icc, 1f /* CTI */ - clr %g2 /* IEU0 */ - lduh [%o0], %g3 /* Load */ - lduh [%o0+2], %g2 /* Load Group */ - add %o0, 4, %o0 /* IEU0 Group */ - sllx %g3, 48, %g3 /* IEU0 Group */ - sllx %g2, 32, %g2 /* IEU0 Group */ - or %g3, %g2, %g2 /* IEU0 Group */ -1: andcc %o1, 2, %g0 /* IEU1 */ - be,a,pn %icc, 1f /* CTI */ - clr %o4 /* IEU0 Group */ - lduh [%o0], %o4 /* Load */ - add %o0, 2, %o0 /* IEU1 */ - sll %o4, 16, %o4 /* IEU0 Group */ -1: andcc %o1, 1, %g0 /* IEU1 */ - be,a,pn %icc, 1f /* CTI */ - clr %o5 /* IEU0 Group */ - ldub [%o0], %o5 /* Load */ - sll %o5, 8, %o5 /* IEU0 Group */ -1: or %g2, %o4, %o4 /* IEU1 */ - or %o5, %o4, %o4 /* IEU0 Group (regdep) */ - addcc %o4, %o2, %o2 /* IEU1 Group (regdep) */ - bcs,a,pn %xcc, 1f /* CTI */ - add %o2, 1, %o2 /* IEU0 */ -1: ba,pt %xcc, 25b /* CTI Group */ - sllx %o2, 32, %g1 /* IEU0 */ +23: brnz,pn %o3, 26f /* CTI+IEU1 Group */ +24: sllx %o2, 32, %g1 /* IEU0 */ +25: addcc %o2, %g1, %o0 /* IEU1 Group */ + srlx %o0, 32, %o0 /* IEU0 Group (regdep) */ + bcs,a,pn %xcc, 1f /* CTI */ + add %o0, 1, %o0 /* IEU1 */ +1: retl /* CTI Group brk forced*/ + srl %o0, 0, %o0 /* IEU0 */ +26: andcc %o1, 8, %g0 /* IEU1 Group */ + be,pn %icc, 1f /* CTI */ + ldx [%o0], %g3 /* Load */ + add %o0, 8, %o0 /* IEU0 Group */ + addcc %g3, %o2, %o2 /* IEU1 Group */ + bcs,a,pn %xcc, 1f /* CTI */ + add %o2, 1, %o2 /* IEU0 */ +1: andcc %o1, 4, %g0 /* IEU1 Group */ + be,a,pn %icc, 1f /* CTI */ + clr %g2 /* IEU0 */ + ld [%o0], %g2 /* Load */ + add %o0, 4, %o0 /* IEU0 Group */ + sllx %g2, 32, %g2 /* IEU0 Group */ +1: andcc %o1, 2, %g0 /* IEU1 */ + be,a,pn %icc, 1f /* CTI */ + clr %o4 /* IEU0 Group */ + lduh [%o0], %o4 /* Load */ + add %o0, 2, %o0 /* IEU1 */ + sll %o4, 16, %o4 /* IEU0 Group */ +1: andcc %o1, 1, %g0 /* IEU1 */ + be,a,pn %icc, 1f /* CTI */ + clr %o5 /* IEU0 Group */ + ldub [%o0], %o5 /* Load */ + sll %o5, 8, %o5 /* IEU0 Group */ +1: or %g2, %o4, %o4 /* IEU1 */ + or %o5, %o4, %o4 /* IEU0 Group (regdep) */ + addcc %o4, %o2, %o2 /* IEU1 Group (regdep) */ + bcs,a,pn %xcc, 1f /* CTI */ + add %o2, 1, %o2 /* IEU0 */ +1: ba,pt %xcc, 25b /* CTI Group */ + sllx %o2, 32, %g1 /* IEU0 */ +21: srl %o2, 0, %o2 /* IEU0 Group */ + cmp %o1, 0 /* IEU1 */ + be,pn %icc, 24b /* CTI */ + andcc %o1, 4, %g0 /* IEU1 Group */ + be,a,pn %icc, 1f /* CTI */ + clr %g2 /* IEU0 */ + lduh [%o0], %g3 /* Load */ + lduh [%o0+2], %g2 /* Load Group */ + add %o0, 4, %o0 /* IEU0 Group */ + sllx %g3, 48, %g3 /* IEU0 Group */ + sllx %g2, 32, %g2 /* IEU0 Group */ + or %g3, %g2, %g2 /* IEU0 Group */ +1: andcc %o1, 2, %g0 /* IEU1 */ + be,a,pn %icc, 1f /* CTI */ + clr %o4 /* IEU0 Group */ + lduh [%o0], %o4 /* Load */ + add %o0, 2, %o0 /* IEU1 */ + sll %o4, 16, %o4 /* IEU0 Group */ +1: andcc %o1, 1, %g0 /* IEU1 */ + be,a,pn %icc, 1f /* CTI */ + clr %o5 /* IEU0 Group */ + ldub [%o0], %o5 /* Load */ + sll %o5, 8, %o5 /* IEU0 Group */ +1: or %g2, %o4, %o4 /* IEU1 */ + or %o5, %o4, %o4 /* IEU0 Group (regdep) */ + addcc %o4, %o2, %o2 /* IEU1 Group (regdep) */ + bcs,a,pn %xcc, 1f /* CTI */ + add %o2, 1, %o2 /* IEU0 */ +1: ba,pt %xcc, 25b /* CTI Group */ + sllx %o2, 32, %g1 /* IEU0 */ diff --git a/arch/sparc64/lib/VIScsumcopy.S b/arch/sparc64/lib/VIScsumcopy.S index 3f89eea29..9b0193022 100644 --- a/arch/sparc64/lib/VIScsumcopy.S +++ b/arch/sparc64/lib/VIScsumcopy.S @@ -1,4 +1,4 @@ -/* $Id: VIScsumcopy.S,v 1.7 2000/01/19 04:06:03 davem Exp $ +/* $Id: VIScsumcopy.S,v 1.8 2000/02/20 23:21:39 davem Exp $ * VIScsumcopy.S: High bandwidth IP checksumming with simultaneous * copying utilizing the UltraSparc Visual Instruction Set. * @@ -62,384 +62,386 @@ * per 64bytes checksummed/copied. */ -#define LDBLK(O0) \ - ldda [%src] %asi, %O0 /* Load Group */ +#define LDBLK(O0) \ + ldda [%src] %asi, %O0 /* Load Group */ -#define STBLK \ - stda %f48, [%dst] ASI_BLK_P /* Store */ +#define STBLK \ + stda %f48, [%dst] ASI_BLK_P /* Store */ -#define ST(fx,off) \ - std %fx, [%dst + off] /* Store */ +#define ST(fx,off) \ + std %fx, [%dst + off] /* Store */ -#define SYNC \ +#define SYNC \ membar #Sync #define DO_THE_TRICK(f0,f2,f4,f6,f8,f10,f12,f14,F0,F2,F4,F6,F8,F10,F12,F14,DUMMY1,A0,A2,A4,A6,A8,A10,A12,A14,B14,DUMMY2,LOAD,STORE1,STORE2,STORE3,STORE4,STORE5,STORE6,STORE7,STORE8,DUMMY3,BRANCH...) \ - LOAD /* Load Group */; \ - faligndata %A14, %F0, %A14 /* FPA Group */; \ - inc %x5 /* IEU0 */; \ - STORE1 /* Store (optional) */; \ - faligndata %F0, %F2, %A0 /* FPA Group */; \ - srl %x5, 1, %x5 /* IEU0 */; \ - add %sum, %x4, %sum /* IEU1 */; \ - fpadd32 %F0, %f0, %F0 /* FPA Group */; \ - inc %x6 /* IEU0 */; \ - STORE2 /* Store (optional) */; \ - faligndata %F2, %F4, %A2 /* FPA Group */; \ - srl %x6, 1, %x6 /* IEU0 */; \ - add %sum, %x5, %sum /* IEU1 */; \ - fpadd32 %F2, %f2, %F2 /* FPA Group */; \ - add %src, 64, %src /* IEU0 */; \ - add %dst, 64, %dst /* IEU1 */; \ - fcmpgt32 %f0, %F0, %x1 /* FPM Group */; \ - inc %x7 /* IEU0 */; \ - STORE3 /* Store (optional) */; \ - faligndata %F4, %F6, %A4 /* FPA */; \ - srl %x7, 1, %x7 /* IEU0 Group */; \ - add %sum, %x6, %sum /* IEU1 */; \ - fpadd32 %F4, %f4, %F4 /* FPA */; \ - fcmpgt32 %f2, %F2, %x2 /* FPM Group */; \ - inc %x8 /* IEU0 */; \ - STORE4 /* Store (optional) */; \ - faligndata %F6, %F8, %A6 /* FPA */; \ - srl %x8, 1, %x8 /* IEU0 Group */; \ - add %sum, %x7, %sum /* IEU1 */; \ - fpadd32 %F6, %f6, %F6 /* FPA */; \ - fcmpgt32 %f4, %F4, %x3 /* FPM Group */; \ - inc %x1 /* IEU0 */; \ - STORE5 /* Store (optional) */; \ - faligndata %F8, %F10, %A8 /* FPA */; \ - srl %x1, 1, %x1 /* IEU0 Group */; \ - add %sum, %x8, %sum /* IEU1 */; \ - fpadd32 %F8, %f8, %F8 /* FPA */; \ - fcmpgt32 %f6, %F6, %x4 /* FPM Group */; \ - inc %x2 /* IEU0 */; \ - STORE6 /* Store (optional) */; \ - faligndata %F10, %F12, %A10 /* FPA */; \ - srl %x2, 1, %x2 /* IEU0 Group */; \ - add %sum, %x1, %sum /* IEU1 */; \ - fpadd32 %F10, %f10, %F10 /* FPA */; \ - fcmpgt32 %f8, %F8, %x5 /* FPM Group */; \ - inc %x3 /* IEU0 */; \ - STORE7 /* Store (optional) */; \ - faligndata %F12, %F14, %A12 /* FPA */; \ - srl %x3, 1, %x3 /* IEU0 Group */; \ - add %sum, %x2, %sum /* IEU1 */; \ - fpadd32 %F12, %f12, %F12 /* FPA */; \ - fcmpgt32 %f10, %F10, %x6 /* FPM Group */; \ - inc %x4 /* IEU0 */; \ - STORE8 /* Store (optional) */; \ - fmovd %F14, %B14 /* FPA */; \ - srl %x4, 1, %x4 /* IEU0 Group */; \ - add %sum, %x3, %sum /* IEU1 */; \ - fpadd32 %F14, %f14, %F14 /* FPA */; \ - fcmpgt32 %f12, %F12, %x7 /* FPM Group */; \ - subcc %len, 64, %len /* IEU1 */; \ - BRANCH /* CTI */; \ - fcmpgt32 %f14, %F14, %x8 /* FPM Group */; \ + LOAD /* Load (Group) */; \ + faligndata %A14, %F0, %A14 /* FPA Group */; \ + inc %x5 /* IEU0 */; \ + STORE1 /* Store (optional) */; \ + faligndata %F0, %F2, %A0 /* FPA Group */; \ + srl %x5, 1, %x5 /* IEU0 */; \ + add %sum, %x4, %sum /* IEU1 */; \ + fpadd32 %F0, %f0, %F0 /* FPA Group */; \ + inc %x6 /* IEU0 */; \ + STORE2 /* Store (optional) */; \ + faligndata %F2, %F4, %A2 /* FPA Group */; \ + srl %x6, 1, %x6 /* IEU0 */; \ + add %sum, %x5, %sum /* IEU1 */; \ + fpadd32 %F2, %f2, %F2 /* FPA Group */; \ + add %src, 64, %src /* IEU0 */; \ + fcmpgt32 %f0, %F0, %x1 /* FPM */; \ + add %dst, 64, %dst /* IEU1 Group */; \ + inc %x7 /* IEU0 */; \ + STORE3 /* Store (optional) */; \ + faligndata %F4, %F6, %A4 /* FPA */; \ + fpadd32 %F4, %f4, %F4 /* FPA Group */; \ + add %sum, %x6, %sum /* IEU1 */; \ + fcmpgt32 %f2, %F2, %x2 /* FPM */; \ + srl %x7, 1, %x7 /* IEU0 Group */; \ + inc %x8 /* IEU1 */; \ + STORE4 /* Store (optional) */; \ + faligndata %F6, %F8, %A6 /* FPA */; \ + fpadd32 %F6, %f6, %F6 /* FPA Group */; \ + srl %x8, 1, %x8 /* IEU0 */; \ + fcmpgt32 %f4, %F4, %x3 /* FPM */; \ + add %sum, %x7, %sum /* IEU0 Group */; \ + inc %x1 /* IEU1 */; \ + STORE5 /* Store (optional) */; \ + faligndata %F8, %F10, %A8 /* FPA */; \ + fpadd32 %F8, %f8, %F8 /* FPA Group */; \ + srl %x1, 1, %x1 /* IEU0 */; \ + fcmpgt32 %f6, %F6, %x4 /* FPM */; \ + add %sum, %x8, %sum /* IEU0 Group */; \ + inc %x2 /* IEU1 */; \ + STORE6 /* Store (optional) */; \ + faligndata %F10, %F12, %A10 /* FPA */; \ + fpadd32 %F10, %f10, %F10 /* FPA Group */; \ + srl %x2, 1, %x2 /* IEU0 */; \ + fcmpgt32 %f8, %F8, %x5 /* FPM */; \ + add %sum, %x1, %sum /* IEU0 Group */; \ + inc %x3 /* IEU1 */; \ + STORE7 /* Store (optional) */; \ + faligndata %F12, %F14, %A12 /* FPA */; \ + fpadd32 %F12, %f12, %F12 /* FPA Group */; \ + srl %x3, 1, %x3 /* IEU0 */; \ + fcmpgt32 %f10, %F10, %x6 /* FPM */; \ + add %sum, %x2, %sum /* IEU0 Group */; \ + inc %x4 /* IEU1 */; \ + STORE8 /* Store (optional) */; \ + fmovd %F14, %B14 /* FPA */; \ + fpadd32 %F14, %f14, %F14 /* FPA Group */; \ + srl %x4, 1, %x4 /* IEU0 */; \ + fcmpgt32 %f12, %F12, %x7 /* FPM */; \ + add %sum, %x3, %sum /* IEU0 Group */; \ + subcc %len, 64, %len /* IEU1 */; \ + BRANCH /* CTI */; \ + fcmpgt32 %f14, %F14, %x8 /* FPM Group */; #define END_THE_TRICK(f0,f2,f4,f6,f8,f10,f12,f14,FA,FB,S0,S1,S2,S3,T0,T1,U0,fz) \ - inc %x5 /* IEU0 Group */; \ - fpadd32 %f2, %f0, %S0 /* FPA */; \ - srl %x5, 1, %x5 /* IEU0 Group */; \ - add %sum, %x4, %sum /* IEU1 */; \ - fpadd32 %f6, %f4, %S1 /* FPA */; \ - inc %x6 /* IEU0 Group */; \ - add %sum, %x5, %sum /* IEU1 */; \ - fcmpgt32 %f0, %S0, %x1 /* FPM Group */; \ - srl %x6, 1, %x6 /* IEU0 */; \ - inc %x7 /* IEU1 */; \ - fpadd32 %f10, %f8, %S2 /* FPA */; \ - fcmpgt32 %f4, %S1, %x2 /* FPM Group */; \ - srl %x7, 1, %x7 /* IEU0 */; \ - add %sum, %x6, %sum /* IEU1 */; \ - fpadd32 %f14, %f12, %S3 /* FPA */; \ - inc %x8 /* IEU0 Group */; \ - add %sum, %x7, %sum /* IEU1 */; \ - fzero %fz /* FPA */; \ - fcmpgt32 %f8, %S2, %x3 /* FPM Group */; \ - srl %x8, 1, %x8 /* IEU0 */; \ - inc %x1 /* IEU1 */; \ - fpadd32 %S0, %S1, %T0 /* FPA */; \ - fcmpgt32 %f12, %S3, %x4 /* FPM Group */; \ - srl %x1, 1, %x1 /* IEU0 */; \ - add %sum, %x8, %sum /* IEU1 */; \ - fpadd32 %S2, %S3, %T1 /* FPA */; \ - inc %x2 /* IEU0 Group */; \ - add %sum, %x1, %sum /* IEU1 */; \ - fcmpgt32 %S0, %T0, %x5 /* FPM Group */; \ - srl %x2, 1, %x2 /* IEU0 */; \ - inc %x3 /* IEU1 */; \ - fcmpgt32 %S2, %T1, %x6 /* FPM Group */; \ - srl %x3, 1, %x3 /* IEU0 */; \ - add %sum, %x2, %sum /* IEU1 */; \ - inc %x4 /* IEU0 Group */; \ - add %sum, %x3, %sum /* IEU1 */; \ - fcmpgt32 %fz, %f2, %x7 /* FPM Group */; \ - srl %x4, 1, %x4 /* IEU0 */; \ - inc %x5 /* IEU1 */; \ - fpadd32 %T0, %T1, %U0 /* FPA */; \ - fcmpgt32 %fz, %f6, %x8 /* FPM Group */; \ - srl %x5, 1, %x5 /* IEU0 */; \ - add %sum, %x4, %sum /* IEU1 */; \ - inc %x6 /* IEU0 Group */; \ - add %sum, %x5, %sum /* IEU1 */; \ - fcmpgt32 %fz, %f10, %x1 /* FPM Group */; \ - srl %x6, 1, %x6 /* IEU0 */; \ - inc %x7 /* IEU1 */; \ - fcmpgt32 %fz, %f14, %x2 /* FPM Group */; \ - ba,pt %xcc, ett /* CTI */; \ - fmovd %FA, %FB /* FPA */; \ + inc %x5 /* IEU0 Group */; \ + fpadd32 %f2, %f0, %S0 /* FPA */; \ + add %sum, %x4, %sum /* IEU1 */; \ + srl %x5, 1, %x5 /* IEU0 Group */; \ + fpadd32 %f6, %f4, %S1 /* FPA */; \ + inc %x6 /* IEU1 */; \ + fpadd32 %f10, %f8, %S2 /* FPA Group */; \ + add %sum, %x5, %sum /* IEU0 */; \ + fcmpgt32 %f0, %S0, %x1 /* FPM */; \ + fpadd32 %f14, %f12, %S3 /* FPA Group */; \ + srl %x6, 1, %x6 /* IEU0 */; \ + fcmpgt32 %f4, %S1, %x2 /* FPM */; \ + add %sum, %x6, %sum /* IEU0 Group */; \ + fzero %fz /* FPA */; \ + fcmpgt32 %f8, %S2, %x3 /* FPM */; \ + inc %x7 /* IEU0 Group */; \ + inc %x8 /* IEU1 */; \ + srl %x7, 1, %x7 /* IEU0 Group */; \ + inc %x1 /* IEU1 */; \ + fpadd32 %S0, %S1, %T0 /* FPA */; \ + fpadd32 %S2, %S3, %T1 /* FPA Group */; \ + add %sum, %x7, %sum /* IEU0 */; \ + fcmpgt32 %f12, %S3, %x4 /* FPM */; \ + srl %x8, 1, %x8 /* IEU0 Group */; \ + inc %x2 /* IEU1 */; \ + srl %x1, 1, %x1 /* IEU0 Group */; \ + add %sum, %x8, %sum /* IEU1 */; \ + add %sum, %x1, %sum /* IEU0 Group */; \ + fcmpgt32 %S0, %T0, %x5 /* FPM */; \ + srl %x2, 1, %x2 /* IEU0 Group */; \ + fcmpgt32 %S2, %T1, %x6 /* FPM */; \ + inc %x3 /* IEU0 Group */; \ + add %sum, %x2, %sum /* IEU1 */; \ + srl %x3, 1, %x3 /* IEU0 Group */; \ + inc %x4 /* IEU1 */; \ + fpadd32 %T0, %T1, %U0 /* FPA Group */; \ + add %sum, %x3, %sum /* IEU0 */; \ + fcmpgt32 %fz, %f2, %x7 /* FPM */; \ + srl %x4, 1, %x4 /* IEU0 Group */; \ + fcmpgt32 %fz, %f6, %x8 /* FPM */; \ + inc %x5 /* IEU0 Group */; \ + add %sum, %x4, %sum /* IEU1 */; \ + srl %x5, 1, %x5 /* IEU0 Group */; \ + fcmpgt32 %fz, %f10, %x1 /* FPM */; \ + inc %x6 /* IEU0 Group */; \ + add %sum, %x5, %sum /* IEU1 */; \ + fmovd %FA, %FB /* FPA Group */; \ + fcmpgt32 %fz, %f14, %x2 /* FPM */; \ + srl %x6, 1, %x6 /* IEU0 Group */; \ + ba,pt %xcc, ett /* CTI */; \ + inc %x7 /* IEU1 */; -#define END_THE_TRICK1(f0,f2,f4,f6,f8,f10,f12,f14,FA,FB) \ +#define END_THE_TRICK1(f0,f2,f4,f6,f8,f10,f12,f14,FA,FB) \ END_THE_TRICK(f0,f2,f4,f6,f8,f10,f12,f14,FA,FB,f48,f50,f52,f54,f56,f58,f60,f62) -#define END_THE_TRICK2(S0,S1,S2,S3,T0,T1,U0,U1,V0,fz) \ - fpadd32 %U0, %U1, %V0 /* FPA Group */; \ - srl %x7, 1, %x7 /* IEU0 */; \ - add %sum, %x6, %sum /* IEU1 */; \ - std %V0, [%sp + STACKOFF] /* Store Group */; \ - inc %x8 /* IEU0 */; \ - sub %sum, %x7, %sum /* IEU1 */; \ - fcmpgt32 %fz, %S1, %x3 /* FPM Group */; \ - srl %x8, 1, %x8 /* IEU0 */; \ - inc %x1 /* IEU1 */; \ - fcmpgt32 %fz, %S3, %x4 /* FPM Group */; \ - srl %x1, 1, %x1 /* IEU0 */; \ - sub %sum, %x8, %sum /* IEU1 */; \ - ldx [%sp + STACKOFF], %x8 /* Load Group */; \ - inc %x2 /* IEU0 */; \ - sub %sum, %x1, %sum /* IEU1 */; \ - fcmpgt32 %fz, %T1, %x5 /* FPM Group */; \ - srl %x2, 1, %x2 /* IEU0 */; \ - inc %x3 /* IEU1 */; \ - fcmpgt32 %T0, %U0, %x6 /* FPM Group */; \ - srl %x3, 1, %x3 /* IEU0 */; \ - sub %sum, %x2, %sum /* IEU1 */; \ - inc %x4 /* IEU0 Group */; \ - sub %sum, %x3, %sum /* IEU1 */; \ - fcmpgt32 %fz, %U1, %x7 /* FPM Group */; \ - srl %x4, 1, %x4 /* IEU0 */; \ - inc %x5 /* IEU1 */; \ - fcmpgt32 %U0, %V0, %x1 /* FPM Group */; \ - srl %x5, 1, %x5 /* IEU0 */; \ - sub %sum, %x4, %sum /* IEU1 */; \ - fcmpgt32 %fz, %V0, %x2 /* FPM Group */; \ - inc %x6 /* IEU0 */; \ - sub %sum, %x5, %sum /* IEU1 */; \ - srl %x6, 1, %x6 /* IEU0 Group */; \ - inc %x7 /* IEU1 */; \ - srl %x7, 1, %x7 /* IEU0 Group */; \ - add %sum, %x6, %sum /* IEU1 */; \ - inc %x1 /* IEU0 Group */; \ - sub %sum, %x7, %sum /* IEU1 */; \ - srl %x1, 1, %x1 /* IEU0 Group */; \ - inc %x2 /* IEU1 */; \ - srl %x2, 1, %x2 /* IEU0 Group */; \ - add %sum, %x1, %sum /* IEU1 */; \ - sub %sum, %x2, %sum /* IEU0 Group */; \ - addcc %sum, %x8, %sum /* IEU Group */; \ - bcs,a,pn %xcc, 33f /* CTI */; \ - add %sum, 1, %sum /* IEU0 */; \ -33: /* That's it */; +#define END_THE_TRICK2(S0,S1,S2,S3,T0,T1,U0,U1,V0,fz) \ + fpadd32 %U0, %U1, %V0 /* FPA Group */; \ + srl %x7, 1, %x7 /* IEU0 */; \ + add %sum, %x6, %sum /* IEU1 */; \ + std %V0, [%sp + STACKOFF] /* Store Group */; \ + inc %x8 /* IEU0 */; \ + sub %sum, %x7, %sum /* IEU1 */; \ + srl %x8, 1, %x8 /* IEU0 Group */; \ + fcmpgt32 %fz, %S1, %x3 /* FPM */; \ + inc %x1 /* IEU0 Group */; \ + fcmpgt32 %fz, %S3, %x4 /* FPM */; \ + srl %x1, 1, %x1 /* IEU0 Group */; \ + sub %sum, %x8, %sum /* IEU1 */; \ + ldx [%sp + STACKOFF], %x8 /* Load Group */; \ + inc %x2 /* IEU0 */; \ + sub %sum, %x1, %sum /* IEU1 */; \ + srl %x2, 1, %x2 /* IEU0 Group */; \ + fcmpgt32 %fz, %T1, %x5 /* FPM */; \ + inc %x3 /* IEU0 Group */; \ + fcmpgt32 %T0, %U0, %x6 /* FPM */; \ + srl %x3, 1, %x3 /* IEU0 Group */; \ + sub %sum, %x2, %sum /* IEU1 */; \ + inc %x4 /* IEU0 Group */; \ + sub %sum, %x3, %sum /* IEU1 */; \ + srl %x4, 1, %x4 /* IEU0 Group */; \ + fcmpgt32 %fz, %U1, %x7 /* FPM */; \ + inc %x5 /* IEU0 Group */; \ + fcmpgt32 %U0, %V0, %x1 /* FPM */; \ + srl %x5, 1, %x5 /* IEU0 Group */; \ + sub %sum, %x4, %sum /* IEU1 */; \ + sub %sum, %x5, %sum /* IEU0 Group */; \ + fcmpgt32 %fz, %V0, %x2 /* FPM */; \ + inc %x6 /* IEU0 Group */; \ + inc %x7 /* IEU1 */; \ + srl %x6, 1, %x6 /* IEU0 Group */; \ + inc %x1 /* IEU1 */; \ + srl %x7, 1, %x7 /* IEU0 Group */; \ + add %sum, %x6, %sum /* IEU1 */; \ + srl %x1, 1, %x1 /* IEU0 Group */; \ + sub %sum, %x7, %sum /* IEU1 */; \ + inc %x2 /* IEU0 Group */; \ + add %sum, %x1, %sum /* IEU1 */; \ + srl %x2, 1, %x2 /* IEU0 Group */; \ + sub %sum, %x2, %sum /* IEU0 Group */; \ + addcc %sum, %x8, %sum /* IEU1 Group */; \ + bcs,a,pn %xcc, 33f /* CTI */; \ + add %sum, 1, %sum /* IEU0 (Group) */; \ +33: /* That's it */; .text .globl csum_partial_copy_vis .align 32 -/* %asi should be either ASI_P or ASI_AIUS for csum_partial_copy resp. csum_partial_copy_from_user */ -/* This assumes that !((%src^%dst)&3) && !((%src|%dst)&1) && %len >= 256 */ +/* %asi should be either ASI_P or ASI_AIUS for csum_partial_copy resp. + * csum_partial_copy_from_user + * This assumes that !((%src^%dst)&3) && !((%src|%dst)&1) && %len >= 256 + */ csum_partial_copy_vis: - andcc %dst, 7, %g0 /* IEU1 Group */ - be,pt %icc, 4f /* CTI */ - and %dst, 0x38, %o4 /* IEU0 */ - mov 1, %g5 /* IEU0 Group */ - andcc %dst, 2, %g0 /* IEU1 */ - be,pt %icc, 1f /* CTI */ - and %dst, 4, %g7 /* IEU0 Group */ - lduha [%src] %asi, %g2 /* Load */ - sub %len, 2, %len /* IEU0 Group */ - add %dst, 2, %dst /* IEU1 */ - andcc %dst, 4, %g7 /* IEU1 Group */ - sll %g5, 16, %g5 /* IEU0 */ - sth %g2, [%dst - 2] /* Store Group */ - sll %g2, 16, %g2 /* IEU0 */ - add %src, 2, %src /* IEU1 */ - addcc %g2, %sum, %sum /* IEU1 Group */ - bcs,a,pn %icc, 1f /* CTI */ - add %sum, %g5, %sum /* IEU0 */ -1: lduwa [%src] %asi, %g2 /* Load */ - brz,a,pn %g7, 4f /* CTI+IEU1 Group */ - and %dst, 0x38, %o4 /* IEU0 */ - add %dst, 4, %dst /* IEU0 Group */ - sub %len, 4, %len /* IEU1 */ - addcc %g2, %sum, %sum /* IEU1 Group */ - bcs,a,pn %icc, 1f /* CTI */ - add %sum, 1, %sum /* IEU0 */ -1: and %dst, 0x38, %o4 /* IEU0 Group */ - stw %g2, [%dst - 4] /* Store */ - add %src, 4, %src /* IEU1 */ + andcc %dst, 7, %g0 /* IEU1 Group */ + be,pt %icc, 4f /* CTI */ + and %dst, 0x38, %o4 /* IEU0 */ + mov 1, %g5 /* IEU0 Group */ + andcc %dst, 2, %g0 /* IEU1 */ + be,pt %icc, 1f /* CTI */ + and %dst, 4, %g7 /* IEU0 Group */ + lduha [%src] %asi, %g2 /* Load */ + sub %len, 2, %len /* IEU0 Group */ + add %dst, 2, %dst /* IEU1 */ + andcc %dst, 4, %g7 /* IEU1 Group */ + sll %g5, 16, %g5 /* IEU0 */ + sth %g2, [%dst - 2] /* Store Group */ + sll %g2, 16, %g2 /* IEU0 */ + add %src, 2, %src /* IEU1 */ + addcc %g2, %sum, %sum /* IEU1 Group */ + bcs,a,pn %icc, 1f /* CTI */ + add %sum, %g5, %sum /* IEU0 */ +1: lduwa [%src] %asi, %g2 /* Load */ + brz,a,pn %g7, 4f /* CTI+IEU1 Group */ + and %dst, 0x38, %o4 /* IEU0 */ + add %dst, 4, %dst /* IEU0 Group */ + sub %len, 4, %len /* IEU1 */ + addcc %g2, %sum, %sum /* IEU1 Group */ + bcs,a,pn %icc, 1f /* CTI */ + add %sum, 1, %sum /* IEU0 */ +1: and %dst, 0x38, %o4 /* IEU0 Group */ + stw %g2, [%dst - 4] /* Store */ + add %src, 4, %src /* IEU1 */ 4: #ifdef __KERNEL__ VISEntry #endif - mov %src, %g7 /* IEU1 Group */ - fzero %f48 /* FPA */ - alignaddr %src, %g0, %src /* Single Group */ - subcc %g7, %src, %g7 /* IEU1 Group */ - be,pt %xcc, 1f /* CTI */ - mov 0x40, %g1 /* IEU0 */ - lduwa [%src] %asi, %g2 /* Load Group */ - subcc %sum, %g2, %sum /* IEU1 Group+load stall */ - bcs,a,pn %icc, 1f /* CTI */ - sub %sum, 1, %sum /* IEU0 */ -1: srl %sum, 0, %sum /* IEU0 Group */ - clr %g5 /* IEU1 */ - brz,pn %o4, 3f /* CTI+IEU1 Group */ - sub %g1, %o4, %g1 /* IEU0 */ - ldda [%src] %asi, %f0 /* Load */ - clr %o4 /* IEU0 Group */ - andcc %dst, 8, %g0 /* IEU1 */ - be,pn %icc, 1f /* CTI */ - ldda [%src + 8] %asi, %f2 /* Load Group */ - add %src, 8, %src /* IEU0 */ - sub %len, 8, %len /* IEU1 */ - fpadd32 %f0, %f48, %f50 /* FPA */ - addcc %dst, 8, %dst /* IEU1 Group */ - faligndata %f0, %f2, %f16 /* FPA */ - fcmpgt32 %f48, %f50, %o4 /* FPM Group */ - fmovd %f2, %f0 /* FPA Group */ - ldda [%src + 8] %asi, %f2 /* Load */ - std %f16, [%dst - 8] /* Store */ - fmovd %f50, %f48 /* FPA */ -1: andcc %g1, 0x10, %g0 /* IEU1 Group */ - be,pn %icc, 1f /* CTI */ - and %g1, 0x20, %g1 /* IEU0 */ - fpadd32 %f0, %f48, %f50 /* FPA */ - ldda [%src + 16] %asi, %f4 /* Load Group */ - add %src, 16, %src /* IEU0 */ - add %dst, 16, %dst /* IEU1 */ - faligndata %f0, %f2, %f16 /* FPA */ - fcmpgt32 %f48, %f50, %g5 /* FPM Group */ - sub %len, 16, %len /* IEU0 */ - inc %o4 /* IEU1 */ - std %f16, [%dst - 16] /* Store Group */ - fpadd32 %f2, %f50, %f48 /* FPA */ - srl %o4, 1, %o5 /* IEU0 */ - faligndata %f2, %f4, %f18 /* FPA Group */ - std %f18, [%dst - 8] /* Store */ - fcmpgt32 %f50, %f48, %o4 /* FPM Group */ - add %o5, %sum, %sum /* IEU0 */ - ldda [%src + 8] %asi, %f2 /* Load */ - fmovd %f4, %f0 /* FPA */ -1: brz,a,pn %g1, 4f /* CTI+IEU1 Group */ - rd %asi, %g2 /* LSU Group + 4 bubbles */ - inc %g5 /* IEU0 */ - fpadd32 %f0, %f48, %f50 /* FPA */ - ldda [%src + 16] %asi, %f4 /* Load Group */ - srl %g5, 1, %g5 /* IEU0 */ - add %dst, 32, %dst /* IEU1 */ - faligndata %f0, %f2, %f16 /* FPA */ - fcmpgt32 %f48, %f50, %o5 /* FPM Group */ - inc %o4 /* IEU0 */ - ldda [%src + 24] %asi, %f6 /* Load */ - srl %o4, 1, %o4 /* IEU0 Group */ - add %g5, %sum, %sum /* IEU1 */ - ldda [%src + 32] %asi, %f8 /* Load */ - fpadd32 %f2, %f50, %f48 /* FPA */ - faligndata %f2, %f4, %f18 /* FPA Group */ - sub %len, 32, %len /* IEU0 */ - std %f16, [%dst - 32] /* Store */ - fcmpgt32 %f50, %f48, %g3 /* FPM Group */ - inc %o5 /* IEU0 */ - add %o4, %sum, %sum /* IEU1 */ - fpadd32 %f4, %f48, %f50 /* FPA */ - faligndata %f4, %f6, %f20 /* FPA Group */ - srl %o5, 1, %o5 /* IEU0 */ - fcmpgt32 %f48, %f50, %g5 /* FPM Group */ - add %o5, %sum, %sum /* IEU0 */ - std %f18, [%dst - 24] /* Store */ - fpadd32 %f6, %f50, %f48 /* FPA */ - inc %g3 /* IEU0 Group */ - std %f20, [%dst - 16] /* Store */ - add %src, 32, %src /* IEU1 */ - faligndata %f6, %f8, %f22 /* FPA */ - fcmpgt32 %f50, %f48, %o4 /* FPM Group */ - srl %g3, 1, %g3 /* IEU0 */ - std %f22, [%dst - 8] /* Store */ - add %g3, %sum, %sum /* IEU0 Group */ -3: rd %asi, %g2 /* LSU Group + 4 bubbles */ + mov %src, %g7 /* IEU1 Group */ + fzero %f48 /* FPA */ + alignaddr %src, %g0, %src /* Single Group */ + subcc %g7, %src, %g7 /* IEU1 Group */ + be,pt %xcc, 1f /* CTI */ + mov 0x40, %g1 /* IEU0 */ + lduwa [%src] %asi, %g2 /* Load Group */ + subcc %sum, %g2, %sum /* IEU1 Group+load stall*/ + bcs,a,pn %icc, 1f /* CTI */ + sub %sum, 1, %sum /* IEU0 */ +1: srl %sum, 0, %sum /* IEU0 Group */ + clr %g5 /* IEU1 */ + brz,pn %o4, 3f /* CTI+IEU1 Group */ + sub %g1, %o4, %g1 /* IEU0 */ + ldda [%src] %asi, %f0 /* Load */ + clr %o4 /* IEU0 Group */ + andcc %dst, 8, %g0 /* IEU1 */ + be,pn %icc, 1f /* CTI */ + ldda [%src + 8] %asi, %f2 /* Load Group */ + add %src, 8, %src /* IEU0 */ + sub %len, 8, %len /* IEU1 */ + fpadd32 %f0, %f48, %f50 /* FPA */ + addcc %dst, 8, %dst /* IEU1 Group */ + faligndata %f0, %f2, %f16 /* FPA */ + fcmpgt32 %f48, %f50, %o4 /* FPM Group */ + fmovd %f2, %f0 /* FPA Group */ + ldda [%src + 8] %asi, %f2 /* Load */ + std %f16, [%dst - 8] /* Store */ + fmovd %f50, %f48 /* FPA */ +1: andcc %g1, 0x10, %g0 /* IEU1 Group */ + be,pn %icc, 1f /* CTI */ + and %g1, 0x20, %g1 /* IEU0 */ + fpadd32 %f0, %f48, %f50 /* FPA */ + ldda [%src + 16] %asi, %f4 /* Load Group */ + add %src, 16, %src /* IEU0 */ + add %dst, 16, %dst /* IEU1 */ + faligndata %f0, %f2, %f16 /* FPA */ + fcmpgt32 %f48, %f50, %g5 /* FPM Group */ + sub %len, 16, %len /* IEU0 */ + inc %o4 /* IEU1 */ + std %f16, [%dst - 16] /* Store Group */ + fpadd32 %f2, %f50, %f48 /* FPA */ + srl %o4, 1, %o5 /* IEU0 */ + faligndata %f2, %f4, %f18 /* FPA Group */ + std %f18, [%dst - 8] /* Store */ + fcmpgt32 %f50, %f48, %o4 /* FPM Group */ + add %o5, %sum, %sum /* IEU0 */ + ldda [%src + 8] %asi, %f2 /* Load */ + fmovd %f4, %f0 /* FPA */ +1: brz,a,pn %g1, 4f /* CTI+IEU1 Group */ + rd %asi, %g2 /* LSU Group + 4 bubbles*/ + inc %g5 /* IEU0 */ + fpadd32 %f0, %f48, %f50 /* FPA */ + ldda [%src + 16] %asi, %f4 /* Load Group */ + srl %g5, 1, %g5 /* IEU0 */ + add %dst, 32, %dst /* IEU1 */ + faligndata %f0, %f2, %f16 /* FPA */ + fcmpgt32 %f48, %f50, %o5 /* FPM Group */ + inc %o4 /* IEU0 */ + ldda [%src + 24] %asi, %f6 /* Load */ + srl %o4, 1, %o4 /* IEU0 Group */ + add %g5, %sum, %sum /* IEU1 */ + ldda [%src + 32] %asi, %f8 /* Load */ + fpadd32 %f2, %f50, %f48 /* FPA */ + faligndata %f2, %f4, %f18 /* FPA Group */ + sub %len, 32, %len /* IEU0 */ + std %f16, [%dst - 32] /* Store */ + fcmpgt32 %f50, %f48, %g3 /* FPM Group */ + inc %o5 /* IEU0 */ + add %o4, %sum, %sum /* IEU1 */ + fpadd32 %f4, %f48, %f50 /* FPA */ + faligndata %f4, %f6, %f20 /* FPA Group */ + srl %o5, 1, %o5 /* IEU0 */ + fcmpgt32 %f48, %f50, %g5 /* FPM Group */ + add %o5, %sum, %sum /* IEU0 */ + std %f18, [%dst - 24] /* Store */ + fpadd32 %f6, %f50, %f48 /* FPA */ + inc %g3 /* IEU0 Group */ + std %f20, [%dst - 16] /* Store */ + add %src, 32, %src /* IEU1 */ + faligndata %f6, %f8, %f22 /* FPA */ + fcmpgt32 %f50, %f48, %o4 /* FPM Group */ + srl %g3, 1, %g3 /* IEU0 */ + std %f22, [%dst - 8] /* Store */ + add %g3, %sum, %sum /* IEU0 Group */ +3: rd %asi, %g2 /* LSU Group + 4 bubbles*/ #ifdef __KERNEL__ -4: sethi %hi(vis0s), %g7 /* IEU0 Group */ - or %g2, ASI_BLK_OR, %g2 /* IEU1 */ +4: sethi %hi(vis0s), %g7 /* IEU0 Group */ + or %g2, ASI_BLK_OR, %g2 /* IEU1 */ #else -4: rd %pc, %g7 /* LSU Group + 4 bubbles */ +4: rd %pc, %g7 /* LSU Group + 4 bubbles*/ #endif - inc %g5 /* IEU0 Group */ - and %src, 0x38, %g3 /* IEU1 */ - membar #StoreLoad /* LSU Group */ - srl %g5, 1, %g5 /* IEU0 */ - inc %o4 /* IEU1 */ - sll %g3, 8, %g3 /* IEU0 Group */ - sub %len, 0xc0, %len /* IEU1 */ - addcc %g5, %sum, %sum /* IEU1 Group */ - srl %o4, 1, %o4 /* IEU0 */ - add %g7, %g3, %g7 /* IEU0 Group */ - add %o4, %sum, %sum /* IEU1 */ + inc %g5 /* IEU0 Group */ + and %src, 0x38, %g3 /* IEU1 */ + membar #StoreLoad /* LSU Group */ + srl %g5, 1, %g5 /* IEU0 */ + inc %o4 /* IEU1 */ + sll %g3, 8, %g3 /* IEU0 Group */ + sub %len, 0xc0, %len /* IEU1 */ + addcc %g5, %sum, %sum /* IEU1 Group */ + srl %o4, 1, %o4 /* IEU0 */ + add %g7, %g3, %g7 /* IEU0 Group */ + add %o4, %sum, %sum /* IEU1 */ #ifdef __KERNEL__ - jmpl %g7 + %lo(vis0s), %g0 /* CTI+IEU1 Group */ + jmpl %g7 + %lo(vis0s), %g0 /* CTI+IEU1 Group */ #else - jmpl %g7 + (vis0s - 4b), %g0 /* CTI+IEU1 Group */ + jmpl %g7 + (vis0s - 4b), %g0 /* CTI+IEU1 Group */ #endif - fzero %f32 /* FPA */ + fzero %f32 /* FPA */ .align 2048 -vis0s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ - add %src, 128, %src /* IEU0 Group */ - ldda [%src-128] %asi, %f0 /* Load Group */ - ldda [%src-64] %asi, %f16 /* Load Group */ - fmovd %f48, %f62 /* FPA Group f0 available */ - faligndata %f0, %f2, %f48 /* FPA Group f2 available */ - fcmpgt32 %f32, %f2, %x1 /* FPM Group f4 available */ - fpadd32 %f0, %f62, %f0 /* FPA */ - fcmpgt32 %f32, %f4, %x2 /* FPM Group f6 available */ - faligndata %f2, %f4, %f50 /* FPA */ - fcmpgt32 %f62, %f0, %x3 /* FPM Group f8 available */ - faligndata %f4, %f6, %f52 /* FPA */ - fcmpgt32 %f32, %f6, %x4 /* FPM Group f10 available */ - inc %x1 /* IEU0 */ - faligndata %f6, %f8, %f54 /* FPA */ - fcmpgt32 %f32, %f8, %x5 /* FPM Group f12 available */ - srl %x1, 1, %x1 /* IEU0 */ - inc %x2 /* IEU1 */ - faligndata %f8, %f10, %f56 /* FPA */ - fcmpgt32 %f32, %f10, %x6 /* FPM Group f14 available */ - srl %x2, 1, %x2 /* IEU0 */ - add %sum, %x1, %sum /* IEU1 */ - faligndata %f10, %f12, %f58 /* FPA */ - fcmpgt32 %f32, %f12, %x7 /* FPM Group */ - inc %x3 /* IEU0 */ - add %sum, %x2, %sum /* IEU1 */ - faligndata %f12, %f14, %f60 /* FPA */ - fcmpgt32 %f32, %f14, %x8 /* FPM Group */ - srl %x3, 1, %x3 /* IEU0 */ - inc %x4 /* IEU1 */ - fmovd %f14, %f62 /* FPA */ - srl %x4, 1, %x4 /* IEU0 Group */ - add %sum, %x3, %sum /* IEU1 */ +vis0s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ + add %src, 128, %src /* IEU0 Group */ + ldda [%src-128] %asi, %f0 /* Load Group */ + ldda [%src-64] %asi, %f16 /* Load Group */ + fmovd %f48, %f62 /* FPA Group f0 available*/ + faligndata %f0, %f2, %f48 /* FPA Group f2 available*/ + fcmpgt32 %f32, %f2, %x1 /* FPM Group f4 available*/ + fpadd32 %f0, %f62, %f0 /* FPA */ + fcmpgt32 %f32, %f4, %x2 /* FPM Group f6 available*/ + faligndata %f2, %f4, %f50 /* FPA */ + fcmpgt32 %f62, %f0, %x3 /* FPM Group f8 available*/ + faligndata %f4, %f6, %f52 /* FPA */ + fcmpgt32 %f32, %f6, %x4 /* FPM Group f10 available*/ + inc %x1 /* IEU0 */ + faligndata %f6, %f8, %f54 /* FPA */ + fcmpgt32 %f32, %f8, %x5 /* FPM Group f12 available*/ + srl %x1, 1, %x1 /* IEU0 */ + inc %x2 /* IEU1 */ + faligndata %f8, %f10, %f56 /* FPA */ + fcmpgt32 %f32, %f10, %x6 /* FPM Group f14 available*/ + srl %x2, 1, %x2 /* IEU0 */ + add %sum, %x1, %sum /* IEU1 */ + faligndata %f10, %f12, %f58 /* FPA */ + fcmpgt32 %f32, %f12, %x7 /* FPM Group */ + inc %x3 /* IEU0 */ + add %sum, %x2, %sum /* IEU1 */ + faligndata %f12, %f14, %f60 /* FPA */ + fcmpgt32 %f32, %f14, %x8 /* FPM Group */ + srl %x3, 1, %x3 /* IEU0 */ + inc %x4 /* IEU1 */ + fmovd %f14, %f62 /* FPA */ + srl %x4, 1, %x4 /* IEU0 Group */ + add %sum, %x3, %sum /* IEU1 */ vis0: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30, - ,f48,f50,f52,f54,f56,f58,f60,f62,f62, - ,LDBLK(f32), STBLK,,,,,,,, + ,f48,f50,f52,f54,f56,f58,f60,f62,f62, + ,LDBLK(f32), STBLK,,,,,,,, ,bcs,pn %icc, vis0e1) DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46, - ,f48,f50,f52,f54,f56,f58,f60,f62,f62, - ,LDBLK(f0), STBLK,,,,,,,, + ,f48,f50,f52,f54,f56,f58,f60,f62,f62, + ,LDBLK(f0), STBLK,,,,,,,, ,bcs,pn %icc, vis0e2) - DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14, + DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14, ,f48,f50,f52,f54,f56,f58,f60,f62,f62, ,LDBLK(f16), STBLK,,,,,,,, ,bcc,pt %icc, vis0) -vis0e3: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30, +vis0e3: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30, ,f48,f50,f52,f54,f56,f58,f60,f62,f32, ,SYNC, STBLK,ST(f48,64),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40),ST(f60,48), ,add %dst, 56, %dst; add %len, 192 - 8*8, %len; ba,pt %icc, e2) @@ -447,39 +449,39 @@ vis0e1: DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f4 ,f48,f50,f52,f54,f56,f58,f60,f62,f0, ,SYNC, STBLK,ST(f48,64),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40),ST(f60,48), ,add %dst, 56, %dst; add %len, 192 - 8*8, %len; ba,pt %icc, e3) -vis0e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14, +vis0e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14, ,f48,f50,f52,f54,f56,f58,f60,f62,f16, ,SYNC, STBLK,ST(f48,64),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40),ST(f60,48), ,add %dst, 56, %dst; add %len, 192 - 8*8, %len; ba,pt %icc, e1) .align 2048 -vis1s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ - add %src, 128 - 8, %src /* IEU0 Group */ - ldda [%src-128] %asi, %f0 /* Load Group */ - ldda [%src-64] %asi, %f16 /* Load Group */ - fmovd %f0, %f58 /* FPA Group */ - fmovd %f48, %f0 /* FPA Group */ - fcmpgt32 %f32, %f2, %x2 /* FPM Group */ - faligndata %f2, %f4, %f48 /* FPA */ - fcmpgt32 %f32, %f4, %x3 /* FPM Group */ - faligndata %f4, %f6, %f50 /* FPA */ - fcmpgt32 %f32, %f6, %x4 /* FPM Group */ - faligndata %f6, %f8, %f52 /* FPA */ - fcmpgt32 %f32, %f8, %x5 /* FPM Group */ - inc %x2 /* IEU1 */ - faligndata %f8, %f10, %f54 /* FPA */ - fcmpgt32 %f32, %f10, %x6 /* FPM Group */ - srl %x2, 1, %x2 /* IEU0 */ - faligndata %f10, %f12, %f56 /* FPA */ - fcmpgt32 %f32, %f12, %x7 /* FPM Group */ - inc %x3 /* IEU0 */ - add %sum, %x2, %sum /* IEU1 */ - faligndata %f12, %f14, %f58 /* FPA */ - fcmpgt32 %f32, %f14, %x8 /* FPM Group */ - srl %x3, 1, %x3 /* IEU0 */ - inc %x4 /* IEU1 */ - fmovd %f14, %f60 /* FPA */ - srl %x4, 1, %x4 /* IEU0 Group */ - add %sum, %x3, %sum /* IEU1 */ +vis1s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ + add %src, 128 - 8, %src /* IEU0 Group */ + ldda [%src-128] %asi, %f0 /* Load Group */ + ldda [%src-64] %asi, %f16 /* Load Group */ + fmovd %f0, %f58 /* FPA Group */ + fmovd %f48, %f0 /* FPA Group */ + fcmpgt32 %f32, %f2, %x2 /* FPM Group */ + faligndata %f2, %f4, %f48 /* FPA */ + fcmpgt32 %f32, %f4, %x3 /* FPM Group */ + faligndata %f4, %f6, %f50 /* FPA */ + fcmpgt32 %f32, %f6, %x4 /* FPM Group */ + faligndata %f6, %f8, %f52 /* FPA */ + fcmpgt32 %f32, %f8, %x5 /* FPM Group */ + inc %x2 /* IEU1 */ + faligndata %f8, %f10, %f54 /* FPA */ + fcmpgt32 %f32, %f10, %x6 /* FPM Group */ + srl %x2, 1, %x2 /* IEU0 */ + faligndata %f10, %f12, %f56 /* FPA */ + fcmpgt32 %f32, %f12, %x7 /* FPM Group */ + inc %x3 /* IEU0 */ + add %sum, %x2, %sum /* IEU1 */ + faligndata %f12, %f14, %f58 /* FPA */ + fcmpgt32 %f32, %f14, %x8 /* FPM Group */ + srl %x3, 1, %x3 /* IEU0 */ + inc %x4 /* IEU1 */ + fmovd %f14, %f60 /* FPA */ + srl %x4, 1, %x4 /* IEU0 Group */ + add %sum, %x3, %sum /* IEU1 */ vis1: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30, ,f62,f48,f50,f52,f54,f56,f58,f60,f60, ,LDBLK(f32), ,STBLK,,,,,,, @@ -505,31 +507,31 @@ vis1e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14 ,SYNC, ,STBLK,ST(f48,0),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40), ,add %dst, 48, %dst; add %len, 192 - 7*8, %len; ba,pt %icc, e1) .align 2048 -vis2s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ - add %src, 128 - 16, %src /* IEU0 Group */ - ldda [%src-128] %asi, %f0 /* Load Group */ - ldda [%src-64] %asi, %f16 /* Load Group */ - fmovd %f0, %f56 /* FPA Group */ - fmovd %f48, %f0 /* FPA Group */ - sub %dst, 64, %dst /* IEU0 */ - fpsub32 %f2, %f2, %f2 /* FPA Group */ - fcmpgt32 %f32, %f4, %x3 /* FPM Group */ - faligndata %f4, %f6, %f48 /* FPA */ - fcmpgt32 %f32, %f6, %x4 /* FPM Group */ - faligndata %f6, %f8, %f50 /* FPA */ - fcmpgt32 %f32, %f8, %x5 /* FPM Group */ - faligndata %f8, %f10, %f52 /* FPA */ - fcmpgt32 %f32, %f10, %x6 /* FPM Group */ - faligndata %f10, %f12, %f54 /* FPA */ - fcmpgt32 %f32, %f12, %x7 /* FPM Group */ - inc %x3 /* IEU0 */ - faligndata %f12, %f14, %f56 /* FPA */ - fcmpgt32 %f32, %f14, %x8 /* FPM Group */ - srl %x3, 1, %x3 /* IEU0 */ - inc %x4 /* IEU1 */ - fmovd %f14, %f58 /* FPA */ - srl %x4, 1, %x4 /* IEU0 Group */ - add %sum, %x3, %sum /* IEU1 */ +vis2s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ + add %src, 128 - 16, %src /* IEU0 Group */ + ldda [%src-128] %asi, %f0 /* Load Group */ + ldda [%src-64] %asi, %f16 /* Load Group */ + fmovd %f0, %f56 /* FPA Group */ + fmovd %f48, %f0 /* FPA Group */ + sub %dst, 64, %dst /* IEU0 */ + fpsub32 %f2, %f2, %f2 /* FPA Group */ + fcmpgt32 %f32, %f4, %x3 /* FPM Group */ + faligndata %f4, %f6, %f48 /* FPA */ + fcmpgt32 %f32, %f6, %x4 /* FPM Group */ + faligndata %f6, %f8, %f50 /* FPA */ + fcmpgt32 %f32, %f8, %x5 /* FPM Group */ + faligndata %f8, %f10, %f52 /* FPA */ + fcmpgt32 %f32, %f10, %x6 /* FPM Group */ + faligndata %f10, %f12, %f54 /* FPA */ + fcmpgt32 %f32, %f12, %x7 /* FPM Group */ + inc %x3 /* IEU0 */ + faligndata %f12, %f14, %f56 /* FPA */ + fcmpgt32 %f32, %f14, %x8 /* FPM Group */ + srl %x3, 1, %x3 /* IEU0 */ + inc %x4 /* IEU1 */ + fmovd %f14, %f58 /* FPA */ + srl %x4, 1, %x4 /* IEU0 Group */ + add %sum, %x3, %sum /* IEU1 */ vis2: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30, ,f60,f62,f48,f50,f52,f54,f56,f58,f58, ,LDBLK(f32), ,,STBLK,,,,,, @@ -555,27 +557,27 @@ vis2e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14 ,SYNC, ,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),ST(f54,88),ST(f56,96), ,add %dst, 104, %dst; add %len, 192 - 6*8, %len; ba,pt %icc, e1) .align 2048 -vis3s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ - add %src, 128 - 24, %src /* IEU0 Group */ - ldda [%src-128] %asi, %f0 /* Load Group */ - ldda [%src-64] %asi, %f16 /* Load Group */ - fmovd %f0, %f54 /* FPA Group */ - fmovd %f48, %f0 /* FPA Group */ - sub %dst, 64, %dst /* IEU0 */ - fpsub32 %f2, %f2, %f2 /* FPA Group */ - fpsub32 %f4, %f4, %f4 /* FPA Group */ - fcmpgt32 %f32, %f6, %x4 /* FPM Group */ - faligndata %f6, %f8, %f48 /* FPA */ - fcmpgt32 %f32, %f8, %x5 /* FPM Group */ - faligndata %f8, %f10, %f50 /* FPA */ - fcmpgt32 %f32, %f10, %x6 /* FPM Group */ - faligndata %f10, %f12, %f52 /* FPA */ - fcmpgt32 %f32, %f12, %x7 /* FPM Group */ - faligndata %f12, %f14, %f54 /* FPA */ - fcmpgt32 %f32, %f14, %x8 /* FPM Group */ - fmovd %f14, %f56 /* FPA */ - inc %x4 /* IEU0 */ - srl %x4, 1, %x4 /* IEU0 Group */ +vis3s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ + add %src, 128 - 24, %src /* IEU0 Group */ + ldda [%src-128] %asi, %f0 /* Load Group */ + ldda [%src-64] %asi, %f16 /* Load Group */ + fmovd %f0, %f54 /* FPA Group */ + fmovd %f48, %f0 /* FPA Group */ + sub %dst, 64, %dst /* IEU0 */ + fpsub32 %f2, %f2, %f2 /* FPA Group */ + fpsub32 %f4, %f4, %f4 /* FPA Group */ + fcmpgt32 %f32, %f6, %x4 /* FPM Group */ + faligndata %f6, %f8, %f48 /* FPA */ + fcmpgt32 %f32, %f8, %x5 /* FPM Group */ + faligndata %f8, %f10, %f50 /* FPA */ + fcmpgt32 %f32, %f10, %x6 /* FPM Group */ + faligndata %f10, %f12, %f52 /* FPA */ + fcmpgt32 %f32, %f12, %x7 /* FPM Group */ + faligndata %f12, %f14, %f54 /* FPA */ + fcmpgt32 %f32, %f14, %x8 /* FPM Group */ + fmovd %f14, %f56 /* FPA */ + inc %x4 /* IEU0 */ + srl %x4, 1, %x4 /* IEU0 Group */ vis3: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30, ,f58,f60,f62,f48,f50,f52,f54,f56,f56, ,LDBLK(f32), ,,,STBLK,,,,, @@ -601,25 +603,25 @@ vis3e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14 ,SYNC, ,,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),ST(f54,88), ,add %dst, 96, %dst; add %len, 192 - 5*8, %len; ba,pt %icc, e1) .align 2048 -vis4s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ - add %src, 128 - 32, %src /* IEU0 Group */ - ldda [%src-128] %asi, %f0 /* Load Group */ - ldda [%src-64] %asi, %f16 /* Load Group */ - fmovd %f0, %f52 /* FPA Group */ - fmovd %f48, %f0 /* FPA Group */ - sub %dst, 64, %dst /* IEU0 */ - fpsub32 %f2, %f2, %f2 /* FPA Group */ - fpsub32 %f4, %f4, %f4 /* FPA Group */ - fpsub32 %f6, %f6, %f6 /* FPA Group */ - clr %x4 /* IEU0 */ - fcmpgt32 %f32, %f8, %x5 /* FPM Group */ - faligndata %f8, %f10, %f48 /* FPA */ - fcmpgt32 %f32, %f10, %x6 /* FPM Group */ - faligndata %f10, %f12, %f50 /* FPA */ - fcmpgt32 %f32, %f12, %x7 /* FPM Group */ - faligndata %f12, %f14, %f52 /* FPA */ - fcmpgt32 %f32, %f14, %x8 /* FPM Group */ - fmovd %f14, %f54 /* FPA */ +vis4s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ + add %src, 128 - 32, %src /* IEU0 Group */ + ldda [%src-128] %asi, %f0 /* Load Group */ + ldda [%src-64] %asi, %f16 /* Load Group */ + fmovd %f0, %f52 /* FPA Group */ + fmovd %f48, %f0 /* FPA Group */ + sub %dst, 64, %dst /* IEU0 */ + fpsub32 %f2, %f2, %f2 /* FPA Group */ + fpsub32 %f4, %f4, %f4 /* FPA Group */ + fpsub32 %f6, %f6, %f6 /* FPA Group */ + clr %x4 /* IEU0 */ + fcmpgt32 %f32, %f8, %x5 /* FPM Group */ + faligndata %f8, %f10, %f48 /* FPA */ + fcmpgt32 %f32, %f10, %x6 /* FPM Group */ + faligndata %f10, %f12, %f50 /* FPA */ + fcmpgt32 %f32, %f12, %x7 /* FPM Group */ + faligndata %f12, %f14, %f52 /* FPA */ + fcmpgt32 %f32, %f14, %x8 /* FPM Group */ + fmovd %f14, %f54 /* FPA */ vis4: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30, ,f56,f58,f60,f62,f48,f50,f52,f54,f54, ,LDBLK(f32), ,,,,STBLK,,,, @@ -645,26 +647,26 @@ vis4e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14 ,SYNC, ,,,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80), ,add %dst, 88, %dst; add %len, 192 - 4*8, %len; ba,pt %icc, e1) .align 2048 -vis5s: add %src, 128 - 40, %src /* IEU0 Group */ - ldda [%src-88] %asi, %f10 /* Load Group */ - ldda [%src-80] %asi, %f12 /* Load Group */ - ldda [%src-72] %asi, %f14 /* Load Group */ - wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ - ldda [%src-64] %asi, %f16 /* Load Group */ - fmovd %f48, %f0 /* FPA Group */ - fmuld %f32, %f32, %f2 /* FPM */ - clr %x4 /* IEU0 */ - faddd %f32, %f32, %f4 /* FPA Group */ - fmuld %f32, %f32, %f6 /* FPM */ - clr %x5 /* IEU0 */ - faddd %f32, %f32, %f8 /* FPA Group */ - fcmpgt32 %f32, %f10, %x6 /* FPM Group */ - sub %dst, 64, %dst /* IEU0 */ - faligndata %f10, %f12, %f48 /* FPA */ - fcmpgt32 %f32, %f12, %x7 /* FPM Group */ - faligndata %f12, %f14, %f50 /* FPA */ - fcmpgt32 %f32, %f14, %x8 /* FPM Group */ - fmovd %f14, %f52 /* FPA */ +vis5s: add %src, 128 - 40, %src /* IEU0 Group */ + ldda [%src-88] %asi, %f10 /* Load Group */ + ldda [%src-80] %asi, %f12 /* Load Group */ + ldda [%src-72] %asi, %f14 /* Load Group */ + wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ + ldda [%src-64] %asi, %f16 /* Load Group */ + fmovd %f48, %f0 /* FPA Group */ + fmuld %f32, %f32, %f2 /* FPM */ + clr %x4 /* IEU0 */ + faddd %f32, %f32, %f4 /* FPA Group */ + fmuld %f32, %f32, %f6 /* FPM */ + clr %x5 /* IEU0 */ + faddd %f32, %f32, %f8 /* FPA Group */ + fcmpgt32 %f32, %f10, %x6 /* FPM Group */ + sub %dst, 64, %dst /* IEU0 */ + faligndata %f10, %f12, %f48 /* FPA */ + fcmpgt32 %f32, %f12, %x7 /* FPM Group */ + faligndata %f12, %f14, %f50 /* FPA */ + fcmpgt32 %f32, %f14, %x8 /* FPM Group */ + fmovd %f14, %f52 /* FPA */ vis5: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30, ,f54,f56,f58,f60,f62,f48,f50,f52,f52, ,LDBLK(f32), ,,,,,STBLK,,, @@ -690,25 +692,25 @@ vis5e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14 ,SYNC, ,,,,,STBLK,ST(f48,64),ST(f50,72), ,add %dst, 80, %dst; add %len, 192 - 3*8, %len; ba,pt %icc, e1) .align 2048 -vis6s: add %src, 128 - 48, %src /* IEU0 Group */ - ldda [%src-80] %asi, %f12 /* Load Group */ - ldda [%src-72] %asi, %f14 /* Load Group */ - wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ - ldda [%src-64] %asi, %f16 /* Load Group */ - fmovd %f48, %f0 /* FPA Group */ - fmuld %f32, %f32, %f2 /* FPM */ - clr %x4 /* IEU0 */ - faddd %f32, %f32, %f4 /* FPA Group */ - fmuld %f32, %f32, %f6 /* FPM */ - clr %x5 /* IEU0 */ - faddd %f32, %f32, %f8 /* FPA Group */ - fmuld %f32, %f32, %f10 /* FPM */ - clr %x6 /* IEU0 */ - fcmpgt32 %f32, %f12, %x7 /* FPM Group */ - sub %dst, 64, %dst /* IEU0 */ - fcmpgt32 %f32, %f14, %x8 /* FPM Group */ - faligndata %f12, %f14, %f48 /* FPA */ - fmovd %f14, %f50 /* FPA Group */ +vis6s: add %src, 128 - 48, %src /* IEU0 Group */ + ldda [%src-80] %asi, %f12 /* Load Group */ + ldda [%src-72] %asi, %f14 /* Load Group */ + wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ + ldda [%src-64] %asi, %f16 /* Load Group */ + fmovd %f48, %f0 /* FPA Group */ + fmuld %f32, %f32, %f2 /* FPM */ + clr %x4 /* IEU0 */ + faddd %f32, %f32, %f4 /* FPA Group */ + fmuld %f32, %f32, %f6 /* FPM */ + clr %x5 /* IEU0 */ + faddd %f32, %f32, %f8 /* FPA Group */ + fmuld %f32, %f32, %f10 /* FPM */ + clr %x6 /* IEU0 */ + fcmpgt32 %f32, %f12, %x7 /* FPM Group */ + sub %dst, 64, %dst /* IEU0 */ + fcmpgt32 %f32, %f14, %x8 /* FPM Group */ + faligndata %f12, %f14, %f48 /* FPA */ + fmovd %f14, %f50 /* FPA Group */ vis6: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30, ,f52,f54,f56,f58,f60,f62,f48,f50,f50, ,LDBLK(f32), ,,,,,,STBLK,, @@ -734,24 +736,24 @@ vis6e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14 ,SYNC, ,,,,,,STBLK,ST(f48,64), ,add %dst, 72, %dst; add %len, 192 - 2*8, %len; ba,pt %icc, e1) .align 2048 -vis7s: add %src, 128 - 56, %src /* IEU0 Group */ - ldda [%src-72] %asi, %f14 /* Load Group */ - wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ - ldda [%src-64] %asi, %f16 /* Load Group */ - fmovd %f48, %f0 /* FPA Group */ - fmuld %f32, %f32, %f2 /* FPM */ - clr %x4 /* IEU0 */ - faddd %f32, %f32, %f4 /* FPA Group */ - fmuld %f32, %f32, %f6 /* FPM */ - clr %x5 /* IEU0 */ - faddd %f32, %f32, %f8 /* FPA Group */ - fmuld %f32, %f32, %f10 /* FPM */ - clr %x6 /* IEU0 */ - faddd %f32, %f32, %f12 /* FPA Group */ - clr %x7 /* IEU0 */ - fcmpgt32 %f32, %f14, %x8 /* FPM Group */ - sub %dst, 64, %dst /* IEU0 */ - fmovd %f14, %f48 /* FPA */ +vis7s: add %src, 128 - 56, %src /* IEU0 Group */ + ldda [%src-72] %asi, %f14 /* Load Group */ + wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ + ldda [%src-64] %asi, %f16 /* Load Group */ + fmovd %f48, %f0 /* FPA Group */ + fmuld %f32, %f32, %f2 /* FPM */ + clr %x4 /* IEU0 */ + faddd %f32, %f32, %f4 /* FPA Group */ + fmuld %f32, %f32, %f6 /* FPM */ + clr %x5 /* IEU0 */ + faddd %f32, %f32, %f8 /* FPA Group */ + fmuld %f32, %f32, %f10 /* FPM */ + clr %x6 /* IEU0 */ + faddd %f32, %f32, %f12 /* FPA Group */ + clr %x7 /* IEU0 */ + fcmpgt32 %f32, %f14, %x8 /* FPM Group */ + sub %dst, 64, %dst /* IEU0 */ + fmovd %f14, %f48 /* FPA */ vis7: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30, ,f50,f52,f54,f56,f58,f60,f62,f48,f48, ,LDBLK(f32), ,,,,,,,STBLK, @@ -779,112 +781,112 @@ vis7e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14 e1: END_THE_TRICK1( f0,f2,f4,f6,f8,f10,f12,f14,f16,f6) e2: END_THE_TRICK1( f16,f18,f20,f22,f24,f26,f28,f30,f32,f6) e3: END_THE_TRICK1( f32,f34,f36,f38,f40,f42,f44,f46,f0,f6) -ett: rd %asi, %x4 /* LSU Group+4bubbles */ - rd %gsr, %x3 /* LSU Group+4bubbles */ +ett: rd %asi, %x4 /* LSU Group+4bubbles */ + rd %gsr, %x3 /* LSU Group+4bubbles */ #ifdef __KERNEL__ - srl %x4, 3, %x5 /* IEU0 Group */ - xor %x4, ASI_BLK_XOR1, %x4 /* IEU1 */ - wr %x4, %x5, %asi /* LSU Group+4bubbles */ + srl %x4, 3, %x5 /* IEU0 Group */ + xor %x4, ASI_BLK_XOR1, %x4 /* IEU1 */ + wr %x4, %x5, %asi /* LSU Group+4bubbles */ #else - wr %x4, ASI_BLK_XOR, %asi /* LSU Group+4bubbles */ + wr %x4, ASI_BLK_XOR, %asi /* LSU Group+4bubbles */ #endif - andcc %x3, 7, %x3 /* IEU1 Group */ - add %dst, 8, %dst /* IEU0 */ - bne,pn %icc, 1f /* CTI */ - fzero %f10 /* FPA */ - brz,a,pn %len, 2f /* CTI+IEU1 Group */ - std %f6, [%dst - 8] /* Store */ -1: cmp %len, 8 /* IEU1 */ - blu,pn %icc, 3f /* CTI */ - sub %src, 64, %src /* IEU0 Group */ -1: ldda [%src] %asi, %f2 /* Load Group */ - fpadd32 %f10, %f2, %f12 /* FPA Group+load stall */ - add %src, 8, %src /* IEU0 */ - add %dst, 8, %dst /* IEU1 */ - faligndata %f6, %f2, %f14 /* FPA Group */ - fcmpgt32 %f10, %f12, %x5 /* FPM Group */ - std %f14, [%dst - 16] /* Store */ - fmovd %f2, %f6 /* FPA */ - fmovd %f12, %f10 /* FPA Group */ - sub %len, 8, %len /* IEU1 */ - fzero %f16 /* FPA Group - FPU nop */ - fzero %f18 /* FPA Group - FPU nop */ - inc %x5 /* IEU0 */ - srl %x5, 1, %x5 /* IEU0 Group (regdep) */ - cmp %len, 8 /* IEU1 */ - bgeu,pt %icc, 1b /* CTI */ - add %x5, %sum, %sum /* IEU0 Group */ -3: brz,a,pt %x3, 2f /* CTI+IEU1 */ - std %f6, [%dst - 8] /* Store Group */ - st %f7, [%dst - 8] /* Store Group */ - sub %dst, 4, %dst /* IEU0 */ - add %len, 4, %len /* IEU1 */ + andcc %x3, 7, %x3 /* IEU1 Group */ + add %dst, 8, %dst /* IEU0 */ + bne,pn %icc, 1f /* CTI */ + fzero %f10 /* FPA */ + brz,a,pn %len, 2f /* CTI+IEU1 Group */ + std %f6, [%dst - 8] /* Store */ +1: cmp %len, 8 /* IEU1 */ + blu,pn %icc, 3f /* CTI */ + sub %src, 64, %src /* IEU0 Group */ +1: ldda [%src] %asi, %f2 /* Load Group */ + fpadd32 %f10, %f2, %f12 /* FPA Group+load stall*/ + add %src, 8, %src /* IEU0 */ + add %dst, 8, %dst /* IEU1 */ + faligndata %f6, %f2, %f14 /* FPA Group */ + fcmpgt32 %f10, %f12, %x5 /* FPM Group */ + std %f14, [%dst - 16] /* Store */ + fmovd %f2, %f6 /* FPA */ + fmovd %f12, %f10 /* FPA Group */ + sub %len, 8, %len /* IEU1 */ + fzero %f16 /* FPA Group - FPU nop */ + fzero %f18 /* FPA Group - FPU nop */ + inc %x5 /* IEU0 */ + srl %x5, 1, %x5 /* IEU0 Group (regdep) */ + cmp %len, 8 /* IEU1 */ + bgeu,pt %icc, 1b /* CTI */ + add %x5, %sum, %sum /* IEU0 Group */ +3: brz,a,pt %x3, 2f /* CTI+IEU1 */ + std %f6, [%dst - 8] /* Store Group */ + st %f7, [%dst - 8] /* Store Group */ + sub %dst, 4, %dst /* IEU0 */ + add %len, 4, %len /* IEU1 */ 2: #ifdef __KERNEL__ - sub %sp, 8, %sp /* IEU0 Group */ + sub %sp, 8, %sp /* IEU0 Group */ #endif END_THE_TRICK2( f48,f50,f52,f54,f56,f58,f60,f10,f12,f62) - membar #Sync /* LSU Group */ + membar #Sync /* LSU Group */ #ifdef __KERNEL__ VISExit - add %sp, 8, %sp /* IEU0 Group */ + add %sp, 8, %sp /* IEU0 Group */ #endif -23: brnz,pn %len, 26f /* CTI+IEU1 Group */ -24: sllx %sum, 32, %g1 /* IEU0 */ -25: addcc %sum, %g1, %src /* IEU1 Group */ - srlx %src, 32, %src /* IEU0 Group (regdep) */ - bcs,a,pn %xcc, 1f /* CTI */ - add %src, 1, %src /* IEU1 */ +23: brnz,pn %len, 26f /* CTI+IEU1 Group */ +24: sllx %sum, 32, %g1 /* IEU0 */ +25: addcc %sum, %g1, %src /* IEU1 Group */ + srlx %src, 32, %src /* IEU0 Group (regdep) */ + bcs,a,pn %xcc, 1f /* CTI */ + add %src, 1, %src /* IEU1 */ #ifndef __KERNEL__ -1: retl /* CTI Group brk forced */ - srl %src, 0, %src /* IEU0 */ +1: retl /* CTI Group brk forced*/ + srl %src, 0, %src /* IEU0 */ #else -1: sethi %uhi(PAGE_OFFSET), %g4 /* IEU0 Group */ - retl /* CTI Group brk forced */ - sllx %g4, 32, %g4 /* IEU0 */ +1: sethi %uhi(PAGE_OFFSET), %g4 /* IEU0 Group */ + retl /* CTI Group brk forced*/ + sllx %g4, 32, %g4 /* IEU0 */ #endif -26: andcc %len, 8, %g0 /* IEU1 Group */ - be,pn %icc, 1f /* CTI */ - lduwa [%src] %asi, %o4 /* Load */ - lduwa [%src+4] %asi, %g2 /* Load Group */ - add %src, 8, %src /* IEU0 */ - add %dst, 8, %dst /* IEU1 */ - sllx %o4, 32, %g5 /* IEU0 Group */ - stw %o4, [%dst - 8] /* Store */ - or %g5, %g2, %g5 /* IEU0 Group */ - stw %g2, [%dst - 4] /* Store */ - addcc %g5, %sum, %sum /* IEU1 Group */ - bcs,a,pn %xcc, 1f /* CTI */ - add %sum, 1, %sum /* IEU0 */ -1: andcc %len, 4, %g0 /* IEU1 Group */ - be,a,pn %icc, 1f /* CTI */ - clr %g2 /* IEU0 */ - lduwa [%src] %asi, %g7 /* Load */ - add %src, 4, %src /* IEU0 Group */ - add %dst, 4, %dst /* IEU1 */ - sllx %g7, 32, %g2 /* IEU0 Group */ - stw %g7, [%dst - 4] /* Store */ -1: andcc %len, 2, %g0 /* IEU1 */ - be,a,pn %icc, 1f /* CTI */ - clr %g3 /* IEU0 Group */ - lduha [%src] %asi, %g7 /* Load */ - add %src, 2, %src /* IEU1 */ - add %dst, 2, %dst /* IEU0 Group */ - sll %g7, 16, %g3 /* IEU0 Group */ - sth %g7, [%dst - 2] /* Store */ -1: andcc %len, 1, %g0 /* IEU1 */ - be,a,pn %icc, 1f /* CTI */ - clr %o5 /* IEU0 Group */ - lduba [%src] %asi, %g7 /* Load */ - sll %g7, 8, %o5 /* IEU0 Group */ - stb %g7, [%dst] /* Store */ -1: or %g2, %g3, %g3 /* IEU1 */ - or %o5, %g3, %g3 /* IEU0 Group (regdep) */ - addcc %g3, %sum, %sum /* IEU1 Group (regdep) */ - bcs,a,pn %xcc, 1f /* CTI */ - add %sum, 1, %sum /* IEU0 */ -1: ba,pt %xcc, 25b /* CTI Group */ - sllx %sum, 32, %g1 /* IEU0 */ +26: andcc %len, 8, %g0 /* IEU1 Group */ + be,pn %icc, 1f /* CTI */ + lduwa [%src] %asi, %o4 /* Load */ + lduwa [%src+4] %asi, %g2 /* Load Group */ + add %src, 8, %src /* IEU0 */ + add %dst, 8, %dst /* IEU1 */ + sllx %o4, 32, %g5 /* IEU0 Group */ + stw %o4, [%dst - 8] /* Store */ + or %g5, %g2, %g5 /* IEU0 Group */ + stw %g2, [%dst - 4] /* Store */ + addcc %g5, %sum, %sum /* IEU1 Group */ + bcs,a,pn %xcc, 1f /* CTI */ + add %sum, 1, %sum /* IEU0 */ +1: andcc %len, 4, %g0 /* IEU1 Group */ + be,a,pn %icc, 1f /* CTI */ + clr %g2 /* IEU0 */ + lduwa [%src] %asi, %g7 /* Load */ + add %src, 4, %src /* IEU0 Group */ + add %dst, 4, %dst /* IEU1 */ + sllx %g7, 32, %g2 /* IEU0 Group */ + stw %g7, [%dst - 4] /* Store */ +1: andcc %len, 2, %g0 /* IEU1 */ + be,a,pn %icc, 1f /* CTI */ + clr %g3 /* IEU0 Group */ + lduha [%src] %asi, %g7 /* Load */ + add %src, 2, %src /* IEU1 */ + add %dst, 2, %dst /* IEU0 Group */ + sll %g7, 16, %g3 /* IEU0 Group */ + sth %g7, [%dst - 2] /* Store */ +1: andcc %len, 1, %g0 /* IEU1 */ + be,a,pn %icc, 1f /* CTI */ + clr %o5 /* IEU0 Group */ + lduba [%src] %asi, %g7 /* Load */ + sll %g7, 8, %o5 /* IEU0 Group */ + stb %g7, [%dst] /* Store */ +1: or %g2, %g3, %g3 /* IEU1 */ + or %o5, %g3, %g3 /* IEU0 Group (regdep) */ + addcc %g3, %sum, %sum /* IEU1 Group (regdep) */ + bcs,a,pn %xcc, 1f /* CTI */ + add %sum, 1, %sum /* IEU0 */ +1: ba,pt %xcc, 25b /* CTI Group */ + sllx %sum, 32, %g1 /* IEU0 */ #ifdef __KERNEL__ end: diff --git a/arch/sparc64/lib/VIScsumcopyusr.S b/arch/sparc64/lib/VIScsumcopyusr.S index 17bbe78b1..4730a1c08 100644 --- a/arch/sparc64/lib/VIScsumcopyusr.S +++ b/arch/sparc64/lib/VIScsumcopyusr.S @@ -1,4 +1,4 @@ -/* $Id: VIScsumcopyusr.S,v 1.1 2000/01/19 04:06:04 davem Exp $ +/* $Id: VIScsumcopyusr.S,v 1.2 2000/02/20 23:21:40 davem Exp $ * VIScsumcopyusr.S: High bandwidth IP checksumming with simultaneous * copying utilizing the UltraSparc Visual Instruction Set. * @@ -91,358 +91,360 @@ #define DO_THE_TRICK(f0,f2,f4,f6,f8,f10,f12,f14,F0,F2,F4,F6,F8,F10,F12,F14,DUMMY1,A0,A2,A4,A6,A8,A10,A12,A14,B14,DUMMY2,LOAD,STORE1,STORE2,STORE3,STORE4,STORE5,STORE6,STORE7,STORE8,DUMMY3,BRANCH...) \ - LOAD /* Load Group */; \ - faligndata %A14, %F0, %A14 /* FPA Group */; \ - inc %x5 /* IEU0 */; \ - STORE1 /* Store (optional) */; \ - faligndata %F0, %F2, %A0 /* FPA Group */; \ - srl %x5, 1, %x5 /* IEU0 */; \ - add %sum, %x4, %sum /* IEU1 */; \ - fpadd32 %F0, %f0, %F0 /* FPA Group */; \ - inc %x6 /* IEU0 */; \ - STORE2 /* Store (optional) */; \ - faligndata %F2, %F4, %A2 /* FPA Group */; \ - srl %x6, 1, %x6 /* IEU0 */; \ - add %sum, %x5, %sum /* IEU1 */; \ - fpadd32 %F2, %f2, %F2 /* FPA Group */; \ - add %src, 64, %src /* IEU0 */; \ - add %dst, 64, %dst /* IEU1 */; \ - fcmpgt32 %f0, %F0, %x1 /* FPM Group */; \ - inc %x7 /* IEU0 */; \ - STORE3 /* Store (optional) */; \ - faligndata %F4, %F6, %A4 /* FPA */; \ - srl %x7, 1, %x7 /* IEU0 Group */; \ - add %sum, %x6, %sum /* IEU1 */; \ - fpadd32 %F4, %f4, %F4 /* FPA */; \ - fcmpgt32 %f2, %F2, %x2 /* FPM Group */; \ - inc %x8 /* IEU0 */; \ - STORE4 /* Store (optional) */; \ - faligndata %F6, %F8, %A6 /* FPA */; \ - srl %x8, 1, %x8 /* IEU0 Group */; \ - add %sum, %x7, %sum /* IEU1 */; \ - fpadd32 %F6, %f6, %F6 /* FPA */; \ - fcmpgt32 %f4, %F4, %x3 /* FPM Group */; \ - inc %x1 /* IEU0 */; \ - STORE5 /* Store (optional) */; \ - faligndata %F8, %F10, %A8 /* FPA */; \ - srl %x1, 1, %x1 /* IEU0 Group */; \ - add %sum, %x8, %sum /* IEU1 */; \ - fpadd32 %F8, %f8, %F8 /* FPA */; \ - fcmpgt32 %f6, %F6, %x4 /* FPM Group */; \ - inc %x2 /* IEU0 */; \ - STORE6 /* Store (optional) */; \ - faligndata %F10, %F12, %A10 /* FPA */; \ - srl %x2, 1, %x2 /* IEU0 Group */; \ - add %sum, %x1, %sum /* IEU1 */; \ - fpadd32 %F10, %f10, %F10 /* FPA */; \ - fcmpgt32 %f8, %F8, %x5 /* FPM Group */; \ - inc %x3 /* IEU0 */; \ - STORE7 /* Store (optional) */; \ - faligndata %F12, %F14, %A12 /* FPA */; \ - srl %x3, 1, %x3 /* IEU0 Group */; \ - add %sum, %x2, %sum /* IEU1 */; \ - fpadd32 %F12, %f12, %F12 /* FPA */; \ - fcmpgt32 %f10, %F10, %x6 /* FPM Group */; \ - inc %x4 /* IEU0 */; \ - STORE8 /* Store (optional) */; \ - fmovd %F14, %B14 /* FPA */; \ - srl %x4, 1, %x4 /* IEU0 Group */; \ - add %sum, %x3, %sum /* IEU1 */; \ - fpadd32 %F14, %f14, %F14 /* FPA */; \ - fcmpgt32 %f12, %F12, %x7 /* FPM Group */; \ - subcc %len, 64, %len /* IEU1 */; \ - BRANCH /* CTI */; \ - fcmpgt32 %f14, %F14, %x8 /* FPM Group */; \ + LOAD /* Load (Group) */; \ + faligndata %A14, %F0, %A14 /* FPA Group */; \ + inc %x5 /* IEU0 */; \ + STORE1 /* Store (optional) */; \ + faligndata %F0, %F2, %A0 /* FPA Group */; \ + srl %x5, 1, %x5 /* IEU0 */; \ + add %sum, %x4, %sum /* IEU1 */; \ + fpadd32 %F0, %f0, %F0 /* FPA Group */; \ + inc %x6 /* IEU0 */; \ + STORE2 /* Store (optional) */; \ + faligndata %F2, %F4, %A2 /* FPA Group */; \ + srl %x6, 1, %x6 /* IEU0 */; \ + add %sum, %x5, %sum /* IEU1 */; \ + fpadd32 %F2, %f2, %F2 /* FPA Group */; \ + add %src, 64, %src /* IEU0 */; \ + fcmpgt32 %f0, %F0, %x1 /* FPM */; \ + add %dst, 64, %dst /* IEU1 Group */; \ + inc %x7 /* IEU0 */; \ + STORE3 /* Store (optional) */; \ + faligndata %F4, %F6, %A4 /* FPA */; \ + fpadd32 %F4, %f4, %F4 /* FPA Group */; \ + add %sum, %x6, %sum /* IEU1 */; \ + fcmpgt32 %f2, %F2, %x2 /* FPM */; \ + srl %x7, 1, %x7 /* IEU0 Group */; \ + inc %x8 /* IEU1 */; \ + STORE4 /* Store (optional) */; \ + faligndata %F6, %F8, %A6 /* FPA */; \ + fpadd32 %F6, %f6, %F6 /* FPA Group */; \ + srl %x8, 1, %x8 /* IEU0 */; \ + fcmpgt32 %f4, %F4, %x3 /* FPM */; \ + add %sum, %x7, %sum /* IEU0 Group */; \ + inc %x1 /* IEU1 */; \ + STORE5 /* Store (optional) */; \ + faligndata %F8, %F10, %A8 /* FPA */; \ + fpadd32 %F8, %f8, %F8 /* FPA Group */; \ + srl %x1, 1, %x1 /* IEU0 */; \ + fcmpgt32 %f6, %F6, %x4 /* FPM */; \ + add %sum, %x8, %sum /* IEU0 Group */; \ + inc %x2 /* IEU1 */; \ + STORE6 /* Store (optional) */; \ + faligndata %F10, %F12, %A10 /* FPA */; \ + fpadd32 %F10, %f10, %F10 /* FPA Group */; \ + srl %x2, 1, %x2 /* IEU0 */; \ + fcmpgt32 %f8, %F8, %x5 /* FPM */; \ + add %sum, %x1, %sum /* IEU0 Group */; \ + inc %x3 /* IEU1 */; \ + STORE7 /* Store (optional) */; \ + faligndata %F12, %F14, %A12 /* FPA */; \ + fpadd32 %F12, %f12, %F12 /* FPA Group */; \ + srl %x3, 1, %x3 /* IEU0 */; \ + fcmpgt32 %f10, %F10, %x6 /* FPM */; \ + add %sum, %x2, %sum /* IEU0 Group */; \ + inc %x4 /* IEU1 */; \ + STORE8 /* Store (optional) */; \ + fmovd %F14, %B14 /* FPA */; \ + fpadd32 %F14, %f14, %F14 /* FPA Group */; \ + srl %x4, 1, %x4 /* IEU0 */; \ + fcmpgt32 %f12, %F12, %x7 /* FPM */; \ + add %sum, %x3, %sum /* IEU0 Group */; \ + subcc %len, 64, %len /* IEU1 */; \ + BRANCH /* CTI */; \ + fcmpgt32 %f14, %F14, %x8 /* FPM Group */; #define END_THE_TRICK(f0,f2,f4,f6,f8,f10,f12,f14,FA,FB,S0,S1,S2,S3,T0,T1,U0,fz) \ - inc %x5 /* IEU0 Group */; \ - fpadd32 %f2, %f0, %S0 /* FPA */; \ - srl %x5, 1, %x5 /* IEU0 Group */; \ - add %sum, %x4, %sum /* IEU1 */; \ - fpadd32 %f6, %f4, %S1 /* FPA */; \ - inc %x6 /* IEU0 Group */; \ - add %sum, %x5, %sum /* IEU1 */; \ - fcmpgt32 %f0, %S0, %x1 /* FPM Group */; \ - srl %x6, 1, %x6 /* IEU0 */; \ - inc %x7 /* IEU1 */; \ - fpadd32 %f10, %f8, %S2 /* FPA */; \ - fcmpgt32 %f4, %S1, %x2 /* FPM Group */; \ - srl %x7, 1, %x7 /* IEU0 */; \ - add %sum, %x6, %sum /* IEU1 */; \ - fpadd32 %f14, %f12, %S3 /* FPA */; \ - inc %x8 /* IEU0 Group */; \ - add %sum, %x7, %sum /* IEU1 */; \ - fzero %fz /* FPA */; \ - fcmpgt32 %f8, %S2, %x3 /* FPM Group */; \ - srl %x8, 1, %x8 /* IEU0 */; \ - inc %x1 /* IEU1 */; \ - fpadd32 %S0, %S1, %T0 /* FPA */; \ - fcmpgt32 %f12, %S3, %x4 /* FPM Group */; \ - srl %x1, 1, %x1 /* IEU0 */; \ - add %sum, %x8, %sum /* IEU1 */; \ - fpadd32 %S2, %S3, %T1 /* FPA */; \ - inc %x2 /* IEU0 Group */; \ - add %sum, %x1, %sum /* IEU1 */; \ - fcmpgt32 %S0, %T0, %x5 /* FPM Group */; \ - srl %x2, 1, %x2 /* IEU0 */; \ - inc %x3 /* IEU1 */; \ - fcmpgt32 %S2, %T1, %x6 /* FPM Group */; \ - srl %x3, 1, %x3 /* IEU0 */; \ - add %sum, %x2, %sum /* IEU1 */; \ - inc %x4 /* IEU0 Group */; \ - add %sum, %x3, %sum /* IEU1 */; \ - fcmpgt32 %fz, %f2, %x7 /* FPM Group */; \ - srl %x4, 1, %x4 /* IEU0 */; \ - inc %x5 /* IEU1 */; \ - fpadd32 %T0, %T1, %U0 /* FPA */; \ - fcmpgt32 %fz, %f6, %x8 /* FPM Group */; \ - srl %x5, 1, %x5 /* IEU0 */; \ - add %sum, %x4, %sum /* IEU1 */; \ - inc %x6 /* IEU0 Group */; \ - add %sum, %x5, %sum /* IEU1 */; \ - fcmpgt32 %fz, %f10, %x1 /* FPM Group */; \ - srl %x6, 1, %x6 /* IEU0 */; \ - inc %x7 /* IEU1 */; \ - fcmpgt32 %fz, %f14, %x2 /* FPM Group */; \ - ba,pt %xcc, ett /* CTI */; \ - fmovd %FA, %FB /* FPA */; \ + inc %x5 /* IEU0 Group */; \ + fpadd32 %f2, %f0, %S0 /* FPA */; \ + add %sum, %x4, %sum /* IEU1 */; \ + srl %x5, 1, %x5 /* IEU0 Group */; \ + fpadd32 %f6, %f4, %S1 /* FPA */; \ + inc %x6 /* IEU1 */; \ + fpadd32 %f10, %f8, %S2 /* FPA Group */; \ + add %sum, %x5, %sum /* IEU0 */; \ + fcmpgt32 %f0, %S0, %x1 /* FPM */; \ + fpadd32 %f14, %f12, %S3 /* FPA Group */; \ + srl %x6, 1, %x6 /* IEU0 */; \ + fcmpgt32 %f4, %S1, %x2 /* FPM */; \ + add %sum, %x6, %sum /* IEU0 Group */; \ + fzero %fz /* FPA */; \ + fcmpgt32 %f8, %S2, %x3 /* FPM */; \ + inc %x7 /* IEU0 Group */; \ + inc %x8 /* IEU1 */; \ + srl %x7, 1, %x7 /* IEU0 Group */; \ + inc %x1 /* IEU1 */; \ + fpadd32 %S0, %S1, %T0 /* FPA */; \ + fpadd32 %S2, %S3, %T1 /* FPA Group */; \ + add %sum, %x7, %sum /* IEU0 */; \ + fcmpgt32 %f12, %S3, %x4 /* FPM */; \ + srl %x8, 1, %x8 /* IEU0 Group */; \ + inc %x2 /* IEU1 */; \ + srl %x1, 1, %x1 /* IEU0 Group */; \ + add %sum, %x8, %sum /* IEU1 */; \ + add %sum, %x1, %sum /* IEU0 Group */; \ + fcmpgt32 %S0, %T0, %x5 /* FPM */; \ + srl %x2, 1, %x2 /* IEU0 Group */; \ + fcmpgt32 %S2, %T1, %x6 /* FPM */; \ + inc %x3 /* IEU0 Group */; \ + add %sum, %x2, %sum /* IEU1 */; \ + srl %x3, 1, %x3 /* IEU0 Group */; \ + inc %x4 /* IEU1 */; \ + fpadd32 %T0, %T1, %U0 /* FPA Group */; \ + add %sum, %x3, %sum /* IEU0 */; \ + fcmpgt32 %fz, %f2, %x7 /* FPM */; \ + srl %x4, 1, %x4 /* IEU0 Group */; \ + fcmpgt32 %fz, %f6, %x8 /* FPM */; \ + inc %x5 /* IEU0 Group */; \ + add %sum, %x4, %sum /* IEU1 */; \ + srl %x5, 1, %x5 /* IEU0 Group */; \ + fcmpgt32 %fz, %f10, %x1 /* FPM */; \ + inc %x6 /* IEU0 Group */; \ + add %sum, %x5, %sum /* IEU1 */; \ + fmovd %FA, %FB /* FPA Group */; \ + fcmpgt32 %fz, %f14, %x2 /* FPM */; \ + srl %x6, 1, %x6 /* IEU0 Group */; \ + ba,pt %xcc, ett /* CTI */; \ + inc %x7 /* IEU1 */; -#define END_THE_TRICK1(f0,f2,f4,f6,f8,f10,f12,f14,FA,FB) \ +#define END_THE_TRICK1(f0,f2,f4,f6,f8,f10,f12,f14,FA,FB) \ END_THE_TRICK(f0,f2,f4,f6,f8,f10,f12,f14,FA,FB,f48,f50,f52,f54,f56,f58,f60,f62) -#define END_THE_TRICK2(S0,S1,S2,S3,T0,T1,U0,U1,V0,fz) \ - fpadd32 %U0, %U1, %V0 /* FPA Group */; \ - srl %x7, 1, %x7 /* IEU0 */; \ - add %sum, %x6, %sum /* IEU1 */; \ - std %V0, [%sp + STACKOFF] /* Store Group */; \ - inc %x8 /* IEU0 */; \ - sub %sum, %x7, %sum /* IEU1 */; \ - fcmpgt32 %fz, %S1, %x3 /* FPM Group */; \ - srl %x8, 1, %x8 /* IEU0 */; \ - inc %x1 /* IEU1 */; \ - fcmpgt32 %fz, %S3, %x4 /* FPM Group */; \ - srl %x1, 1, %x1 /* IEU0 */; \ - sub %sum, %x8, %sum /* IEU1 */; \ - ldx [%sp + STACKOFF], %x8 /* Load Group */; \ - inc %x2 /* IEU0 */; \ - sub %sum, %x1, %sum /* IEU1 */; \ - fcmpgt32 %fz, %T1, %x5 /* FPM Group */; \ - srl %x2, 1, %x2 /* IEU0 */; \ - inc %x3 /* IEU1 */; \ - fcmpgt32 %T0, %U0, %x6 /* FPM Group */; \ - srl %x3, 1, %x3 /* IEU0 */; \ - sub %sum, %x2, %sum /* IEU1 */; \ - inc %x4 /* IEU0 Group */; \ - sub %sum, %x3, %sum /* IEU1 */; \ - fcmpgt32 %fz, %U1, %x7 /* FPM Group */; \ - srl %x4, 1, %x4 /* IEU0 */; \ - inc %x5 /* IEU1 */; \ - fcmpgt32 %U0, %V0, %x1 /* FPM Group */; \ - srl %x5, 1, %x5 /* IEU0 */; \ - sub %sum, %x4, %sum /* IEU1 */; \ - fcmpgt32 %fz, %V0, %x2 /* FPM Group */; \ - inc %x6 /* IEU0 */; \ - sub %sum, %x5, %sum /* IEU1 */; \ - srl %x6, 1, %x6 /* IEU0 Group */; \ - inc %x7 /* IEU1 */; \ - srl %x7, 1, %x7 /* IEU0 Group */; \ - add %sum, %x6, %sum /* IEU1 */; \ - inc %x1 /* IEU0 Group */; \ - sub %sum, %x7, %sum /* IEU1 */; \ - srl %x1, 1, %x1 /* IEU0 Group */; \ - inc %x2 /* IEU1 */; \ - srl %x2, 1, %x2 /* IEU0 Group */; \ - add %sum, %x1, %sum /* IEU1 */; \ - sub %sum, %x2, %sum /* IEU0 Group */; \ - addcc %sum, %x8, %sum /* IEU Group */; \ - bcs,a,pn %xcc, 33f /* CTI */; \ - add %sum, 1, %sum /* IEU0 */; \ -33: /* That's it */; +#define END_THE_TRICK2(S0,S1,S2,S3,T0,T1,U0,U1,V0,fz) \ + fpadd32 %U0, %U1, %V0 /* FPA Group */; \ + srl %x7, 1, %x7 /* IEU0 */; \ + add %sum, %x6, %sum /* IEU1 */; \ + std %V0, [%sp + STACKOFF] /* Store Group */; \ + inc %x8 /* IEU0 */; \ + sub %sum, %x7, %sum /* IEU1 */; \ + srl %x8, 1, %x8 /* IEU0 Group */; \ + fcmpgt32 %fz, %S1, %x3 /* FPM */; \ + inc %x1 /* IEU0 Group */; \ + fcmpgt32 %fz, %S3, %x4 /* FPM */; \ + srl %x1, 1, %x1 /* IEU0 Group */; \ + sub %sum, %x8, %sum /* IEU1 */; \ + ldx [%sp + STACKOFF], %x8 /* Load Group */; \ + inc %x2 /* IEU0 */; \ + sub %sum, %x1, %sum /* IEU1 */; \ + srl %x2, 1, %x2 /* IEU0 Group */; \ + fcmpgt32 %fz, %T1, %x5 /* FPM */; \ + inc %x3 /* IEU0 Group */; \ + fcmpgt32 %T0, %U0, %x6 /* FPM */; \ + srl %x3, 1, %x3 /* IEU0 Group */; \ + sub %sum, %x2, %sum /* IEU1 */; \ + inc %x4 /* IEU0 Group */; \ + sub %sum, %x3, %sum /* IEU1 */; \ + srl %x4, 1, %x4 /* IEU0 Group */; \ + fcmpgt32 %fz, %U1, %x7 /* FPM */; \ + inc %x5 /* IEU0 Group */; \ + fcmpgt32 %U0, %V0, %x1 /* FPM */; \ + srl %x5, 1, %x5 /* IEU0 Group */; \ + sub %sum, %x4, %sum /* IEU1 */; \ + sub %sum, %x5, %sum /* IEU0 Group */; \ + fcmpgt32 %fz, %V0, %x2 /* FPM */; \ + inc %x6 /* IEU0 Group */; \ + inc %x7 /* IEU1 */; \ + srl %x6, 1, %x6 /* IEU0 Group */; \ + inc %x1 /* IEU1 */; \ + srl %x7, 1, %x7 /* IEU0 Group */; \ + add %sum, %x6, %sum /* IEU1 */; \ + srl %x1, 1, %x1 /* IEU0 Group */; \ + sub %sum, %x7, %sum /* IEU1 */; \ + inc %x2 /* IEU0 Group */; \ + add %sum, %x1, %sum /* IEU1 */; \ + srl %x2, 1, %x2 /* IEU0 Group */; \ + sub %sum, %x2, %sum /* IEU0 Group */; \ + addcc %sum, %x8, %sum /* IEU1 Group */; \ + bcs,a,pn %xcc, 33f /* CTI */; \ + add %sum, 1, %sum /* IEU0 (Group) */; \ +33: /* That's it */; .text .globl csum_partial_copy_user_vis .align 32 -/* %asi should be either ASI_P or ASI_AIUS for csum_partial_copy resp. csum_partial_copy_from_user */ -/* This assumes that !((%src^%dst)&3) && !((%src|%dst)&1) && %len >= 256 */ +/* %asi should be either ASI_P or ASI_AIUS for csum_partial_copy resp. + * csum_partial_copy_from_user + * This assumes that !((%src^%dst)&3) && !((%src|%dst)&1) && %len >= 256 + */ csum_partial_copy_user_vis: - andcc %dst, 7, %g0 /* IEU1 Group */ - be,pt %icc, 4f /* CTI */ - and %dst, 0x38, %o4 /* IEU0 */ - mov 1, %g5 /* IEU0 Group */ - andcc %dst, 2, %g0 /* IEU1 */ - be,pt %icc, 1f /* CTI */ - and %dst, 4, %g7 /* IEU0 Group */ - lduh [%src], %g2 /* Load */ - sub %len, 2, %len /* IEU0 Group */ - add %dst, 2, %dst /* IEU1 */ - andcc %dst, 4, %g7 /* IEU1 Group */ - sll %g5, 16, %g5 /* IEU0 */ - stha %g2, [%dst - 2] %asi /* Store Group */ - sll %g2, 16, %g2 /* IEU0 */ - add %src, 2, %src /* IEU1 */ - addcc %g2, %sum, %sum /* IEU1 Group */ - bcs,a,pn %icc, 1f /* CTI */ - add %sum, %g5, %sum /* IEU0 */ -1: lduw [%src], %g2 /* Load */ - brz,a,pn %g7, 4f /* CTI+IEU1 Group */ - and %dst, 0x38, %o4 /* IEU0 */ - add %dst, 4, %dst /* IEU0 Group */ - sub %len, 4, %len /* IEU1 */ - addcc %g2, %sum, %sum /* IEU1 Group */ - bcs,a,pn %icc, 1f /* CTI */ - add %sum, 1, %sum /* IEU0 */ -1: and %dst, 0x38, %o4 /* IEU0 Group */ - stwa %g2, [%dst - 4] %asi /* Store */ - add %src, 4, %src /* IEU1 */ + andcc %dst, 7, %g0 /* IEU1 Group */ + be,pt %icc, 4f /* CTI */ + and %dst, 0x38, %o4 /* IEU0 */ + mov 1, %g5 /* IEU0 Group */ + andcc %dst, 2, %g0 /* IEU1 */ + be,pt %icc, 1f /* CTI */ + and %dst, 4, %g7 /* IEU0 Group */ + lduh [%src], %g2 /* Load */ + sub %len, 2, %len /* IEU0 Group */ + add %dst, 2, %dst /* IEU1 */ + andcc %dst, 4, %g7 /* IEU1 Group */ + sll %g5, 16, %g5 /* IEU0 */ + stha %g2, [%dst - 2] %asi /* Store Group */ + sll %g2, 16, %g2 /* IEU0 */ + add %src, 2, %src /* IEU1 */ + addcc %g2, %sum, %sum /* IEU1 Group */ + bcs,a,pn %icc, 1f /* CTI */ + add %sum, %g5, %sum /* IEU0 */ +1: lduw [%src], %g2 /* Load */ + brz,a,pn %g7, 4f /* CTI+IEU1 Group */ + and %dst, 0x38, %o4 /* IEU0 */ + add %dst, 4, %dst /* IEU0 Group */ + sub %len, 4, %len /* IEU1 */ + addcc %g2, %sum, %sum /* IEU1 Group */ + bcs,a,pn %icc, 1f /* CTI */ + add %sum, 1, %sum /* IEU0 */ +1: and %dst, 0x38, %o4 /* IEU0 Group */ + stwa %g2, [%dst - 4] %asi /* Store */ + add %src, 4, %src /* IEU1 */ 4: #ifdef __KERNEL__ VISEntry #endif - mov %src, %g7 /* IEU1 Group */ - fzero %f48 /* FPA */ - alignaddr %src, %g0, %src /* Single Group */ - subcc %g7, %src, %g7 /* IEU1 Group */ - be,pt %xcc, 1f /* CTI */ - mov 0x40, %g1 /* IEU0 */ - lduw [%src], %g2 /* Load Group */ - subcc %sum, %g2, %sum /* IEU1 Group+load stall */ - bcs,a,pn %icc, 1f /* CTI */ - sub %sum, 1, %sum /* IEU0 */ -1: srl %sum, 0, %sum /* IEU0 Group */ - clr %g5 /* IEU1 */ - brz,pn %o4, 3f /* CTI+IEU1 Group */ - sub %g1, %o4, %g1 /* IEU0 */ - ldd [%src], %f0 /* Load */ - clr %o4 /* IEU0 Group */ - andcc %dst, 8, %g0 /* IEU1 */ - be,pn %icc, 1f /* CTI */ - ldd [%src + 8], %f2 /* Load Group */ - add %src, 8, %src /* IEU0 */ - sub %len, 8, %len /* IEU1 */ - fpadd32 %f0, %f48, %f50 /* FPA */ - addcc %dst, 8, %dst /* IEU1 Group */ - faligndata %f0, %f2, %f16 /* FPA */ - fcmpgt32 %f48, %f50, %o4 /* FPM Group */ - fmovd %f2, %f0 /* FPA Group */ - ldd [%src + 8], %f2 /* Load */ - stda %f16, [%dst - 8] %asi /* Store */ - fmovd %f50, %f48 /* FPA */ -1: andcc %g1, 0x10, %g0 /* IEU1 Group */ - be,pn %icc, 1f /* CTI */ - and %g1, 0x20, %g1 /* IEU0 */ - fpadd32 %f0, %f48, %f50 /* FPA */ - ldd [%src + 16], %f4 /* Load Group */ - add %src, 16, %src /* IEU0 */ - add %dst, 16, %dst /* IEU1 */ - faligndata %f0, %f2, %f16 /* FPA */ - fcmpgt32 %f48, %f50, %g5 /* FPM Group */ - sub %len, 16, %len /* IEU0 */ - inc %o4 /* IEU1 */ - stda %f16, [%dst - 16] %asi /* Store Group */ - fpadd32 %f2, %f50, %f48 /* FPA */ - srl %o4, 1, %o5 /* IEU0 */ - faligndata %f2, %f4, %f18 /* FPA Group */ - stda %f18, [%dst - 8] %asi /* Store */ - fcmpgt32 %f50, %f48, %o4 /* FPM Group */ - add %o5, %sum, %sum /* IEU0 */ - ldd [%src + 8], %f2 /* Load */ - fmovd %f4, %f0 /* FPA */ -1: brz,a,pn %g1, 4f /* CTI+IEU1 Group */ - rd %asi, %g2 /* LSU Group + 4 bubbles */ - inc %g5 /* IEU0 */ - fpadd32 %f0, %f48, %f50 /* FPA */ - ldd [%src + 16], %f4 /* Load Group */ - srl %g5, 1, %g5 /* IEU0 */ - add %dst, 32, %dst /* IEU1 */ - faligndata %f0, %f2, %f16 /* FPA */ - fcmpgt32 %f48, %f50, %o5 /* FPM Group */ - inc %o4 /* IEU0 */ - ldd [%src + 24], %f6 /* Load */ - srl %o4, 1, %o4 /* IEU0 Group */ - add %g5, %sum, %sum /* IEU1 */ - ldd [%src + 32], %f8 /* Load */ - fpadd32 %f2, %f50, %f48 /* FPA */ - faligndata %f2, %f4, %f18 /* FPA Group */ - sub %len, 32, %len /* IEU0 */ - stda %f16, [%dst - 32] %asi /* Store */ - fcmpgt32 %f50, %f48, %g3 /* FPM Group */ - inc %o5 /* IEU0 */ - add %o4, %sum, %sum /* IEU1 */ - fpadd32 %f4, %f48, %f50 /* FPA */ - faligndata %f4, %f6, %f20 /* FPA Group */ - srl %o5, 1, %o5 /* IEU0 */ - fcmpgt32 %f48, %f50, %g5 /* FPM Group */ - add %o5, %sum, %sum /* IEU0 */ - stda %f18, [%dst - 24] %asi /* Store */ - fpadd32 %f6, %f50, %f48 /* FPA */ - inc %g3 /* IEU0 Group */ - stda %f20, [%dst - 16] %asi /* Store */ - add %src, 32, %src /* IEU1 */ - faligndata %f6, %f8, %f22 /* FPA */ - fcmpgt32 %f50, %f48, %o4 /* FPM Group */ - srl %g3, 1, %g3 /* IEU0 */ - stda %f22, [%dst - 8] %asi /* Store */ - add %g3, %sum, %sum /* IEU0 Group */ -3: rd %asi, %g2 /* LSU Group + 4 bubbles */ + mov %src, %g7 /* IEU1 Group */ + fzero %f48 /* FPA */ + alignaddr %src, %g0, %src /* Single Group */ + subcc %g7, %src, %g7 /* IEU1 Group */ + be,pt %xcc, 1f /* CTI */ + mov 0x40, %g1 /* IEU0 */ + lduw [%src], %g2 /* Load Group */ + subcc %sum, %g2, %sum /* IEU1 Group+load stall*/ + bcs,a,pn %icc, 1f /* CTI */ + sub %sum, 1, %sum /* IEU0 */ +1: srl %sum, 0, %sum /* IEU0 Group */ + clr %g5 /* IEU1 */ + brz,pn %o4, 3f /* CTI+IEU1 Group */ + sub %g1, %o4, %g1 /* IEU0 */ + ldd [%src], %f0 /* Load */ + clr %o4 /* IEU0 Group */ + andcc %dst, 8, %g0 /* IEU1 */ + be,pn %icc, 1f /* CTI */ + ldd [%src + 8], %f2 /* Load Group */ + add %src, 8, %src /* IEU0 */ + sub %len, 8, %len /* IEU1 */ + fpadd32 %f0, %f48, %f50 /* FPA */ + addcc %dst, 8, %dst /* IEU1 Group */ + faligndata %f0, %f2, %f16 /* FPA */ + fcmpgt32 %f48, %f50, %o4 /* FPM Group */ + fmovd %f2, %f0 /* FPA Group */ + ldd [%src + 8], %f2 /* Load */ + stda %f16, [%dst - 8] %asi /* Store */ + fmovd %f50, %f48 /* FPA */ +1: andcc %g1, 0x10, %g0 /* IEU1 Group */ + be,pn %icc, 1f /* CTI */ + and %g1, 0x20, %g1 /* IEU0 */ + fpadd32 %f0, %f48, %f50 /* FPA */ + ldd [%src + 16], %f4 /* Load Group */ + add %src, 16, %src /* IEU0 */ + add %dst, 16, %dst /* IEU1 */ + faligndata %f0, %f2, %f16 /* FPA */ + fcmpgt32 %f48, %f50, %g5 /* FPM Group */ + sub %len, 16, %len /* IEU0 */ + inc %o4 /* IEU1 */ + stda %f16, [%dst - 16] %asi /* Store Group */ + fpadd32 %f2, %f50, %f48 /* FPA */ + srl %o4, 1, %o5 /* IEU0 */ + faligndata %f2, %f4, %f18 /* FPA Group */ + stda %f18, [%dst - 8] %asi /* Store */ + fcmpgt32 %f50, %f48, %o4 /* FPM Group */ + add %o5, %sum, %sum /* IEU0 */ + ldd [%src + 8], %f2 /* Load */ + fmovd %f4, %f0 /* FPA */ +1: brz,a,pn %g1, 4f /* CTI+IEU1 Group */ + rd %asi, %g2 /* LSU Group + 4 bubbles*/ + inc %g5 /* IEU0 */ + fpadd32 %f0, %f48, %f50 /* FPA */ + ldd [%src + 16], %f4 /* Load Group */ + srl %g5, 1, %g5 /* IEU0 */ + add %dst, 32, %dst /* IEU1 */ + faligndata %f0, %f2, %f16 /* FPA */ + fcmpgt32 %f48, %f50, %o5 /* FPM Group */ + inc %o4 /* IEU0 */ + ldd [%src + 24], %f6 /* Load */ + srl %o4, 1, %o4 /* IEU0 Group */ + add %g5, %sum, %sum /* IEU1 */ + ldd [%src + 32], %f8 /* Load */ + fpadd32 %f2, %f50, %f48 /* FPA */ + faligndata %f2, %f4, %f18 /* FPA Group */ + sub %len, 32, %len /* IEU0 */ + stda %f16, [%dst - 32] %asi /* Store */ + fcmpgt32 %f50, %f48, %g3 /* FPM Group */ + inc %o5 /* IEU0 */ + add %o4, %sum, %sum /* IEU1 */ + fpadd32 %f4, %f48, %f50 /* FPA */ + faligndata %f4, %f6, %f20 /* FPA Group */ + srl %o5, 1, %o5 /* IEU0 */ + fcmpgt32 %f48, %f50, %g5 /* FPM Group */ + add %o5, %sum, %sum /* IEU0 */ + stda %f18, [%dst - 24] %asi /* Store */ + fpadd32 %f6, %f50, %f48 /* FPA */ + inc %g3 /* IEU0 Group */ + stda %f20, [%dst - 16] %asi /* Store */ + add %src, 32, %src /* IEU1 */ + faligndata %f6, %f8, %f22 /* FPA */ + fcmpgt32 %f50, %f48, %o4 /* FPM Group */ + srl %g3, 1, %g3 /* IEU0 */ + stda %f22, [%dst - 8] %asi /* Store */ + add %g3, %sum, %sum /* IEU0 Group */ +3: rd %asi, %g2 /* LSU Group + 4 bubbles*/ #ifdef __KERNEL__ -4: sethi %hi(vis0s), %g7 /* IEU0 Group */ - or %g2, ASI_BLK_OR, %g2 /* IEU1 */ +4: sethi %hi(vis0s), %g7 /* IEU0 Group */ + or %g2, ASI_BLK_OR, %g2 /* IEU1 */ #else -4: rd %pc, %g7 /* LSU Group + 4 bubbles */ +4: rd %pc, %g7 /* LSU Group + 4 bubbles*/ #endif - inc %g5 /* IEU0 Group */ - and %src, 0x38, %g3 /* IEU1 */ - membar #StoreLoad /* LSU Group */ - srl %g5, 1, %g5 /* IEU0 */ - inc %o4 /* IEU1 */ - sll %g3, 8, %g3 /* IEU0 Group */ - sub %len, 0xc0, %len /* IEU1 */ - addcc %g5, %sum, %sum /* IEU1 Group */ - srl %o4, 1, %o4 /* IEU0 */ - add %g7, %g3, %g7 /* IEU0 Group */ - add %o4, %sum, %sum /* IEU1 */ + inc %g5 /* IEU0 Group */ + and %src, 0x38, %g3 /* IEU1 */ + membar #StoreLoad /* LSU Group */ + srl %g5, 1, %g5 /* IEU0 */ + inc %o4 /* IEU1 */ + sll %g3, 8, %g3 /* IEU0 Group */ + sub %len, 0xc0, %len /* IEU1 */ + addcc %g5, %sum, %sum /* IEU1 Group */ + srl %o4, 1, %o4 /* IEU0 */ + add %g7, %g3, %g7 /* IEU0 Group */ + add %o4, %sum, %sum /* IEU1 */ #ifdef __KERNEL__ - jmpl %g7 + %lo(vis0s), %g0 /* CTI+IEU1 Group */ + jmpl %g7 + %lo(vis0s), %g0 /* CTI+IEU1 Group */ #else - jmpl %g7 + (vis0s - 4b), %g0 /* CTI+IEU1 Group */ + jmpl %g7 + (vis0s - 4b), %g0 /* CTI+IEU1 Group */ #endif - fzero %f32 /* FPA */ + fzero %f32 /* FPA */ .align 2048 -vis0s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ - ldda [%src] ASI_BLK_P, %f0 /* Load Group */ - add %src, 64, %src /* IEU0 Group */ - ldda [%src] ASI_BLK_P, %f16 /* Load Group */ - add %src, 64, %src /* IEU0 Group */ - fmovd %f48, %f62 /* FPA Group f0 available */ - faligndata %f0, %f2, %f48 /* FPA Group f2 available */ - fcmpgt32 %f32, %f2, %x1 /* FPM Group f4 available */ - fpadd32 %f0, %f62, %f0 /* FPA */ - fcmpgt32 %f32, %f4, %x2 /* FPM Group f6 available */ - faligndata %f2, %f4, %f50 /* FPA */ - fcmpgt32 %f62, %f0, %x3 /* FPM Group f8 available */ - faligndata %f4, %f6, %f52 /* FPA */ - fcmpgt32 %f32, %f6, %x4 /* FPM Group f10 available */ - inc %x1 /* IEU0 */ - faligndata %f6, %f8, %f54 /* FPA */ - fcmpgt32 %f32, %f8, %x5 /* FPM Group f12 available */ - srl %x1, 1, %x1 /* IEU0 */ - inc %x2 /* IEU1 */ - faligndata %f8, %f10, %f56 /* FPA */ - fcmpgt32 %f32, %f10, %x6 /* FPM Group f14 available */ - srl %x2, 1, %x2 /* IEU0 */ - add %sum, %x1, %sum /* IEU1 */ - faligndata %f10, %f12, %f58 /* FPA */ - fcmpgt32 %f32, %f12, %x7 /* FPM Group */ - inc %x3 /* IEU0 */ - add %sum, %x2, %sum /* IEU1 */ - faligndata %f12, %f14, %f60 /* FPA */ - fcmpgt32 %f32, %f14, %x8 /* FPM Group */ - srl %x3, 1, %x3 /* IEU0 */ - inc %x4 /* IEU1 */ - fmovd %f14, %f62 /* FPA */ - srl %x4, 1, %x4 /* IEU0 Group */ - add %sum, %x3, %sum /* IEU1 */ +vis0s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ + ldda [%src] ASI_BLK_P, %f0 /* Load Group */ + add %src, 64, %src /* IEU0 Group */ + ldda [%src] ASI_BLK_P, %f16 /* Load Group */ + add %src, 64, %src /* IEU0 Group */ + fmovd %f48, %f62 /* FPA Group f0 available*/ + faligndata %f0, %f2, %f48 /* FPA Group f2 available*/ + fcmpgt32 %f32, %f2, %x1 /* FPM Group f4 available*/ + fpadd32 %f0, %f62, %f0 /* FPA */ + fcmpgt32 %f32, %f4, %x2 /* FPM Group f6 available*/ + faligndata %f2, %f4, %f50 /* FPA */ + fcmpgt32 %f62, %f0, %x3 /* FPM Group f8 available*/ + faligndata %f4, %f6, %f52 /* FPA */ + fcmpgt32 %f32, %f6, %x4 /* FPM Group f10 available*/ + inc %x1 /* IEU0 */ + faligndata %f6, %f8, %f54 /* FPA */ + fcmpgt32 %f32, %f8, %x5 /* FPM Group f12 available*/ + srl %x1, 1, %x1 /* IEU0 */ + inc %x2 /* IEU1 */ + faligndata %f8, %f10, %f56 /* FPA */ + fcmpgt32 %f32, %f10, %x6 /* FPM Group f14 available*/ + srl %x2, 1, %x2 /* IEU0 */ + add %sum, %x1, %sum /* IEU1 */ + faligndata %f10, %f12, %f58 /* FPA */ + fcmpgt32 %f32, %f12, %x7 /* FPM Group */ + inc %x3 /* IEU0 */ + add %sum, %x2, %sum /* IEU1 */ + faligndata %f12, %f14, %f60 /* FPA */ + fcmpgt32 %f32, %f14, %x8 /* FPM Group */ + srl %x3, 1, %x3 /* IEU0 */ + inc %x4 /* IEU1 */ + fmovd %f14, %f62 /* FPA */ + srl %x4, 1, %x4 /* IEU0 Group */ + add %sum, %x3, %sum /* IEU1 */ vis0: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30, ,f48,f50,f52,f54,f56,f58,f60,f62,f62, ,LDBLK(f32), STBLK,,,,,,,, @@ -468,36 +470,36 @@ vis0e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14 ,SYNC, STBLK_XORASI(x1,x2),ST(f48,64),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40),ST(f60,48), ,add %dst, 56, %dst; add %len, 192 - 8*8, %len; ba,pt %icc, e1) .align 2048 -vis1s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ - sub %src, 8, %src /* IEU0 Group */ - ldda [%src] ASI_BLK_P, %f0 /* Load Group */ - add %src, 64, %src /* IEU0 Group */ - ldda [%src] ASI_BLK_P, %f16 /* Load Group */ - add %src, 64, %src /* IEU0 Group */ - fmovd %f0, %f58 /* FPA Group */ - fmovd %f48, %f0 /* FPA Group */ - fcmpgt32 %f32, %f2, %x2 /* FPM Group */ - faligndata %f2, %f4, %f48 /* FPA */ - fcmpgt32 %f32, %f4, %x3 /* FPM Group */ - faligndata %f4, %f6, %f50 /* FPA */ - fcmpgt32 %f32, %f6, %x4 /* FPM Group */ - faligndata %f6, %f8, %f52 /* FPA */ - fcmpgt32 %f32, %f8, %x5 /* FPM Group */ - inc %x2 /* IEU1 */ - faligndata %f8, %f10, %f54 /* FPA */ - fcmpgt32 %f32, %f10, %x6 /* FPM Group */ - srl %x2, 1, %x2 /* IEU0 */ - faligndata %f10, %f12, %f56 /* FPA */ - fcmpgt32 %f32, %f12, %x7 /* FPM Group */ - inc %x3 /* IEU0 */ - add %sum, %x2, %sum /* IEU1 */ - faligndata %f12, %f14, %f58 /* FPA */ - fcmpgt32 %f32, %f14, %x8 /* FPM Group */ - srl %x3, 1, %x3 /* IEU0 */ - inc %x4 /* IEU1 */ - fmovd %f14, %f60 /* FPA */ - srl %x4, 1, %x4 /* IEU0 Group */ - add %sum, %x3, %sum /* IEU1 */ +vis1s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ + sub %src, 8, %src /* IEU0 Group */ + ldda [%src] ASI_BLK_P, %f0 /* Load Group */ + add %src, 64, %src /* IEU0 Group */ + ldda [%src] ASI_BLK_P, %f16 /* Load Group */ + add %src, 64, %src /* IEU0 Group */ + fmovd %f0, %f58 /* FPA Group */ + fmovd %f48, %f0 /* FPA Group */ + fcmpgt32 %f32, %f2, %x2 /* FPM Group */ + faligndata %f2, %f4, %f48 /* FPA */ + fcmpgt32 %f32, %f4, %x3 /* FPM Group */ + faligndata %f4, %f6, %f50 /* FPA */ + fcmpgt32 %f32, %f6, %x4 /* FPM Group */ + faligndata %f6, %f8, %f52 /* FPA */ + fcmpgt32 %f32, %f8, %x5 /* FPM Group */ + inc %x2 /* IEU1 */ + faligndata %f8, %f10, %f54 /* FPA */ + fcmpgt32 %f32, %f10, %x6 /* FPM Group */ + srl %x2, 1, %x2 /* IEU0 */ + faligndata %f10, %f12, %f56 /* FPA */ + fcmpgt32 %f32, %f12, %x7 /* FPM Group */ + inc %x3 /* IEU0 */ + add %sum, %x2, %sum /* IEU1 */ + faligndata %f12, %f14, %f58 /* FPA */ + fcmpgt32 %f32, %f14, %x8 /* FPM Group */ + srl %x3, 1, %x3 /* IEU0 */ + inc %x4 /* IEU1 */ + fmovd %f14, %f60 /* FPA */ + srl %x4, 1, %x4 /* IEU0 Group */ + add %sum, %x3, %sum /* IEU1 */ vis1: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30, ,f62,f48,f50,f52,f54,f56,f58,f60,f60, ,LDBLK(f32), ,STBLK,,,,,,, @@ -523,33 +525,33 @@ vis1e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14 ,SYNC, ,STBLK_XORASI(x1,x2),ST(f48,0),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40), ,add %dst, 48, %dst; add %len, 192 - 7*8, %len; ba,pt %icc, e1) .align 2048 -vis2s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ - sub %src, 16, %src /* IEU0 Group */ - ldda [%src] ASI_BLK_P, %f0 /* Load Group */ - add %src, 64, %src /* IEU0 Group */ - ldda [%src] ASI_BLK_P, %f16 /* Load Group */ - add %src, 64, %src /* IEU0 Group */ - fmovd %f0, %f56 /* FPA Group */ - fmovd %f48, %f0 /* FPA Group */ - sub %dst, 64, %dst /* IEU0 */ - fpsub32 %f2, %f2, %f2 /* FPA Group */ - fcmpgt32 %f32, %f4, %x3 /* FPM Group */ - faligndata %f4, %f6, %f48 /* FPA */ - fcmpgt32 %f32, %f6, %x4 /* FPM Group */ - faligndata %f6, %f8, %f50 /* FPA */ - fcmpgt32 %f32, %f8, %x5 /* FPM Group */ - faligndata %f8, %f10, %f52 /* FPA */ - fcmpgt32 %f32, %f10, %x6 /* FPM Group */ - faligndata %f10, %f12, %f54 /* FPA */ - fcmpgt32 %f32, %f12, %x7 /* FPM Group */ - inc %x3 /* IEU0 */ - faligndata %f12, %f14, %f56 /* FPA */ - fcmpgt32 %f32, %f14, %x8 /* FPM Group */ - srl %x3, 1, %x3 /* IEU0 */ - inc %x4 /* IEU1 */ - fmovd %f14, %f58 /* FPA */ - srl %x4, 1, %x4 /* IEU0 Group */ - add %sum, %x3, %sum /* IEU1 */ +vis2s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ + sub %src, 16, %src /* IEU0 Group */ + ldda [%src] ASI_BLK_P, %f0 /* Load Group */ + add %src, 64, %src /* IEU0 Group */ + ldda [%src] ASI_BLK_P, %f16 /* Load Group */ + add %src, 64, %src /* IEU0 Group */ + fmovd %f0, %f56 /* FPA Group */ + fmovd %f48, %f0 /* FPA Group */ + sub %dst, 64, %dst /* IEU0 */ + fpsub32 %f2, %f2, %f2 /* FPA Group */ + fcmpgt32 %f32, %f4, %x3 /* FPM Group */ + faligndata %f4, %f6, %f48 /* FPA */ + fcmpgt32 %f32, %f6, %x4 /* FPM Group */ + faligndata %f6, %f8, %f50 /* FPA */ + fcmpgt32 %f32, %f8, %x5 /* FPM Group */ + faligndata %f8, %f10, %f52 /* FPA */ + fcmpgt32 %f32, %f10, %x6 /* FPM Group */ + faligndata %f10, %f12, %f54 /* FPA */ + fcmpgt32 %f32, %f12, %x7 /* FPM Group */ + inc %x3 /* IEU0 */ + faligndata %f12, %f14, %f56 /* FPA */ + fcmpgt32 %f32, %f14, %x8 /* FPM Group */ + srl %x3, 1, %x3 /* IEU0 */ + inc %x4 /* IEU1 */ + fmovd %f14, %f58 /* FPA */ + srl %x4, 1, %x4 /* IEU0 Group */ + add %sum, %x3, %sum /* IEU1 */ vis2: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30, ,f60,f62,f48,f50,f52,f54,f56,f58,f58, ,LDBLK(f32), ,,STBLK,,,,,, @@ -575,29 +577,29 @@ vis2e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14 ,SYNC, ,,STBLK_XORASI(x2,x3),ST(f48,64),ST(f50,72),ST(f52,80),ST(f54,88),ST(f56,96), ,add %dst, 104, %dst; add %len, 192 - 6*8, %len; ba,pt %icc, e1) .align 2048 -vis3s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ - sub %src, 24, %src /* IEU0 Group */ - ldda [%src] ASI_BLK_P, %f0 /* Load Group */ - add %src, 64, %src /* IEU0 Group */ - ldda [%src] ASI_BLK_P, %f16 /* Load Group */ - add %src, 64, %src /* IEU0 Group */ - fmovd %f0, %f54 /* FPA Group */ - fmovd %f48, %f0 /* FPA Group */ - sub %dst, 64, %dst /* IEU0 */ - fpsub32 %f2, %f2, %f2 /* FPA Group */ - fpsub32 %f4, %f4, %f4 /* FPA Group */ - fcmpgt32 %f32, %f6, %x4 /* FPM Group */ - faligndata %f6, %f8, %f48 /* FPA */ - fcmpgt32 %f32, %f8, %x5 /* FPM Group */ - faligndata %f8, %f10, %f50 /* FPA */ - fcmpgt32 %f32, %f10, %x6 /* FPM Group */ - faligndata %f10, %f12, %f52 /* FPA */ - fcmpgt32 %f32, %f12, %x7 /* FPM Group */ - faligndata %f12, %f14, %f54 /* FPA */ - fcmpgt32 %f32, %f14, %x8 /* FPM Group */ - fmovd %f14, %f56 /* FPA */ - inc %x4 /* IEU0 */ - srl %x4, 1, %x4 /* IEU0 Group */ +vis3s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ + sub %src, 24, %src /* IEU0 Group */ + ldda [%src] ASI_BLK_P, %f0 /* Load Group */ + add %src, 64, %src /* IEU0 Group */ + ldda [%src] ASI_BLK_P, %f16 /* Load Group */ + add %src, 64, %src /* IEU0 Group */ + fmovd %f0, %f54 /* FPA Group */ + fmovd %f48, %f0 /* FPA Group */ + sub %dst, 64, %dst /* IEU0 */ + fpsub32 %f2, %f2, %f2 /* FPA Group */ + fpsub32 %f4, %f4, %f4 /* FPA Group */ + fcmpgt32 %f32, %f6, %x4 /* FPM Group */ + faligndata %f6, %f8, %f48 /* FPA */ + fcmpgt32 %f32, %f8, %x5 /* FPM Group */ + faligndata %f8, %f10, %f50 /* FPA */ + fcmpgt32 %f32, %f10, %x6 /* FPM Group */ + faligndata %f10, %f12, %f52 /* FPA */ + fcmpgt32 %f32, %f12, %x7 /* FPM Group */ + faligndata %f12, %f14, %f54 /* FPA */ + fcmpgt32 %f32, %f14, %x8 /* FPM Group */ + fmovd %f14, %f56 /* FPA */ + inc %x4 /* IEU0 */ + srl %x4, 1, %x4 /* IEU0 Group */ vis3: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30, ,f58,f60,f62,f48,f50,f52,f54,f56,f56, ,LDBLK(f32), ,,,STBLK,,,,, @@ -623,27 +625,27 @@ vis3e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14 ,SYNC, ,,,STBLK_XORASI(x3,x4),ST(f48,64),ST(f50,72),ST(f52,80),ST(f54,88), ,add %dst, 96, %dst; add %len, 192 - 5*8, %len; ba,pt %icc, e1) .align 2048 -vis4s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ - sub %src, 32, %src /* IEU0 Group */ - ldda [%src] ASI_BLK_P, %f0 /* Load Group */ - add %src, 64, %src /* IEU0 Group */ - ldda [%src] ASI_BLK_P, %f16 /* Load Group */ - add %src, 64, %src /* IEU0 Group */ - fmovd %f0, %f52 /* FPA Group */ - fmovd %f48, %f0 /* FPA Group */ - sub %dst, 64, %dst /* IEU0 */ - fpsub32 %f2, %f2, %f2 /* FPA Group */ - fpsub32 %f4, %f4, %f4 /* FPA Group */ - fpsub32 %f6, %f6, %f6 /* FPA Group */ - clr %x4 /* IEU0 */ - fcmpgt32 %f32, %f8, %x5 /* FPM Group */ - faligndata %f8, %f10, %f48 /* FPA */ - fcmpgt32 %f32, %f10, %x6 /* FPM Group */ - faligndata %f10, %f12, %f50 /* FPA */ - fcmpgt32 %f32, %f12, %x7 /* FPM Group */ - faligndata %f12, %f14, %f52 /* FPA */ - fcmpgt32 %f32, %f14, %x8 /* FPM Group */ - fmovd %f14, %f54 /* FPA */ +vis4s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ + sub %src, 32, %src /* IEU0 Group */ + ldda [%src] ASI_BLK_P, %f0 /* Load Group */ + add %src, 64, %src /* IEU0 Group */ + ldda [%src] ASI_BLK_P, %f16 /* Load Group */ + add %src, 64, %src /* IEU0 Group */ + fmovd %f0, %f52 /* FPA Group */ + fmovd %f48, %f0 /* FPA Group */ + sub %dst, 64, %dst /* IEU0 */ + fpsub32 %f2, %f2, %f2 /* FPA Group */ + fpsub32 %f4, %f4, %f4 /* FPA Group */ + fpsub32 %f6, %f6, %f6 /* FPA Group */ + clr %x4 /* IEU0 */ + fcmpgt32 %f32, %f8, %x5 /* FPM Group */ + faligndata %f8, %f10, %f48 /* FPA */ + fcmpgt32 %f32, %f10, %x6 /* FPM Group */ + faligndata %f10, %f12, %f50 /* FPA */ + fcmpgt32 %f32, %f12, %x7 /* FPM Group */ + faligndata %f12, %f14, %f52 /* FPA */ + fcmpgt32 %f32, %f14, %x8 /* FPM Group */ + fmovd %f14, %f54 /* FPA */ vis4: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30, ,f56,f58,f60,f62,f48,f50,f52,f54,f54, ,LDBLK(f32), ,,,,STBLK,,,, @@ -669,27 +671,27 @@ vis4e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14 ,SYNC, ,,,,STBLK_XORASI(x4,x5),ST(f48,64),ST(f50,72),ST(f52,80), ,add %dst, 88, %dst; add %len, 192 - 4*8, %len; ba,pt %icc, e1) .align 2048 -vis5s: ldd [%src+0], %f10 /* Load Group */ - ldd [%src+8], %f12 /* Load Group */ - ldd [%src+16], %f14 /* Load Group */ - add %src, 24, %src /* IEU0 Group */ - wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ - ldda [%src] ASI_BLK_P, %f16 /* Load Group */ - add %src, 64, %src /* IEU0 Group */ - fmovd %f48, %f0 /* FPA Group */ - fmuld %f32, %f32, %f2 /* FPM */ - clr %x4 /* IEU0 */ - faddd %f32, %f32, %f4 /* FPA Group */ - fmuld %f32, %f32, %f6 /* FPM */ - clr %x5 /* IEU0 */ - faddd %f32, %f32, %f8 /* FPA Group */ - fcmpgt32 %f32, %f10, %x6 /* FPM Group */ - sub %dst, 64, %dst /* IEU0 */ - faligndata %f10, %f12, %f48 /* FPA */ - fcmpgt32 %f32, %f12, %x7 /* FPM Group */ - faligndata %f12, %f14, %f50 /* FPA */ - fcmpgt32 %f32, %f14, %x8 /* FPM Group */ - fmovd %f14, %f52 /* FPA */ +vis5s: ldd [%src+0], %f10 /* Load Group */ + ldd [%src+8], %f12 /* Load Group */ + ldd [%src+16], %f14 /* Load Group */ + add %src, 24, %src /* IEU0 Group */ + wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ + ldda [%src] ASI_BLK_P, %f16 /* Load Group */ + add %src, 64, %src /* IEU0 Group */ + fmovd %f48, %f0 /* FPA Group */ + fmuld %f32, %f32, %f2 /* FPM */ + clr %x4 /* IEU0 */ + faddd %f32, %f32, %f4 /* FPA Group */ + fmuld %f32, %f32, %f6 /* FPM */ + clr %x5 /* IEU0 */ + faddd %f32, %f32, %f8 /* FPA Group */ + fcmpgt32 %f32, %f10, %x6 /* FPM Group */ + sub %dst, 64, %dst /* IEU0 */ + faligndata %f10, %f12, %f48 /* FPA */ + fcmpgt32 %f32, %f12, %x7 /* FPM Group */ + faligndata %f12, %f14, %f50 /* FPA */ + fcmpgt32 %f32, %f14, %x8 /* FPM Group */ + fmovd %f14, %f52 /* FPA */ vis5: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30, ,f54,f56,f58,f60,f62,f48,f50,f52,f52, ,LDBLK(f32), ,,,,,STBLK,,, @@ -715,26 +717,26 @@ vis5e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14 ,SYNC, ,,,,,STBLK_XORASI(x5,x6),ST(f48,64),ST(f50,72), ,add %dst, 80, %dst; add %len, 192 - 3*8, %len; ba,pt %icc, e1) .align 2048 -vis6s: ldd [%src+0], %f12 /* Load Group */ - ldd [%src+8], %f14 /* Load Group */ - add %src, 16, %src /* IEU0 Group */ - wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ - ldda [%src] ASI_BLK_P, %f16 /* Load Group */ - add %src, 64, %src /* IEU0 Group */ - fmovd %f48, %f0 /* FPA Group */ - fmuld %f32, %f32, %f2 /* FPM */ - clr %x4 /* IEU0 */ - faddd %f32, %f32, %f4 /* FPA Group */ - fmuld %f32, %f32, %f6 /* FPM */ - clr %x5 /* IEU0 */ - faddd %f32, %f32, %f8 /* FPA Group */ - fmuld %f32, %f32, %f10 /* FPM */ - clr %x6 /* IEU0 */ - fcmpgt32 %f32, %f12, %x7 /* FPM Group */ - sub %dst, 64, %dst /* IEU0 */ - fcmpgt32 %f32, %f14, %x8 /* FPM Group */ - faligndata %f12, %f14, %f48 /* FPA */ - fmovd %f14, %f50 /* FPA Group */ +vis6s: ldd [%src+0], %f12 /* Load Group */ + ldd [%src+8], %f14 /* Load Group */ + add %src, 16, %src /* IEU0 Group */ + wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ + ldda [%src] ASI_BLK_P, %f16 /* Load Group */ + add %src, 64, %src /* IEU0 Group */ + fmovd %f48, %f0 /* FPA Group */ + fmuld %f32, %f32, %f2 /* FPM */ + clr %x4 /* IEU0 */ + faddd %f32, %f32, %f4 /* FPA Group */ + fmuld %f32, %f32, %f6 /* FPM */ + clr %x5 /* IEU0 */ + faddd %f32, %f32, %f8 /* FPA Group */ + fmuld %f32, %f32, %f10 /* FPM */ + clr %x6 /* IEU0 */ + fcmpgt32 %f32, %f12, %x7 /* FPM Group */ + sub %dst, 64, %dst /* IEU0 */ + fcmpgt32 %f32, %f14, %x8 /* FPM Group */ + faligndata %f12, %f14, %f48 /* FPA */ + fmovd %f14, %f50 /* FPA Group */ vis6: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30, ,f52,f54,f56,f58,f60,f62,f48,f50,f50, ,LDBLK(f32), ,,,,,,STBLK,, @@ -760,25 +762,25 @@ vis6e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14 ,SYNC, ,,,,,,STBLK_XORASI(x6,x7),ST(f48,64), ,add %dst, 72, %dst; add %len, 192 - 2*8, %len; ba,pt %icc, e1) .align 2048 -vis7s: ldd [%src+0], %f14 /* Load Group */ - add %src, 8, %src /* IEU0 Group */ - wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ - ldda [%src] ASI_BLK_P, %f16 /* Load Group */ - add %src, 64, %src /* IEU0 Group */ - fmovd %f48, %f0 /* FPA Group */ - fmuld %f32, %f32, %f2 /* FPM */ - clr %x4 /* IEU0 */ - faddd %f32, %f32, %f4 /* FPA Group */ - fmuld %f32, %f32, %f6 /* FPM */ - clr %x5 /* IEU0 */ - faddd %f32, %f32, %f8 /* FPA Group */ - fmuld %f32, %f32, %f10 /* FPM */ - clr %x6 /* IEU0 */ - faddd %f32, %f32, %f12 /* FPA Group */ - clr %x7 /* IEU0 */ - fcmpgt32 %f32, %f14, %x8 /* FPM Group */ - sub %dst, 64, %dst /* IEU0 */ - fmovd %f14, %f48 /* FPA */ +vis7s: ldd [%src+0], %f14 /* Load Group */ + add %src, 8, %src /* IEU0 Group */ + wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ + ldda [%src] ASI_BLK_P, %f16 /* Load Group */ + add %src, 64, %src /* IEU0 Group */ + fmovd %f48, %f0 /* FPA Group */ + fmuld %f32, %f32, %f2 /* FPM */ + clr %x4 /* IEU0 */ + faddd %f32, %f32, %f4 /* FPA Group */ + fmuld %f32, %f32, %f6 /* FPM */ + clr %x5 /* IEU0 */ + faddd %f32, %f32, %f8 /* FPA Group */ + fmuld %f32, %f32, %f10 /* FPM */ + clr %x6 /* IEU0 */ + faddd %f32, %f32, %f12 /* FPA Group */ + clr %x7 /* IEU0 */ + fcmpgt32 %f32, %f14, %x8 /* FPM Group */ + sub %dst, 64, %dst /* IEU0 */ + fmovd %f14, %f48 /* FPA */ vis7: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30, ,f50,f52,f54,f56,f58,f60,f62,f48,f48, ,LDBLK(f32), ,,,,,,,STBLK, @@ -806,104 +808,104 @@ vis7e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14 e1: END_THE_TRICK1( f0,f2,f4,f6,f8,f10,f12,f14,f16,f6) e2: END_THE_TRICK1( f16,f18,f20,f22,f24,f26,f28,f30,f32,f6) e3: END_THE_TRICK1( f32,f34,f36,f38,f40,f42,f44,f46,f0,f6) -ett: rd %gsr, %x3 /* LSU Group+4bubbles */ - andcc %x3, 7, %x3 /* IEU1 Group */ - add %dst, 8, %dst /* IEU0 */ - bne,pn %icc, 1f /* CTI */ - fzero %f10 /* FPA */ - brz,a,pn %len, 2f /* CTI+IEU1 Group */ - stda %f6, [%dst - 8] %asi /* Store */ -1: cmp %len, 8 /* IEU1 */ - blu,pn %icc, 3f /* CTI */ - sub %src, 64, %src /* IEU0 Group */ -1: ldd [%src], %f2 /* Load Group */ - fpadd32 %f10, %f2, %f12 /* FPA Group+load stall */ - add %src, 8, %src /* IEU0 */ - add %dst, 8, %dst /* IEU1 */ - faligndata %f6, %f2, %f14 /* FPA Group */ - fcmpgt32 %f10, %f12, %x5 /* FPM Group */ - stda %f14, [%dst - 16] %asi /* Store */ - fmovd %f2, %f6 /* FPA */ - fmovd %f12, %f10 /* FPA Group */ - sub %len, 8, %len /* IEU1 */ - fzero %f16 /* FPA Group - FPU nop */ - fzero %f18 /* FPA Group - FPU nop */ - inc %x5 /* IEU0 */ - srl %x5, 1, %x5 /* IEU0 Group (regdep) */ - cmp %len, 8 /* IEU1 */ - bgeu,pt %icc, 1b /* CTI */ - add %x5, %sum, %sum /* IEU0 Group */ -3: brz,a,pt %x3, 2f /* CTI+IEU1 */ - stda %f6, [%dst - 8] %asi /* Store Group */ - sta %f7, [%dst - 8] %asi /* Store Group */ - sub %dst, 4, %dst /* IEU0 */ - add %len, 4, %len /* IEU1 */ +ett: rd %gsr, %x3 /* LSU Group+4bubbles */ + andcc %x3, 7, %x3 /* IEU1 Group */ + add %dst, 8, %dst /* IEU0 */ + bne,pn %icc, 1f /* CTI */ + fzero %f10 /* FPA */ + brz,a,pn %len, 2f /* CTI+IEU1 Group */ + stda %f6, [%dst - 8] %asi /* Store */ +1: cmp %len, 8 /* IEU1 */ + blu,pn %icc, 3f /* CTI */ + sub %src, 64, %src /* IEU0 Group */ +1: ldd [%src], %f2 /* Load Group */ + fpadd32 %f10, %f2, %f12 /* FPA Group+load stall*/ + add %src, 8, %src /* IEU0 */ + add %dst, 8, %dst /* IEU1 */ + faligndata %f6, %f2, %f14 /* FPA Group */ + fcmpgt32 %f10, %f12, %x5 /* FPM Group */ + stda %f14, [%dst - 16] %asi /* Store */ + fmovd %f2, %f6 /* FPA */ + fmovd %f12, %f10 /* FPA Group */ + sub %len, 8, %len /* IEU1 */ + fzero %f16 /* FPA Group - FPU nop */ + fzero %f18 /* FPA Group - FPU nop */ + inc %x5 /* IEU0 */ + srl %x5, 1, %x5 /* IEU0 Group (regdep) */ + cmp %len, 8 /* IEU1 */ + bgeu,pt %icc, 1b /* CTI */ + add %x5, %sum, %sum /* IEU0 Group */ +3: brz,a,pt %x3, 2f /* CTI+IEU1 */ + stda %f6, [%dst - 8] %asi /* Store Group */ + sta %f7, [%dst - 8] %asi /* Store Group */ + sub %dst, 4, %dst /* IEU0 */ + add %len, 4, %len /* IEU1 */ 2: #ifdef __KERNEL__ - sub %sp, 8, %sp /* IEU0 Group */ + sub %sp, 8, %sp /* IEU0 Group */ #endif END_THE_TRICK2( f48,f50,f52,f54,f56,f58,f60,f10,f12,f62) - membar #Sync /* LSU Group */ + membar #Sync /* LSU Group */ #ifdef __KERNEL__ VISExit - add %sp, 8, %sp /* IEU0 Group */ + add %sp, 8, %sp /* IEU0 Group */ #endif -23: brnz,pn %len, 26f /* CTI+IEU1 Group */ -24: sllx %sum, 32, %g1 /* IEU0 */ -25: addcc %sum, %g1, %src /* IEU1 Group */ - srlx %src, 32, %src /* IEU0 Group (regdep) */ - bcs,a,pn %xcc, 1f /* CTI */ - add %src, 1, %src /* IEU1 */ +23: brnz,pn %len, 26f /* CTI+IEU1 Group */ +24: sllx %sum, 32, %g1 /* IEU0 */ +25: addcc %sum, %g1, %src /* IEU1 Group */ + srlx %src, 32, %src /* IEU0 Group (regdep) */ + bcs,a,pn %xcc, 1f /* CTI */ + add %src, 1, %src /* IEU1 */ #ifndef __KERNEL__ -1: retl /* CTI Group brk forced */ - srl %src, 0, %src /* IEU0 */ +1: retl /* CTI Group brk forced*/ + srl %src, 0, %src /* IEU0 */ #else -1: sethi %uhi(PAGE_OFFSET), %g4 /* IEU0 Group */ - retl /* CTI Group brk forced */ - sllx %g4, 32, %g4 /* IEU0 */ +1: sethi %uhi(PAGE_OFFSET), %g4 /* IEU0 Group */ + retl /* CTI Group brk forced*/ + sllx %g4, 32, %g4 /* IEU0 */ #endif -26: andcc %len, 8, %g0 /* IEU1 Group */ - be,pn %icc, 1f /* CTI */ - lduw [%src], %o4 /* Load */ - lduw [%src+4], %g2 /* Load Group */ - add %src, 8, %src /* IEU0 */ - add %dst, 8, %dst /* IEU1 */ - sllx %o4, 32, %g5 /* IEU0 Group */ - stwa %o4, [%dst - 8] %asi /* Store */ - or %g5, %g2, %g5 /* IEU0 Group */ - stwa %g2, [%dst - 4] %asi /* Store */ - addcc %g5, %sum, %sum /* IEU1 Group */ - bcs,a,pn %xcc, 1f /* CTI */ - add %sum, 1, %sum /* IEU0 */ -1: andcc %len, 4, %g0 /* IEU1 Group */ - be,a,pn %icc, 1f /* CTI */ - clr %g2 /* IEU0 */ - lduw [%src], %g7 /* Load */ - add %src, 4, %src /* IEU0 Group */ - add %dst, 4, %dst /* IEU1 */ - sllx %g7, 32, %g2 /* IEU0 Group */ - stwa %g7, [%dst - 4] %asi /* Store */ -1: andcc %len, 2, %g0 /* IEU1 */ - be,a,pn %icc, 1f /* CTI */ - clr %g3 /* IEU0 Group */ - lduh [%src], %g7 /* Load */ - add %src, 2, %src /* IEU1 */ - add %dst, 2, %dst /* IEU0 Group */ - sll %g7, 16, %g3 /* IEU0 Group */ - stha %g7, [%dst - 2] %asi /* Store */ -1: andcc %len, 1, %g0 /* IEU1 */ - be,a,pn %icc, 1f /* CTI */ - clr %o5 /* IEU0 Group */ - ldub [%src], %g7 /* Load */ - sll %g7, 8, %o5 /* IEU0 Group */ - stba %g7, [%dst] %asi /* Store */ -1: or %g2, %g3, %g3 /* IEU1 */ - or %o5, %g3, %g3 /* IEU0 Group (regdep) */ - addcc %g3, %sum, %sum /* IEU1 Group (regdep) */ - bcs,a,pn %xcc, 1f /* CTI */ - add %sum, 1, %sum /* IEU0 */ -1: ba,pt %xcc, 25b /* CTI Group */ - sllx %sum, 32, %g1 /* IEU0 */ +26: andcc %len, 8, %g0 /* IEU1 Group */ + be,pn %icc, 1f /* CTI */ + lduw [%src], %o4 /* Load */ + lduw [%src+4], %g2 /* Load Group */ + add %src, 8, %src /* IEU0 */ + add %dst, 8, %dst /* IEU1 */ + sllx %o4, 32, %g5 /* IEU0 Group */ + stwa %o4, [%dst - 8] %asi /* Store */ + or %g5, %g2, %g5 /* IEU0 Group */ + stwa %g2, [%dst - 4] %asi /* Store */ + addcc %g5, %sum, %sum /* IEU1 Group */ + bcs,a,pn %xcc, 1f /* CTI */ + add %sum, 1, %sum /* IEU0 */ +1: andcc %len, 4, %g0 /* IEU1 Group */ + be,a,pn %icc, 1f /* CTI */ + clr %g2 /* IEU0 */ + lduw [%src], %g7 /* Load */ + add %src, 4, %src /* IEU0 Group */ + add %dst, 4, %dst /* IEU1 */ + sllx %g7, 32, %g2 /* IEU0 Group */ + stwa %g7, [%dst - 4] %asi /* Store */ +1: andcc %len, 2, %g0 /* IEU1 */ + be,a,pn %icc, 1f /* CTI */ + clr %g3 /* IEU0 Group */ + lduh [%src], %g7 /* Load */ + add %src, 2, %src /* IEU1 */ + add %dst, 2, %dst /* IEU0 Group */ + sll %g7, 16, %g3 /* IEU0 Group */ + stha %g7, [%dst - 2] %asi /* Store */ +1: andcc %len, 1, %g0 /* IEU1 */ + be,a,pn %icc, 1f /* CTI */ + clr %o5 /* IEU0 Group */ + ldub [%src], %g7 /* Load */ + sll %g7, 8, %o5 /* IEU0 Group */ + stba %g7, [%dst] %asi /* Store */ +1: or %g2, %g3, %g3 /* IEU1 */ + or %o5, %g3, %g3 /* IEU0 Group (regdep) */ + addcc %g3, %sum, %sum /* IEU1 Group (regdep) */ + bcs,a,pn %xcc, 1f /* CTI */ + add %sum, 1, %sum /* IEU0 */ +1: ba,pt %xcc, 25b /* CTI Group */ + sllx %sum, 32, %g1 /* IEU0 */ #ifdef __KERNEL__ end: diff --git a/drivers/Makefile b/drivers/Makefile index 1c99a05a7..1d4653233 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -57,6 +57,11 @@ SUB_DIRS += macintosh MOD_SUB_DIRS += macintosh endif +ifdef CONFIG_PPC +SUB_DIRS += macintosh +MOD_SUB_DIRS += macintosh +endif + ifeq ($(CONFIG_USB),y) SUB_DIRS += usb MOD_SUB_DIRS += usb diff --git a/drivers/atm/Config.in b/drivers/atm/Config.in index 07e712751..8fb55632a 100644 --- a/drivers/atm/Config.in +++ b/drivers/atm/Config.in @@ -51,4 +51,29 @@ if [ "$CONFIG_PCI" = "y" ]; then bool ' Enable debugging messages' CONFIG_ATM_IA_DEBUG fi fi +if [ "$CONFIG_PCI" = "y" -o "$CONFIG_SBUS" = "y" ]; then + tristate 'FORE Systems 200E-series' CONFIG_ATM_FORE200E + if [ "$CONFIG_ATM_FORE200E" != "n" ]; then + if [ "$CONFIG_PCI" = "y" ]; then + bool ' PCA-200E support' CONFIG_ATM_FORE200E_PCA y + if [ "$CONFIG_ATM_FORE200E_PCA" = "y" ]; then + bool ' Use default PCA-200E firmware (normally enabled)' CONFIG_ATM_FORE200E_PCA_DEFAULT_FW + if [ "$CONFIG_ATM_FORE200E_PCA_DEFAULT_FW" = "n" ]; then + string ' Pathname of user-supplied binary firmware' CONFIG_ATM_FORE200E_PCA_FW + fi + fi + fi + if [ "$CONFIG_SBUS" = "y" ]; then + bool ' SBA-200E support' CONFIG_ATM_FORE200E_SBA y + if [ "$CONFIG_ATM_FORE200E_SBA" = "y" ]; then + bool ' Use default SBA-200E firmware (normally enabled)' CONFIG_ATM_FORE200E_SBA_DEFAULT_FW + if [ "$CONFIG_ATM_FORE200E_SBA_DEFAULT_FW" = "n" ]; then + string ' Pathname of user-supplied binary firmware' CONFIG_ATM_FORE200E_SBA_FW "" + fi + fi + fi + int ' Maximum number of tx retries' CONFIG_ATM_FORE200E_TX_RETRY 16 + int ' Debugging level (0-3)' CONFIG_ATM_FORE200E_DEBUG 0 + fi +fi endmenu diff --git a/drivers/atm/Makefile b/drivers/atm/Makefile index 25b57fdd4..f126bd232 100644 --- a/drivers/atm/Makefile +++ b/drivers/atm/Makefile @@ -100,6 +100,58 @@ else LX_OBJS += $(NEED_IDT77105_LX) endif +ifeq ($(CONFIG_ATM_FORE200E_PCA),y) +FORE200E_FW_OBJS += fore200e_pca_fw.o + ifeq ($(CONFIG_ATM_FORE200E_PCA_DEFAULT_FW),y) +# guess the target endianess to choose the right PCA-200E firmware image + CONFIG_ATM_FORE200E_PCA_FW := $(shell if test -n "`$(CC) -E -dM ../../include/asm/byteorder.h | grep ' __LITTLE_ENDIAN '`"; then echo pca200e.bin; else echo pca200e_ecd.bin2; fi) + endif +endif +ifeq ($(CONFIG_ATM_FORE200E_SBA),y) +FORE200E_FW_OBJS += fore200e_sba_fw.o + ifeq ($(CONFIG_ATM_FORE200E_SBA_DEFAULT_FW),y) + CONFIG_ATM_FORE200E_SBA_FW := sba200e_ecd.bin2 + endif +endif +ifeq ($(CONFIG_ATM_FORE200E),y) +L_OBJS += fore200e.o $(FORE200E_FW_OBJS) +else + ifeq ($(CONFIG_ATM_FORE200E),m) + M_OBJS += fore_200e.o + endif +endif + EXTRA_CFLAGS=-g include $(TOPDIR)/Rules.make + +# FORE Systems 200E-series firmware magic +fore200e_pca_fw.c: $(patsubst "%", %, $(CONFIG_ATM_FORE200E_PCA_FW)) \ + fore200e_mkfirm + ./fore200e_mkfirm -k -b _fore200e_pca_fw \ + -i $(CONFIG_ATM_FORE200E_PCA_FW) -o $@ + +fore200e_sba_fw.c: $(patsubst "%", %, $(CONFIG_ATM_FORE200E_SBA_FW)) \ + fore200e_mkfirm + ./fore200e_mkfirm -k -b _fore200e_sba_fw \ + -i $(CONFIG_ATM_FORE200E_SBA_FW) -o $@ + +fore200e_mkfirm: fore200e_mkfirm.c + $(HOSTCC) $(HOSTCFLAGS) $< -o $@ + +# deal with the various suffixes of the firmware images +%.bin: %.data + objcopy -Iihex $< -Obinary $@.gz + gzip -df $@.gz + +%.bin1: %.data + objcopy -Iihex $< -Obinary $@.gz + gzip -df $@.gz + +%.bin2: %.data + objcopy -Iihex $< -Obinary $@.gz + gzip -df $@.gz + +# module build +fore_200e.o: fore200e.o $(FORE200E_FW_OBJS) + $(LD) -r -o $@ $< $(FORE200E_FW_OBJS) diff --git a/drivers/atm/atmdev_init.c b/drivers/atm/atmdev_init.c index 20fcaee4a..357cbdbe0 100644 --- a/drivers/atm/atmdev_init.c +++ b/drivers/atm/atmdev_init.c @@ -28,6 +28,9 @@ extern int hrz_detect(void); #ifdef CONFIG_ATM_IA extern int ia_detect(void); #endif +#ifdef CONFIG_ATM_FORE200E +extern int fore200e_detect(void); +#endif int __init atmdev_init(void) @@ -55,6 +58,9 @@ int __init atmdev_init(void) #endif #ifdef CONFIG_ATM_IA devs += ia_detect(); +#endif +#ifdef CONFIG_ATM_FORE200E + devs += fore200e_detect(); #endif return devs; } diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c index 1904b7e71..081fcdfed 100644 --- a/drivers/atm/eni.c +++ b/drivers/atm/eni.c @@ -156,7 +156,8 @@ static int tx_complete = 0,dma_complete = 0,queued = 0,requeued = 0, static struct atm_dev *eni_boards = NULL; -static u32 *zeroes = NULL; /* aligned "magic" zeroes */ +static u32 *cpu_zeroes = NULL; /* aligned "magic" zeroes */ +static dma_addr_t zeroes; /* Read/write registers on card */ #define eni_in(r) readl(eni_dev->reg+(r)*4) @@ -349,18 +350,21 @@ static int do_rx_dma(struct atm_vcc *vcc,struct sk_buff *skb, struct eni_vcc *eni_vcc; u32 dma_rd,dma_wr; u32 dma[RX_DMA_BUF*2]; - unsigned long paddr,here; + dma_addr_t paddr; + unsigned long here; int i,j; eni_dev = ENI_DEV(vcc->dev); eni_vcc = ENI_VCC(vcc); paddr = 0; /* GCC, shut up */ if (skb) { - paddr = (unsigned long) skb->data; + paddr = pci_map_single(eni_dev->pci_dev,skb->data,skb->len, + PCI_DMA_FROMDEVICE); + ENI_PRV_PADDR(skb) = paddr; if (paddr & 3) printk(KERN_CRIT DEV_LABEL "(itf %d): VCI %d has " "mis-aligned RX data (0x%lx)\n",vcc->dev->number, - vcc->vci,paddr); + vcc->vci,(unsigned long) paddr); ENI_PRV_SIZE(skb) = size+skip; /* PDU plus descriptor */ ATM_SKB(skb)->vcc = vcc; @@ -390,7 +394,7 @@ static int do_rx_dma(struct atm_vcc *vcc,struct sk_buff *skb, if (init > words) init = words; dma[j++] = MID_DT_WORD | (init << MID_DMA_COUNT_SHIFT) | (vcc->vci << MID_DMA_VCI_SHIFT); - dma[j++] = virt_to_bus((void *) paddr); + dma[j++] = paddr; paddr += init << 2; words -= init; } @@ -399,7 +403,7 @@ static int do_rx_dma(struct atm_vcc *vcc,struct sk_buff *skb, dma[j++] = MID_DT_16W | ((words >> 4) << MID_DMA_COUNT_SHIFT) | (vcc->vci << MID_DMA_VCI_SHIFT); - dma[j++] = virt_to_bus((void *) paddr); + dma[j++] = paddr; paddr += (words & ~15) << 2; words &= 15; } @@ -409,7 +413,7 @@ static int do_rx_dma(struct atm_vcc *vcc,struct sk_buff *skb, dma[j++] = MID_DT_8W | ((words >> 3) << MID_DMA_COUNT_SHIFT) | (vcc->vci << MID_DMA_VCI_SHIFT); - dma[j++] = virt_to_bus((void *) paddr); + dma[j++] = paddr; paddr += (words & ~7) << 2; words &= 7; } @@ -419,7 +423,7 @@ static int do_rx_dma(struct atm_vcc *vcc,struct sk_buff *skb, dma[j++] = MID_DT_4W | ((words >> 2) << MID_DMA_COUNT_SHIFT) | (vcc->vci << MID_DMA_VCI_SHIFT); - dma[j++] = virt_to_bus((void *) paddr); + dma[j++] = paddr; paddr += (words & ~3) << 2; words &= 3; } @@ -429,7 +433,7 @@ static int do_rx_dma(struct atm_vcc *vcc,struct sk_buff *skb, dma[j++] = MID_DT_2W | ((words >> 1) << MID_DMA_COUNT_SHIFT) | (vcc->vci << MID_DMA_VCI_SHIFT); - dma[j++] = virt_to_bus((void *) paddr); + dma[j++] = paddr; paddr += (words & ~1) << 2; words &= 1; } @@ -437,7 +441,7 @@ static int do_rx_dma(struct atm_vcc *vcc,struct sk_buff *skb, if (words) { dma[j++] = MID_DT_WORD | (words << MID_DMA_COUNT_SHIFT) | (vcc->vci << MID_DMA_VCI_SHIFT); - dma[j++] = virt_to_bus((void *) paddr); + dma[j++] = paddr; } } if (size != eff) { @@ -447,8 +451,7 @@ static int do_rx_dma(struct atm_vcc *vcc,struct sk_buff *skb, } if (!j || j > 2*RX_DMA_BUF) { printk(KERN_CRIT DEV_LABEL "!j or j too big!!!\n"); - if (skb) kfree_skb(skb); - return -1; + goto trouble; } dma[j-2] |= MID_DMA_END; j = j >> 1; @@ -461,8 +464,7 @@ static int do_rx_dma(struct atm_vcc *vcc,struct sk_buff *skb, if (!NEPMOK(dma_wr,j+j+1,dma_rd,NR_DMA_RX)) { /* @@@ +1 is ugly */ printk(KERN_WARNING DEV_LABEL "(itf %d): RX DMA full\n", vcc->dev->number); - if (skb) kfree_skb(skb); - return -1; + goto trouble; } for (i = 0; i < j; i++) { writel(dma[i*2],eni_dev->rx_dma+dma_wr*8); @@ -472,12 +474,19 @@ static int do_rx_dma(struct atm_vcc *vcc,struct sk_buff *skb, if (skb) { ENI_PRV_POS(skb) = eni_vcc->descr+size+1; skb_queue_tail(&eni_dev->rx_queue,skb); -eni_vcc->last = skb; + eni_vcc->last = skb; rx_enqueued++; } eni_vcc->descr = here; eni_out(dma_wr,MID_DMA_WR_RX); return 0; + +trouble: + if (paddr) + pci_unmap_single(eni_dev->pci_dev,paddr,skb->len, + PCI_DMA_FROMDEVICE); + if (skb) dev_kfree_skb_irq(skb); + return -1; } @@ -747,7 +756,9 @@ rx_dequeued++; } eni_vcc->rxing--; eni_vcc->rx_pos = ENI_PRV_POS(skb) & (eni_vcc->words-1); - if (!skb->len) kfree_skb(skb); + pci_unmap_single(eni_dev->pci_dev,ENI_PRV_PADDR(skb),skb->len, + PCI_DMA_TODEVICE); + if (!skb->len) dev_kfree_skb_irq(skb); else { EVENT("pushing (len=%ld)\n",skb->len,0); if (vcc->qos.aal == ATM_AAL0) @@ -902,13 +913,13 @@ static int start_rx(struct atm_dev *dev) enum enq_res { enq_ok,enq_next,enq_jam }; -static inline void put_dma(int chan,u32 *dma,int *j,unsigned long paddr, +static inline void put_dma(int chan,u32 *dma,int *j,dma_addr_t paddr, u32 size) { u32 init,words; - DPRINTK("put_dma: 0x%lx+0x%x\n",paddr,size); - EVENT("put_dma: 0x%lx+0x%lx\n",paddr,size); + DPRINTK("put_dma: 0x%lx+0x%x\n",(unsigned long) paddr,size); + EVENT("put_dma: 0x%lx+0x%lx\n",(unsigned long) paddr,size); #if 0 /* don't complain anymore */ if (paddr & 3) printk(KERN_ERR "put_dma: unaligned addr (0x%lx)\n",paddr); @@ -918,10 +929,11 @@ static inline void put_dma(int chan,u32 *dma,int *j,unsigned long paddr, if (paddr & 3) { init = 4-(paddr & 3); if (init > size || size < 7) init = size; - DPRINTK("put_dma: %lx DMA: %d/%d bytes\n",paddr,init,size); + DPRINTK("put_dma: %lx DMA: %d/%d bytes\n", + (unsigned long) paddr,init,size); dma[(*j)++] = MID_DT_BYTE | (init << MID_DMA_COUNT_SHIFT) | (chan << MID_DMA_CHAN_SHIFT); - dma[(*j)++] = virt_to_bus((void *) paddr); + dma[(*j)++] = paddr; paddr += init; size -= init; } @@ -930,10 +942,11 @@ static inline void put_dma(int chan,u32 *dma,int *j,unsigned long paddr, if (words && (paddr & 31)) { init = 8-((paddr & 31) >> 2); if (init > words) init = words; - DPRINTK("put_dma: %lx DMA: %d/%d words\n",paddr,init,words); + DPRINTK("put_dma: %lx DMA: %d/%d words\n", + (unsigned long) paddr,init,words); dma[(*j)++] = MID_DT_WORD | (init << MID_DMA_COUNT_SHIFT) | (chan << MID_DMA_CHAN_SHIFT); - dma[(*j)++] = virt_to_bus((void *) paddr); + dma[(*j)++] = paddr; paddr += init << 2; words -= init; } @@ -943,18 +956,18 @@ static inline void put_dma(int chan,u32 *dma,int *j,unsigned long paddr, words); dma[(*j)++] = MID_DT_16W | ((words >> 4) << MID_DMA_COUNT_SHIFT) | (chan << MID_DMA_CHAN_SHIFT); - dma[(*j)++] = virt_to_bus((void *) paddr); + dma[(*j)++] = paddr; paddr += (words & ~15) << 2; words &= 15; } #endif #ifdef CONFIG_ATM_ENI_BURST_TX_8W /* recommended */ if (words & ~7) { - DPRINTK("put_dma: %lx DMA: %d*8/%d words\n",paddr,words >> 3, - words); + DPRINTK("put_dma: %lx DMA: %d*8/%d words\n", + (unsigned long) paddr,words >> 3,words); dma[(*j)++] = MID_DT_8W | ((words >> 3) << MID_DMA_COUNT_SHIFT) | (chan << MID_DMA_CHAN_SHIFT); - dma[(*j)++] = virt_to_bus((void *) paddr); + dma[(*j)++] = paddr; paddr += (words & ~7) << 2; words &= 7; } @@ -965,7 +978,7 @@ static inline void put_dma(int chan,u32 *dma,int *j,unsigned long paddr, words); dma[(*j)++] = MID_DT_4W | ((words >> 2) << MID_DMA_COUNT_SHIFT) | (chan << MID_DMA_CHAN_SHIFT); - dma[(*j)++] = virt_to_bus((void *) paddr); + dma[(*j)++] = paddr; paddr += (words & ~3) << 2; words &= 3; } @@ -976,23 +989,25 @@ static inline void put_dma(int chan,u32 *dma,int *j,unsigned long paddr, words); dma[(*j)++] = MID_DT_2W | ((words >> 1) << MID_DMA_COUNT_SHIFT) | (chan << MID_DMA_CHAN_SHIFT); - dma[(*j)++] = virt_to_bus((void *) paddr); + dma[(*j)++] = paddr; paddr += (words & ~1) << 2; words &= 1; } #endif if (words) { - DPRINTK("put_dma: %lx DMA: %d words\n",paddr,words); + DPRINTK("put_dma: %lx DMA: %d words\n",(unsigned long) paddr, + words); dma[(*j)++] = MID_DT_WORD | (words << MID_DMA_COUNT_SHIFT) | (chan << MID_DMA_CHAN_SHIFT); - dma[(*j)++] = virt_to_bus((void *) paddr); + dma[(*j)++] = paddr; paddr += words << 2; } if (size) { - DPRINTK("put_dma: %lx DMA: %d bytes\n",paddr,size); + DPRINTK("put_dma: %lx DMA: %d bytes\n",(unsigned long) paddr, + size); dma[(*j)++] = MID_DT_BYTE | (size << MID_DMA_COUNT_SHIFT) | (chan << MID_DMA_CHAN_SHIFT); - dma[(*j)++] = virt_to_bus((void *) paddr); + dma[(*j)++] = paddr; } } @@ -1003,6 +1018,7 @@ static enum enq_res do_tx(struct sk_buff *skb) struct eni_dev *eni_dev; struct eni_vcc *eni_vcc; struct eni_tx *tx; + dma_addr_t paddr; u32 dma_rd,dma_wr; u32 size; /* in words */ int aal5,dma_size,i,j; @@ -1079,6 +1095,9 @@ DPRINTK("iovcnt = %d\n",ATM_SKB(skb)->iovcnt); vcc->dev->number); return enq_jam; } + paddr = pci_map_single(eni_dev->pci_dev,skb->data,skb->len, + PCI_DMA_TODEVICE); + ENI_PRV_PADDR(skb) = paddr; /* prepare DMA queue entries */ j = 0; eni_dev->dma[j++] = (((tx->tx_pos+TX_DESCR_SIZE) & (tx->words-1)) << @@ -1086,21 +1105,17 @@ DPRINTK("iovcnt = %d\n",ATM_SKB(skb)->iovcnt); MID_DT_JK; j++; if (!ATM_SKB(skb)->iovcnt) - if (aal5) - put_dma(tx->index,eni_dev->dma,&j, - (unsigned long) skb->data,skb->len); - else put_dma(tx->index,eni_dev->dma,&j, - (unsigned long) skb->data+4,skb->len-4); + if (aal5) put_dma(tx->index,eni_dev->dma,&j,paddr,skb->len); + else put_dma(tx->index,eni_dev->dma,&j,paddr+4,skb->len-4); else { -DPRINTK("doing direct send\n"); +DPRINTK("doing direct send\n"); /* @@@ well, this doesn't work anyway */ for (i = 0; i < ATM_SKB(skb)->iovcnt; i++) put_dma(tx->index,eni_dev->dma,&j,(unsigned long) ((struct iovec *) skb->data)[i].iov_base, ((struct iovec *) skb->data)[i].iov_len); } if (skb->len & 3) - put_dma(tx->index,eni_dev->dma,&j, - (unsigned long) zeroes,4-(skb->len & 3)); + put_dma(tx->index,eni_dev->dma,&j,zeroes,4-(skb->len & 3)); /* JK for AAL5 trailer - AAL0 doesn't need it, but who cares ... */ eni_dev->dma[j++] = (((tx->tx_pos+size) & (tx->words-1)) << MID_DMA_COUNT_SHIFT) | (tx->index << MID_DMA_CHAN_SHIFT) | @@ -1188,8 +1203,10 @@ static void dequeue_tx(struct atm_dev *dev) break; } ENI_VCC(vcc)->txing -= ENI_PRV_SIZE(skb); + pci_unmap_single(eni_dev->pci_dev,ENI_PRV_PADDR(skb),skb->len, + PCI_DMA_TODEVICE); if (vcc->pop) vcc->pop(vcc,skb); - else dev_kfree_skb(skb); + else dev_kfree_skb_irq(skb); vcc->stats->tx++; wake_up(&eni_dev->tx_wait); dma_complete++; @@ -1670,7 +1687,7 @@ static int __init eni_init(struct atm_dev *dev) (eni_dev->asic ? PCI_COMMAND_PARITY | PCI_COMMAND_SERR : 0)))) { printk(KERN_ERR DEV_LABEL "(itf %d): can't enable memory " "(0x%02x)\n",dev->number,error); - return error; + return -EIO; } printk(KERN_NOTICE DEV_LABEL "(itf %d): rev.%d,base=0x%lx,irq=%d,", dev->number,revision,real_base,eni_dev->irq); @@ -2020,7 +2037,6 @@ static int eni_send(struct atm_vcc *vcc,struct sk_buff *skb) if (!skb) { printk(KERN_CRIT "!skb in eni_send ?\n"); if (vcc->pop) vcc->pop(vcc,skb); - else dev_kfree_skb(skb); return -EINVAL; } if (vcc->qos.aal == ATM_AAL0) { @@ -2195,7 +2211,14 @@ int __init eni_detect(void) struct atm_dev *dev; struct eni_dev *eni_dev; int devs,type; + struct sk_buff *skb; + DPRINTK("eni_detect\n"); + if (sizeof(skb->cb) < sizeof(struct eni_skb_prv)) { + printk(KERN_ERR "eni_detect: skb->cb is too small (%d < %d)\n", + sizeof(skb->cb),sizeof(struct eni_skb_prv)); + return 0; + } eni_dev = (struct eni_dev *) kmalloc(sizeof(struct eni_dev), GFP_KERNEL); if (!eni_dev) return -ENOMEM; @@ -2208,8 +2231,9 @@ int __init eni_detect(void) PCI_DEVICE_ID_EF_ATM_ASIC : PCI_DEVICE_ID_EF_ATM_FPGA, pci_dev))) { if (!devs) { - zeroes = kmalloc(4,GFP_KERNEL); - if (!zeroes) { + cpu_zeroes = pci_alloc_consistent(pci_dev, + ENI_ZEROES_SIZE,&zeroes); + if (!cpu_zeroes) { kfree(eni_dev); return -ENOMEM; } @@ -2231,11 +2255,12 @@ int __init eni_detect(void) if (!eni_dev) break; } } - kfree(eni_dev); - if (!devs && zeroes) { - kfree(zeroes); - zeroes = NULL; + if (!devs && cpu_zeroes) { + pci_free_consistent(eni_dev->pci_dev,ENI_ZEROES_SIZE, + cpu_zeroes,zeroes); + cpu_zeroes = NULL; } + kfree(eni_dev); return devs; } diff --git a/drivers/atm/eni.h b/drivers/atm/eni.h index ca1749f59..76d0dd482 100644 --- a/drivers/atm/eni.h +++ b/drivers/atm/eni.h @@ -27,6 +27,8 @@ #define DEFAULT_RX_MULT 300 /* max_sdu*3 */ #define DEFAULT_TX_MULT 300 /* max_sdu*3 */ +#define ENI_ZEROES_SIZE 4 /* need that many DMA-able zero bytes */ + struct eni_free { unsigned long start; /* counting in bytes */ @@ -113,9 +115,11 @@ struct eni_skb_prv { struct atm_skb_data _; /* reserved */ unsigned long pos; /* position of next descriptor */ int size; /* PDU size in reassembly buffer */ + dma_addr_t paddr; /* DMA handle */ }; #define ENI_PRV_SIZE(skb) (((struct eni_skb_prv *) (skb)->cb)->size) #define ENI_PRV_POS(skb) (((struct eni_skb_prv *) (skb)->cb)->pos) +#define ENI_PRV_PADDR(skb) (((struct eni_skb_prv *) (skb)->cb)->paddr) #endif diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c new file mode 100644 index 000000000..4c07f2e7f --- /dev/null +++ b/drivers/atm/fore200e.c @@ -0,0 +1,2973 @@ +/* + $Id: fore200e.c,v 1.1 2000/02/21 16:04:31 davem Exp $ + + A FORE Systems 200E-series driver for ATM on Linux. + Christophe Lizzi (lizzi@cnam.fr), October 1999-February 2000. + + Based on the PCA-200E driver from Uwe Dannowski (Uwe.Dannowski@inf.tu-dresden.de). + + This driver simultaneously supports PCA-200E and SBA-200E adapters + on i386, alpha (untested), powerpc, sparc and sparc64 architectures. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_ATM_FORE200E_PCA +#include +#endif + +#ifdef CONFIG_ATM_FORE200E_SBA +#include +#include +#include +#include +#include +#endif + +#ifdef MODULE +#include +#endif + +#include "fore200e.h" +#include "suni.h" + +#if 1 /* ensure correct handling of 52-byte AAL0 SDUs used by atmdump-like apps */ +#define FORE200E_52BYTE_AAL0_SDU +#endif + +#define FORE200E_VERSION "0.2a" + + +#define FORE200E "fore200e: " + +#if defined(CONFIG_ATM_FORE200E_DEBUG) && (CONFIG_ATM_FORE200E_DEBUG > 0) +#define DPRINTK(level, format, args...) do { if (CONFIG_ATM_FORE200E_DEBUG >= (level)) \ + printk(FORE200E format, ##args); } while(0) +#else +#define DPRINTK(level, format, args...) while(0) +#endif + + +#define FORE200E_ALIGN(addr, alignment) \ + ((((unsigned long)(addr) + (alignment - 1)) & ~(alignment - 1)) - (unsigned long)(addr)) + +#define FORE200E_DMA_INDEX(dma_addr, type, index) ((dma_addr) + (index) * sizeof(type)) + +#define FORE200E_INDEX(virt_addr, type, index) (&((type *)(virt_addr))[ index ]) + +#define FORE200E_NEXT_ENTRY(index, modulo) (index = ++(index) % (modulo)) + + +#define MSECS(ms) (((ms)*HZ/1000)+1) + + +extern const struct atmdev_ops fore200e_ops; +extern const struct fore200e_bus fore200e_bus[]; + +static struct fore200e* fore200e_boards = NULL; + + +#ifdef MODULE +MODULE_AUTHOR("Christophe Lizzi - credits to Uwe Dannowski and Heikki Vatiainen"); +MODULE_DESCRIPTION("FORE Systems 200E-series ATM driver - version " FORE200E_VERSION); +MODULE_SUPPORTED_DEVICE("PCA-200E, SBA-200E"); +#endif + + +static const int fore200e_rx_buf_nbr[ BUFFER_SCHEME_NBR ][ BUFFER_MAGN_NBR ] = { + { BUFFER_S1_NBR, BUFFER_L1_NBR }, + { BUFFER_S2_NBR, BUFFER_L2_NBR } +}; + +static const int fore200e_rx_buf_size[ BUFFER_SCHEME_NBR ][ BUFFER_MAGN_NBR ] = { + { BUFFER_S1_SIZE, BUFFER_L1_SIZE }, + { BUFFER_S2_SIZE, BUFFER_L2_SIZE } +}; + + +#if defined(CONFIG_ATM_FORE200E_DEBUG) && (CONFIG_ATM_FORE200E_DEBUG > 0) +static const char* fore200e_traffic_class[] = { "NONE", "UBR", "CBR", "VBR", "ABR", "ANY" }; +#endif + + +#if 0 /* currently unused */ +static int +fore200e_fore2atm_aal(enum fore200e_aal aal) +{ + switch(aal) { + case FORE200E_AAL0: return ATM_AAL0; + case FORE200E_AAL34: return ATM_AAL34; + case FORE200E_AAL5: return ATM_AAL5; + } + + return -EINVAL; +} +#endif + + +static enum fore200e_aal +fore200e_atm2fore_aal(int aal) +{ + switch(aal) { + case ATM_AAL0: return FORE200E_AAL0; + case ATM_AAL34: return FORE200E_AAL34; + case ATM_AAL1: + case ATM_AAL2: + case ATM_AAL5: return FORE200E_AAL5; + } + + return -EINVAL; +} + + +static char* +fore200e_irq_itoa(int irq) +{ +#if defined(__sparc_v9__) + return __irq_itoa(irq); +#else + static char str[8]; + sprintf(str, "%d", irq); + return str; +#endif +} + + +static void* +fore200e_kmalloc(int size, int flags) +{ + void* chunk = kmalloc(size, flags); + + if (chunk) + memset(chunk, 0x00, size); + else + printk(FORE200E "kmalloc() failed, requested size = %d, flags = 0x%x\n", size, flags); + + return chunk; +} + + +static void +fore200e_kfree(void* chunk) +{ + kfree(chunk); +} + + +/* allocate and align a chunk of memory intended to hold the data behing exchanged + between the driver and the adapter (using streaming DVMA on SBUS hosts) */ + +static int +fore200e_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, int size, int alignment) +{ + unsigned long offset = 0; + + if (alignment <= sizeof(int)) + alignment = 0; + + chunk->alloc_size = size + alignment; + chunk->align_size = size; + + chunk->alloc_addr = fore200e_kmalloc(chunk->alloc_size, GFP_KERNEL | GFP_DMA); + if (chunk->alloc_addr == NULL) + return -ENOMEM; + + if (alignment > 0) + offset = FORE200E_ALIGN(chunk->alloc_addr, alignment); + + chunk->align_addr = chunk->alloc_addr + offset; + + chunk->dma_addr = fore200e->bus->dma_map(fore200e, chunk->align_addr, chunk->align_size); + + return 0; +} + + +/* free a chunk of memory */ + +static void +fore200e_chunk_free(struct fore200e* fore200e, struct chunk* chunk) +{ + fore200e->bus->dma_unmap(fore200e, chunk->dma_addr, chunk->dma_size); + + fore200e_kfree(chunk->alloc_addr); +} + + + +#if 0 /* currently unused */ +static int +fore200e_checkup(struct fore200e* fore200e) +{ + u32 hb1, hb2; + + hb1 = fore200e->bus->read(&fore200e->cp_queues->heartbeat); + fore200e_spin(10); + hb2 = fore200e->bus->read(&fore200e->cp_queues->heartbeat); + + if (hb2 <= hb1) { + printk(FORE200E "device %s heartbeat is not counting upwards, hb1 = %x; hb2 = %x\n", + fore200e->name, hb1, hb2); + return -EIO; + } + printk(FORE200E "device %s heartbeat is ok\n", fore200e->name); + + return 0; +} +#endif + + +static void +fore200e_spin(int msecs) +{ + unsigned long timeout = jiffies + MSECS(msecs); + while (jiffies < timeout); +} + + +static int +fore200e_poll(struct fore200e* fore200e, volatile u32* addr, u32 val, int msecs) +{ + unsigned long timeout = jiffies + MSECS(msecs); + int ok; + + mb(); + do { + if ((ok = (*addr == val)) || (*addr & STATUS_ERROR)) + break; + + } while (jiffies < timeout); + +#if 1 + if (!ok) { + printk(FORE200E "cmd polling failed, got status 0x%08x, expected 0x%08x\n", + *addr, val); + } +#endif + + return ok; +} + + +static int +fore200e_io_poll(struct fore200e* fore200e, volatile u32* addr, u32 val, int msecs) +{ + unsigned long timeout = jiffies + MSECS(msecs); + int ok; + + do { + if ((ok = (fore200e->bus->read(addr) == val))) + break; + + } while (jiffies < timeout); + +#if 1 + if (!ok) { + printk(FORE200E "I/O polling failed, got status 0x%08x, expected 0x%08x\n", + fore200e->bus->read(addr), val); + } +#endif + + return ok; +} + + +static void +fore200e_free_rx_buf(struct fore200e* fore200e) +{ + int scheme, magn, nbr; + struct buffer* buffer; + + for (scheme = 0; scheme < BUFFER_SCHEME_NBR; scheme++) { + for (magn = 0; magn < BUFFER_MAGN_NBR; magn++) { + + if ((buffer = fore200e->host_bsq[ scheme ][ magn ].buffer) != NULL) { + + for (nbr = 0; nbr < fore200e_rx_buf_nbr[ scheme ][ magn ]; nbr++) { + + struct chunk* data = &buffer[ nbr ].data; + + if (data->alloc_addr != NULL) + fore200e_chunk_free(fore200e, data); + } + } + } + } +} + + +static void +fore200e_uninit_bs_queue(struct fore200e* fore200e) +{ + int scheme, magn; + + for (scheme = 0; scheme < BUFFER_SCHEME_NBR; scheme++) { + for (magn = 0; magn < BUFFER_MAGN_NBR; magn++) { + + struct chunk* status = &fore200e->host_bsq[ scheme ][ magn ].status; + struct chunk* rbd_block = &fore200e->host_bsq[ scheme ][ magn ].rbd_block; + + if (status->alloc_addr) + fore200e->bus->dma_chunk_free(fore200e, status); + + if (rbd_block->alloc_addr) + fore200e->bus->dma_chunk_free(fore200e, rbd_block); + } + } +} + + +static int +fore200e_reset(struct fore200e* fore200e, int diag) +{ + int ok; + + fore200e->cp_monitor = (struct cp_monitor*)(fore200e->virt_base + FORE200E_CP_MONITOR_OFFSET); + + fore200e->bus->write(BSTAT_COLD_START, &fore200e->cp_monitor->bstat); + + fore200e->bus->reset(fore200e); + + if (diag) { + ok = fore200e_io_poll(fore200e, &fore200e->cp_monitor->bstat, BSTAT_SELFTEST_OK, 1000); + if (ok == 0) { + + printk(FORE200E "device %s self-test failed\n", fore200e->name); + return -ENODEV; + } + + printk(FORE200E "device %s self-test passed\n", fore200e->name); + + fore200e->state = FORE200E_STATE_RESET; + } + + return 0; +} + + +static void +fore200e_shutdown(struct fore200e* fore200e) +{ + printk(FORE200E "removing device %s at 0x%lx, IRQ %s\n", + fore200e->name, fore200e->phys_base, + fore200e_irq_itoa(fore200e->irq)); + + if (fore200e->state > FORE200E_STATE_RESET) { + /* first, reset the board to prevent further interrupts or data transfers */ + fore200e_reset(fore200e, 0); + } + + /* then, release all allocated resources */ + switch(fore200e->state) { + + case FORE200E_STATE_COMPLETE: + if (fore200e->stats) + kfree(fore200e->stats); + + case FORE200E_STATE_IRQ: + free_irq(fore200e->irq, fore200e->atm_dev); + + case FORE200E_STATE_ALLOC_BUF: + fore200e_free_rx_buf(fore200e); + + case FORE200E_STATE_INIT_BSQ: + fore200e_uninit_bs_queue(fore200e); + + case FORE200E_STATE_INIT_RXQ: + fore200e->bus->dma_chunk_free(fore200e, &fore200e->host_rxq.status); + fore200e->bus->dma_chunk_free(fore200e, &fore200e->host_rxq.rpd); + + case FORE200E_STATE_INIT_TXQ: + fore200e->bus->dma_chunk_free(fore200e, &fore200e->host_txq.status); + fore200e->bus->dma_chunk_free(fore200e, &fore200e->host_txq.tpd); + + case FORE200E_STATE_INIT_CMDQ: + fore200e->bus->dma_chunk_free(fore200e, &fore200e->host_cmdq.status); + + case FORE200E_STATE_INITIALIZE: + /* nothing to do for that state */ + + case FORE200E_STATE_START_FW: + /* nothing to do for that state */ + + case FORE200E_STATE_LOAD_FW: + /* nothing to do for that state */ + + case FORE200E_STATE_RESET: + /* nothing to do for that state */ + + case FORE200E_STATE_MAP: + fore200e->bus->unmap(fore200e); + + case FORE200E_STATE_CONFIGURE: + /* nothing to do for that state */ + + case FORE200E_STATE_REGISTER: + /* XXX shouldn't we *start* by deregistering the device? */ + atm_dev_deregister(fore200e->atm_dev); + + case FORE200E_STATE_BLANK: + /* nothing to do for that state */ + } +} + + +#ifdef CONFIG_ATM_FORE200E_PCA + +static u32 fore200e_pca_read(volatile u32* addr) +{ + /* on big-endian hosts, the board is configured to convert + the endianess of slave RAM accesses */ + return le32_to_cpu(readl(addr)); +} + + +static void fore200e_pca_write(u32 val, volatile u32* addr) +{ + /* on big-endian hosts, the board is configured to convert + the endianess of slave RAM accesses */ + writel(cpu_to_le32(val), addr); +} + + +static u32 +fore200e_pca_dma_map(struct fore200e* fore200e, void* virt_addr, int size) +{ + u32 dma_addr = pci_map_single((struct pci_dev*)fore200e->bus_dev, virt_addr, size, PCI_DMA_BIDIRECTIONAL); + + DPRINTK(3, "PCI DVMA mapping: virt_addr = 0x%p, size = %d --> dma_addr = 0x%08x\n", + virt_addr, size, dma_addr); + + return dma_addr; +} + + +static void +fore200e_pca_dma_unmap(struct fore200e* fore200e, u32 dma_addr, int size) +{ + DPRINTK(3, "PCI DVMA unmapping: dma_addr = 0x%08x, size = %d\n", dma_addr, size); + + pci_unmap_single((struct pci_dev*)fore200e->bus_dev, dma_addr, size, + PCI_DMA_BIDIRECTIONAL); +} + + +static void +fore200e_pca_dma_sync(struct fore200e* fore200e, u32 dma_addr, int size) +{ + DPRINTK(3, "PCI DVMA sync: dma_addr = 0x%08x, size = %d\n", dma_addr, size); + + pci_dma_sync_single((struct pci_dev*)fore200e->bus_dev, dma_addr, size, + PCI_DMA_BIDIRECTIONAL); +} + + +/* allocate a DMA consistent chunk of memory intended to act as a communication mechanism + (to hold descriptors, status, queues, etc.) shared by the driver and the adapter */ + +static int +fore200e_pca_dma_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, int size, int nbr, int alignment) +{ +#if defined(__sparc_v9__) + /* returned chunks are page-aligned */ + chunk->alloc_addr = pci_alloc_consistent((struct pci_dev*)fore200e->bus_dev, + chunk->alloc_size, + &chunk->dma_addr); + + if (chunk->alloc_addr == NULL || chunk->dma_addr == 0) + return -ENOMEM; + + chunk->align_addr = chunk->alloc_addr; +#else + if (fore200e_chunk_alloc(fore200e, chunk, size * nbr, alignment) < 0) + return -ENOMEM; + + chunk->dma_addr = fore200e_pca_dma_map(fore200e, chunk->align_addr, chunk->align_size); +#endif + + return 0; +} + + +/* free a DMA consistent chunk of memory */ + +static void +fore200e_pca_dma_chunk_free(struct fore200e* fore200e, struct chunk* chunk) +{ +#if defined(__sparc_v9__) + pci_free_consistent((struct pci_dev*)fore200e->bus_dev, + chunk->alloc_size, + chunk->alloc_addr, + chunk->dma_addr); +#else + fore200e_pca_dma_unmap(fore200e, chunk->dma_addr, chunk->dma_size); + + fore200e_chunk_free(fore200e, chunk); +#endif +} + + +static int +fore200e_pca_irq_check(struct fore200e* fore200e) +{ + /* this is a 1 bit register */ + return readl(fore200e->regs.pca.psr); +} + + +static void +fore200e_pca_irq_ack(struct fore200e* fore200e) +{ + writel(PCA200E_HCR_CLRINTR, fore200e->regs.pca.hcr); +} + + +static void +fore200e_pca_reset(struct fore200e* fore200e) +{ + writel(PCA200E_HCR_RESET, fore200e->regs.pca.hcr); + fore200e_spin(10); + writel(0, fore200e->regs.pca.hcr); +} + + +static int __init +fore200e_pca_map(struct fore200e* fore200e) +{ + DPRINTK(2, "device %s being mapped in memory\n", fore200e->name); + + fore200e->virt_base = ioremap(fore200e->phys_base, PCA200E_IOSPACE_LENGTH); + + if (fore200e->virt_base == NULL) { + printk(FORE200E "can't map device %s\n", fore200e->name); + return -EFAULT; + } + + DPRINTK(1, "device %s mapped to 0x%p\n", fore200e->name, fore200e->virt_base); + + /* gain access to the PCA-200E specific registers */ + fore200e->regs.pca.hcr = (u32*)(fore200e->virt_base + PCA200E_HCR_OFFSET); + fore200e->regs.pca.imr = (u32*)(fore200e->virt_base + PCA200E_IMR_OFFSET); + fore200e->regs.pca.psr = (u32*)(fore200e->virt_base + PCA200E_PSR_OFFSET); + + fore200e->state = FORE200E_STATE_MAP; + return 0; +} + + +static void +fore200e_pca_unmap(struct fore200e* fore200e) +{ + DPRINTK(2, "device %s being unmapped from memory\n", fore200e->name); + + /* XXX iounmap() does nothing on PowerPC (at least in 2.2.12 and 2.3.41), + this leads to a kernel panic if the module is loaded and unloaded several times */ + if (fore200e->virt_base != NULL) + iounmap(fore200e->virt_base); +} + + +static int __init +fore200e_pca_configure(struct fore200e* fore200e) +{ + struct pci_dev* pci_dev = (struct pci_dev*)fore200e->bus_dev; + u8 master_ctrl; + + DPRINTK(2, "device %s being configured\n", fore200e->name); + + if ((pci_dev->irq == 0) || (pci_dev->irq == 0xFF)) { + printk(FORE200E "incorrect IRQ setting - misconfigured PCI-PCI bridge?\n"); + return -EIO; + } + + pci_read_config_byte(pci_dev, PCA200E_PCI_MASTER_CTRL, &master_ctrl); + + master_ctrl = master_ctrl +#if 0 + | PCA200E_CTRL_DIS_CACHE_RD + | PCA200E_CTRL_DIS_WRT_INVAL +#endif +#if defined(__BIG_ENDIAN) + /* request the PCA board to convert the endianess of slave RAM accesses */ + | PCA200E_CTRL_CONVERT_ENDIAN +#endif + | PCA200E_CTRL_LARGE_PCI_BURSTS; + + pci_write_config_byte(pci_dev, PCA200E_PCI_MASTER_CTRL, master_ctrl); + + fore200e->state = FORE200E_STATE_CONFIGURE; + return 0; +} + + +static struct fore200e* __init +fore200e_pca_detect(const struct fore200e_bus* bus, int index) +{ + struct fore200e* fore200e; + struct pci_dev* pci_dev = NULL; + int count = index; + + if (pci_present() == 0) { + printk(FORE200E "no PCI subsystem\n"); + return NULL; + } + + do { + pci_dev = pci_find_device(PCI_VENDOR_ID_FORE, PCI_DEVICE_ID_FORE_PCA200E, pci_dev); + if (pci_dev == NULL) + return NULL; + } while (count--); + + fore200e = fore200e_kmalloc(sizeof(struct fore200e), GFP_KERNEL); + if (fore200e == NULL) + return NULL; + + fore200e->bus = bus; + fore200e->bus_dev = pci_dev; + fore200e->irq = pci_dev->irq; + fore200e->phys_base = (pci_dev->resource[0].start & PCI_BASE_ADDRESS_MEM_MASK); + +#if defined(__powerpc__) + fore200e->phys_base += KERNELBASE; +#endif + + sprintf(fore200e->name, "%s-%d", bus->model_name, index - 1); + + pci_set_master(pci_dev); + + return fore200e; +} + + +static int __init +fore200e_pca_prom_read(struct fore200e* fore200e, struct prom_data* prom) +{ + struct host_cmdq* cmdq = &fore200e->host_cmdq; + struct host_cmdq_entry* entry = &cmdq->host_entry[ cmdq->head ]; + struct prom_opcode opcode; + int ok; + u32 prom_dma; + + FORE200E_NEXT_ENTRY(cmdq->head, QUEUE_SIZE_CMD); + + opcode.opcode = OPCODE_GET_PROM; + opcode.pad = 0; + + prom_dma = fore200e->bus->dma_map(fore200e, prom, sizeof(struct prom_data)); + + fore200e->bus->write(prom_dma, &entry->cp_entry->cmd.prom_block.prom_haddr); + + *entry->status = STATUS_PENDING; + + fore200e->bus->write(*(u32*)&opcode, (u32*)&entry->cp_entry->cmd.prom_block.opcode); + + ok = fore200e_poll(fore200e, entry->status, STATUS_COMPLETE, 400); + + *entry->status = STATUS_FREE; + + fore200e->bus->dma_unmap(fore200e, prom_dma, sizeof(struct prom_data)); + + if (ok == 0) { + printk(FORE200E "unable to get PROM data from device %s\n", fore200e->name); + return -EIO; + } + +#if defined(__BIG_ENDIAN) + +#define swap_here(addr) (*((u32*)(addr)) = swab32( *((u32*)(addr)) )) + + /* MAC address is stored as little-endian */ + swap_here(&prom->mac_addr[0]); + swap_here(&prom->mac_addr[4]); +#endif + + return 0; +} + + +static int +fore200e_pca_proc_read(struct fore200e* fore200e, char *page) +{ + struct pci_dev* pci_dev = (struct pci_dev*)fore200e->bus_dev; + + return sprintf(page, " PCI bus/slot/function:\t%d/%d/%d\n", + pci_dev->bus->number, PCI_SLOT(pci_dev->devfn), PCI_FUNC(pci_dev->devfn)); +} + +#endif /* CONFIG_ATM_FORE200E_PCA */ + + + + +#ifdef CONFIG_ATM_FORE200E_SBA + +static u32 +fore200e_sba_read(volatile u32* addr) +{ + return sbus_readl(addr); +} + + +static void +fore200e_sba_write(u32 val, volatile u32* addr) +{ + sbus_writel(val, addr); +} + + +static u32 +fore200e_sba_dma_map(struct fore200e* fore200e, void* virt_addr, int size) +{ + u32 dma_addr = sbus_map_single((struct sbus_dev*)fore200e->bus_dev, virt_addr, size); + + DPRINTK(3, "SBUS DVMA mapping: virt_addr = 0x%p, size = %d --> dma_addr = 0x%08x\n", virt_addr, size, dma_addr); + + return dma_addr; +} + + +static void +fore200e_sba_dma_unmap(struct fore200e* fore200e, u32 dma_addr, int size) +{ + DPRINTK(3, "SBUS DVMA unmapping: dma_addr = 0x%08x, size = %d\n", dma_addr, size); + + sbus_unmap_single((struct sbus_dev*)fore200e->bus_dev, dma_addr, size); +} + + +static void +fore200e_sba_dma_sync(struct fore200e* fore200e, u32 dma_addr, int size) +{ + DPRINTK(3, "SBUS DVMA sync: dma_addr = 0x%08x, size = %d\n", dma_addr, size); + + sbus_dma_sync_single((struct sbus_dev*)fore200e->bus_dev, dma_addr, size); +} + + +/* allocate a DVMA consistent chunk of memory intended to act as a communication mechanism + (to hold descriptors, status, queues, etc.) shared by the driver and the adapter */ + +static int +fore200e_sba_dma_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, int size, int nbr, int alignment) +{ + chunk->alloc_size = chunk->align_size = size * nbr; + + /* returned chunks are page-aligned */ + chunk->alloc_addr = sbus_alloc_consistent((struct sbus_dev*)fore200e->bus_dev, + chunk->alloc_size, + &chunk->dma_addr); + + if (chunk->alloc_addr == NULL || chunk->dma_addr == 0) + return -ENOMEM; + + chunk->align_addr = chunk->alloc_addr; + + return 0; +} + + +/* free a DVMA consistent chunk of memory */ + +static void +fore200e_sba_dma_chunk_free(struct fore200e* fore200e, struct chunk* chunk) +{ + sbus_free_consistent((struct sbus_dev*)fore200e->bus_dev, + chunk->alloc_size, + chunk->alloc_addr, + chunk->dma_addr); +} + + +static void +fore200e_sba_irq_enable(struct fore200e* fore200e) +{ + u32 hcr = fore200e->bus->read(fore200e->regs.sba.hcr) & SBA200E_HCR_STICKY; + fore200e->bus->write(hcr | SBA200E_HCR_INTR_ENA, fore200e->regs.sba.hcr); +} + + +static int +fore200e_sba_irq_check(struct fore200e* fore200e) +{ + return fore200e->bus->read(fore200e->regs.sba.hcr) & SBA200E_HCR_INTR_REQ; +} + + +static void +fore200e_sba_irq_ack(struct fore200e* fore200e) +{ + u32 hcr = fore200e->bus->read(fore200e->regs.sba.hcr) & SBA200E_HCR_STICKY; + fore200e->bus->write(hcr | SBA200E_HCR_INTR_CLR, fore200e->regs.sba.hcr); +} + + +static void +fore200e_sba_reset(struct fore200e* fore200e) +{ + fore200e->bus->write(SBA200E_HCR_RESET, fore200e->regs.sba.hcr); + fore200e_spin(10); + fore200e->bus->write(0, fore200e->regs.sba.hcr); +} + + +static int __init +fore200e_sba_map(struct fore200e* fore200e) +{ + struct sbus_dev* sbus_dev = (struct sbus_dev*)fore200e->bus_dev; + unsigned int bursts; + + /* gain access to the SBA-200E specific registers */ + + fore200e->regs.sba.hcr = (u32*)sbus_ioremap(&sbus_dev->resource[0], 0, SBA200E_HCR_LENGTH, "SBA HCR"); + fore200e->regs.sba.bsr = (u32*)sbus_ioremap(&sbus_dev->resource[1], 0, SBA200E_BSR_LENGTH, "SBA BSR"); + fore200e->regs.sba.isr = (u32*)sbus_ioremap(&sbus_dev->resource[2], 0, SBA200E_ISR_LENGTH, "SBA ISR"); + fore200e->virt_base = (u32*)sbus_ioremap(&sbus_dev->resource[3], 0, SBA200E_RAM_LENGTH, "SBA RAM"); + + if (fore200e->virt_base == NULL) { + printk(FORE200E "unable to map RAM of device %s\n", fore200e->name); + return -EFAULT; + } + + DPRINTK(1, "device %s mapped to 0x%p\n", fore200e->name, fore200e->virt_base); + + fore200e->bus->write(0x02, fore200e->regs.sba.isr); /* XXX hardwired interrupt level */ + + /* get the supported DVMA burst sizes */ + bursts = prom_getintdefault(sbus_dev->bus->prom_node, "burst-sizes", 0x00); + + if (sbus_can_dma_64bit(sbus_dev)) + sbus_set_sbus64(sbus_dev, bursts); + +#if 0 + if (bursts & DMA_BURST16) + fore200e->bus->write(SBA200E_BSR_BURST16, fore200e->regs.sba.bsr); + else + if (bursts & DMA_BURST8) + fore200e->bus->write(SBA200E_BSR_BURST8, fore200e->regs.sba.bsr); + else + if (bursts & DMA_BURST4) + fore200e->bus->write(SBA200E_BSR_BURST4, fore200e->regs.sba.bsr); +#endif + + fore200e->state = FORE200E_STATE_MAP; + return 0; +} + + +static void +fore200e_sba_unmap(struct fore200e* fore200e) +{ + sbus_iounmap((ulong)fore200e->regs.sba.hcr, SBA200E_HCR_LENGTH); + sbus_iounmap((ulong)fore200e->regs.sba.bsr, SBA200E_BSR_LENGTH); + sbus_iounmap((ulong)fore200e->regs.sba.isr, SBA200E_ISR_LENGTH); + sbus_iounmap((ulong)fore200e->virt_base, SBA200E_RAM_LENGTH); +} + + +static int __init +fore200e_sba_configure(struct fore200e* fore200e) +{ + fore200e->state = FORE200E_STATE_CONFIGURE; + return 0; +} + + +static struct fore200e* __init +fore200e_sba_detect(const struct fore200e_bus* bus, int index) +{ + struct fore200e* fore200e; + struct sbus_bus* sbus_bus; + struct sbus_dev* sbus_dev = NULL; + + unsigned int count = 0; + + for_each_sbus (sbus_bus) { + for_each_sbusdev (sbus_dev, sbus_bus) { + if (strcmp(sbus_dev->prom_name, SBA200E_PROM_NAME) == 0) { + if (count >= index) + goto found; + count++; + } + } + } + return NULL; + + found: +#if 1 + if (sbus_dev->num_registers != 4) { + printk(FORE200E "this %s device has %d instead of 4 registers\n", + bus->model_name, sbus_dev->num_registers); + return NULL; + } +#endif + + fore200e = fore200e_kmalloc(sizeof(struct fore200e), GFP_KERNEL); + if (fore200e == NULL) + return NULL; + + fore200e->bus = bus; + fore200e->bus_dev = sbus_dev; + fore200e->irq = sbus_dev->irqs[ 0 ]; + + fore200e->phys_base = (unsigned long)sbus_dev; + + sprintf(fore200e->name, "%s-%d", bus->model_name, index - 1); + + return fore200e; +} + + +static int __init +fore200e_sba_prom_read(struct fore200e* fore200e, struct prom_data* prom) +{ + struct sbus_dev* sbus_dev = (struct sbus_dev*) fore200e->bus_dev; + int len; + + len = prom_getproperty(sbus_dev->prom_node, "macaddrlo2", &prom->mac_addr[ 4 ], 4); + if (len < 0) + return -EBUSY; + + len = prom_getproperty(sbus_dev->prom_node, "macaddrhi4", &prom->mac_addr[ 2 ], 4); + if (len < 0) + return -EBUSY; + + prom_getproperty(sbus_dev->prom_node, "serialnumber", + (char*)&prom->serial_number, sizeof(prom->serial_number)); + + prom_getproperty(sbus_dev->prom_node, "promversion", + (char*)&prom->hw_revision, sizeof(prom->hw_revision)); + + return 0; +} + + +static int +fore200e_sba_proc_read(struct fore200e* fore200e, char *page) +{ + struct sbus_dev* sbus_dev = (struct sbus_dev*)fore200e->bus_dev; + + return sprintf(page, " SBUS slot/device:\t\t%d/'%s'\n", sbus_dev->slot, sbus_dev->prom_name); +} +#endif /* CONFIG_ATM_FORE200E_SBA */ + + +static void +fore200e_irq_tx(struct fore200e* fore200e) +{ + struct host_txq_entry* entry; + int i; + + entry = fore200e->host_txq.host_entry; + + for (i = 0; i < QUEUE_SIZE_TX; i++) { + + if (*entry->status & STATUS_COMPLETE) { + + DPRINTK(3, "TX COMPLETED: entry = %p, vcc = %p, skb = %p\n", entry, entry->vcc, entry->skb); + + /* free copy of misaligned data */ + if (entry->data) + kfree(entry->data); + + /* remove DMA mapping */ + fore200e->bus->dma_unmap(fore200e, entry->tpd->tsd[ 0 ].buffer, entry->tpd->tsd[ 0 ].length); + + /* notify tx completion */ + if (entry->vcc->pop) + entry->vcc->pop(entry->vcc, entry->skb); + else + dev_kfree_skb_irq(entry->skb); + + /* check error condition */ + if (*entry->status & STATUS_ERROR) + entry->vcc->stats->tx_err++; + else + entry->vcc->stats->tx++; + + *entry->status = STATUS_FREE; + + fore200e->host_txq.txing--; + } + entry++; + } +} + + +static void +fore200e_supply(struct fore200e* fore200e) +{ + int scheme, magn, i; + + struct host_bsq* bsq; + struct host_bsq_entry* entry; + struct buffer* buffer; + + for (scheme = 0; scheme < BUFFER_SCHEME_NBR; scheme++) { + for (magn = 0; magn < BUFFER_MAGN_NBR; magn++) { + + bsq = &fore200e->host_bsq[ scheme ][ magn ]; + + if (fore200e_rx_buf_nbr[ scheme ][ magn ] - bsq->count > RBD_BLK_SIZE) { + + DPRINTK(2, "supplying rx buffers to queue %d / %d, count = %d\n", + scheme, magn, bsq->count); + + entry = &bsq->host_entry[ bsq->head ]; + + FORE200E_NEXT_ENTRY(bsq->head, QUEUE_SIZE_BS); + + for (i = 0; i < RBD_BLK_SIZE; i++) { + + buffer = &bsq->buffer[ bsq->free ]; + + FORE200E_NEXT_ENTRY(bsq->free, fore200e_rx_buf_nbr[ scheme ][ magn ]); + + entry->rbd_block->rbd[ i ].buffer_haddr = buffer->data.dma_addr; + entry->rbd_block->rbd[ i ].handle = FORE200E_BUF2HDL(buffer); + } + + /* increase the number of supplied rx buffers */ + bsq->count += RBD_BLK_SIZE; + + *entry->status = STATUS_PENDING; + fore200e->bus->write(entry->rbd_block_dma, &entry->cp_entry->rbd_block_haddr); + } + } + } +} + + + +static struct atm_vcc* +fore200e_find_vcc(struct fore200e* fore200e, struct rpd* rpd) +{ + struct atm_vcc* vcc; + + for (vcc = fore200e->atm_dev->vccs; vcc; vcc = vcc->next) { + + if (vcc->vpi == rpd->atm_header.vpi && vcc->vci == rpd->atm_header.vci) + break; + } + + return vcc; +} + + +static void +fore200e_push_rpd(struct fore200e* fore200e, struct rpd* rpd) +{ + struct atm_vcc* vcc; + struct sk_buff* skb; + struct buffer* buffer; + struct fore200e_vcc* fore200e_vcc; + int i, pdu_len = 0; +#ifdef FORE200E_52BYTE_AAL0_SDU + u32 cell_header = 0; +#endif + + vcc = fore200e_find_vcc(fore200e, rpd); + if (vcc == NULL) { + + printk(FORE200E "no vcc found for PDU received on %d.%d.%d\n", + fore200e->atm_dev->number, rpd->atm_header.vpi, rpd->atm_header.vci); + return; + } + + fore200e_vcc = FORE200E_VCC(vcc); + +#ifdef FORE200E_52BYTE_AAL0_SDU + if ((vcc->qos.aal == ATM_AAL0) && (vcc->qos.rxtp.max_sdu == ATM_AAL0_SDU)) { + + cell_header = (rpd->atm_header.gfc << ATM_HDR_GFC_SHIFT) | + (rpd->atm_header.vpi << ATM_HDR_VPI_SHIFT) | + (rpd->atm_header.vci << ATM_HDR_VCI_SHIFT) | + (rpd->atm_header.plt << ATM_HDR_PTI_SHIFT) | + rpd->atm_header.clp; + pdu_len = 4; + } +#endif + + /* compute total PDU length */ + for (i = 0; i < rpd->nseg; i++) + pdu_len += rpd->rsd[ i ].length; + + skb = alloc_skb(pdu_len, GFP_ATOMIC); + if (skb == NULL) { + + printk(FORE200E "unable to alloc new skb, rx PDU length = %d\n", pdu_len); + vcc->stats->rx_drop++; + return; + } + + skb->stamp = vcc->timestamp = xtime; + +#ifdef FORE200E_52BYTE_AAL0_SDU + if (cell_header) { + *((u32*)skb_put(skb, 4)) = cell_header; + } +#endif + + /* reassemble segments */ + for (i = 0; i < rpd->nseg; i++) { + + /* rebuild rx buffer address from rsd handle */ + buffer = FORE200E_HDL2BUF(rpd->rsd[ i ].handle); + + /* ensure DMA synchronisation */ + fore200e->bus->dma_sync(fore200e, buffer->data.dma_addr, rpd->rsd[ i ].length); + + memcpy(skb_put(skb, rpd->rsd[ i ].length), buffer->data.align_addr, rpd->rsd[ i ].length); + } + + DPRINTK(3, "rx skb: len = %d, truesize = %d\n", skb->len, skb->truesize); + + if (pdu_len < fore200e_vcc->rx_min_pdu) + fore200e_vcc->rx_min_pdu = pdu_len; + if (pdu_len > fore200e_vcc->rx_max_pdu) + fore200e_vcc->rx_max_pdu = pdu_len; + + /* push PDU */ + if (atm_charge(vcc, skb->truesize) == 0) { + + DPRINTK(2, "receive buffers saturated for %d.%d.%d - PDU dropped\n", + vcc->itf, vcc->vpi, vcc->vci); + + dev_kfree_skb_irq(skb); + return; + } + + vcc->push(vcc, skb); + vcc->stats->rx++; +} + + +static void +fore200e_collect_rpd(struct fore200e* fore200e, struct rpd* rpd) +{ + struct buffer* buffer; + int i; + + for (i = 0; i < rpd->nseg; i++) { + + /* rebuild rx buffer address from rsd handle */ + buffer = FORE200E_HDL2BUF(rpd->rsd[ i ].handle); + + /* decrease the number of supplied rx buffers */ + fore200e->host_bsq[ buffer->scheme ][ buffer->magn ].count--; + } +} + + +static void +fore200e_irq_rx(struct fore200e* fore200e) +{ + struct host_rxq* rxq = &fore200e->host_rxq; + struct host_rxq_entry* entry; + + for (;;) { + + entry = &rxq->host_entry[ rxq->head ]; + + /* no more received PDUs */ + if ((*entry->status & STATUS_COMPLETE) == 0) + break; + + FORE200E_NEXT_ENTRY(rxq->head, QUEUE_SIZE_RX); + + if ((*entry->status & STATUS_ERROR) == 0) { + + fore200e_push_rpd(fore200e, entry->rpd); + } + else { + printk(FORE200E "damaged PDU on %d.%d.%d\n", + fore200e->atm_dev->number, entry->rpd->atm_header.vpi, entry->rpd->atm_header.vci); + } + + fore200e_collect_rpd(fore200e, entry->rpd); + + fore200e_supply(fore200e); + + /* rewrite the rpd address to ack the received PDU */ + fore200e->bus->write(entry->rpd_dma, &entry->cp_entry->rpd_haddr); + *entry->status = STATUS_FREE; + } +} + + +static void +fore200e_interrupt(int irq, void* dev, struct pt_regs* regs) +{ + struct fore200e* fore200e = FORE200E_DEV((struct atm_dev*)dev); + + if (fore200e->bus->irq_check(fore200e) == 0) { + + DPRINTK(3, "unexpected interrupt on device %c\n", fore200e->name[9]); + return; + } + DPRINTK(3, "valid interrupt on device %c\n", fore200e->name[9]); + + fore200e_irq_rx(fore200e); + + if (fore200e->host_txq.txing) + fore200e_irq_tx(fore200e); + + fore200e->bus->irq_ack(fore200e); +} + + +static int +fore200e_select_scheme(struct atm_vcc* vcc) +{ + int scheme; + +#if 1 + /* fairly balance VCs over (identical) buffer schemes */ + scheme = vcc->vci % 2 ? BUFFER_SCHEME_ONE : BUFFER_SCHEME_TWO; +#else + /* bit 7 of VPI magically selects the second buffer scheme */ + if (vcc->vpi & (1<<7)) { + vcc->vpi &= ((1<<7) - 1); /* reset the magic bit */ + scheme = BUFFER_SCHEME_TWO; + } + else { + scheme = BUFFER_SCHEME_ONE; + } +#endif + + DPRINTK(1, "vpvc %d.%d.%d uses the %s buffer scheme\n", + vcc->itf, vcc->vpi, vcc->vci, scheme == BUFFER_SCHEME_ONE ? "first" : "second"); + + return scheme; +} + + + +static int +fore200e_activate_vcin(struct fore200e* fore200e, int activate, struct atm_vcc* vcc, int mtu) +{ + struct host_cmdq* cmdq = &fore200e->host_cmdq; + struct host_cmdq_entry* entry = &cmdq->host_entry[ cmdq->head ]; + struct activate_opcode activ_opcode; + struct deactivate_opcode deactiv_opcode; + struct vpvc vpvc; + int ok; + enum fore200e_aal aal = fore200e_atm2fore_aal(vcc->qos.aal); + + FORE200E_NEXT_ENTRY(cmdq->head, QUEUE_SIZE_CMD); + + if (activate) { + FORE200E_VCC(vcc)->scheme = fore200e_select_scheme(vcc); + + activ_opcode.opcode = OPCODE_ACTIVATE_VCIN; + activ_opcode.aal = aal; + activ_opcode.scheme = FORE200E_VCC(vcc)->scheme; + activ_opcode.pad = 0; + } + else { + deactiv_opcode.opcode = OPCODE_DEACTIVATE_VCIN; + deactiv_opcode.pad = 0; + } + + vpvc.vci = vcc->vci; + vpvc.vpi = vcc->vpi; + + *entry->status = STATUS_PENDING; + + if (activate) { + +#ifdef FORE200E_52BYTE_AAL0_SDU + mtu = 48; +#endif + /* the MTU is unused by the cp, except in the case of AAL0 */ + fore200e->bus->write(mtu, &entry->cp_entry->cmd.activate_block.mtu); + fore200e->bus->write(*(u32*)&vpvc, (u32*)&entry->cp_entry->cmd.activate_block.vpvc); + fore200e->bus->write(*(u32*)&activ_opcode, (u32*)&entry->cp_entry->cmd.activate_block.opcode); + } + else { + fore200e->bus->write(*(u32*)&vpvc, (u32*)&entry->cp_entry->cmd.deactivate_block.vpvc); + fore200e->bus->write(*(u32*)&deactiv_opcode, (u32*)&entry->cp_entry->cmd.deactivate_block.opcode); + } + + ok = fore200e_poll(fore200e, entry->status, STATUS_COMPLETE, 400); + + *entry->status = STATUS_FREE; + + if (ok == 0) { + printk(FORE200E "unable to %s vpvc %d.%d on device %s\n", + activate ? "open" : "close", vcc->vpi, vcc->vci, fore200e->name); + return -EIO; + } + + DPRINTK(1, "vpvc %d.%d %sed on device %s\n", vcc->vpi, vcc->vci, + activate ? "open" : "clos", fore200e->name); + + return 0; +} + + +static int +fore200e_walk_vccs(struct atm_vcc *vcc, short *vpi, int *vci) +{ + struct atm_vcc* walk; + + /* find a free VPI */ + if (*vpi == ATM_VPI_ANY) { + + for (*vpi = 0, walk = vcc->dev->vccs; walk; walk = walk->next) { + + if ((walk->vci == *vci) && (walk->vpi == *vpi)) { + (*vpi)++; + walk = vcc->dev->vccs; + } + } + } + + /* find a free VCI */ + if (*vci == ATM_VCI_ANY) { + + for (*vci = ATM_NOT_RSV_VCI, walk = vcc->dev->vccs; walk; walk = walk->next) { + + if ((walk->vpi = *vpi) && (walk->vci == *vci)) { + *vci = walk->vci + 1; + walk = vcc->dev->vccs; + } + } + } + + return 0; +} + + +#define FORE200E_MAX_BACK2BACK_CELLS 255 /* XXX depends on CDVT */ + +static void +fore200e_rate_ctrl(struct atm_qos* qos, struct tpd_rate* rate) +{ + if (qos->txtp.max_pcr < ATM_OC3_PCR) { + + /* compute the data cells to idle cells ratio from the PCR */ + rate->data_cells = qos->txtp.max_pcr * FORE200E_MAX_BACK2BACK_CELLS / ATM_OC3_PCR; + rate->idle_cells = FORE200E_MAX_BACK2BACK_CELLS - rate->data_cells; + } + else { + /* disable rate control */ + rate->data_cells = rate->idle_cells = 0; + } +} + + +static int +fore200e_open(struct atm_vcc *vcc, short vpi, int vci) +{ + struct fore200e* fore200e = FORE200E_DEV(vcc->dev); + struct fore200e_vcc* fore200e_vcc; + + /* find a free VPI/VCI */ + fore200e_walk_vccs(vcc, &vpi, &vci); + + vcc->vpi = vpi; + vcc->vci = vci; + + /* ressource checking only? */ + if (vci == ATM_VCI_UNSPEC || vpi == ATM_VPI_UNSPEC) + return 0; + + vcc->flags |= ATM_VF_ADDR; + vcc->itf = vcc->dev->number; + + DPRINTK(2, "opening %d.%d.%d:%d QoS = (tx: cl=%s, pcr=%d-%d, cdv=%d, max_sdu=%d; " + "rx: cl=%s, pcr=%d-%d, cdv=%d, max_sdu=%d)\n", + vcc->itf, vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal), + fore200e_traffic_class[ vcc->qos.txtp.traffic_class ], + vcc->qos.txtp.min_pcr, vcc->qos.txtp.max_pcr, vcc->qos.txtp.max_cdv, vcc->qos.txtp.max_sdu, + fore200e_traffic_class[ vcc->qos.rxtp.traffic_class ], + vcc->qos.rxtp.min_pcr, vcc->qos.rxtp.max_pcr, vcc->qos.rxtp.max_cdv, vcc->qos.rxtp.max_sdu); + + if ((vcc->qos.txtp.traffic_class == ATM_CBR) && (vcc->qos.txtp.max_pcr > 0)) { + + down(&fore200e->rate_sf); + if (fore200e->available_cell_rate < vcc->qos.txtp.max_pcr) { + up(&fore200e->rate_sf); + return -EAGAIN; + } + /* reserving the pseudo-CBR bandwidth at this point grants us + to reduce the length of the critical section protected + by 'rate_sf'. in counterpart, we have to reset the available + bandwidth if we later encounter an error */ + + fore200e->available_cell_rate -= vcc->qos.txtp.max_pcr; + up(&fore200e->rate_sf); + } + + fore200e_vcc = fore200e_kmalloc(sizeof(struct fore200e_vcc), GFP_KERNEL); + if (fore200e_vcc == NULL) { + down(&fore200e->rate_sf); + fore200e->available_cell_rate += vcc->qos.txtp.max_pcr; + up(&fore200e->rate_sf); + return -ENOMEM; + } + + FORE200E_VCC(vcc) = fore200e_vcc; + + if (fore200e_activate_vcin(fore200e, 1, vcc, vcc->qos.rxtp.max_sdu) < 0) { + kfree(fore200e_vcc); + down(&fore200e->rate_sf); + fore200e->available_cell_rate += vcc->qos.txtp.max_pcr; + up(&fore200e->rate_sf); + return -EBUSY; + } + +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif + + /* compute rate control parameters */ + if ((vcc->qos.txtp.traffic_class == ATM_CBR) && (vcc->qos.txtp.max_pcr > 0)) { + + fore200e_rate_ctrl(&vcc->qos, &fore200e_vcc->rate); + + DPRINTK(3, "tx on %d.%d.%d:%d, tx PCR = %d, rx PCR = %d, data_cells = %u, idle_cells = %u\n", + vcc->itf, vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal), + vcc->qos.txtp.max_pcr, vcc->qos.rxtp.max_pcr, + fore200e_vcc->rate.data_cells, fore200e_vcc->rate.idle_cells); + } + + fore200e_vcc->tx_min_pdu = fore200e_vcc->rx_min_pdu = 65536; + fore200e_vcc->tx_max_pdu = fore200e_vcc->rx_max_pdu = 0; + + vcc->flags |= ATM_VF_READY; + return 0; +} + + + +static void +fore200e_close(struct atm_vcc* vcc) +{ + struct fore200e* fore200e = FORE200E_DEV(vcc->dev); + + DPRINTK(2, "closing %d.%d.%d:%d\n", vcc->itf, vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal)); + + fore200e_activate_vcin(fore200e, 0, vcc, 0); + +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif + + kfree(FORE200E_VCC(vcc)); + + if ((vcc->qos.txtp.traffic_class == ATM_CBR) && (vcc->qos.txtp.max_pcr > 0)) { + down(&fore200e->rate_sf); + fore200e->available_cell_rate += vcc->qos.txtp.max_pcr; + up(&fore200e->rate_sf); + } +} + + +#if 0 +#define FORE200E_SYNC_SEND /* wait tx completion before returning */ +#endif + + +static int +fore200e_send(struct atm_vcc *vcc, struct sk_buff *skb) +{ + struct fore200e* fore200e = FORE200E_DEV(vcc->dev); + struct fore200e_vcc* fore200e_vcc = FORE200E_VCC(vcc); + struct host_txq* txq = &fore200e->host_txq; + struct host_txq_entry* entry; + struct tpd* tpd; + struct tpd_haddr tpd_haddr; + unsigned long flags; + int retry = CONFIG_ATM_FORE200E_TX_RETRY; + int tx_copy = 0; + int tx_len = skb->len; + u32* cell_header = NULL; + unsigned char* skb_data; + int skb_len; + +#ifdef FORE200E_52BYTE_AAL0_SDU + if ((vcc->qos.aal == ATM_AAL0) && (vcc->qos.txtp.max_sdu == ATM_AAL0_SDU)) { + cell_header = (u32*) skb->data; + skb_data = skb->data + 4; /* skip 4-byte cell header */ + skb_len = tx_len = skb->len - 4; + + DPRINTK(3, "skipping user-supplied cell header 0x%08x", *cell_header); + } + else +#endif + { + skb_data = skb->data; + skb_len = skb->len; + } + + retry_here: + + spin_lock_irqsave(&fore200e->tx_lock, flags); + + entry = &txq->host_entry[ txq->head ]; + + if (*entry->status != STATUS_FREE) { + + /* try to free completed tx queue entries */ + fore200e_irq_tx(fore200e); + + if (*entry->status != STATUS_FREE) { + + spin_unlock_irqrestore(&fore200e->tx_lock, flags); + + /* retry once again? */ + if(--retry > 0) + goto retry_here; + + vcc->stats->tx_err++; + + printk(FORE200E "tx queue of device %s is saturated, PDU dropped - heartbeat is %08x\n", + fore200e->name, fore200e->cp_queues->heartbeat); + + return -EIO; + } + } + + tpd = entry->tpd; + + if (((unsigned long)skb_data) & 0x3) { + + DPRINTK(2, "misaligned tx PDU on device %s\n", fore200e->name); + tx_copy = 1; + tx_len = skb_len; + } + + if ((vcc->qos.aal == ATM_AAL0) && (skb_len % ATM_CELL_PAYLOAD)) { + + /* this simply NUKES the PCA-200E board */ + DPRINTK(2, "incomplete tx AAL0 PDU on device %s\n", fore200e->name); + tx_copy = 1; + tx_len = ((skb_len / ATM_CELL_PAYLOAD) + 1) * ATM_CELL_PAYLOAD; + } + + if (tx_copy) { + + entry->data = kmalloc(tx_len, GFP_ATOMIC | GFP_DMA); + if (entry->data == NULL) { + + spin_unlock_irqrestore(&fore200e->tx_lock, flags); + return -ENOMEM; + } + + memcpy(entry->data, skb_data, skb_len); + if (skb_len < tx_len) + memset(entry->data + skb_len, 0x00, tx_len - skb_len); + + tpd->tsd[ 0 ].buffer = fore200e->bus->dma_map(fore200e, entry->data, tx_len); + } + else { + entry->data = NULL; + tpd->tsd[ 0 ].buffer = fore200e->bus->dma_map(fore200e, skb_data, tx_len); + } + + tpd->tsd[ 0 ].length = tx_len; + + FORE200E_NEXT_ENTRY(txq->head, QUEUE_SIZE_TX); + txq->txing++; + + spin_unlock_irqrestore(&fore200e->tx_lock, flags); + + /* ensure DMA synchronisation */ + fore200e->bus->dma_sync(fore200e, tpd->tsd[ 0 ].buffer, tpd->tsd[ 0 ].length); + + DPRINTK(3, "tx on %d.%d.%d:%d, len = %u (%u)\n", + vcc->itf, vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal), + tpd->tsd[0].length, skb_len); + + if (skb_len < fore200e_vcc->tx_min_pdu) + fore200e_vcc->tx_min_pdu = skb_len; + if (skb_len > fore200e_vcc->tx_max_pdu) + fore200e_vcc->tx_max_pdu = skb_len; + + entry->vcc = vcc; + entry->skb = skb; + + /* set tx rate control information */ + tpd->rate.data_cells = fore200e_vcc->rate.data_cells; + tpd->rate.idle_cells = fore200e_vcc->rate.idle_cells; + + if (cell_header) { + tpd->atm_header.clp = (*cell_header & ATM_HDR_CLP); + tpd->atm_header.plt = (*cell_header & ATM_HDR_PTI_MASK) >> ATM_HDR_PTI_SHIFT; + tpd->atm_header.vci = (*cell_header & ATM_HDR_VCI_MASK) >> ATM_HDR_VCI_SHIFT; + tpd->atm_header.vpi = (*cell_header & ATM_HDR_VPI_MASK) >> ATM_HDR_VPI_SHIFT; + tpd->atm_header.gfc = (*cell_header & ATM_HDR_GFC_MASK) >> ATM_HDR_GFC_SHIFT; + } + else { + /* set the ATM header, common to all cells conveying the PDU */ + tpd->atm_header.clp = 0; + tpd->atm_header.plt = 0; + tpd->atm_header.vci = vcc->vci; + tpd->atm_header.vpi = vcc->vpi; + tpd->atm_header.gfc = 0; + } + + tpd->spec.length = tx_len; + tpd->spec.nseg = 1; + tpd->spec.aal = fore200e_atm2fore_aal(vcc->qos.aal); +#ifdef FORE200E_SYNC_SEND + tpd->spec.intr = 0; +#else + tpd->spec.intr = 1; +#endif + + tpd_haddr.size = sizeof(struct tpd) / 32; /* size is expressed in 32 byte blocks */ + tpd_haddr.pad = 0; + tpd_haddr.haddr = entry->tpd_dma >> 5; /* shift the address, as we are in a bitfield */ + + *entry->status = STATUS_PENDING; + fore200e->bus->write(*(u32*)&tpd_haddr, (u32*)&entry->cp_entry->tpd_haddr); + + +#ifdef FORE200E_SYNC_SEND + { + int ok = fore200e_poll(fore200e, entry->status, STATUS_COMPLETE, 10); + + fore200e->bus->dma_unmap(fore200e, entry->tpd->tsd[ 0 ].buffer, entry->tpd->tsd[ 0 ].length); + + if (ok == 0) { + printk(FORE200E "synchronous tx on %d:%d:%d failed\n", vcc->itf, vcc->vpi, vcc->vci); + + entry->vcc->stats->tx_err++; + return -EIO; + } + entry->vcc->stats->tx++; + + DPRINTK(3, "synchronous tx on %d:%d:%d succeeded\n", vcc->itf, vcc->vpi, vcc->vci); + + /* free tmp copy of misaligned data */ + if (entry->data) + kfree(entry->data); + + /* notify tx completion */ + if (vcc->pop) + vcc->pop(vcc, skb); + else + dev_kfree_skb(skb); + } +#endif + + return 0; +} + + +static int +fore200e_getstats(struct fore200e* fore200e) +{ + struct host_cmdq* cmdq = &fore200e->host_cmdq; + struct host_cmdq_entry* entry = &cmdq->host_entry[ cmdq->head ]; + struct stats_opcode opcode; + int ok; + u32 stats_dma_addr; + + if (fore200e->stats == NULL) { + fore200e->stats = fore200e_kmalloc(sizeof(struct stats), GFP_KERNEL | GFP_DMA); + if (fore200e->stats == NULL) + return -ENOMEM; + } + + stats_dma_addr = fore200e->bus->dma_map(fore200e, fore200e->stats, sizeof(struct stats)); + + FORE200E_NEXT_ENTRY(cmdq->head, QUEUE_SIZE_CMD); + + opcode.opcode = OPCODE_GET_STATS; + opcode.pad = 0; + + fore200e->bus->write(stats_dma_addr, &entry->cp_entry->cmd.stats_block.stats_haddr); + + *entry->status = STATUS_PENDING; + + fore200e->bus->write(*(u32*)&opcode, (u32*)&entry->cp_entry->cmd.stats_block.opcode); + + ok = fore200e_poll(fore200e, entry->status, STATUS_COMPLETE, 400); + + *entry->status = STATUS_FREE; + + fore200e->bus->dma_unmap(fore200e, stats_dma_addr, sizeof(struct stats)); + + if (ok == 0) { + printk(FORE200E "unable to get statistics from device %s\n", fore200e->name); + return -EIO; + } + + return 0; +} + + +static int +fore200e_getsockopt (struct atm_vcc* vcc, int level, int optname, void* optval, int optlen) +{ + // struct fore200e* fore200e = FORE200E_DEV(vcc->dev); + + DPRINTK(2, "getsockopt %d.%d.%d, level = %d, optname = 0x%x, optval = 0x%p, optlen = %d\n", + vcc->itf, vcc->vpi, vcc->vci, level, optname, optval, optlen); + + return -EINVAL; +} + + +static int +fore200e_setsockopt(struct atm_vcc* vcc, int level, int optname, void* optval, int optlen) +{ + // struct fore200e* fore200e = FORE200E_DEV(vcc->dev); + + DPRINTK(2, "setsockopt %d.%d.%d, level = %d, optname = 0x%x, optval = 0x%p, optlen = %d\n", + vcc->itf, vcc->vpi, vcc->vci, level, optname, optval, optlen); + + return -EINVAL; +} + + +#if 0 /* currently unused */ +static int +fore200e_get_oc3(struct fore200e* fore200e, struct oc3_regs* regs) +{ + struct host_cmdq* cmdq = &fore200e->host_cmdq; + struct host_cmdq_entry* entry = &cmdq->host_entry[ cmdq->head ]; + struct oc3_opcode opcode; + int ok; + u32 oc3_regs_dma_addr; + + oc3_regs_dma_addr = fore200e->bus->dma_map(fore200e, regs, sizeof(struct oc3_regs)); + + FORE200E_NEXT_ENTRY(cmdq->head, QUEUE_SIZE_CMD); + + opcode.opcode = OPCODE_GET_OC3; + opcode.reg = 0; + opcode.value = 0; + opcode.mask = 0; + + fore200e->bus->write(oc3_regs_dma_addr, &entry->cp_entry->cmd.oc3_block.regs_haddr); + + *entry->status = STATUS_PENDING; + + fore200e->bus->write(*(u32*)&opcode, (u32*)&entry->cp_entry->cmd.oc3_block.opcode); + + ok = fore200e_poll(fore200e, entry->status, STATUS_COMPLETE, 400); + + *entry->status = STATUS_FREE; + + fore200e->bus_dma_unmap(fore200e, oc3_regs_dma_addr, sizeof(struct oc3_regs)); + + if (ok == 0) { + printk(FORE200E "unable to get OC-3 regs of device %s\n", fore200e->name); + return -EIO; + } + + return 0; +} +#endif + + +static int +fore200e_set_oc3(struct fore200e* fore200e, u32 reg, u32 value, u32 mask) +{ + struct host_cmdq* cmdq = &fore200e->host_cmdq; + struct host_cmdq_entry* entry = &cmdq->host_entry[ cmdq->head ]; + struct oc3_opcode opcode; + int ok; + + FORE200E_NEXT_ENTRY(cmdq->head, QUEUE_SIZE_CMD); + + opcode.opcode = OPCODE_SET_OC3; + opcode.reg = reg; + opcode.value = value; + opcode.mask = mask; + + fore200e->bus->write(0, &entry->cp_entry->cmd.oc3_block.regs_haddr); + + *entry->status = STATUS_PENDING; + + fore200e->bus->write(*(u32*)&opcode, (u32*)&entry->cp_entry->cmd.oc3_block.opcode); + + ok = fore200e_poll(fore200e, entry->status, STATUS_COMPLETE, 400); + + *entry->status = STATUS_FREE; + + if (ok == 0) { + printk(FORE200E "unable to set OC-3 reg 0x%02x of device %s\n", reg, fore200e->name); + return -EIO; + } + + return 0; +} + + +static int +fore200e_setloop(struct fore200e* fore200e, int loop_mode) +{ + u32 mct_value, mct_mask; + int error; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + switch (loop_mode) { + + case SUNI_LM_NONE: + mct_value = 0; + mct_mask = SUNI_MCT_DLE | SUNI_MCT_LLE; + break; + + case SUNI_LM_DIAG: + mct_value = mct_mask = SUNI_MCT_DLE; + break; + + case SUNI_LM_LOOP: + mct_value = mct_mask = SUNI_MCT_LLE; + break; + + default: + return -EINVAL; + } + + error = fore200e_set_oc3(fore200e, SUNI_MCT, mct_value, mct_mask); + if ( error == 0) + fore200e->loop_mode = loop_mode; + + return error; +} + + +static inline unsigned int +fore200e_swap(unsigned int in) +{ +#if defined(__LITTLE_ENDIAN) + return swab32(in); +#else + return in; +#endif +} + + +static int +fore200e_fetch_stats(struct fore200e* fore200e, struct sonet_stats* arg) +{ + struct sonet_stats tmp; + + if (fore200e_getstats(fore200e) < 0) + return -EIO; + + tmp.section_bip = fore200e_swap(fore200e->stats->oc3.section_bip8_errors); + tmp.line_bip = fore200e_swap(fore200e->stats->oc3.line_bip24_errors); + tmp.path_bip = fore200e_swap(fore200e->stats->oc3.path_bip8_errors); + tmp.line_febe = fore200e_swap(fore200e->stats->oc3.line_febe_errors); + tmp.path_febe = fore200e_swap(fore200e->stats->oc3.path_febe_errors); + tmp.corr_hcs = fore200e_swap(fore200e->stats->oc3.corr_hcs_errors); + tmp.uncorr_hcs = fore200e_swap(fore200e->stats->oc3.ucorr_hcs_errors); + tmp.tx_cells = fore200e_swap(fore200e->stats->aal0.cells_transmitted) + + fore200e_swap(fore200e->stats->aal34.cells_transmitted) + + fore200e_swap(fore200e->stats->aal5.cells_transmitted); + tmp.rx_cells = fore200e_swap(fore200e->stats->aal0.cells_received) + + fore200e_swap(fore200e->stats->aal34.cells_received) + + fore200e_swap(fore200e->stats->aal5.cells_received); + + if (arg) + return copy_to_user(arg, &tmp, sizeof(struct sonet_stats)) ? -EFAULT : 0; + + return 0; +} + + +static int +fore200e_ioctl(struct atm_dev* dev, unsigned int cmd, void* arg) +{ + struct fore200e* fore200e = FORE200E_DEV(dev); + + DPRINTK(2, "ioctl cmd = 0x%x (%u), arg = 0x%p (%lu)\n", cmd, cmd, arg, (unsigned long)arg); + + switch (cmd) { + + case SONET_GETSTAT: + return fore200e_fetch_stats(fore200e, (struct sonet_stats*)arg); + + case SONET_GETDIAG: + return put_user(0, (int*)arg) ? -EFAULT : 0; + + case SUNI_SETLOOP: + return fore200e_setloop(fore200e, (int)(unsigned long)arg); + + case SUNI_GETLOOP: + return put_user(fore200e->loop_mode, (int*)arg) ? -EFAULT : 0; + } + + return -ENOSYS; /* not implemented */ +} + + +static int +fore200e_change_qos(struct atm_vcc* vcc,struct atm_qos* qos, int flags) +{ + struct fore200e_vcc* fore200e_vcc = FORE200E_VCC(vcc); + struct fore200e* fore200e = FORE200E_DEV(vcc->dev); + + DPRINTK(2, "change_qos %d.%d.%d, " + "(tx: cl=%s, pcr=%d-%d, cdv=%d, max_sdu=%d; " + "rx: cl=%s, pcr=%d-%d, cdv=%d, max_sdu=%d), flags = 0x%x\n" + "available_cell_rate = %u", + vcc->itf, vcc->vpi, vcc->vci, + fore200e_traffic_class[ qos->txtp.traffic_class ], + qos->txtp.min_pcr, qos->txtp.max_pcr, qos->txtp.max_cdv, qos->txtp.max_sdu, + fore200e_traffic_class[ qos->rxtp.traffic_class ], + qos->rxtp.min_pcr, qos->rxtp.max_pcr, qos->rxtp.max_cdv, qos->rxtp.max_sdu, + flags, fore200e->available_cell_rate); + + if ((qos->txtp.traffic_class == ATM_CBR) && (qos->txtp.max_pcr > 0)) { + + down(&fore200e->rate_sf); + if (fore200e->available_cell_rate + vcc->qos.txtp.max_pcr < qos->txtp.max_pcr) { + up(&fore200e->rate_sf); + return -EAGAIN; + } + + fore200e->available_cell_rate += vcc->qos.txtp.max_pcr; + fore200e->available_cell_rate -= qos->txtp.max_pcr; + up(&fore200e->rate_sf); + + memcpy(&vcc->qos, qos, sizeof(struct atm_qos)); + + /* update rate control parameters */ + fore200e_rate_ctrl(qos, &fore200e_vcc->rate); + + vcc->flags |= ATM_VF_HASQOS; + return 0; + } + + return -EINVAL; +} + + +static int __init +fore200e_irq_request(struct fore200e* fore200e) +{ + if (request_irq(fore200e->irq, fore200e_interrupt, SA_SHIRQ, fore200e->name, fore200e->atm_dev) < 0) { + + printk(FORE200E "unable to reserve IRQ %s for device %s\n", + fore200e_irq_itoa(fore200e->irq), fore200e->name); + return -EBUSY; + } + + printk(FORE200E "IRQ %s reserved for device %s\n", + fore200e_irq_itoa(fore200e->irq), fore200e->name); + + fore200e->state = FORE200E_STATE_IRQ; + return 0; +} + + +static int __init +fore200e_get_esi(struct fore200e* fore200e) +{ + struct prom_data* prom = fore200e_kmalloc(sizeof(struct prom_data), GFP_KERNEL | GFP_DMA); + int ok, i; + + ok = fore200e->bus->prom_read(fore200e, prom); + if (ok < 0) + return -EBUSY; + + printk(FORE200E "device %s, rev. %c, S/N: %d, ESI: %02x:%02x:%02x:%02x:%02x:%02x\n", + fore200e->name, + (prom->hw_revision & 0xFF) + '@', /* probably meaningless with SBA boards */ + prom->serial_number & 0xFFFF, + prom->mac_addr[ 2 ], prom->mac_addr[ 3 ], prom->mac_addr[ 4 ], + prom->mac_addr[ 5 ], prom->mac_addr[ 6 ], prom->mac_addr[ 7 ]); + + for (i = 0; i < ESI_LEN; i++) { + fore200e->esi[ i ] = fore200e->atm_dev->esi[ i ] = prom->mac_addr[ i + 2 ]; + } + + fore200e_kfree(prom); + + return 0; +} + + +static int __init +fore200e_alloc_rx_buf(struct fore200e* fore200e) +{ + int scheme, magn, nbr, size, i; + + struct host_bsq* bsq; + struct buffer* buffer; + + for (scheme = 0; scheme < BUFFER_SCHEME_NBR; scheme++) { + for (magn = 0; magn < BUFFER_MAGN_NBR; magn++) { + + bsq = &fore200e->host_bsq[ scheme ][ magn ]; + + nbr = fore200e_rx_buf_nbr[ scheme ][ magn ]; + size = fore200e_rx_buf_size[ scheme ][ magn ]; + + DPRINTK(2, "rx buffers %d / %d are being allocated\n", scheme, magn); + + /* allocate the array of receive buffers */ + buffer = bsq->buffer = fore200e_kmalloc(nbr * sizeof(struct buffer), GFP_KERNEL); + + if (buffer == NULL) + return -ENOMEM; + + for (i = 0; i < nbr; i++) { + + buffer[ i ].scheme = scheme; + buffer[ i ].magn = magn; + + /* allocate the receive buffer body */ + if (fore200e_chunk_alloc(fore200e, + &buffer[ i ].data, size, fore200e->bus->buffer_alignment) < 0) { + + while (i > 0) + fore200e_chunk_free(fore200e, &buffer[ --i ].data); + fore200e_kfree(buffer); + + return -ENOMEM; + } + } + /* set next free buffer index */ + bsq->free = 0; + } + } + + fore200e->state = FORE200E_STATE_ALLOC_BUF; + return 0; +} + + +static int __init +fore200e_init_bs_queue(struct fore200e* fore200e) +{ + int scheme, magn, i; + + struct host_bsq* bsq; + struct cp_bsq_entry* cp_entry; + + for (scheme = 0; scheme < BUFFER_SCHEME_NBR; scheme++) { + for (magn = 0; magn < BUFFER_MAGN_NBR; magn++) { + + DPRINTK(2, "buffer supply queue %d / %d is being initialized\n", scheme, magn); + + bsq = &fore200e->host_bsq[ scheme ][ magn ]; + + /* allocate and align the array of status words */ + if (fore200e->bus->dma_chunk_alloc(fore200e, + &bsq->status, + sizeof(enum status), + QUEUE_SIZE_BS, + fore200e->bus->status_alignment) < 0) { + return -ENOMEM; + } + + /* allocate and align the array of receive buffer descriptors */ + if (fore200e->bus->dma_chunk_alloc(fore200e, + &bsq->rbd_block, + sizeof(struct rbd_block), + QUEUE_SIZE_BS, + fore200e->bus->descr_alignment) < 0) { + + fore200e->bus->dma_chunk_free(fore200e, &bsq->status); + return -ENOMEM; + } + + /* get the base address of the cp resident buffer supply queue entries */ + cp_entry = (struct cp_bsq_entry*)(fore200e->virt_base + + fore200e->bus->read(&fore200e->cp_queues->cp_bsq[ scheme ][ magn ])); + + /* fill the host resident and cp resident buffer supply queue entries */ + for (i = 0; i < QUEUE_SIZE_BS; i++) { + + bsq->host_entry[ i ].status = + FORE200E_INDEX(bsq->status.align_addr, enum status, i); + bsq->host_entry[ i ].rbd_block = + FORE200E_INDEX(bsq->rbd_block.align_addr, struct rbd_block, i); + bsq->host_entry[ i ].rbd_block_dma = + FORE200E_DMA_INDEX(bsq->rbd_block.dma_addr, struct rbd_block, i); + bsq->host_entry[ i ].cp_entry = &cp_entry[ i ]; + + *bsq->host_entry[ i ].status = STATUS_FREE; + + fore200e->bus->write(FORE200E_DMA_INDEX(bsq->status.dma_addr, enum status, i), + &cp_entry[ i ].status_haddr); + } + } + } + + fore200e->state = FORE200E_STATE_INIT_BSQ; + return 0; +} + + +static int __init +fore200e_init_rx_queue(struct fore200e* fore200e) +{ + struct host_rxq* rxq = &fore200e->host_rxq; + struct cp_rxq_entry* cp_entry; + int i; + + DPRINTK(2, "receive queue is being initialized\n"); + + /* allocate and align the array of status words */ + if (fore200e->bus->dma_chunk_alloc(fore200e, + &rxq->status, + sizeof(enum status), + QUEUE_SIZE_RX, + fore200e->bus->status_alignment) < 0) { + return -ENOMEM; + } + + /* allocate and align the array of receive PDU descriptors */ + if (fore200e->bus->dma_chunk_alloc(fore200e, + &rxq->rpd, + sizeof(struct rpd), + QUEUE_SIZE_RX, + fore200e->bus->descr_alignment) < 0) { + + fore200e->bus->dma_chunk_free(fore200e, &rxq->status); + return -ENOMEM; + } + + /* get the base address of the cp resident rx queue entries */ + cp_entry = (struct cp_rxq_entry*)(fore200e->virt_base + + fore200e->bus->read(&fore200e->cp_queues->cp_rxq)); + + /* fill the host resident and cp resident rx entries */ + for (i=0; i < QUEUE_SIZE_RX; i++) { + + rxq->host_entry[ i ].status = + FORE200E_INDEX(rxq->status.align_addr, enum status, i); + rxq->host_entry[ i ].rpd = + FORE200E_INDEX(rxq->rpd.align_addr, struct rpd, i); + rxq->host_entry[ i ].rpd_dma = + FORE200E_DMA_INDEX(rxq->rpd.dma_addr, struct rpd, i); + rxq->host_entry[ i ].cp_entry = &cp_entry[ i ]; + + *rxq->host_entry[ i ].status = STATUS_FREE; + + fore200e->bus->write(FORE200E_DMA_INDEX(rxq->status.dma_addr, enum status, i), + &cp_entry[ i ].status_haddr); + + fore200e->bus->write(FORE200E_DMA_INDEX(rxq->rpd.dma_addr, struct rpd, i), + &cp_entry[ i ].rpd_haddr); + } + + /* set the head entry of the queue */ + rxq->head = 0; + + fore200e->state = FORE200E_STATE_INIT_RXQ; + return 0; +} + + +static int __init +fore200e_init_tx_queue(struct fore200e* fore200e) +{ + struct host_txq* txq = &fore200e->host_txq; + struct cp_txq_entry* cp_entry; + int i; + + DPRINTK(2, "transmit queue is being initialized\n"); + + /* allocate and align the array of status words */ + if (fore200e->bus->dma_chunk_alloc(fore200e, + &txq->status, + sizeof(enum status), + QUEUE_SIZE_TX, + fore200e->bus->status_alignment) < 0) { + return -ENOMEM; + } + + /* allocate and align the array of transmit PDU descriptors */ + if (fore200e->bus->dma_chunk_alloc(fore200e, + &txq->tpd, + sizeof(struct tpd), + QUEUE_SIZE_TX, + fore200e->bus->descr_alignment) < 0) { + + fore200e->bus->dma_chunk_free(fore200e, &txq->status); + return -ENOMEM; + } + + /* get the base address of the cp resident tx queue entries */ + cp_entry = (struct cp_txq_entry*)(fore200e->virt_base + + fore200e->bus->read(&fore200e->cp_queues->cp_txq)); + + /* fill the host resident and cp resident tx entries */ + for (i=0; i < QUEUE_SIZE_TX; i++) { + + txq->host_entry[ i ].status = + FORE200E_INDEX(txq->status.align_addr, enum status, i); + txq->host_entry[ i ].tpd = + FORE200E_INDEX(txq->tpd.align_addr, struct tpd, i); + txq->host_entry[ i ].tpd_dma = + FORE200E_DMA_INDEX(txq->tpd.dma_addr, struct tpd, i); + txq->host_entry[ i ].cp_entry = &cp_entry[ i ]; + + *txq->host_entry[ i ].status = STATUS_FREE; + + fore200e->bus->write(FORE200E_DMA_INDEX(txq->status.dma_addr, enum status, i), + &cp_entry[ i ].status_haddr); + + /* although there is a one-to-one mapping of tx queue entries and tpds, + we do not write here the DMA (physical) base address of each tpd into + the related cp resident entry, because the cp relies on this write + operation to detect that a new pdu has been submitted for tx */ +} + + /* set the head entry of the queue */ + txq->head = 0; + + fore200e->state = FORE200E_STATE_INIT_TXQ; + return 0; +} + + +static int __init +fore200e_init_cmd_queue(struct fore200e* fore200e) +{ + struct host_cmdq* cmdq = &fore200e->host_cmdq; + struct cp_cmdq_entry* cp_entry; + int i; + + DPRINTK(2, "command queue is being initialized\n"); + + /* allocate and align the array of status words */ + if (fore200e->bus->dma_chunk_alloc(fore200e, + &cmdq->status, + sizeof(enum status), + QUEUE_SIZE_CMD, + fore200e->bus->status_alignment) < 0) { + return -ENOMEM; + } + + /* get the base address of the cp resident cmd queue entries */ + cp_entry = (struct cp_cmdq_entry*)(fore200e->virt_base + + fore200e->bus->read(&fore200e->cp_queues->cp_cmdq)); + + /* fill the host resident and cp resident cmd entries */ + for (i=0; i < QUEUE_SIZE_CMD; i++) { + + cmdq->host_entry[ i ].status = + FORE200E_INDEX(cmdq->status.align_addr, enum status, i); + cmdq->host_entry[ i ].cp_entry = &cp_entry[ i ]; + + *cmdq->host_entry[ i ].status = STATUS_FREE; + + fore200e->bus->write(FORE200E_DMA_INDEX(cmdq->status.dma_addr, enum status, i), + &cp_entry[ i ].status_haddr); + } + + /* set the head entry of the queue */ + cmdq->head = 0; + + fore200e->state = FORE200E_STATE_INIT_CMDQ; + return 0; +} + + +static void __init +fore200e_param_bs_queue(struct fore200e* fore200e, + enum buffer_scheme scheme, enum buffer_magn magn, + int queue_length, int pool_size, int supply_blksize) +{ + struct bs_spec* bs_spec = &fore200e->cp_queues->init.bs_spec[ scheme ][ magn ]; + + /* dumb value; the firmware doesn't allow us to activate a VC while + selecting a buffer scheme with zero-sized rbd pools */ + + if (pool_size == 0) + pool_size = 64; + + fore200e->bus->write(queue_length, &bs_spec->queue_length); + fore200e->bus->write(fore200e_rx_buf_size[ scheme ][ magn ], &bs_spec->buffer_size); + fore200e->bus->write(pool_size, &bs_spec->pool_size); + fore200e->bus->write(supply_blksize, &bs_spec->supply_blksize); +} + + +static int __init +fore200e_initialize(struct fore200e* fore200e) +{ + struct cp_queues* cpq; + int ok, scheme, magn; + + DPRINTK(2, "device %s being initialized\n", fore200e->name); + + spin_lock_init(&fore200e->tx_lock); + init_MUTEX(&fore200e->rate_sf); + + cpq = fore200e->cp_queues = (struct cp_queues*) (fore200e->virt_base + FORE200E_CP_QUEUES_OFFSET); + + /* enable cp to host interrupts */ + fore200e->bus->write(1, &cpq->imask); + + if (fore200e->bus->irq_enable) + fore200e->bus->irq_enable(fore200e); + + fore200e->bus->write(NBR_CONNECT, &cpq->init.num_connect); + + fore200e->bus->write(QUEUE_SIZE_CMD, &cpq->init.cmd_queue_len); + fore200e->bus->write(QUEUE_SIZE_RX, &cpq->init.rx_queue_len); + fore200e->bus->write(QUEUE_SIZE_TX, &cpq->init.tx_queue_len); + + fore200e->bus->write(RSD_EXTENSION, &cpq->init.rsd_extension); + fore200e->bus->write(TSD_EXTENSION, &cpq->init.tsd_extension); + + for (scheme = 0; scheme < BUFFER_SCHEME_NBR; scheme++) + for (magn = 0; magn < BUFFER_MAGN_NBR; magn++) + fore200e_param_bs_queue(fore200e, scheme, magn, + QUEUE_SIZE_BS, + fore200e_rx_buf_nbr[ scheme ][ magn ], + RBD_BLK_SIZE); + + /* issue the initialize command */ + fore200e->bus->write(STATUS_PENDING, &cpq->init.status); + fore200e->bus->write(OPCODE_INITIALIZE, &cpq->init.opcode); + + ok = fore200e_io_poll(fore200e, &cpq->init.status, STATUS_COMPLETE, 3000); + if (ok == 0) { + printk(FORE200E "device %s initialization failed\n", fore200e->name); + return -ENODEV; + } + + printk(FORE200E "device %s initialized\n", fore200e->name); + + fore200e->state = FORE200E_STATE_INITIALIZE; + return 0; +} + + +static void __init +fore200e_monitor_putc(struct fore200e* fore200e, char c) +{ + struct cp_monitor* monitor = fore200e->cp_monitor; + +#if 0 + printk("%c", c); +#endif + fore200e->bus->write(((u32) c) | FORE200E_CP_MONITOR_UART_AVAIL, &monitor->soft_uart.send); +} + + +static int __init +fore200e_monitor_getc(struct fore200e* fore200e) +{ + struct cp_monitor* monitor = fore200e->cp_monitor; + unsigned long timeout = jiffies + MSECS(50); + int c; + + while (jiffies < timeout) { + + c = (int) fore200e->bus->read(&monitor->soft_uart.recv); + + if (c & FORE200E_CP_MONITOR_UART_AVAIL) { + + fore200e->bus->write(FORE200E_CP_MONITOR_UART_FREE, &monitor->soft_uart.recv); +#if 0 + printk("%c", c & 0xFF); +#endif + return c & 0xFF; + } + } + + return -1; +} + + +static void __init +fore200e_monitor_puts(struct fore200e* fore200e, char* str) +{ + while(*str) { + + /* the i960 monitor doesn't accept any new character if it has something to say */ + while (fore200e_monitor_getc(fore200e) >= 0); + + fore200e_monitor_putc(fore200e, *str++); + } + + while (fore200e_monitor_getc(fore200e) >= 0); +} + + +static int __init +fore200e_start_fw(struct fore200e* fore200e) +{ + int ok; + char cmd[ 48 ]; + struct fw_header* fw_header = (struct fw_header*) fore200e->bus->fw_data; + + DPRINTK(2, "device %s firmware being started\n", fore200e->name); + + sprintf(cmd, "\rgo %x\r", le32_to_cpu(fw_header->start_offset)); + + fore200e_monitor_puts(fore200e, cmd); + + ok = fore200e_io_poll(fore200e, &fore200e->cp_monitor->bstat, BSTAT_CP_RUNNING, 1000); + if (ok == 0) { + printk(FORE200E "device %s firmware didn't start\n", fore200e->name); + return -ENODEV; + } + + printk(FORE200E "device %s firmware started\n", fore200e->name); + + fore200e->state = FORE200E_STATE_START_FW; + return 0; +} + + +static int __init +fore200e_load_fw(struct fore200e* fore200e) +{ + u32* fw_data = (u32*) fore200e->bus->fw_data; + u32 fw_size = (u32) *fore200e->bus->fw_size / sizeof(u32); + + struct fw_header* fw_header = (struct fw_header*) fw_data; + + u32* load_addr = fore200e->virt_base + le32_to_cpu(fw_header->load_offset); + + DPRINTK(2, "device %s firmware being loaded at 0x%p (%d words)\n", + fore200e->name, load_addr, fw_size); + +#if 1 + if (le32_to_cpu(fw_header->magic) != FW_HEADER_MAGIC) { + printk(FORE200E "corrupted %s firmware image\n", fore200e->bus->model_name); + return -ENODEV; + } +#endif + + for (; fw_size--; fw_data++, load_addr++) + fore200e->bus->write(le32_to_cpu(*fw_data), load_addr); + + fore200e->state = FORE200E_STATE_LOAD_FW; + return 0; +} + + +static int __init +fore200e_register(struct fore200e* fore200e) +{ + struct atm_dev* atm_dev; + + DPRINTK(2, "device %s being registered\n", fore200e->name); + + atm_dev = atm_dev_register(fore200e->bus->proc_name, &fore200e_ops, -1, 0); + if (atm_dev == NULL) { + printk(FORE200E "unable to register device %s\n", fore200e->name); + return -ENODEV; + } + + FORE200E_DEV(atm_dev) = fore200e; + fore200e->atm_dev = atm_dev; + + atm_dev->ci_range.vpi_bits = 8; + atm_dev->ci_range.vci_bits = 10; + + fore200e->available_cell_rate = ATM_OC3_PCR; + + fore200e->state = FORE200E_STATE_REGISTER; + return 0; +} + + +static int __init +fore200e_init(struct fore200e* fore200e) +{ + if (fore200e_register(fore200e) < 0) + return -ENODEV; + + if (fore200e->bus->configure(fore200e) < 0) + return -ENODEV; + + if (fore200e->bus->map(fore200e) < 0) + return -ENODEV; + + if (fore200e_reset(fore200e, 1) < 0) + return -ENODEV; + + if (fore200e_load_fw(fore200e) < 0) + return -ENODEV; + + if (fore200e_start_fw(fore200e) < 0) + return -ENODEV; + + if (fore200e_initialize(fore200e) < 0) + return -ENODEV; + + if (fore200e_init_cmd_queue(fore200e) < 0) + return -ENOMEM; + + if (fore200e_init_tx_queue(fore200e) < 0) + return -ENOMEM; + + if (fore200e_init_rx_queue(fore200e) < 0) + return -ENOMEM; + + if (fore200e_init_bs_queue(fore200e) < 0) + return -ENOMEM; + + if (fore200e_alloc_rx_buf(fore200e) < 0) + return -ENOMEM; + + if (fore200e_get_esi(fore200e) < 0) + return -EIO; + + if (fore200e_irq_request(fore200e) < 0) + return -EBUSY; + + fore200e_supply(fore200e); + + /* all done, board initialization is now complete */ + fore200e->state = FORE200E_STATE_COMPLETE; + return 0; +} + + +int __init +fore200e_detect(void) +{ + const struct fore200e_bus* bus; + struct fore200e* fore200e; + int index, link; + + printk(FORE200E "FORE Systems 200E-series driver - version " FORE200E_VERSION "\n"); + + /* for each configured bus interface */ + for (link = 0, bus = fore200e_bus; bus->model_name; bus++) { + + /* detect all boards present on that bus */ + for (index = 0; (fore200e = bus->detect(bus, index)); index++) { + + printk(FORE200E "device %s found at 0x%lx, IRQ %s\n", + fore200e->bus->model_name, + fore200e->phys_base, fore200e_irq_itoa(fore200e->irq)); + + sprintf(fore200e->name, "%s-%d", bus->model_name, index); + + if (fore200e_init(fore200e) < 0) { + + fore200e_shutdown(fore200e); + break; + } + + link++; + + fore200e->next = fore200e_boards; + fore200e_boards = fore200e; + } + } + +#if 0 /* XXX uncomment this to forbid module unloading */ +#ifdef MODULE + if (link > 0) + MOD_INC_USE_COUNT; +#endif +#endif + + return link; +} + + +#ifdef MODULE +static void +fore200e_cleanup(struct fore200e** head) +{ + struct fore200e* fore200e = *head; + + fore200e_shutdown(fore200e); + + *head = fore200e->next; + + kfree(fore200e); +} +#endif + + +static int +fore200e_proc_read(struct atm_dev *dev,loff_t* pos,char* page) +{ + struct fore200e* fore200e = FORE200E_DEV(dev); + int len, left = *pos; + + if (!left--) { + + if (fore200e_getstats(fore200e) < 0) + return -EIO; + + len = sprintf(page,"\n" + " device:\n" + " internal name:\t\t%s\n", fore200e->name); + + /* print bus-specific information */ + if (fore200e->bus->proc_read) + len += fore200e->bus->proc_read(fore200e, page + len); + + len += sprintf(page + len, + " interrupt line:\t\t%s\n" + " physical base address:\t0x%p\n" + " virtual base address:\t0x%p\n" + " factory address (ESI):\t%02x:%02x:%02x:%02x:%02x:%02x\n" + " board serial number:\t\t%d\n\n", + fore200e_irq_itoa(fore200e->irq), + (void*)fore200e->phys_base, + (void*)fore200e->virt_base, + fore200e->esi[0], fore200e->esi[1], fore200e->esi[2], + fore200e->esi[3], fore200e->esi[4], fore200e->esi[5], + fore200e->esi[4] * 256 + fore200e->esi[5]); + + return len; + } + + if (!left--) + return sprintf(page, + " supplied small bufs (1):\t%d\n" + " supplied large bufs (1):\t%d\n" + " supplied small bufs (2):\t%d\n" + " supplied large bufs (2):\t%d\n", + fore200e->host_bsq[ BUFFER_SCHEME_ONE ][ BUFFER_MAGN_SMALL ].count, + fore200e->host_bsq[ BUFFER_SCHEME_ONE ][ BUFFER_MAGN_LARGE ].count, + fore200e->host_bsq[ BUFFER_SCHEME_TWO ][ BUFFER_MAGN_SMALL ].count, + fore200e->host_bsq[ BUFFER_SCHEME_TWO ][ BUFFER_MAGN_LARGE ].count); + if (!left--) { + u32 hb = fore200e->bus->read(&fore200e->cp_queues->heartbeat); + + len = sprintf(page,"\n\n" + " cell processor:\n" + " heartbeat state:\t\t"); + + if (hb >> 16 != 0xDEAD) + len += sprintf(page + len, "0x%08x\n", hb); + else + len += sprintf(page + len, "*** FATAL ERROR %04x ***\n", hb & 0xFFFF); + + return len; + } + + if (!left--) { + static const char* media_name[] = { + "unshielded twisted pair", + "multimode optical fiber ST", + "multimode optical fiber SC", + "single-mode optical fiber ST", + "single-mode optical fiber SC", + "unknown" + }; + + static const char* oc3_mode[] = { + "normal operation", + "diagnostic loopback", + "line loopback" + }; + + u32 fw_release = fore200e->bus->read(&fore200e->cp_queues->fw_release); + u32 mon960_release = fore200e->bus->read(&fore200e->cp_queues->mon960_release); + u32 oc3_revision = fore200e->bus->read(&fore200e->cp_queues->oc3_revision); + u32 media_index = FORE200E_MEDIA_INDEX(fore200e->bus->read(&fore200e->cp_queues->media_type)); + + if (media_index < 0 || media_index > 4) + media_index = 5; + + return sprintf(page, + " firmware release:\t\t%d.%d.%d\n" + " monitor release:\t\t%d.%d\n" + " media type:\t\t\t%s\n" + " OC-3 revision:\t\t0x%x\n" + " OC-3 mode:\t\t\t%s", + fw_release >> 16, fw_release << 16 >> 24, fw_release << 24 >> 24, + mon960_release >> 16, mon960_release << 16 >> 16, + media_name[ media_index ], + oc3_revision, + oc3_mode[ fore200e->loop_mode ]); + } + + if (!left--) { + struct cp_monitor* cp_monitor = fore200e->cp_monitor; + + return sprintf(page, + "\n\n" + " monitor:\n" + " version number:\t\t%d\n" + " boot status word:\t\t0x%08x\n", + fore200e->bus->read(&cp_monitor->mon_version), + fore200e->bus->read(&cp_monitor->bstat)); + } + + if (!left--) + return sprintf(page, + "\n" + " device statistics:\n" + " 4b5b:\n" + " crc_header_errors:\t\t%10u\n" + " framing_errors:\t\t%10u\n", + fore200e_swap(fore200e->stats->phy.crc_header_errors), + fore200e_swap(fore200e->stats->phy.framing_errors)); + + if (!left--) + return sprintf(page, "\n" + " OC-3:\n" + " section_bip8_errors:\t%10u\n" + " path_bip8_errors:\t\t%10u\n" + " line_bip24_errors:\t\t%10u\n" + " line_febe_errors:\t\t%10u\n" + " path_febe_errors:\t\t%10u\n" + " corr_hcs_errors:\t\t%10u\n" + " ucorr_hcs_errors:\t\t%10u\n", + fore200e_swap(fore200e->stats->oc3.section_bip8_errors), + fore200e_swap(fore200e->stats->oc3.path_bip8_errors), + fore200e_swap(fore200e->stats->oc3.line_bip24_errors), + fore200e_swap(fore200e->stats->oc3.line_febe_errors), + fore200e_swap(fore200e->stats->oc3.path_febe_errors), + fore200e_swap(fore200e->stats->oc3.corr_hcs_errors), + fore200e_swap(fore200e->stats->oc3.ucorr_hcs_errors)); + + if (!left--) + return sprintf(page,"\n" + " ATM:\t\t\t\t cells\n" + " TX:\t\t\t%10u\n" + " RX:\t\t\t%10u\n" + " vpi out of range:\t\t%10u\n" + " vpi no conn:\t\t%10u\n" + " vci out of range:\t\t%10u\n" + " vci no conn:\t\t%10u\n", + fore200e_swap(fore200e->stats->atm.cells_transmitted), + fore200e_swap(fore200e->stats->atm.cells_received), + fore200e_swap(fore200e->stats->atm.vpi_bad_range), + fore200e_swap(fore200e->stats->atm.vpi_no_conn), + fore200e_swap(fore200e->stats->atm.vci_bad_range), + fore200e_swap(fore200e->stats->atm.vci_no_conn)); + + if (!left--) + return sprintf(page,"\n" + " AAL0:\t\t\t cells\n" + " TX:\t\t\t%10u\n" + " RX:\t\t\t%10u\n" + " dropped:\t\t\t%10u\n", + fore200e_swap(fore200e->stats->aal0.cells_transmitted), + fore200e_swap(fore200e->stats->aal0.cells_received), + fore200e_swap(fore200e->stats->aal0.cells_dropped)); + + if (!left--) + return sprintf(page,"\n" + " AAL3/4:\n" + " SAR sublayer:\t\t cells\n" + " TX:\t\t\t%10u\n" + " RX:\t\t\t%10u\n" + " dropped:\t\t\t%10u\n" + " CRC errors:\t\t%10u\n" + " protocol errors:\t\t%10u\n\n" + " CS sublayer:\t\t PDUs\n" + " TX:\t\t\t%10u\n" + " RX:\t\t\t%10u\n" + " dropped:\t\t\t%10u\n" + " protocol errors:\t\t%10u\n", + fore200e_swap(fore200e->stats->aal34.cells_transmitted), + fore200e_swap(fore200e->stats->aal34.cells_received), + fore200e_swap(fore200e->stats->aal34.cells_dropped), + fore200e_swap(fore200e->stats->aal34.cells_crc_errors), + fore200e_swap(fore200e->stats->aal34.cells_protocol_errors), + fore200e_swap(fore200e->stats->aal34.cspdus_transmitted), + fore200e_swap(fore200e->stats->aal34.cspdus_received), + fore200e_swap(fore200e->stats->aal34.cspdus_dropped), + fore200e_swap(fore200e->stats->aal34.cspdus_protocol_errors)); + + if (!left--) + return sprintf(page,"\n" + " AAL5:\n" + " SAR sublayer:\t\t cells\n" + " TX:\t\t\t%10u\n" + " RX:\t\t\t%10u\n" + " dropped:\t\t\t%10u\n" + " congestions:\t\t%10u\n\n" + " CS sublayer:\t\t PDUs\n" + " TX:\t\t\t%10u\n" + " RX:\t\t\t%10u\n" + " dropped:\t\t\t%10u\n" + " CRC errors:\t\t%10u\n" + " protocol errors:\t\t%10u\n", + fore200e_swap(fore200e->stats->aal5.cells_transmitted), + fore200e_swap(fore200e->stats->aal5.cells_received), + fore200e_swap(fore200e->stats->aal5.cells_dropped), + fore200e_swap(fore200e->stats->aal5.congestion_experienced), + fore200e_swap(fore200e->stats->aal5.cspdus_transmitted), + fore200e_swap(fore200e->stats->aal5.cspdus_received), + fore200e_swap(fore200e->stats->aal5.cspdus_dropped), + fore200e_swap(fore200e->stats->aal5.cspdus_crc_errors), + fore200e_swap(fore200e->stats->aal5.cspdus_protocol_errors)); + + if (!left--) + return sprintf(page,"\n" + " AUX:\t\t allocation failures\n" + " small b1:\t\t\t%10u\n" + " large b1:\t\t\t%10u\n" + " small b2:\t\t\t%10u\n" + " large b2:\t\t\t%10u\n" + " RX PDUs:\t\t\t%10u\n", + fore200e_swap(fore200e->stats->aux.small_b1_failed), + fore200e_swap(fore200e->stats->aux.large_b1_failed), + fore200e_swap(fore200e->stats->aux.small_b2_failed), + fore200e_swap(fore200e->stats->aux.large_b2_failed), + fore200e_swap(fore200e->stats->aux.rpd_alloc_failed)); + + if (!left--) + return sprintf(page,"\n" + " receive carrier:\t\t\t%s\n", + fore200e->stats->aux.receive_carrier ? "ON" : "OFF!"); + + if (!left--) { + struct atm_vcc *vcc; + struct fore200e_vcc* fore200e_vcc; + + len = sprintf(page,"\n" + " VCCs:\n address\tVPI.VCI:AAL\t(min/max tx PDU size) (min/max rx PDU size)\n"); + + for (vcc = fore200e->atm_dev->vccs; vcc; vcc = vcc->next) { + + fore200e_vcc = FORE200E_VCC(vcc); + + len += sprintf(page + len, + " %x\t%d.%d:%d\t\t(%d/%d)\t(%d/%d)\n", + (u32)(unsigned long)vcc, + vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal), + fore200e_vcc->tx_min_pdu > 0xFFFF ? 0 : fore200e_vcc->tx_min_pdu, + fore200e_vcc->tx_max_pdu, + fore200e_vcc->rx_min_pdu > 0xFFFF ? 0 : fore200e_vcc->rx_min_pdu, + fore200e_vcc->rx_max_pdu + ); + } + + return len; + } + + return 0; +} + + +#ifdef MODULE +unsigned int +init_module(void) +{ + DPRINTK(1, "module loaded\n"); + return fore200e_detect() == 0; +} + +void +cleanup_module(void) +{ + while (fore200e_boards) { + fore200e_cleanup(&fore200e_boards); + } + DPRINTK(1, "module being removed\n"); +} +#endif + + +static const struct atmdev_ops fore200e_ops = +{ + NULL, /* fore200e_dev_close */ + fore200e_open, + fore200e_close, + fore200e_ioctl, + fore200e_getsockopt, + fore200e_setsockopt, + fore200e_send, + NULL, /* fore200e_sg_send, */ + NULL, /* fore200e_send_oam, */ + NULL, /* fore200e_phy_put, */ + NULL, /* fore200e_phy_get, */ + NULL, /* fore200e_feedback, */ + fore200e_change_qos, + NULL, /* fore200e_free_rx_skb */ + fore200e_proc_read +}; + + +#ifdef CONFIG_ATM_FORE200E_PCA +extern const unsigned char _fore200e_pca_fw_data[]; +extern const unsigned int _fore200e_pca_fw_size; +#endif +#ifdef CONFIG_ATM_FORE200E_SBA +extern const unsigned char _fore200e_sba_fw_data[]; +extern const unsigned int _fore200e_sba_fw_size; +#endif + +static const struct fore200e_bus fore200e_bus[] = { +#ifdef CONFIG_ATM_FORE200E_PCA + { "PCA-200E", "pca200e", 32, 4, 32, + _fore200e_pca_fw_data, &_fore200e_pca_fw_size, + fore200e_pca_read, + fore200e_pca_write, + fore200e_pca_dma_map, + fore200e_pca_dma_unmap, + fore200e_pca_dma_sync, + fore200e_pca_dma_chunk_alloc, + fore200e_pca_dma_chunk_free, + fore200e_pca_detect, + fore200e_pca_configure, + fore200e_pca_map, + fore200e_pca_reset, + fore200e_pca_prom_read, + fore200e_pca_unmap, + NULL, + fore200e_pca_irq_check, + fore200e_pca_irq_ack, + fore200e_pca_proc_read, + }, +#endif +#ifdef CONFIG_ATM_FORE200E_SBA + { "SBA-200E", "sba200e", 32, 64, 32, + _fore200e_sba_fw_data, &_fore200e_sba_fw_size, + fore200e_sba_read, + fore200e_sba_write, + fore200e_sba_dma_map, + fore200e_sba_dma_unmap, + fore200e_sba_dma_sync, + fore200e_sba_dma_chunk_alloc, + fore200e_sba_dma_chunk_free, + fore200e_sba_detect, + fore200e_sba_configure, + fore200e_sba_map, + fore200e_sba_reset, + fore200e_sba_prom_read, + fore200e_sba_unmap, + fore200e_sba_irq_enable, + fore200e_sba_irq_check, + fore200e_sba_irq_ack, + fore200e_sba_proc_read, + }, +#endif + {} +}; diff --git a/drivers/atm/fore200e.h b/drivers/atm/fore200e.h new file mode 100644 index 000000000..eea20162b --- /dev/null +++ b/drivers/atm/fore200e.h @@ -0,0 +1,952 @@ +#ifndef _FORE200E_H +#define _FORE200E_H + +#ifdef __KERNEL__ + +/* rx buffer sizes */ + +#define SMALL_BUFFER_SIZE 384 /* size of small buffers (multiple of 48 (PCA) and 64 (SBA) bytes) */ +#define LARGE_BUFFER_SIZE 4032 /* size of large buffers (multiple of 48 (PCA) and 64 (SBA) bytes) */ + + +#define RBD_BLK_SIZE 32 /* nbr of supplied rx buffers per rbd */ + + +#define MAX_PDU_SIZE 65535 /* maximum PDU size supported by AALs */ + + +#define BUFFER_S1_SIZE SMALL_BUFFER_SIZE /* size of small buffers, scheme 1 */ +#define BUFFER_L1_SIZE LARGE_BUFFER_SIZE /* size of large buffers, scheme 1 */ + +#define BUFFER_S2_SIZE SMALL_BUFFER_SIZE /* size of small buffers, scheme 2 */ +#define BUFFER_L2_SIZE LARGE_BUFFER_SIZE /* size of large buffers, scheme 2 */ + +#define BUFFER_S1_NBR (RBD_BLK_SIZE * 2) +#define BUFFER_L1_NBR (RBD_BLK_SIZE * 2) + +#define BUFFER_S2_NBR (RBD_BLK_SIZE * 2) +#define BUFFER_L2_NBR (RBD_BLK_SIZE * 2) + + +#define QUEUE_SIZE_CMD 16 /* command queue capacity */ +#define QUEUE_SIZE_RX 64 /* receive queue capacity */ +#define QUEUE_SIZE_TX 256 /* transmit queue capacity */ +#define QUEUE_SIZE_BS 16 /* buffer supply queue capacity */ + +#define NBR_CONNECT 1024 /* number of ATM connections */ + + +#define TSD_FIXED 2 +#define TSD_EXTENSION 0 +#define TSD_NBR (TSD_FIXED + TSD_EXTENSION) + + +/* the cp starts putting a received PDU into one *small* buffer, + then it uses a number of *large* buffers for the trailing data. + we compute here the total number of receive segment descriptors + required to hold the largest possible PDU */ + +#define RSD_REQUIRED (((MAX_PDU_SIZE - SMALL_BUFFER_SIZE + LARGE_BUFFER_SIZE) / LARGE_BUFFER_SIZE) + 1) + +#define RSD_FIXED 3 + +/* RSD_REQUIRED receive segment descriptors are enough to describe a max-sized PDU, + but we have to keep the size of the receive PDU descriptor multiple of 32 bytes, + so we add one extra RSD to RSD_EXTENSION + (WARNING: THIS MAY CHANGE IF BUFFER SIZES ARE MODIFIED) */ + +#define RSD_EXTENSION ((RSD_REQUIRED - RSD_FIXED) + 1) +#define RSD_NBR (RSD_FIXED + RSD_EXTENSION) + + +#define FORE200E_DEV(d) ((struct fore200e*)((d)->dev_data)) +#define FORE200E_VCC(d) ((struct fore200e_vcc*)((d)->dev_data)) + +/* bitfields endian games */ + +#if defined(__LITTLE_ENDIAN_BITFIELD) +#define BITFIELD2(b1, b2) b1; b2; +#define BITFIELD3(b1, b2, b3) b1; b2; b3; +#define BITFIELD4(b1, b2, b3, b4) b1; b2; b3; b4; +#define BITFIELD5(b1, b2, b3, b4, b5) b1; b2; b3; b4; b5; +#define BITFIELD6(b1, b2, b3, b4, b5, b6) b1; b2; b3; b4; b5; b6; +#elif defined(__BIG_ENDIAN_BITFIELD) +#define BITFIELD2(b1, b2) b2; b1; +#define BITFIELD3(b1, b2, b3) b3; b2; b1; +#define BITFIELD4(b1, b2, b3, b4) b4; b3; b2; b1; +#define BITFIELD5(b1, b2, b3, b4, b5) b5; b4; b3; b2; b1; +#define BITFIELD6(b1, b2, b3, b4, b5, b6) b6; b5; b4; b3; b2; b1; +#else +#error unknown bitfield endianess +#endif + + +/* ATM cell header (minus HEC byte) */ + +typedef struct atm_header { + BITFIELD5( + u32 clp : 1, /* cell loss priority */ + u32 plt : 3, /* payload type */ + u32 vci : 16, /* virtual channel identifier */ + u32 vpi : 8, /* virtual path identifier */ + u32 gfc : 4 /* generic flow control */ + ) +} atm_header_t; + + +/* ATM adaptation layer id */ + +typedef enum fore200e_aal { + FORE200E_AAL0 = 0, + FORE200E_AAL34 = 4, + FORE200E_AAL5 = 5, +} fore200e_aal_t; + + +/* transmit PDU descriptor specification */ + +typedef struct tpd_spec { + BITFIELD4( + u32 length : 16, /* total PDU length */ + u32 nseg : 8, /* number of transmit segments */ + enum fore200e_aal aal : 4, /* adaptation layer */ + u32 intr : 4 /* interrupt requested */ + ) +} tpd_spec_t; + + +/* transmit PDU rate control */ + +typedef struct tpd_rate +{ + BITFIELD2( + u32 idle_cells : 16, /* number of idle cells to insert */ + u32 data_cells : 16 /* number of data cells to transmit */ + ) +} tpd_rate_t; + + +/* transmit segment descriptor */ + +typedef struct tsd { + u32 buffer; /* transmit buffer DMA address */ + u32 length; /* number of bytes in buffer */ +} tsd_t; + + +/* transmit PDU descriptor */ + +typedef struct tpd { + struct atm_header atm_header; /* ATM header minus HEC byte */ + struct tpd_spec spec; /* tpd specification */ + struct tpd_rate rate; /* tpd rate control */ + u32 pad; /* reserved */ + struct tsd tsd[ TSD_NBR ]; /* transmit segment descriptors */ +} tpd_t; + + +/* receive segment descriptor */ + +typedef struct rsd { + u32 handle; /* host supplied receive buffer handle */ + u32 length; /* number of bytes in buffer */ +} rsd_t; + + +/* receive PDU descriptor */ + +typedef struct rpd { + struct atm_header atm_header; /* ATM header minus HEC byte */ + u32 nseg; /* number of receive segments */ + struct rsd rsd[ RSD_NBR ]; /* receive segment descriptors */ +} rpd_t; + + +/* buffer scheme */ + +typedef enum buffer_scheme { + BUFFER_SCHEME_ONE, + BUFFER_SCHEME_TWO, + BUFFER_SCHEME_NBR /* always last */ +} buffer_scheme_t; + + +/* buffer magnitude */ + +typedef enum buffer_magn { + BUFFER_MAGN_SMALL, + BUFFER_MAGN_LARGE, + BUFFER_MAGN_NBR /* always last */ +} buffer_magn_t; + + +/* receive buffer descriptor */ + +typedef struct rbd { + u32 handle; /* host supplied handle */ + u32 buffer_haddr; /* host DMA address of host buffer */ +} rbd_t; + + +/* receive buffer descriptor block */ + +typedef struct rbd_block { + struct rbd rbd[ RBD_BLK_SIZE ]; /* receive buffer descriptor */ +} rbd_block_t; + + +/* tpd DMA address */ + +typedef struct tpd_haddr { + BITFIELD3( + u32 size : 4, /* tpd size expressed in 32 byte blocks */ + u32 pad : 1, /* reserved */ + u32 haddr : 27 /* tpd DMA addr aligned on 32 byte boundary */ + ) +} tpd_haddr_t; + + +/* cp resident transmit queue entry */ + +typedef struct cp_txq_entry { + struct tpd_haddr tpd_haddr; /* host DMA address of tpd */ + u32 status_haddr; /* host DMA address of completion status */ +} cp_txq_entry_t; + + +/* cp resident receive queue entry */ + +typedef struct cp_rxq_entry { + u32 rpd_haddr; /* host DMA address of rpd */ + u32 status_haddr; /* host DMA address of completion status */ +} cp_rxq_entry_t; + + +/* cp resident buffer supply queue entry */ + +typedef struct cp_bsq_entry { + u32 rbd_block_haddr; /* host DMA address of rbd block */ + u32 status_haddr; /* host DMA address of completion status */ +} cp_bsq_entry_t; + + +/* completion status */ + +typedef volatile enum status { + STATUS_PENDING = (1<<0), /* initial status (written by host) */ + STATUS_COMPLETE = (1<<1), /* completion status (written by cp) */ + STATUS_FREE = (1<<2), /* initial status (written by host) */ + STATUS_ERROR = (1<<3) /* completion status (written by cp) */ +} status_t; + + +/* cp operation code */ + +typedef enum opcode { + OPCODE_INITIALIZE = 1, /* initialize board */ + OPCODE_ACTIVATE_VCIN, /* activate incoming VCI */ + OPCODE_ACTIVATE_VCOUT, /* activate outgoing VCI */ + OPCODE_DEACTIVATE_VCIN, /* deactivate incoming VCI */ + OPCODE_DEACTIVATE_VCOUT, /* deactivate incoing VCI */ + OPCODE_GET_STATS, /* get board statistics */ + OPCODE_SET_OC3, /* set OC-3 registers */ + OPCODE_GET_OC3, /* get OC-3 registers */ + OPCODE_RESET_STATS, /* reset board statistics */ + OPCODE_GET_PROM, /* get expansion PROM data (PCI specific) */ + OPCODE_SET_VPI_BITS, /* set x bits of those decoded by the + firmware to be low order bits from + the VPI field of the ATM cell header */ + OPCODE_REQUEST_INTR = (1<<7) /* request interrupt */ +} opcode_t; + + +/* virtual path / virtual channel identifers */ + +typedef struct vpvc { + BITFIELD3( + u32 vci : 16, /* virtual channel identifier */ + u32 vpi : 8, /* virtual path identifier */ + u32 pad : 8 /* reserved */ + ) +} vpvc_t; + + +/* activate VC command opcode */ + +typedef struct activate_opcode { + BITFIELD4( + enum opcode opcode : 8, /* cp opcode */ + enum fore200e_aal aal : 8, /* adaptation layer */ + enum buffer_scheme scheme : 8, /* buffer scheme */ + u32 pad : 8 /* reserved */ + ) +} activate_opcode_t; + + +/* activate VC command block */ + +typedef struct activate_block { + struct activate_opcode opcode; /* activate VC command opcode */ + struct vpvc vpvc; /* VPI/VCI */ + u32 mtu; /* for AAL0 only */ + +} activate_block_t; + + +/* deactivate VC command opcode */ + +typedef struct deactivate_opcode { + BITFIELD2( + enum opcode opcode : 8, /* cp opcode */ + u32 pad : 24 /* reserved */ + ) +} deactivate_opcode_t; + + +/* deactivate VC command block */ + +typedef struct deactivate_block { + struct deactivate_opcode opcode; /* deactivate VC command opcode */ + struct vpvc vpvc; /* VPI/VCI */ +} deactivate_block_t; + + +/* OC-3 registers */ + +typedef struct oc3_regs { + u32 reg[ 128 ]; /* see the PMC Sierra PC5346 S/UNI-155-Lite + Saturn User Network Interface documentation + for a description of the OC-3 chip registers */ +} oc3_regs_t; + + +/* set/get OC-3 regs command opcode */ + +typedef struct oc3_opcode { + BITFIELD4( + enum opcode opcode : 8, /* cp opcode */ + u32 reg : 8, /* register index */ + u32 value : 8, /* register value */ + u32 mask : 8 /* register mask that specifies which + bits of the register value field + are significant */ + ) +} oc3_opcode_t; + + +/* set/get OC-3 regs command block */ + +typedef struct oc3_block { + struct oc3_opcode opcode; /* set/get OC-3 regs command opcode */ + u32 regs_haddr; /* host DMA address of OC-3 regs buffer */ +} oc3_block_t; + + +/* physical encoding statistics */ + +typedef struct stats_phy { + u32 crc_header_errors; /* cells received with bad header CRC */ + u32 framing_errors; /* cells received with bad framing */ + u32 pad[ 2 ]; /* i960 padding */ +} stats_phy_t; + + +/* OC-3 statistics */ + +typedef struct stats_oc3 { + u32 section_bip8_errors; /* section 8 bit interleaved parity */ + u32 path_bip8_errors; /* path 8 bit interleaved parity */ + u32 line_bip24_errors; /* line 24 bit interleaved parity */ + u32 line_febe_errors; /* line far end block errors */ + u32 path_febe_errors; /* path far end block errors */ + u32 corr_hcs_errors; /* correctable header check sequence */ + u32 ucorr_hcs_errors; /* uncorrectable header check sequence */ + u32 pad[ 1 ]; /* i960 padding */ +} stats_oc3_t; + + +/* ATM statistics */ + +typedef struct stats_atm { + u32 cells_transmitted; /* cells transmitted */ + u32 cells_received; /* cells received */ + u32 vpi_bad_range; /* cell drops: VPI out of range */ + u32 vpi_no_conn; /* cell drops: no connection for VPI */ + u32 vci_bad_range; /* cell drops: VCI out of range */ + u32 vci_no_conn; /* cell drops: no connection for VCI */ + u32 pad[ 2 ]; /* i960 padding */ +} stats_atm_t; + +/* AAL0 statistics */ + +typedef struct stats_aal0 { + u32 cells_transmitted; /* cells transmitted */ + u32 cells_received; /* cells received */ + u32 cells_dropped; /* cells dropped */ + u32 pad[ 1 ]; /* i960 padding */ +} stats_aal0_t; + + +/* AAL3/4 statistics */ + +typedef struct stats_aal34 { + u32 cells_transmitted; /* cells transmitted from segmented PDUs */ + u32 cells_received; /* cells reassembled into PDUs */ + u32 cells_crc_errors; /* payload CRC error count */ + u32 cells_protocol_errors; /* SAR or CS layer protocol errors */ + u32 cells_dropped; /* cells dropped: partial reassembly */ + u32 cspdus_transmitted; /* CS PDUs transmitted */ + u32 cspdus_received; /* CS PDUs received */ + u32 cspdus_protocol_errors; /* CS layer protocol errors */ + u32 cspdus_dropped; /* reassembled PDUs drop'd (in cells) */ + u32 pad[ 3 ]; /* i960 padding */ +} stats_aal34_t; + + +/* AAL5 statistics */ + +typedef struct stats_aal5 { + u32 cells_transmitted; /* cells transmitted from segmented SDUs */ + u32 cells_received; /* cells reassembled into SDUs */ + u32 cells_dropped; /* reassembled PDUs dropped (in cells) */ + u32 congestion_experienced; /* CRC error and length wrong */ + u32 cspdus_transmitted; /* CS PDUs transmitted */ + u32 cspdus_received; /* CS PDUs received */ + u32 cspdus_crc_errors; /* CS PDUs CRC errors */ + u32 cspdus_protocol_errors; /* CS layer protocol errors */ + u32 cspdus_dropped; /* reassembled PDUs dropped */ + u32 pad[ 3 ]; /* i960 padding */ +} stats_aal5_t; + + +/* auxiliary statistics */ + +typedef struct stats_aux { + u32 small_b1_failed; /* receive BD allocation failures */ + u32 large_b1_failed; /* receive BD allocation failures */ + u32 small_b2_failed; /* receive BD allocation failures */ + u32 large_b2_failed; /* receive BD allocation failures */ + u32 rpd_alloc_failed; /* receive PDU allocation failures */ + u32 receive_carrier; /* no carrier = 0, carrier = 1 */ + u32 pad[ 2 ]; /* i960 padding */ +} stats_aux_t; + + +/* whole statistics buffer */ + +typedef struct stats { + struct stats_phy phy; /* physical encoding statistics */ + struct stats_oc3 oc3; /* OC-3 statistics */ + struct stats_atm atm; /* ATM statistics */ + struct stats_aal0 aal0; /* AAL0 statistics */ + struct stats_aal34 aal34; /* AAL3/4 statistics */ + struct stats_aal5 aal5; /* AAL5 statistics */ + struct stats_aux aux; /* auxiliary statistics */ +} stats_t; + + +/* get statistics command opcode */ + +typedef struct stats_opcode { + BITFIELD2( + enum opcode opcode : 8, /* cp opcode */ + u32 pad : 24 /* reserved */ + ) +} stats_opcode_t; + + +/* get statistics command block */ + +typedef struct stats_block { + struct stats_opcode opcode; /* get statistics command opcode */ + u32 stats_haddr; /* host DMA address of stats buffer */ +} stats_block_t; + + +/* expansion PROM data (PCI specific) */ + +typedef struct prom_data { + u32 hw_revision; /* hardware revision */ + u32 serial_number; /* board serial number */ + u8 mac_addr[ 8 ]; /* board MAC address */ +} prom_data_t; + + +/* get expansion PROM data command opcode */ + +typedef struct prom_opcode { + BITFIELD2( + enum opcode opcode : 8, /* cp opcode */ + u32 pad : 24 /* reserved */ + ) +} prom_opcode_t; + + +/* get expansion PROM data command block */ + +typedef struct prom_block { + struct prom_opcode opcode; /* get PROM data command opcode */ + u32 prom_haddr; /* host DMA address of PROM buffer */ +} prom_block_t; + + +/* cp command */ + +typedef union cmd { + enum opcode opcode; /* operation code */ + struct activate_block activate_block; /* activate VC */ + struct deactivate_block deactivate_block; /* deactivate VC */ + struct stats_block stats_block; /* get statistics */ + struct prom_block prom_block; /* get expansion PROM data */ + struct oc3_block oc3_block; /* get/set OC-3 registers */ + u32 pad[ 4 ]; /* i960 padding */ +} cmd_t; + + +/* cp resident command queue */ + +typedef struct cp_cmdq_entry { + union cmd cmd; /* command */ + u32 status_haddr; /* host DMA address of completion status */ + u32 pad[ 3 ]; /* i960 padding */ +} cp_cmdq_entry_t; + + +/* host resident transmit queue entry */ + +typedef struct host_txq_entry { + struct cp_txq_entry* cp_entry; /* addr of cp resident tx queue entry */ + enum status* status; /* addr of host resident status */ + struct tpd* tpd; /* addr of transmit PDU descriptor */ + u32 tpd_dma; /* DMA address of tpd */ + struct sk_buff* skb; /* related skb */ + struct atm_vcc* vcc; /* related vcc */ + void* data; /* copy of misaligned data */ +} host_txq_entry_t; + + +/* host resident receive queue entry */ + +typedef struct host_rxq_entry { + struct cp_rxq_entry* cp_entry; /* addr of cp resident rx queue entry */ + enum status* status; /* addr of host resident status */ + struct rpd* rpd; /* addr of receive PDU descriptor */ + u32 rpd_dma; /* DMA address of rpd */ +} host_rxq_entry_t; + + +/* host resident buffer supply queue entry */ + +typedef struct host_bsq_entry { + struct cp_bsq_entry* cp_entry; /* addr of cp resident buffer supply queue entry */ + enum status* status; /* addr of host resident status */ + struct rbd_block* rbd_block; /* addr of receive buffer descriptor block */ + u32 rbd_block_dma; /* DMA address od rdb */ +} host_bsq_entry_t; + + +/* host resident command queue entry */ + +typedef struct host_cmdq_entry { + struct cp_cmdq_entry* cp_entry; /* addr of cp resident cmd queue entry */ + enum status* status; /* addr of host resident status */ +} host_cmdq_entry_t; + + +/* chunk of memory */ + +typedef struct chunk { + void* alloc_addr; /* base address of allocated chunk */ + void* align_addr; /* base address of aligned chunk */ + u32 dma_addr; /* DMA address of aligned chunk */ + u32 alloc_size; /* length of allocated chunk */ + u32 align_size; /* length of aligned chunk */ +} chunk_t; + +#define dma_size align_size /* DMA useable size */ + + +/* host resident receive buffer */ + +typedef struct buffer { + struct buffer* next; /* next receive buffer */ + enum buffer_scheme scheme; /* buffer scheme */ + enum buffer_magn magn; /* buffer magnitude */ + struct chunk data; /* data buffer */ +} buffer_t; + + +#if (BITS_PER_LONG == 32) +#define FORE200E_BUF2HDL(buffer) ((u32)(buffer)) +#define FORE200E_HDL2BUF(handle) ((struct buffer*)(handle)) +#else /* deal with 64 bit pointers */ +#define FORE200E_BUF2HDL(buffer) ((u32)((u64)(buffer))) +#define FORE200E_HDL2BUF(handle) ((struct buffer*)(((u64)(handle)) | PAGE_OFFSET)) +#endif + + +/* host resident command queue */ + +typedef struct host_cmdq { + struct host_cmdq_entry host_entry[ QUEUE_SIZE_CMD ]; /* host resident cmd queue entries */ + int head; /* head of cmd queue */ + struct chunk status; /* array of completion status */ +} host_cmdq_t; + + +/* host resident transmit queue */ + +typedef struct host_txq { + struct host_txq_entry host_entry[ QUEUE_SIZE_TX ]; /* host resident tx queue entries */ + int head; /* head of tx queue */ + struct chunk tpd; /* array of tpds */ + struct chunk status; /* arry of completion status */ + int txing; /* number of pending PDUs in tx queue */ +} host_txq_t; + + +/* host resident receive queue */ + +typedef struct host_rxq { + struct host_rxq_entry host_entry[ QUEUE_SIZE_RX ]; /* host resident rx queue entries */ + int head; /* head of rx queue */ + struct chunk rpd; /* array of rpds */ + struct chunk status; /* array of completion status */ +} host_rxq_t; + + +/* host resident buffer supply queues */ + +typedef struct host_bsq { + struct host_bsq_entry host_entry[ QUEUE_SIZE_BS ]; /* host resident buffer supply queue entries */ + int head; /* head of buffer supply queue */ + struct chunk rbd_block; /* array of rbds */ + struct chunk status; /* array of completion status */ + struct buffer* buffer; /* array of rx buffers */ + int free; /* index of first free rx buffer */ + volatile int count; /* count of supplied rx buffers */ +} host_bsq_t; + + +/* header of the firmware image */ + +typedef struct fw_header { + u32 magic; /* magic number */ + u32 version; /* firware version id */ + u32 load_offset; /* fw load offset in board memory */ + u32 start_offset; /* fw execution start address in board memory */ +} fw_header_t; + +#define FW_HEADER_MAGIC 0x65726f66 /* 'fore' */ + + +/* receive buffer supply queues scheme specification */ + +typedef struct bs_spec { + u32 queue_length; /* queue capacity */ + u32 buffer_size; /* host buffer size */ + u32 pool_size; /* number of rbds */ + u32 supply_blksize; /* num of rbds in I/O block (multiple + of 4 between 4 and 124 inclusive) */ +} bs_spec_t; + + +/* initialization command block (one-time command, not in cmd queue) */ + +typedef struct init_block { + enum opcode opcode; /* initialize command */ + enum status status; /* related status word */ + u32 receive_threshold; /* not used */ + u32 num_connect; /* ATM connections */ + u32 cmd_queue_len; /* length of command queue */ + u32 tx_queue_len; /* length of transmit queue */ + u32 rx_queue_len; /* length of receive queue */ + u32 rsd_extension; /* number of extra 32 byte blocks */ + u32 tsd_extension; /* number of extra 32 byte blocks */ + u32 conless_vpvc; /* not used */ + u32 pad[ 2 ]; /* force quad alignment */ + struct bs_spec bs_spec[ BUFFER_SCHEME_NBR ][ BUFFER_MAGN_NBR ]; /* buffer supply queues spec */ +} init_block_t; + + +typedef enum media_type { + MEDIA_TYPE_CAT5_UTP = 0x06, /* unshielded twisted pair */ + MEDIA_TYPE_MM_OC3_ST = 0x16, /* multimode fiber ST */ + MEDIA_TYPE_MM_OC3_SC = 0x26, /* multimode fiber SC */ + MEDIA_TYPE_SM_OC3_ST = 0x36, /* single-mode fiber ST */ + MEDIA_TYPE_SM_OC3_SC = 0x46 /* single-mode fiber SC */ +} media_type_t; + +#define FORE200E_MEDIA_INDEX(media_type) ((media_type)>>4) + + +/* cp resident queues */ + +typedef struct cp_queues { + u32 cp_cmdq; /* command queue */ + u32 cp_txq; /* transmit queue */ + u32 cp_rxq; /* receive queue */ + u32 cp_bsq[ BUFFER_SCHEME_NBR ][ BUFFER_MAGN_NBR ]; /* buffer supply queues */ + u32 imask; /* 1 enables cp to host interrupts */ + u32 istat; /* 1 for interrupt posted */ + u32 heap_base; /* offset form beginning of ram */ + u32 heap_size; /* space available for queues */ + u32 hlogger; /* non zero for host logging */ + u32 heartbeat; /* cp heartbeat */ + u32 fw_release; /* firmware version */ + u32 mon960_release; /* i960 monitor version */ + u32 tq_plen; /* transmit throughput measurements */ + /* make sure the init block remains on a quad word boundary */ + struct init_block init; /* one time cmd, not in cmd queue */ + enum media_type media_type; /* media type id */ + u32 oc3_revision; /* OC-3 revision number */ +} cp_queues_t; + + +/* boot status */ + +typedef enum boot_status { + BSTAT_COLD_START = (u32) 0xc01dc01d, /* cold start */ + BSTAT_SELFTEST_OK = (u32) 0x02201958, /* self-test ok */ + BSTAT_SELFTEST_FAIL = (u32) 0xadbadbad, /* self-test failed */ + BSTAT_CP_RUNNING = (u32) 0xce11feed, /* cp is running */ + BSTAT_MON_TOO_BIG = (u32) 0x10aded00 /* i960 monitor is too big */ +} boot_status_t; + + +/* software UART */ + +typedef struct soft_uart { + u32 send; /* write register */ + u32 recv; /* read register */ +} soft_uart_t; + +#define FORE200E_CP_MONITOR_UART_FREE 0x00000000 +#define FORE200E_CP_MONITOR_UART_AVAIL 0x01000000 + + +/* i960 monitor */ + +typedef struct cp_monitor { + struct soft_uart soft_uart; /* software UART */ + enum boot_status bstat; /* boot status */ + u32 app_base; /* application base offset */ + u32 mon_version; /* i960 monitor version */ +} cp_monitor_t; + + +/* device state */ + +typedef enum fore200e_state { + FORE200E_STATE_BLANK, /* initial state */ + FORE200E_STATE_REGISTER, /* device registered */ + FORE200E_STATE_CONFIGURE, /* bus interface configured */ + FORE200E_STATE_MAP, /* board space mapped in host memory */ + FORE200E_STATE_RESET, /* board resetted */ + FORE200E_STATE_LOAD_FW, /* firmware loaded */ + FORE200E_STATE_START_FW, /* firmware started */ + FORE200E_STATE_INITIALIZE, /* initialize command successful */ + FORE200E_STATE_INIT_CMDQ, /* command queue initialized */ + FORE200E_STATE_INIT_TXQ, /* transmit queue initialized */ + FORE200E_STATE_INIT_RXQ, /* receive queue initialized */ + FORE200E_STATE_INIT_BSQ, /* buffer supply queue initialized */ + FORE200E_STATE_ALLOC_BUF, /* receive buffers allocated */ + FORE200E_STATE_IRQ, /* host interrupt requested */ + FORE200E_STATE_COMPLETE /* initialization completed */ +} fore200e_state; + + +/* PCA-200E registers */ + +typedef struct fore200e_pca_regs { + volatile u32* hcr; /* address of host control register */ + volatile u32* imr; /* address of host interrupt mask register */ + volatile u32* psr; /* address of PCI specific register */ +} fore200e_pca_regs_t; + + +/* SBA-200E registers */ + +typedef struct fore200e_sba_regs { + volatile u32* hcr; /* address of host control register */ + volatile u32* bsr; /* address of burst transfer size register */ + volatile u32* isr; /* address of interrupt level selection register */ +} fore200e_sba_regs_t; + + +/* model-specific registers */ + +typedef union fore200e_regs { + struct fore200e_pca_regs pca; /* PCA-200E registers */ + struct fore200e_sba_regs sba; /* SBA-200E registers */ +} fore200e_regs; + + +struct fore200e; + +/* bus-dependent data */ + +typedef struct fore200e_bus { + char* model_name; /* board model name */ + char* proc_name; /* board name under /proc/atm */ + int descr_alignment; /* tpd/rpd/rbd DMA alignment requirement */ + int buffer_alignment; /* rx buffers DMA alignment requirement */ + int status_alignment; /* status words DMA alignment requirement */ + const unsigned char* fw_data; /* address of firmware data start */ + const unsigned int* fw_size; /* address of firmware data size */ + u32 (*read)(volatile u32*); + void (*write)(u32, volatile u32*); + u32 (*dma_map)(struct fore200e*, void*, int); + void (*dma_unmap)(struct fore200e*, u32, int); + void (*dma_sync)(struct fore200e*, u32, int); + int (*dma_chunk_alloc)(struct fore200e*, struct chunk*, int, int, int); + void (*dma_chunk_free)(struct fore200e*, struct chunk*); + struct fore200e* (*detect)(const struct fore200e_bus*, int); + int (*configure)(struct fore200e*); + int (*map)(struct fore200e*); + void (*reset)(struct fore200e*); + int (*prom_read)(struct fore200e*, struct prom_data*); + void (*unmap)(struct fore200e*); + void (*irq_enable)(struct fore200e*); + int (*irq_check)(struct fore200e*); + void (*irq_ack)(struct fore200e*); + int (*proc_read)(struct fore200e*, char*); +} fore200e_bus_t; + + +/* per-device data */ + +typedef struct fore200e { + struct fore200e* next; /* next device */ + const struct fore200e_bus* bus; /* bus-dependent code and data */ + union fore200e_regs regs; /* bus-dependent registers */ + struct atm_dev* atm_dev; /* ATM device */ + + enum fore200e_state state; /* device state */ + + char name[16]; /* device name */ + void* bus_dev; /* bus-specific kernel data */ + int irq; /* irq number */ + unsigned long phys_base; /* physical base address */ + void* virt_base; /* virtual base address */ + + unsigned char esi[ ESI_LEN ]; /* end system identifier */ + + struct cp_monitor* cp_monitor; /* i960 monitor address */ + struct cp_queues* cp_queues; /* cp resident queues */ + struct host_cmdq host_cmdq; /* host resident cmd queue */ + struct host_txq host_txq; /* host resident tx queue */ + struct host_rxq host_rxq; /* host resident rx queue */ + /* host resident buffer supply queues */ + struct host_bsq host_bsq[ BUFFER_SCHEME_NBR ][ BUFFER_MAGN_NBR ]; + + u32 available_cell_rate; /* remaining pseudo-CBR bw on link */ + + int loop_mode; /* S/UNI loopback mode */ + + struct stats* stats; /* last snapshot of the stats */ + + struct semaphore rate_sf; /* protects rate reservation ops */ + spinlock_t tx_lock; /* protects tx ops */ + +} fore200e_t; + + +/* per-vcc data */ + +typedef struct fore200e_vcc { + enum buffer_scheme scheme; /* rx buffer scheme */ + struct tpd_rate rate; /* tx rate control data */ + int rx_min_pdu; /* size of smallest PDU received */ + int rx_max_pdu; /* size of largest PDU received */ + int tx_min_pdu; /* size of smallest PDU transmitted */ + int tx_max_pdu; /* size of largest PDU transmitted */ +} fore200e_vcc_t; + + + +/* 200E-series common memory layout */ + +#define FORE200E_CP_MONITOR_OFFSET 0x00000400 /* i960 monitor interface */ +#define FORE200E_CP_QUEUES_OFFSET 0x00004d40 /* cp resident queues */ + + +/* PCA-200E memory layout */ + +#define PCA200E_IOSPACE_LENGTH 0x00200000 + +#define PCA200E_HCR_OFFSET 0x00100000 /* board control register */ +#define PCA200E_IMR_OFFSET 0x00100004 /* host IRQ mask register */ +#define PCA200E_PSR_OFFSET 0x00100008 /* PCI specific register */ + + +/* PCA-200E host control register */ + +#define PCA200E_HCR_RESET (1<<0) /* read / write */ +#define PCA200E_HCR_HOLD_LOCK (1<<1) /* read / write */ +#define PCA200E_HCR_I960FAIL (1<<2) /* read */ +#define PCA200E_HCR_INTRB (1<<2) /* write */ +#define PCA200E_HCR_HOLD_ACK (1<<3) /* read */ +#define PCA200E_HCR_INTRA (1<<3) /* write */ +#define PCA200E_HCR_OUTFULL (1<<4) /* read */ +#define PCA200E_HCR_CLRINTR (1<<4) /* write */ +#define PCA200E_HCR_ESPHOLD (1<<5) /* read */ +#define PCA200E_HCR_INFULL (1<<6) /* read */ +#define PCA200E_HCR_TESTMODE (1<<7) /* read */ + + +/* PCA-200E PCI bus interface regs (offsets in PCI config space) */ + +#define PCA200E_PCI_LATENCY 0x40 /* maximum slave latenty */ +#define PCA200E_PCI_MASTER_CTRL 0x41 /* master control */ +#define PCA200E_PCI_THRESHOLD 0x42 /* burst / continous req threshold */ + +/* PBI master control register */ + +#define PCA200E_CTRL_DIS_CACHE_RD (1<<0) /* disable cache-line reads */ +#define PCA200E_CTRL_DIS_WRT_INVAL (1<<1) /* disable writes and invalidates */ +#define PCA200E_CTRL_2_CACHE_WRT_INVAL (1<<2) /* require 2 cache-lines for writes and invalidates */ +#define PCA200E_CTRL_IGN_LAT_TIMER (1<<3) /* ignore the latency timer */ +#define PCA200E_CTRL_ENA_CONT_REQ_MODE (1<<4) /* enable continuous request mode */ +#define PCA200E_CTRL_LARGE_PCI_BURSTS (1<<5) /* force large PCI bus bursts */ +#define PCA200E_CTRL_CONVERT_ENDIAN (1<<6) /* convert endianess of slave RAM accesses */ + + + +#define SBA200E_PROM_NAME "FORE,sba-200e" /* device name in openprom tree */ + + +/* size of SBA-200E registers */ + +#define SBA200E_HCR_LENGTH 4 +#define SBA200E_BSR_LENGTH 4 +#define SBA200E_ISR_LENGTH 4 +#define SBA200E_RAM_LENGTH 0x40000 + + +/* SBA-200E SBUS burst transfer size register */ + +#define SBA200E_BSR_BURST4 0x04 +#define SBA200E_BSR_BURST8 0x08 +#define SBA200E_BSR_BURST16 0x10 + + +/* SBA-200E host control register */ + +#define SBA200E_HCR_RESET (1<<0) /* read / write (sticky) */ +#define SBA200E_HCR_HOLD_LOCK (1<<1) /* read / write (sticky) */ +#define SBA200E_HCR_I960FAIL (1<<2) /* read */ +#define SBA200E_HCR_I960SETINTR (1<<2) /* write */ +#define SBA200E_HCR_OUTFULL (1<<3) /* read */ +#define SBA200E_HCR_INTR_CLR (1<<3) /* write */ +#define SBA200E_HCR_INTR_ENA (1<<4) /* read / write (sticky) */ +#define SBA200E_HCR_ESPHOLD (1<<5) /* read */ +#define SBA200E_HCR_INFULL (1<<6) /* read */ +#define SBA200E_HCR_TESTMODE (1<<7) /* read */ +#define SBA200E_HCR_INTR_REQ (1<<8) /* read */ + +#define SBA200E_HCR_STICKY (SBA200E_HCR_RESET | SBA200E_HCR_HOLD_LOCK | SBA200E_HCR_INTR_ENA) + + +#endif /* __KERNEL__ */ +#endif /* _FORE200E_H */ diff --git a/drivers/atm/fore200e_firmware_copyright b/drivers/atm/fore200e_firmware_copyright new file mode 100644 index 000000000..d58e64908 --- /dev/null +++ b/drivers/atm/fore200e_firmware_copyright @@ -0,0 +1,31 @@ + +These microcode data are placed under the terms of the GNU General Public License. + +We would prefer you not to distribute modified versions of it and not to ask +for assembly or other microcode source. + +Copyright (c) 1995-2000 FORE Systems, Inc., as an unpublished work. This +notice does not imply unrestricted or public access to these materials which +are a trade secret of FORE Systems, Inc. or its subsidiaries or affiliates +(together referred to as "FORE"), and which may not be reproduced, used, sold +or transferred to any third party without FORE's prior written consent. All +rights reserved. + +U.S. Government Restricted Rights. If you are licensing the Software on +behalf of the U.S. Government ("Government"), the following provisions apply +to you. If the software is supplied to the Department of Defense ("DoD"), it +is classified as "Commercial Computer Software" under paragraph 252.227-7014 +of the DoD Supplement to the Federal Acquisition Regulations ("DFARS") (or any +successor regulations) and the Government is acquiring only the license +rights granted herein (the license rights customarily provided to non-Government +users). If the Software is supplied to any unit or agency of the Government +other than the DoD, it is classified as "Restricted Computer Software" and +the Government's rights in the Software are defined in paragraph 52.227-19 of +the Federal Acquisition Regulations ("FAR") (or any successor regulations) or, +in the cases of NASA, in paragraph 18.52.227-86 of the NASA Supplement to the FAR +(or any successor regulations). + +FORE Systems is a registered trademark, and ForeRunner, ForeRunnerLE, and +ForeThought are trademarks of FORE Systems, Inc. All other brands or product +names are trademarks or registered trademarks of their respective holders. + diff --git a/drivers/atm/fore200e_mkfirm.c b/drivers/atm/fore200e_mkfirm.c new file mode 100644 index 000000000..10e972840 --- /dev/null +++ b/drivers/atm/fore200e_mkfirm.c @@ -0,0 +1,155 @@ +/* + $Id: fore200e_mkfirm.c,v 1.1 2000/02/21 16:04:32 davem Exp $ + + mkfirm.c: generates a C readable file from a binary firmware image + + Christophe Lizzi (lizzi@{csti.fr, cnam.fr}), June 1999. + + This software may be used and distributed according to the terms + of the GNU General Public License, incorporated herein by reference. +*/ + +#include +#include +#include + +char* default_basename = "pca200e"; /* was initially written for the PCA-200E firmware */ +char* default_infname = ""; +char* default_outfname = ""; + +char* progname; +int verbose = 0; +int inkernel = 0; + + +void usage(void) +{ + fprintf(stderr, + "%s: [-v] [-k] [-b basename ] [-i firmware.bin] [-o firmware.c]\n", + progname); + exit(-1); +} + + +int main(int argc, char** argv) +{ + time_t now; + char* infname = NULL; + char* outfname = NULL; + char* basename = NULL; + FILE* infile; + FILE* outfile; + unsigned firmsize; + int c; + + progname = *(argv++); + + while (argc > 1) { + if ((*argv)[0] == '-') { + switch ((*argv)[1]) { + case 'i': + if (argc-- < 3) + usage(); + infname = *(++argv); + break; + case 'o': + if (argc-- < 3) + usage(); + outfname = *(++argv); + break; + case 'b': + if (argc-- < 3) + usage(); + basename = *(++argv); + break; + case 'v': + verbose = 1; + break; + case 'k': + inkernel = 1; + break; + default: + usage(); + } + } + else { + usage(); + } + argc--; + argv++; + } + + if (infname != NULL) { + infile = fopen(infname, "r"); + if (infile == NULL) { + fprintf(stderr, "%s: can't open %s for reading\n", + progname, infname); + exit(-2); + } + } + else { + infile = stdin; + infname = default_infname; + } + + if (outfname) { + outfile = fopen(outfname, "w"); + if (outfile == NULL) { + fprintf(stderr, "%s: can't open %s for writing\n", + progname, outfname); + exit(-3); + } + } + else { + outfile = stdout; + outfname = default_outfname; + } + + if (basename == NULL) + basename = default_basename; + + if (verbose) { + fprintf(stderr, "%s: input file = %s\n", progname, infname ); + fprintf(stderr, "%s: output file = %s\n", progname, outfname ); + fprintf(stderr, "%s: firmware basename = %s\n", progname, basename ); + } + + time(&now); + fprintf(outfile, "/*\n generated by %s from %s on %s" + " DO NOT EDIT!\n*/\n\n", + progname, infname, ctime(&now)); + + if (inkernel) + fprintf(outfile, "#include \n\n" ); + + /* XXX force 32 bit alignment? */ + fprintf(outfile, "const unsigned char%s %s_data[] = {\n", + inkernel ? " __initdata" : "", basename ); + + c = getc(infile); + fprintf(outfile,"\t0x%02x", c); + firmsize = 1; + + while ((c = getc(infile)) >= 0) { + + if (firmsize++ % 8) + fprintf(outfile,", 0x%02x", c); + else + fprintf(outfile,",\n\t0x%02x", c); + } + + fprintf(outfile, "\n};\n\n"); + + fprintf(outfile, "const unsigned int%s %s_size = %u;\n", + inkernel ? " __initdata" : "", basename, firmsize ); + + if (infile != stdin) + fclose(infile); + if (outfile != stdout) + fclose(outfile); + + if(verbose) + fprintf(stderr, "%s: firmware size = %u\n", progname, firmsize); + + exit(0); +} diff --git a/drivers/atm/iphase.c b/drivers/atm/iphase.c index 5208fd62d..84bdda6d6 100644 --- a/drivers/atm/iphase.c +++ b/drivers/atm/iphase.c @@ -2359,7 +2359,7 @@ __initfunc(static int ia_init(struct atm_dev *dev)) { printk(DEV_LABEL "(itf %d): can't enable memory (0x%x)\n", dev->number,error); - return error; + return -EIO; } /* * Delay at least 1us before doing any mem accesses (how 'bout 10?) @@ -2499,7 +2499,7 @@ __initfunc(static int ia_start(struct atm_dev *dev)) printk(KERN_ERR DEV_LABEL "(itf %d): can't enable memory+" "master (0x%x)\n",dev->number, error); free_irq(iadev->irq, dev); - return error; + return -EIO; } udelay(10); @@ -3074,7 +3074,7 @@ static int ia_send(struct atm_vcc *vcc, struct sk_buff *skb) { if (!skb) printk(KERN_CRIT "null skb in ia_send\n"); - dev_kfree_skb(skb); + else dev_kfree_skb(skb); return -EINVAL; } spin_lock_irqsave(&iadev->tx_lock, flags); diff --git a/drivers/atm/pca200e.data b/drivers/atm/pca200e.data new file mode 100644 index 000000000..e78e83bec --- /dev/null +++ b/drivers/atm/pca200e.data @@ -0,0 +1,850 @@ +:150000001F8B0808AB5A10380203706361323030652E62696E4D +:150015007D00E43A0D7014D7796FA5BDE84EC86211A7333020EE +:15002A00AD89C00A23EA83AA589C7E7C38D8152EB887477677D3 +:15003F0095C39C3DB2AB388CA324C4A509352BFBB085BBD0C73F +:150054007210B903C92991CCD1B1C242255BCCD81EA5C34C6826 +:1500690006271AC6D36A3A31B976D4A9A683DB4B07BB38265C56 +:15007E00BFEFBDB7777BA7030B2733994C35737AFBBEF7BDEFE7 +:15009300EF7DDFF7BEF7769FFEEAD79F221221E1ED844C3E4677 +:1500A8007EA3BFF036F827CF8597C3AF0C7E920B16595BCE5AA8 +:1500BD00296B6483D83E9F7DBE8FF50BE74A0B45FB1F274FAA79 +:1500D200D82E2867139DF637FD937EF1D55FB0769FE8678BDAFB +:1500E7007D9BD8885451515172FE27E4138E9FC9949CBFF026BC +:1500FC00741DF83ECE59823FF23BF89346493F6B4F17C1B3A7CE +:15011100B3B79C97D3275B5ABFEC3CF9579457703B3CBFEFD600 +:15012600FC38236CA91B5E347EDBFA67F7ED4397956EA4D3C5F4 +:15013B007CE6A567799EFFF5CFC4FF7BDF938BF83E83EDE59F02 +:15015000FEAC24BF8A3C3F2FF9FDFF933CF51EF2FFEC2FEBFA11 +:150165002341C38CBC5F4EAA265F5EAF04BC51F0059FD1419ED8 +:15017A00063493D465A2384E66A0171C30231F40AB5CB5646FC8 +:15018F005CBFB633DECCC614D2DAF622F15D3189EFEA3EE28B83 +:1501A4007D99F8DABE4D7C2418A438AF3129015D7507F1032EBA +:1501B900E174827F46C82229AE2BC63A9D50E9253960EC005FCA +:1501CE00F2EDFE0AF12A9D5EBD6A35F1B5AC441A49BAD94F22C6 +:1501E300DECB544F180D1A51FACD8C4A7C034B93DAFD6455A8F9 +:1501F8009AAC5AB74C9542EF11E23DB0946A0F1B0DA10BF0CC0C +:15020D00F9A4A8097BCA1D751474A02FEC02593C75C9E870D176 +:15022200B8CF352EC3783C379E1C2893C98017C6A57B3CDD0E4D +:15023700CE32426A9CB99F03FC2E81BF46AD0D06544FD0190B08 +:15024C00C0580B8E897EFDF490DE08FD652E9CFAE911DD5F24FE +:15026100CF832469DAB1116BE0F3C437B686F8D275C437AC9220 +:150276000542BFF6CC0320B22AB7237E1F5B97A4E927A397490C +:15028B0064C43AFF0CD8ACCE8886D37F632A7F4C16005E289CAF +:1502A0003E491DDAFB083513C6B0A6B8E4929626F531E0877479 +:1502B50082E58C9E2503DDD45DC4777E3BF1051F253E09684E42 +:1502CA00C3BAC26825AC39F5225F6598EE23B366227C52ABFC3A +:1502DF00BC2754E61BD1FFEBAE6DCDFE8D49AAEA38EE89A35A1B +:1502F4009DF0DCF4254234681BBB09E98536033F2F3C5F835F24 +:15030900107E147E1AE8AA0406A36989DB63C95ADE9F9272EBA7 +:15031E00C17C6131AC4519193457028723BE118D0433D6F063E5 +:150333005C6E1C77EC2981FD118663B2FA3A455F8D11A2D66BC0 +:15034800AFE9B096E6D4A38454D70D004ECA8235541117C7A5F2 +:15035D002D26F8E4B07D3848BA956402FC7BF8EC956CB6B6D35F +:1503720091EB21B280C218CAB04122B5957583D126189B7D88FF +:15038700FB2BDA46560F52056C867C6CE85FF1135F19E0C948D1 +:15039C0023873342916798F3A6E45FA58C9021887DB9A8DF9307 +:1503B1002EECF7421F693AB054DE6F73F4FDF414E83A6B66B2C0 +:1503C6000B11C3BA0E45D0D1074E3318C92C24FE074FF267E847 +:1503DB00E03AE67193D635C40D9FD66A65B471CABA5AC66D9C17 +:1503F00081B68DE4F5200AEA316B3E3EF5F8D4CAF0C902BFBC6E +:1504050003FD12ED00BE39F8E7C4E765F2A6F8BCC8083DA6B648 +:15041A00335DAAA0AFC4DEA66A6CDC8418EA26910FAD6A0821BE +:15042F0012B4A9C269D1DDAC9DB05A98BD06B91D807702D6021B +:15044400F02CA479BF88CD3D82BE3F92D49137C262E0EB5969BB +:15045900D6AC8DA4F4A3A0EB808FEB8570E6F34897F9F77CE4C2 +:15046E0071E4E07C73F2C0FC256AC3208B2D5C834D43BA3F060F +:15048300F39566B386103FC611E321E23D02F1168A79426C3DFD +:15049800E159DA32AAA34C083FBA62DC2474847A94BF031D86A2 +:1504AD00ACE5EAEB969CDC4FF3F3216F03DE5414FD8ED3DA3050 +:1504C2005F5AC953795A804F2146D05612811C0DB6A0BC0E67DE +:1504D7007C6E471FC3A5CFA04B06639EFA201E11FA182E7D3E53 +:1504EC009556913E89227D129F511FDBA5CF05970CF63CF54199 +:15050100BCE097B83EB64B9F4FA555A4CF60913E839F511F752A +:1505160026AF4FCB4C5E0684CF471FC48B75737DF079C37C69B3 +:15052B0015E973BC489FE32E7DC231AFD997FEF15925301975DC +:150540007CBC5E33F5D918F2E53E82FD69D1B745FF82E8237F22 +:15055500EC4FB07ED2A4626FD8C3F7363321FA29D11F14FD6938 +:15056A00D13F2EFA9D40678FFA1ACBD131181B507F88FBA8451E +:15057F00E179507D8362EC4FC2734A7D8786D5D526CF431356CC +:1505940010E6D51152BB2CE6690F243DED35694FBB17D6017487 +:1505A900B251C766F514A3D3037337AB67189D043C77A9E728AB +:1505BE00CE3FCFE5A0C8B347ED17F9CDB09A812EE4A09AFBC861 +:1505D30005F3ECCE1F76B0B8059C6AD51342D87777BEC16093F7 +:1505E8002ED82B3BDF613094C9813DB7F3A50E87FE6A95AF1F58 +:1505FD00D259C69E53B447F047991EAA1FDDE8D0747091968332 +:15061200EBC88AB2D5095CA4FB07AA87ED030961D37494DB348F +:15062700C27225D77D497EBF32958271CE6F8DA0D12CF612E37F +:15063C00718ED32568206F3FDF874C7B477EAC4DD8310AE35B40 +:15065100C17E683B139EA3EA6178A6D65B4CA65926E72EF555F4 +:150666007A82D977D06A9A610E58F3D80D4F6BFDF4DDFAC37506 +:15067B00E7D67D672AA93DD881720C301B55C6E4D0860EB97506 +:150690007D5DFF3A0A636BD898CDE4AD4C7A42CBDE915B037587 +:1506A50087D7593056DDC1E5477B55429CDCF8B5DCFAAB15AFBD +:1506BA00AE3B0263FFD3EE69AF8C5584FEF3FD0FDA90E6BFADE7 +:1506CF0030DB70FEBF9C186B43DC4BEFBFDE4682BD8C27C86F5A +:1506E400B3BC185CC264063DED086BF730DA2418B655D6F63110 +:1506F900394850B53126EEFCD1AC2EBD1B83F83B6D56056C5662 +:15070E0027F079B3565739DFC3A2AC8D591AB48B37FD4097B6BD +:150723007D4527CA41F38E00D6C48665887A30CEDA5E6BA09CE8 +:15073800EF7568CF8A7EC03FF80DC05F6B56078280AFB25C86D9 +:15074D00F863ACEDB32658DBC26CBEE04780FFEEB7017F9BB98C +:15076200301001FCB0C5E54E5A0DD0BEC8D6618FD53893DFDBC0 +:15077700489D0A781A5B9B27616DFAD4435409C08E179C365B01 +:15078C00B86D2C5EB34E5BCDD0CEC0B98106CBBA25A29A87AEC7 +:1507A100676BD0977601BC4A7DCDC2BA15ED575E1DD7B78610CF +:1507B6008FC715EE954F0A5CB4B78837139F9F079E8AEFA21E32 +:1507CB00DF9814679714AB9163E99F59FEBDE3263A704FFA4DF8 +:1507E0000BFAD400D9FCE1115DF1C541C7772D591DB7BA1C7929 +:1507F500D4BBCC1B9F701EC761BE22E4A1429EB736E6E5C1BDA9 +:15080A00EE92C09D74C933790B79222E79BA401EE8535A429E39 +:15081F00F3ABF2F23C2B785CC43812F24C0A799A5CF2E05E759D +:15083400BFC0457F73E4C1E79BC91376C9B319E4813E4D9690D5 +:15084900A7D925CFE55F711E6D33B8A771799007CA73BC252F86 +:15085E000FEE3567392EE35506B935DE3E625D87B3AC9363DDC5 +:15087300675D387B325FEEC53DCA370CF1D064D2707F1F9E1BAD +:15088800BCCC7732962CFCB60AF76B17AFD80C1694A4D6EBDAB7 +:15089D0047E58DFC1CEB75E1E10563311E21B6794C95704FA00C +:1508B20031EEBF8BC93DD0270326EC0F8A54674771FCCEF0B040 +:1508C7007E67F81CD864D8EA401CC819480FE1811DBC76E5FDFE +:1508DC00733A83FDD508D6AA24406D9DCF3FA75FCC66FD65D592 +:1508F100FDFAEE7BF332F5F0FDC225936D769033AD01550A3A24 +:15090600BCF12CBF86F184F305E007567C68E59EDB3FCCF1498D +:15091B00D79F692B73E8803CC25E4CAEDA152370463A4A2DE42F +:15093000AB34998BC0DE1BD01C0AA7C5715314ED0FC74F4B510E +:150945005ED2BDC9319893001F18B3A2AE734B17D4E2CFA89EB1 +:15095A00D6B7245E6394E2F350520E95A6DD6079943780F65B70 +:15096F00507B1C857AE36D0B6B12491D8133EA88E6D41A72B92A +:15098400A835607E52D421448C255D7548EE0F723FD656E84744 +:15099900CA3D28974DE33C4751AF90CFEB9603D61BE545BA8197 +:1509AE00906D2A44D446CA190BE550DE5F85B273DF637264CCC1 +:1509C300C15E487501388B928C8974B4ED9C4E8FD80F395D9B32 +:1509D800D9A7F6FDFD5482B3B6141B358F92514D3A30CEEA2EE8 +:1509ED003EC7B6108744E478BE6ECB98555F46FA54D0E77A23D8 +:150A0200FDE876AE1FE7932AE0C3EC226CC2EC98E676BC7347DE +:150A1700DC0A446C361675F3A48267306C72595A4C85D9A5D310 +:150A2C006467AB60D0E4761AA00C1E19A6CFDE057584F27DAC4C +:150A4100810A64F09F5845DD6B073896ACC05936324E1D3FC1D0 +:150A56001C843796C7485C2391FD168998CC2EAC0E807119F419 +:150A6B00A52D86899716E555719D1E5CABF77860FDA686D87D2E +:150A8000881FD74839ABCBEADB34C06AE6FC196F49F9DC3367A7 +:150A9500FF9653FCBCE83E774E9DC198FD9433E7203F734E0EF2 +:150AAA00E7CE9BECEC19F9BEE5F8961C30A2634DFCFEA0D0B70D +:150ABF00B82FA14CBDC23E6C6D4249E6574419B2081DA247F1E2 +:150AD400AE02FC0A7D81D9CC00FA74C84ADCC82E72F9336B3524 +:150AE90075186487D8A757CCC5B06FE37D56B5BAAAF912D674D6 +:150AFE0012F13EA3AE0D5D83985C9FF6B7B3DAEE31CEB713DA06 +:150B130045E420F33B90DB12700BE117C47D4058E0468A700568 +:150B2800DC42F87111EF0EFD1E316777D11C01B710DE2BE8F75C +:150B3D000A5CA30857C02D84B709FA2B05FD06818B78F8BCDCC9 +:150B5200956F1A5D63F88C67293C4379C18FCAAB46C037862CF0 +:150B6700B497ACBCA2E37A07D5613B00F6AA091FED901553AFF3 +:150B7C00EDBFA257A9A7AC65C6076D814DFFADCBB131EB44D2FC +:150B9100D3ED8D9966269B5D0C355EAB1CBB62393E5B09B92DA1 +:150BA6007D3DEB73C7C0B7A0CE95599D4AE7C4A388AF5C5E4121 +:150BBB001ACAA1213D513EACA16C353B1A2C279ED9DA634E30EB +:150BD0002027A4DFC63C22E273C22A8E67F405C61362C61D27AE +:150BE5002FDE11D7C365DC0F1591D33E2D4E5E82FD3B17230768 +:150BFA008634CC078AD84F31565642CAC2B3E0D3AC9E17310500 +:150C0F00F1F318F89BA8DF73B0FBC5B9E2E6B1D4226269A8F448 +:150C2400FD8D2B9E7ABEF0DBCFD57473E2296C3D2DEC7EBCF2E1 +:150C3900AE00DF13950DDEA802CFB7FA713CC25A35E0ECA52AC3 +:150C4E00D412F544A96ED2E3655F78CA23E0B4C678CA19C73BC6 +:150C63007A25DCF084ECD008279EA8719E37E5E1B9FD8ADDB182 +:150C78000DC0764CD423AADC4D73B519BFDF7C84EDF7B3589BA5 +:150C8D002978178F2324729206D4F666ACDF181C6C7FFDBEF62F +:150CA2003F04FFB4091D3E8BEDE2C8A08EF7A1481361354A427E +:150CB700BF0075C79CFD52F0EFBA09FFF58CFF80C9F2281DB6EB +:150CCC00918E943ECEE946809780E173BA047D6A637DC3E9E326 +:150CE100FD30D41426ABD5A0BF066353F5B7AD57AB426111E732 +:150CF6002175793BD0A435CA01DD9101E36E51513FF72CF85916 +:150D0B00533FD0D6AB0F846AD4079A03EAAAD056276FA94F71C2 +:150D2000DA82A6E43B3E87AEF48FB786AD4E2F6F75EEA36584E2 +:150D3500837D8F64208743DE10F7CD8B56A7E5565C0F7627CD82 +:150D4A0071E811C84132E2404C200ECA9A85BA8E1AFB35425244 +:150D5F00980BCDECDF9F97C1AF71CF55D02E2C2EA660BF823D2D +:150D74006135190E61FC6476BEDEE1BEA7FD9C787F107F84E908 +:150D89005860EF2C9930495D2A9AA76D08DAB6C1624F81FD644F +:150D9E0072445B638C94A45D2168373E42BCEE7D285F5F65CC2D +:150DB300E4D7B03E3172F5C9FCF381CDF301E856321F28AE3A51 +:150DC80028771E688C4A5BD641CD07B107B58A72379C210E6DFD +:150DDD00D477415EF648712D0AAD1C4846132A3F977C1772DDE5 +:150DF200B1E4C7CDE4EA10BDF6B5FC7B8D3D5FFFDDFEA623C476 +:150E070037F149D60767196DF37D72BB73D787F76764B77176CD +:150E1C0012DFEDED4E9E9D62ED24C612B4E9B319F6CE0FCEC553 +:150E310060A795E28EC5592B49ACD55EA03DFBA77C1F408D2F19 +:150E4600C19925111ED61AB1FD22D431CC768DCC76686BC46913 +:150E5B00025948755C5BFE89B05F4C62F603E3079A805E15C03F +:150E70007F7E9F7C2F5BCFEDA2BE82166B17AC59900EF6BB59E8 +:150E85003D95F781473ED50706C49DFE70491F5072FB7DC6422E +:150E9A009DC136B6B08D2D6C630BDBD8689B72C8E56E9F99AF8B +:150EAF003DF1DD13D451C14A757F10CEF8BE3C6C2DC00E06535C +:150EC40005B03F02D8D1E09803AB42582DC056042711C6EE3D4A +:150ED900B87DDFFB18EC09763DFFF15CBBBEF730F18D7D8C764C +:150EEE006DB877BE7ACD579F7809FF2813FE1105BE17B615CA1F +:150F0300D922135F23C8E20159979490B511E67899AC4DF7DEFF +:150F1800CE1ACC57DEDE12F2960B795F0759976C9BEBCF06FAC8 +:150F2D004B095F8E5DCBFACA408FC8B5B97AC4804EF81AEAE194 +:150F4200BFF7767DE976F4E929A18F2CF4F9F956E2EB84DF675D +:150F5700E1BFF97F4127B5812A6A1365EFE620074AB029B701EC +:150F6C001CFB32E934357C0E6AA60AD659AEEA96A26EFA5B76F9 +:150F8100970E79676B6C88BD2B8E7D53DCF73CC76A5433FD0D60 +:150F9600A89D643847E33B55DC9401EF62EC9455F5C419EBC295 +:150FAB00479C3601BAD9858639057D89F7BD631F15CA33267057 +:150FC000DF83B68B244DBFCAF9118DF3433EC8CFDE5DC86F3932 +:150FD500E0553D71CADA0AFC3441837EC4F9C5043FE87BDDF609 +:150FEA0054843DCD3FE1EFB8AF3E440AC61789F15D62FCBDA29D +:150FFF00F11A31BE558C8F158D2F16E34D623CC1C63366D79E29 +:15101400FC793F0B3A5202FB37ECD5DEE52452707687BF81A5FC +:15102900B646E14C41EA923BF0AC5963EC5F87EFF53591D70ED8 +:15103E002C9DD53AC22F873A5DF7E92F4C3CF113B4D573BB2F35 +:1510530075045DF0CBAFFEF57584B7EEF84987FBFE7DFA8D6F83 +:151068009D40F893FFF0E30EC2BE871834E3FFFC179BFC0163E8 +:15107D0047B297F8269F24BE3972BAEE17827F59B87FCB380E23 +:15109200F9167388548D39197231C24AECC74EAE81B351FBEE40 +:1510A7002DE2DE07700F6C19D52A638F065F811671F66EE7672C +:1510BC003C1C73CE320C5644AF8EDFF7F1EF332E0FE8F683F8F2 +:1510D1001D01FB1640C47E8ADD2918BE51B6571056CB2419BE69 +:1510E6005F39CDEE52768B7B1784A9EA283B4BED71C18202D67F +:1510FB00E7823509D8DE99FCB707866B1CED4B26086954472D8C +:15111000370CBF436C2882554932692E84518A67BFD838550E10 +:151125008DEA2D3826F4C6EF6508BD9BD99D8AF91FDC58F453B2 +:15113A002F9B9FF345D18A7E649C4A07F09C0338ECFD3DE713EE +:15114F005647E93EA827B19EC2F3EE65F0B7441FE9C6F74ED3D0 +:15116400397FE1B66DACE2760DA74FE6E40CA74FD3FE2DE3DA2C +:151179006675DC72D37C79E98086FB33D28C15ECEFA3ECEE6226 +:15118E00AB80ED1132EE113206605F6732E27B2576864DE1DED8 +:1511A300CF6A05B6F78BB51C106B298B6F2998CDA06605DE16C5 +:1511B8007EFF9280338317CFA17866127A7845AB14B5176F64D1 +:1511CD000BEA546EDF93EC5E0EF76903F4C3332E3E3B30F2F086 +:1511E2005C58991BC6EAE794D509272B493C6F56381C6C66A124 +:1511F700DD6A33CCCE0143C8C160013B1AD89812E727389FC223 +:15120C009C5A03D60DD688B591717321D2A3A356297C52029F42 +:15122100E4F0DFE4F605183C5B7B9DCFF944FCBD20F4E4B19C55 +:1512360062758BE4E804CF57A514F3F7A03F3FFEF296FCB8034D +:15124B007BA9044C7E782ECCE386B9623AE7DF22A69C7875C78E +:15126000727F512C633B25C66E36C72831C7196BC4F68BF9B97C +:151275009590BB8DBBC902278FA04D5E747C0E9EEBA7E37AAC39 +:15128A00687CC1E594CE69A4CC1648B68998A71B7CAC06F7016D +:15129F0073733E27A17F605C38637DEE31F6ED1BA7C35A178D76 +:1512B400CE221A8E0DB80F7298510C037A2F38307F1E66948027 +:1512C900555617C250A7FD2E9D1D58BC04ACBCDA0D334CBB4EC1 +:1512DE0026E1D5C23EB08F60CEC0B8F483CF634D85DFE4B17ECD +:1512F3002015AD75BD4B225584BD3342FFF533FF1D311D3FAFDB +:151308003C84DF1BD87400BFB50BF35C568A8672DB34600CF7B2 +:15131D00176514F12C2D1717498AF91CF3E12ECC25D0C77907C1 +:1513320097A634461F7DC54F6829B8E2829B6EFC25A5E10AC018 +:151347007B9DEFDEEA788E75DB6BAB74137BF94BEBBAE0B20DCC +:15135C0067E4D1BE83504BB03C301FBBFD1669A19EB75A03F3CC +:1513710076E4FACCB40AD7D51679DED9AB793E2EB475613E2E11 +:15138600210BCCE1B2A44CD602ED85480F6ABE927628814F729C +:15139B00F885F2ED75F91DC6AF543D37BE49F5DCF82EAB9E1BB7 +:1513B000CBA404EC15DFDCF8F654CF8D65B90886F847DC73F32E +:1513C500EF3C2B79FD8531CEF706B469BD6BEF83D6D825BEDF9F +:1513DA0020AEBD50291A935D63FEA231AF6B6C49D158956B6C58 +:1513EF00B922F611E52D4A1493CAEA307BCFC4BF63A4F41A6BD3 +:1514040007E9F532BEE765581B34A1A82072F5889E30C635FCEE +:151419005676B13CA21F2B1FD78E854735AC55BE639CD3BC1730 +:15142E003FD0192E201F360E68CA5653AF81BC5CE97AFF8BDFE1 +:151443008FCAE638833F17AB0ACDB8D613DFFBFFD37DFC7B9AE7 +:1514580058EEDB1B80CFF0335F65F2D7CDCB92DFC4EF4EC4B7BF +:15146D003313ECBB277E5F3EC1BF8D080E50FEBD0C1538830C25 +:15148200A7D7F57E03DF9F3F2BF84CCEE17347011FFE7DCD0460 +:15149700FB7ECAE1630B3E5D820FC719345551A725A13D119479 +:1514AC00BA2B0E8DE8FEF02AFD353C9FC4EE6E0BC42A425745A7 +:1514C1007C5D8ADD139A85672FD8BF5E8BEBD433DA5719F3B4AB +:1514D600E33A292ABE8B033BBE097935297577A9A72C388AD66C +:1514EB00C8CA5A88EB03B42E7CB0ED30665CA5DFC46F5D37FF53 +:151500003B9CEB22BFB41AD45F5ACEFBE836F58015560F5BFEA9 +:15151500F408FDBFF6BE3E3A8AEBCAF355AB5A6A498DA816ADA6 +:15152A0046C2209588708447715A422648964C43182F78306934 +:15153F00639CAD12C26EDB644C1C26A3DD61E7704E58BB255AC4 +:1515540020E10729D548462638B4B064E30938322B123C47248E +:1515690062E275F02C61B48CC390C4269D19C626332456BC4A65 +:15157E0086CD38F4DEDFABAAEE9210FE9839B367FF58D5D1A9A8 +:15159300EA57EFE3BE7BEFBBEFDEF7EEBB657887B6D5087BF17D +:1515A800081FA63A83A941B22B5F3491CE945E0EDF6E779BEBA1 +:1515BD00BF3ED0EC2E5FA1FD996EDA75A02C9E5157FCDBF00DF9 +:1515D200AF6E8D4C2B5F4CE523EA336693FA8A5DBE77C6F2D17B +:1515E700E31818D5AD80254CEF6AD47623AC7673ACFB9A2CD1D0 +:1515FC00A6A93F37BD12FC228E7293F5B5C9B184594CF2CC8307 +:151611007DE9E8A0E98BF59AFED8A869EDDBB8F9F8A4CDC7F152 +:15162600297C9CE1DFB1214D71F16F51CCDB98E151EC1B61AFE5 +:15163B008478348FE466095BA45B7DABB6FA16196876F3735093 +:15165000ED364231F94E6BBFC1E0F0E51DF97BAC8FC45BA1DF9D +:15166500AF6E60F987CA929AA22E16B459053AC0F5491D31629D +:15167A00EA5123A26EE04A68756B1FE9A75864EF1B7F41737C57 +:15168F00777BEDF1DB6FF95B14BBFD285AA9BF3945A7743575DF +:1516A4008C67CB1C31B9ED0FE7E415FB9AE349AD9878DC5D3E9C +:1516B900AAF61A1BA87D8DE0D0D483F47FD56853AB8CED6A8D70 +:1516CE001157EB8D2EB5C930D45544BB477493FD595B754AEC79 +:1516E3009FB6F553FEA43A6A1C51B9D1F7EC515EC28EE97336A4 +:1516F8003DCB17BC759527367D92772E58CC776DAAE5BB9F6D89 +:15170D00E05D6FADE04F2F38CEB166F2B91FC0892426ECBAFDF3 +:15172200CF9EE2FED387F59EB7F6F262B677A91B2E3205F38BA3 +:15173700D455CD99B46807AF92587EB13B4D74A083F39BA4BF13 +:15174C0071217D43BA16EB3032FB606FDDF89E191DFCFD821912 +:15176100EA235E1B79279D5F953C6C88B1053FE0CB37DAD7F014 +:151776008388129F788B3A85AE7290F2BC1FCCFA9DF8A6FB9DCA +:15178B0010AF1E14B65E3B7C7A4CE13F4D63DF4B32A32F49FA86 +:1517A0006CD3104F596B5EA6DF3A5F31A744D87D9326DEAB6A39 +:1517B500027BA94167BC63FD5E8B55124FE0EC483B8FBBDA56CD +:1517CA0066F0C3F1C5A85D3127C44DEC57F6A9528B323AC0AF33 +:1517DF00D96D627F734A9BF4DE37ADCDE9FB071B5CED3357FB1F +:1517F400EA0CEDCBAEF6E7CFD07ED5C76C1FFE3589863077601A +:15180900010C3BE65830CCA7B6A6B7AF8CBE28DA526303A46BCC +:15181E000CB732A5D384EF8F4CB67188DA9D1F1B309E5EF06B13 +:15183300E1D331E9F6F371EDCFAC7D2AEB3F22E52774A9ECA464 +:15184800BE7EACB3D1B78E0B5D46B92FA995EC18E1511F8B60C6 +:15185D007C96EC18E4317A866F01F21B296F0B337E6D62EF18A4 +:15187200699E6969D4D712C77F24188AB5865929DFD939B88DCC +:15188700190F70F08FFA790234A4B5FACEEDA1F64EF292D096AF +:15189C00D6B93B8EF208B5118C5B3A33F2083F10E3707FF1B807 +:1518B10021F67738C13277473D27B9DDD6B177ADF0F3098696FE +:1518C600B576DCFB29FD3CE1E9B598E74ECFA5FF20CE4084AD8B +:1518DB00730562BF0D739DBD9F2CF6434331A9B94059AFA36E52 +:1518F00094654A3397A5C37AA7381BF0B258170EC2C732BA3C2A +:15190500B35621C717E9589F484C785A426F35F0D08A7B74362A +:15191A003E6286562CB6FD5AC4BA96B557611C3597624F3D3A72 +:15192F0018BF4DDDB4043693D88735068633FFCA603C4875F9B3 +:15194400F32BF52BE974E08DE57AD3E34F7A9A1C5A5DA0BEB02D +:15195900F0761BEEB69BC2EDB954A1CBA79337C21E5E6686ED09 +:15196E00F593E9F04346032FE883D59719FA30FE0D731DFA6039 +:151983003C175F29FA10113028D1B80EF80D35A70577C08F3B83 +:15199800F15EC92CCC25E37BF8E0EFD285428F540EC7C7976FC2 +:1519AD00AA1FA5BEADA2BE39EF77FCCE75D410FE24048BAFE8E2 +:1519C200A8E085B93B4EF00999C598B16838A00CEA993335F4F6 +:1519D7005B8D25E8FD31FE3EDEC37710FB414A3B6C06E386DFF9 +:1519EC006E7FA97D597EF71525048FB3FA041F233316FB9D6202 +:151A0100BF69D883FD6A137BBB57D3E950D6FF89C6CBBFB17C5F +:151A1600625F767D5894CF961DB6FF8DCCFFB4F5E2B6988F27FD +:151A2B0053DF3715E2733535305C1CDA4EF56CE1C154A5312B41 +:151A400095D3B22AB5D80884DA88DE63A2CE10CDC92CFAFBFC5E +:151A55003519FBF21A87AF8EFCFA2384C752BE16FABD021FF809 +:151A6A00A8F0B5EA8DD7697F1EA96DBE47F5349FF75EE1A1C844 +:151A7F002797826E1BD2E9C249C9B193BA8D3CD02D2AEF32DA11 +:151A9400E013B89683D6C85743F9CEDAF9C2A91554EF6A739572 +:151AA900C573C38286F6BD26760FEF16FB8295246F5682A68619 +:151ABE0045C3A9F70E09EB8657787A391C7107881F3FAD4DE607 +:151AD30058F517F101FD41755663B13AABF6A5CA924673E18293 +:151AE800C657F18EE018BC9E2E5CA84A8D024E85F4B072A3D58F +:151AFD00C7FAF9E51FA7F333E7F1C60F5B7B8DE387CD4365D585 +:151B12001AF58C63BFABD7AE9FCA37A32E8DEA72F23AF9B6524A +:151B27009E7D6B06B45D34C6D0875B49E64D6F6BFB8FAD3D8A0C +:151B3C00522AFFAA64C185737B5D180BE37163BE7F500FFE6E98 +:151B5100BF8101BE3AF5A2619DD34A3333F282D647F5CEF3D710 +:151B6600E8A42B97C0D7BC865DE189C837DB70F62E89B1BB66B3 +:151B7B00B16E12AD72D990EE25FEC7DE506364A89129CF59B491 +:151B9000B1F5378C6159F0994A70455A05FCCA73E69B3F4AE70C +:151BA5001FF558FD5C49B46E9A81A6B751DBD3FB34F8A3B4D82E +:151BBA0013443D5BEDF2F36252A3779C6440740FF7F8137A2424 +:151BCF00B59F375D4AE73B6573699CE02CDDA88D779CE714B2F2 +:151BE40080F0E0E4E9A777E2D9788AC77F98B6CE3F529E37DF4D +:151BF9009F8A7BF0E04CB012FE4B4A53ED46FD050BE783D3CA28 +:151C0E008D02FFE07371566D0F77708D3371AB530326C73E7BDE +:151C2300785ABF5957A6DF472F5AFD06ED515F1BD55763D34CAD +:151C3800F0E6A0C59BF04B97D6FCBE1EA5F7B73AFC67D3C2C2FA +:151C4D0063B60EEDA2056B1BF1C4C8BF583C31CF5FAF8706A432 +:151C6200468737B662BC5BE73B6DDE209D3F32A42D64279AC1E8 +:151C770017C18661C10F667CA1E6EB7E519769AE5C68F381E5DB +:151C8C00F73A95EEA493FA42CA61E2F9765E447C116CAFD595EC +:151CA100376C7C3BE3C15506F6D44CF8BE1DE39DF203E737B4A5 +:151CB60043E3E928D5E9F8D3E4BA78631BF186FAA6C51B12E1DB +:151CCB0057B67963EDDF5AF8157B568493CBBFCDD20FF5CD8A7C +:151CE0006ED1B59F7CA99E649C599D5A6356A5569824E74C9214 +:151CF50083C60CFB4DE21C33F4143FD901C2276E063F6FD2937B +:151D0A00785E51B7DE06BF4CD2DFA09749F9033AF6B5BAEC73CC +:151D1F000BF02D7B50F8330D0B5B4AF877E34C34D94F87CA4E3B +:151D34006ACC1812BEDE4AB2D384BDBB2A794AE877F1E410782A +:151D4900728EA2769AABD453A641F712E388FEAA6ABD67954398 +:151D5E00FCF24DF43FD8438150B4750FE66FA58A17939CAF263F +:151D73003BE676F8E23B7633D96915DA55BD27B2BF0DF8F35FD4 +:151D8800C8DACDADEA7DE6DB3F93EE94957BF52A7505AF225DD7 +:151D9D00FE92EA6D0ED2FD5BF04514E36C0F2F3D9FCE7FAD5214 +:151DB2006E249BDC207BD698C78EDD15211B50B6694D76AC01A8 +:151DC70059D9E44A433E25146EA53ACD2ED5DFECF8589692BDD0 +:151DDC009BC72C3D0DBF8F52DDBB95A7DAA08F55CF618580CB48 +:151DF1006D67BA6DCCE80FAD71D029F257F36BC5AC9029EF99AF +:151E0600412A0399E186C9E2BF7A7E3BCD0B800F7004D5970D68 +:151E1B00F4218F781FEBE76C7C31749E6068C5A774F41D7A90B7 +:151E3000F774834E6085AAA82E21038C1E1E559FE1AFCE26DABE +:151E45002BC46754DE6907766090F41F4A33DD6DDE934E8B36D0 +:151E5A00855EA51C364748472B8FD9B22C6AC939D4D9361BEBFD +:151E6F00F6614A3B2CE0F2B2BD7A0FE08AEE3121A71CBA396BC1 +:151E84001ED13740BBF704ED707E5C55498F573A877DEA1DA687 +:151E99007705E940D1BDA26EE8F5D0E9FDEAB366CD75A929AB9C +:151EAE00CF583470F0EDA6C360C0F2BFBCD97B1E60856E7A0042 +:151EC3009EB1BFA139D2A117E495526526D6701D7AD4E49355C5 +:151ED800774DE7D7A87D9E2F9E7AC72C095D6CCD49922D7DFE54 +:151EED000A8D8D2FF00AED4FF425B16FF37D9D27DAC43E90ED91 +:151F0200971EA6BBB087B08608C28CC1C77DD80C8BB3DCDF30DF +:151F1700E684CE50BB3F249952DAEA8B3D493AED72CC2B66C792 +:151F2C00BD0F918E7BBFD171EFBD7A774A024E857E9B87392E76 +:151F41001CB5F5DB2ECB2F8FC66CCCF6B31F16F76ADB0638627B +:151F56008CDC073B2B4265B6087D3A2D7C44525C444EC819E394 +:151F6B00E1582D9F9DCC69093CBB9E074EB7E852F2040F40BFA2 +:151F8000879E7C1F7CD25F163EB87DEC9B1ACABD4FCA53DF677C +:151F9500BF69EDA7517DFBD97734B6ED1847F4903EF66D0DBA40 +:151FAA0018E4771F7B4D832F2DE089920E87FC80E55689059E76 +:151FBF00227915185BA9DF4DFDF12B8FE8B2FA9C81BE3A7E50F6 +:151FD4002C7A9FD931EB5EE1039C4F3031638DD9C70632FE501A +:151FE90028CFA2CF99AF125FFACE8DE86CA4D384FD04FA0FDB39 +:151FFE007BCC68ABE8524AEFCD7941E8F56BB1AE3C72CC1C63DA +:15201300225F1CFA3CFCE2B0B78867D80758AF213917C7BC7364 +:15202800ADE27073B9EA69F49D233DBCFE18A7726DED852B5BE4 +:15203D00A05F930D5A124DBD635468DFD3674BCF0B9DD8E33F85 +:15205200A1236F09FC1BEA87903F7270672FCD457DC236050FD3 +:15206700887764234E923CF49D3BA8CF3BF79CCE2607054C382D +:15207C00EF437C2564FC1FC6D6365978F986E13BFD72960F9219 +:15209100DE0C1F84C007842787F6BEC82ABDABCD63D111F4336D +:1520A600BA4D879E4FB31735879E2CFA0D73103ABACD2B53F1A0 +:1520BB0067E1EDABAFFF9186337253717644E0ACA44DF848DBB0 +:1520D000381B06CE026CFC581CBEDAD79EBC7789A80FB6CCA84C +:1520E5008533165D346CFD77F65B733B1B9E3B7A42E047AC7FA6 +:1520FA0019C7CC02E8C5935FE16F104B127F9414A53CCDC0ED45 +:15210F00E39E2796FE69CA736728E66976F30978C373E91DDDF8 +:1521240027BDA077AB599C04A78C0DCBF6035D2D7EB6C60AF085 +:1521390094E1F5E9769FBDEF6EAAEBEFF49DBBAAC367D9EAA701 +:15214E00C1710644E83FE1301778D9F669AB7FCA401C6BEB2D2E +:15216300EA034BB0FFE1659D7A70C75745FFD8E6E778EFD81756 +:15217800493E7CD174D93BFDC2D6C19E36E18245474CA78E203C +:15218D00D951852E5C8C117F2797AF6FBA7EDDC2C76FCA9FA8EE +:1521A200DD40FA96859FBFD7EBA4273F003FDF27FC3CFFEF82DF +:1521B7009F97809F7577E98E6D9E6661CE267F6EE1836CE6DE14 +:1521CC0038EC050B1F0BD8223DF8FE62818F9C68A95E1E2F6F3A +:1521E100BE45CC71FB782CF5AEB9ED97B0974B5BE9D9807CB1CE +:1521F600EC1FC21BFBE32C0F2A583310FF84BB0117EE5E369D99 +:15220B00F6A6E3AE9770B78D70F77736EE2E12EED07EC8D5FE2D +:15222000B55F586D4F6DF7056D5FFE505666DC5C56CC71C98A24 +:15223500A64C3EEBEC74667C2CC4BAEEBAE7333244D8E7E3545F +:15224A002E3EA44D2EF70AD8204B204722A4E3418E604D0A67B3 +:15225F002050EEE9944B9EE4BCA461FF0FE736F05EBCB3E449EC +:15227400896FDD4BFA016A5BC8946D4362CC627D0A7D2E76F53C +:1522890059A63EBB65CD74FFA551F8E6285C2FBA64E801D20F34 +:15229E00FA9232F547354EDE27F4CA906B8F8C063EE99034B72D +:1522B3000357276DFE4079DF42962F8FEFD495F33BB5A9FEFC1E +:1522C80086B0357697F56B42B7945917703526D65C86E20BB10B +:1522DD00A743632327752C2EA74EC47D7ED27308BF05F1A1C669 +:1522F200E2A841F301E73D29B94556137CAEF217382B182AC2CA +:1523070019BA0C4C5161776CC799BBF2D5ADD0B1587958D821CF +:15231C00D095271EB07C67AFE15EBE8CE6DDDF3F207CF7C2EA17 +:15233100F1D40333FB731B87B07ED12FD62F76931E5C34D629A3 +:15234600D609D8B89C301A8E58B04787E245F06FB4D33DB1A12D +:15235B00B8D2302CFAD7C3F66A384FE85B47F3883104BD08739A +:152370008C41735BA67FC591C146A7ACB58F9B79BE019E6B8741 +:15238500B2EB31BBCB86B5A2B80D8F711378285D215B1AB0B83F +:15239A00DB94ACFD988ECC5A8DBD3F8FBD68567ED2DAF7B4FD65 +:1523AF00110977167EACB5F4A978543A0F4CF12FA27110BF1F74 +:1523C4007D305A31164897E928B77CA2E21D94DE1B4D6ABE22CE +:1523D9004B2F4B114C5772E258F32AC4FBE87ACB96C1DAC1428D +:1523EE00DB8F6AB5E09123F1FBE89D03BB809BF26BEBC51EA3A5 +:15240300D8075C6BE7D35DF956A45EE8A0FF38D28DF558CFF983 +:15241800761CF31EFA82FD4FC0D1BB73480B8ED9F050BAD3EE10 +:15242D0016BBBE9E19DAED77B5BBD5CEF78C2BDF4A6A17F99220 +:15244200AE7C6D76BE8119E05B99FA661C67108E0818BF1BC70A +:152457001ED815824521F89E16BC734CF8CDF47E8F6065D6BA3B +:15246C00E01517ACDBECBA5F9C01D661170CDBED7C2FCF00EB9F +:152481004957BE1D76BE573E0056D0D881F5EA87C07AD5056B9E +:15249600CAAEBBFDFE1B61EDBA3F0BC3653B5FF7FD37A1E7FD24 +:1524AB00597A5EBE093D2FBBDABDE2D0738676FB5DED5E75E845 +:1524C000799376B76CC0F81A050E8C0977BBE8AFBD7E8F74875A +:1524D500E71FA7FCFBD95086E737782D9E7F5FB2783EB621DB46 +:1524EA0076D46BB5FDF0860F681BFBA576BB4E7B93AE7E6EB0F7 +:1524FF00EBF8E2CC751818B38E6FCEB5E9328FE4CBE5C1ACBCF8 +:1525140013E359ACCD22E69421FC099832624057F1F93BF5DD6E +:152529006586A6D0FCA0AC3DA597F213FA3E9A12DC32E809EAA9 +:15253E00D74CB2C729179286B4FDA437825F2CFFC7BD644B24A5 +:152553003BE0EFBD52D4959D1BEAA82E0FCD0B19B94A7A896F04 +:15256800DD9090A9429E3AF3451CF27448C853650DC14F725439 +:15257D00723D4F9D8FB0DFDBAF4965869EC61A18F6DAADB37498 +:15259200F6DC346CB56FD8F234DA678A35D5F121C3EACBA0069B +:1525A7007F17EC0B189897C85E99ABBCA2FB48E7C6DC34E37C24 +:1525BC0032945D0FC73A1CF6944270D7856FBEFD9BE6F339D379 +:1525D100D7C2AD75DCA3864CF348A0419C756301E917FA933497 +:1525E600B72D10BAC911331264D1D7688EF6150D0A9F0E2B1601 +:1525FB0058B5D807DA5DA66AAC7E2F6F13FB0B3D64EF579AE254 +:152610004CDCFFEDFFC3BD1C30B36DEFF238D159C0EE7ABF99F3 +:15262500F4B6E5F4FECBEC1F9722C609FAB0ABEC88735E5915B9 +:15263A007D237D48F44321BBE2E3FE0FF4F29215EFEAD9B4A1AD +:15264F00E175B1F412A7AD0ACDB2D53F4A5BF1E48D7535C6BE43 +:152664002BEA8A7E40F918952B5D33B5DCEDB18796587433CC8C +:15267900D5A09B5D2E4C79FDD3F2D6C52AECBC2A17FB43365DAB +:15268E006591AFC75C3061C77B237CE26C5D5D2CAF51ECBDC060 +:1526A3007F53E44F7092F13109F989A7113746B6E2C319880F2E +:1526B80027CE3F132F89B399E383A67B3FA9F5886B3F087BA603 +:1526CD00DB388F603F272A6C1B71BE5251E0FF613FAB3807990B +:1526E200DD0FEA75955F18931B9D3D21D421AFE17A8F589B1E44 +:1526F7001C9E74EDA33AECEF63A3F96FC977E57CD9F39EF47519 +:15270C00E951E9335250BAC6FE8EFD35FB2E7B990DB1AF319314 +:1527210075B30EB683FD2929DA5F628FB147D9436C23D3D8036A +:152736006C3DFB1CBB97FD015BCDEE66ABD84AB6822D67CDACF0 +:15274B008935B206B68C2D6577B07AB684D5B15A16669F66B73C +:15276000B34FB11ABA7E8FDDC616D355CD3E49D7AD6C115D55E8 +:15277500747D82AE857455D2A5D25521AE72BA16886BBEB86E5A +:15278A0011D73CFB2A1357A97DCDCD5C21FB2AC95C41D735C7EC +:15279F0075154FB902D32EE5866BF60D57D18CD7AC9B5EFE0F7A +:1527B400BC0A3FF42AF8C857FE875E3E26CE181FB7D6B754E111 +:1527C9008B4EBA3DE9F151A61E475A15A519F673353D8FDBCFB4 +:1527DE0035F4AC48F48C35BEF26ACA1FE1065BCDC7C95E5024A0 +:1527F3008D2BEAC2E34A8CFE93F49F5A785C8C2BB11E522DF667 +:15280800DB55D54ECBB7D3244A8BD96905769A87D292765AA167 +:15281D009D964369A88FDA14B02B2C1AB6EB825F60D8AE037E98 +:152832008061BB2CFCFEC254262AC16651F9F04B5828BD8D33C0 +:1528470075E1016F6899A8272AE2EED41AC549A9CE776631CD9E +:15285C006B95077C671A843C887FC0BBE10F78073F38BC2BA2B2 +:1528710077946E225D7EBD41176D8F2F361DDC3938473FC66D43 +:15288600189561411343153E7661037E200CFD1465C2ADC02FED +:15289B0070A878ACFCA96FDBEF99CA9BD485A661D7C35EB1D235 +:1528B000A3942F8A754A65A129FBC8A6BFC93D2A65F38CBB9EA0 +:1528C500154FF6D9B0D345FD63E9D988ED64F947AA7C42ACE7CD +:1528DA00A8563C48B12EAA8A5891B9F6B3F043F310AF617D2323 +:1528EF00BC8C477FE16109CF32332FA4B6CA91067DA2B241C487 +:15290400A998F8AEF70EE004BFE12B3046E5FC6C19CEE49A35C6 +:15291900840B529EB84FAD33F3D86D04FB6DA63714691D9F2168 +:15292E004D91AC34A6BE67C2BEAACE99AE9FA98648037FD3FD64 +:152943004155AA9389664ABCBD4E86FF8C5209F9ED634A2D354B +:15295800B9CCA81171196A4DA6002E55C012F594521B8B0DB4AE +:15296D002F9F29D595F8E27ADC7DF1C575B847D1D7F1B090F94B +:15298200C82BF818F29DF489B81813CB7844F8D946901E4BCFE8 +:152997005E4D79A2464CAC776BF659FC188F88B5932DD699FCEB +:1529AC00709B75469E6DB7E3F076D9677810F764360195205DD9 +:1529C1002461182CA141FFC1EFF796CB77B0F10EC3AFCA752C4C +:1529D600BAD39844BFC655C35A07B2CE2DD7A472EA449D549F2D +:1529EB00386783E768AFD15516D72431FFF59A9973E3D1FFDE24 +:152A00008FFECD579F3664F575D21913464495EF78E9A197A820 +:152A1500FED7FA918EB41A4A3B302DAD94D2764D4BDBB69CE0E0 +:152A2A0052DEEEFFF243EFD49262C6FDEA25633B3BC3E7AF7812 +:152A3F00476FA9F869EDD7965DB17DA5E362BD6D41FC027C739B +:152A5400845EB160C5395D4E0E1A9EF223ADAAFAAD7E664C9A2E +:152A6900BEAE5EA193637EF68DF52D0D618EA47698F10DF3161F +:152A7E00E91D1D7828603FAD1D7EE8974B0906A2E92582EB9C07 +:152A930021F17DFAD736BDCD6F89D05CACEC330967F1EBCB57B1 +:152AA800D5FABAA9BDE8CE617624176BE5C33E1F7483DD077C9B +:152ABD00ABDFA1F4FD07ACDF2FD8BFBF7DE00CCDB7C9EBD3C29B +:152AD20060477FD89FF09C3180B7ED6C8CC7BF935BF7C413B97E +:152AE70075581F3830FE356DDEF9FD5ACEB937F4BBD985DA799A +:152AFC0063A774C41685FE62AD2F8E8BBE96287FAE4F3E7CC918 +:152B11009C27BD46EF2F98BEF8B1A5D88342DD130F9F337CC974 +:152B2600DCBA912773EF10671887451C98E3090FD90CCA090325 +:152B3B007DF9EDA1CEFAD069AA5BF9078EFE28803BFABD611FD5 +:152B5000620529BB8F2B02FEEF1F7F9BC66081BAB70B6BB57987 +:152B65006A67BC27CE3589F49389CA1F1AD05192A4777CD58762 +:152B7A00F83ABC6BA2F2D726E5DDF34BB5E68E28E5DF115B5586 +:152B8F0007BB4A8C2DE59821279F2519E9AD8B8D1DAD63C60920 +:152BA4006302BC47EF317ED653BA9C3C46FCD3297C13ABEDD81E +:152BB9006D62AC197BC53E47B5186706F725F7D2388B73996858 +:152BCE00AB305E8FBB8FF13ADC113FCA97ECA33AC68C36EC2BC0 +:152BE300261386E4231C85C74CFC061F627C9CF92EDE0D923EE6 +:152BF800493A7F3261DE16E7227D8CD2F11BFBC81395DCF0C751 +:152C0D00E4BA00E96B1827139583E63CB22746AF7BEF205C9AE6 +:152C220067DE4FFB1482A789DAB8807115EEE71324839BA85E80 +:152C3700963C68BE91F1E7EE32FC8481300177A193D733E374C9 +:152C4C00BFF0632179D61D39A7FDE51772EBFA59A7D61FEFD3ED +:152C61007E5925DFD14FF6DADC44AFDEB3936B3D0D17C55EB4FD +:152C7600927ABAFFB645E59F11BA5B383E8C9824810509C4C806 +:152C8B0032E627459FAC182F3EE8A37111C3A55AC6DEFBDB8611 +:152CA000B41AF18A5F357BC6B806FF415FF22095DB0D3C8B58F6 +:152CB50057A5A9A7CDF9A9AF9BD5849BF9D4D7642EF634778BAF +:152CCA00F159ADEE16BEF1A20E85236E9FAF54FDAA217CF63673 +:152CDF00714EE50CC806393662D4A7BE437977D358E9A579EE05 +:152CF400A08E3A3D6787442CE5B6BF60AC0CF62FD980885722D7 +:152D0900AFDBA5539F0E78D6EDD3B7E4B1A9E3631CB16EBAF850 +:152D1E0057DE92BFFFB424E82262000553F033EA177E46C029AE +:152D3300E2FE045942AC5F8A78669FB77CBF906E8EF56AA5A9CF +:152D48005DFDE1D4F3496505D77DA403E7ACE5BAAC72D3EF4371 +:152D5D008CB783BC3AD2B714EBBE25EDC43FEA102F8DE3F709B1 +:152D72003364FF464C0D4BEE937D9AF2D7210DEBC2BE8CFF7CCB +:152D8700BF8881E3016EC67B8D2A4107EB8CA2447637CEE55AC6 +:152D9C006713AD3DBD37A92E896000ED413FA9EB981E5AD069C0 +:152DB100EE8F58E7DA104346FA032EF47445D0D1107E6A8AE003 +:152DC600EBE78E5F1636449788B723A748868D4F0A3C07C84604 +:152DDB00F60B1F837E116FC72362565BBE6BCC78CA443C46C088 +:152DF00029A5BEC2AB539FA875CB76C874D04FC8F58C4C27F975 +:152E0500BE25B72598FA8D29E22C1E07FFED32F7FC2E5D520F81 +:152E1A003F3B9B06C07130B5CFF0F05E3DD068C5BCF3906C4040 +:152E2F00DC763FEB5DE2271E99C77A6B41BFAD2EDEDC6AD1C9B0 +:152E4400D88E7BF99556C15B4437FC96C5B982B888E3047A8367 +:152E5900BE22361FC632D1733A2D6551D6A2C387E1F623D3083F +:152E6E003470E3DEA1C7C7A04181A041BF1DE7284B8B0FA58182 +:152E83006B6E75F03FF62DC4A72C0ABB69511CFB64ADB04BA3BE +:152E9800EDC3D79EFCE452259647F368BB01DB13B28A7F25B730 +:152EAD00EEE2BF38F2C79217A544ABE205DC94A84FA01DFA68E6 +:152EC200C53AB2DA407BA83B130F23A31F59F42873D1628780A9 +:152ED700A7CB3AB740EF11574B49ED33253521F808BF35D77979 +:152EEC00E0A0AB7CF0F399F8E022AE783F1B12FB163ED0BC7DCA +:152F010048F3AB5E218B15F007C99EB288257B32E38EFA2C6D48 +:152F1600C1FC4BF735E7040E689C06FB7F6BF53735EDB313D89E +:152F2B00A3290D75B596D1DCAFB2E4F1301B3B1E61A9E3D72E7F +:152F4000A4F3E93E4CBF87297D58B3CBDF2CFF9137A7E6AFB6EC +:152F5500F3631E1FFD8DDBFF14F32C8BBACB8AB8C362CF8D1B4F +:152F6A00D79F94EF6882BF8B3A1AFFEA99535A2E9917B2DADB5D +:152F7F0085B84805EAAB5D38FF68F9838F8933508A3A42764A45 +:152F9400C2F0A716D5C97F93CE071ECE5E4AE74FAFD30D9B3808 +:152FA9003B48659BD4678CC99F71D2890C1173C9E2C33F330520 +:152FBE00EF5AB19D267A483FAC233DE8E3F0E6C4CF7A8D84A7CE +:152FD300CB6047E496899F7133E1E9379BD41EF337D7313EE251 +:152FE800B62DD26E5E86EE13361CBDD48AEB6E1C34A0034B3494 +:152FFD006E003BFD3677FC17D2FBC25113FAAE83B39387B2F8C4 +:153012006EFD7516BFF3110B22544A7A79BB7196E0DECE629CE6 +:15302700A5C2FDD88FF2A7AA8DDCD3B5FAB7E28B6B3B972D9B72 +:15303C00A22BE631F8892E13FA539EF428C98F35869A8AF63372 +:15305100E557A6CF57A9C3D7D4D213172E2D205BC453AE8936F5 +:15306600105F167AB6B7BD562F8AD4D617509B472BEE5C3A3F3C +:15307B00A5D25C576D94A6C286E46FD43B9FADE5DE31B2FBC612 +:153090009799CE1E37621B0A5D5D6927FDB1AA56C65E6AF49146 +:1530A50061663C7CC0D785F301FF49DC53CB3D7764D7834AED9C +:1530BA00B882D5B69C0A939C5AA6414F9FA74A61118F54C869C1 +:1530CF00B241A83FB22B2695357F3E3F5C3676502FB3D7338382 +:1530E400340F63BE65E3AF9801E9B25E5759F419567EA695B16D +:1530F9002B5C61FFB03428BDABEF53BD75D005C32413E74B43AF +:15310E007A49E864AB2FF20F4BE6D3DD73AE4FF8AD601D6FEEF2 +:153123000AC4C23B69FBC7C4F9159AD78BE327F4C07CD24B94E8 +:153138008EE18FFA3F97746FDCFB97E7D517C7F2C82679C5604B +:15314D00A9E78FBF41E3687EEA6903B24AC411A0FE07683EBE55 +:153162005AD6BB2442BA0CE69B07BC86D05F7EFC0CAF75749694 +:15317700ABBF4BDF546719FEDFE99BEA2CCB6EA6B344DFE129A5 +:15318C00E7FC27640CE1CA57F985A505620F0F783BB53478FAFC +:1531A1001754FF29BE9E70B77F99E19CA917780AC54732780A6C +:1531B600A516D5FAAE604FB963587EFD14E473685E6A562DFD13 +:1531CB00368A5325E25E905A20EE06C9F199FA4FF369BD67F568 +:1531E000BBFAE56B691FF080BED6D87D9F78DFEAFBFC19FA8E7C +:1531F50032C3D73E7EFF1710DD4B2147A33DFD6DBF9966BF5070 +:15320A001FC55AAA8B9E6BDD79A27DC63DAC9F6F201D3DF78709 +:15321F00BD4B54F5345920295E2C91DEA55C3083365FCA381F10 +:15323400A4FCC4DCCE2EF280745587DCBB65C5BB7A78EC3BF5FD +:15324900B73458F8BC85BD63F975517BB7C05E095F143805CF3D +:15325E00C1BF133EA2E5296F9D9367EEE94B19BCCFA5B28ADA53 +:15327300DE1F2F4CB420EF56ECE54447FA117B31E7CC29BC3BCF +:15328800E0397B4A37D26427D1FB6AF50B4B71073C93CBF3EE4B +:15329D00D8F6D04F491FFC89E1535F3E50A3FEC85C3669F73195 +:1532B200BA6BD88FF8AAC9F5DC7A86ADB46BF8CA72ABFC49C28D +:1532C7005BD0AEEBDAF2C796DECE5EA813B68E2B2FCAA20E77B1 +:1532DC00B9B394A7E3A90B5A58FD8F4B908EF99154E5CFE1F98C +:1532F10019CC91D15D49E89F285B803D65C225BE1F33BFE7B062 +:15330600C0EB3C957402BBFEA229CF736B3DD6737F813ABB967E +:15331B00EE86A7C8D2CB51BFE7EB7B74A1037C876405E9576696 +:15333000E4794D8924F4529A3B443C16C53A83F361FF34A7745C +:15334500495DEB75F8193265A7987794129A3FEC7947CC41785F +:15335A00F731E61F67EEB1E7A119E71FCC3D9883EAC599FBCC51 +:15336F005CC3D5316BAEB1DA5159A9FA2B730E74099A977C6AF3 +:15338400B7B9E5BDB4AF20C9BB0A08EEFA48A2CEB1FF4A691EE8 +:15339900439ED5EF39F4EE349AEA2CBB716254BC37F03E4CF834 +:1533AE00417996BC6C486557881F39D98D5D3C37998817533BB2 +:1533C3004A72A41F632E27758AA34EF01A78AE5AFDD901F0D4A9 +:1533D800C5F71DFDCC8699607DA3E7591AC3EDC6D65F58F3BB94 +:1533ED005897A5B6467F951D5F8190E5EFE1B3CF1924432C9F18 +:1534020074CFFC2B01EB77DCCBF23748AC707B0ECBC77986F8A2 +:15341700D8D46F3B4DFC2D4D4C1711129DBA46FF6DF46FD0FFC6 +:15342C0030FD8FD3FF04FD2B3FA2F73FB2F28ABD83A0EAC46896 +:15344100E467C7F0E1884A1DB1F06F555B97B0FA5F755EA47C51 +:1534560015FDCF100EAE926CBE6AB2FA761EFB4B7B9DAD7E8045 +:15346B0027E9B947F5B62834AEC7DE465F470DC4BC14E73EEA46 +:15348000BB39DAA977F43BCA1FA7FCB7B2BDCDE299DA539A5FFA +:15349500340CF4433961C0BF36B4E298CE627B39DEA3EC7EF867 +:1534AA0063217634D5592CEA7C45B429621B7D601DC77851E412 +:1534BF005433F2A3CDB9A11BFDA9597082F7B2ECFEADF0DF0892 +:1534D40066CFECBF799A1AA43993D59FE216AEE1DB316CF5B34B +:1534E9007E888B36C73B0DAC81948C1DD3156AB7247E54878F79 +:1534FE009EAC4E4DC31A888FD202E35D7ACF84A7C5FDCE47EF92 +:1535130042CA7FD3FD64878E601FD4D97725F8FCCC155F697AF0 +:153528000CA57FE37B9C131A0922364775EB55BA7B953A1D3188 +:15353D0072FDB14A3397CA5C0BB142F9BFB61B56BC617917D2C3 +:153552000629CD1F1BA03967917E71B9749757E9D0C7290DF1AC +:153567004BBB903F5669E07C8D8A73A29426C706CC61A4D3B355 +:15357C00417C7B9164217CFC6BE63271C68307B23609CE1C5FF6 +:15359100F558F1B2B6219DE007C079471077F45DAE9C7F464330 +:1535A6003F4AE11BA48C709FFF98BE8E6CB339AADC92973A2800 +:1535BB00E2B610FCC5A114F2EFED90BA7B853F27CE18DE966C99 +:1535D0005AA2F82D5F0BC466982DEA1C3AE0A33C3E2B4FB034D1 +:1535E500292F918EDC589645F304DE0C9AF7AAE658DF8082FF11 +:1535FA00BDC3E7E373E0979EC8F887C9EAA4D95A427822B92460 +:15360F00137EA2F4CC66F0E72F25BC5BDF3CF96B737BEA6F0F36 +:15362400C897DAF5CBC553EBC7F744DAECFABDA1B156CA6B50E9 +:15363900DE7ED4B58764E75A196B3AED343E2254FF6AEE53F13D +:15364E001C6D853FB7447A2EE9C2A65FD5CDB504838C33722494 +:15366300A7F17D95F96A3B87DCDC537646C37AECAAD43F13CFF4 +:15367800FEC05C4DF724F1C25ABAAF4E7DA61FB410FEE76AEDB5 +:15368D00011FD5514FF59706587E581DE0169C5FE8079C388F73 +:1536A200BD92F475D8309EF258EB9EB2360DF23E42EDC4A82EF4 +:1536B700CA773C4AF7CDF41FA1FA733167184D7C436AB919A3B7 +:1536CC0076A2A9FDFD38F3B09ADA89AA3D070E521E8DDA3AAA9F +:1536E100D8676C4987403B84C0923D6549AD551D306304D7662A +:1536F600AA7F82F07335C00A7D54E632DD714E9EF8CFBC46CFF7 +:15370B00ABA88E8900CE1924F8167A7E35007E575BDFA4FB6AE1 +:153720004A93296D989EFD418B46D371ECA697F7525CDF4C7926 +:153735008B55B939C745CFB03A48B8867F31F68427699C0F9A63 +:15374A008A4A73DA349A875F9B2AAFE12FA284734806776564EA +:15375F00301C123057DF4DD38107E71CB78D7051CE386594ECF6 +:1537740018B4E4DCB663960C8AEE35E0D33217320A6B58888D3C +:1537890019957765DADD3669CBEF1E9249581B3C684A65713D24 +:15379E00E37F4678A0692F9FE62E23389BE5E3AC06D9408DFDF8 +:1537B30012CB273E32A89F8D7E1AC705EA82CFACCA63F9F3E96C +:1537C80019DF929195DDFA28F169BFC20ABFCCAA1A494008FC7C +:1537DD003E42CF09C5C26B39AB6A8EDA721FB240C04675602E4B +:1537F20088501E12E685CBE8AE282FEA997874341F5FA8686FF7 +:1538070084CFA788BD46F7ABCBBDCD0AE5DB5A7CE31872C60954 +:15381C00F6CC300E2798F50D3C278F9FF860A7FD9DBA72D5DBD0 +:153831005C4DF5E4975F213A1D9A820B85FA73167CA3DC26CE74 +:15384600D0EC8AE13B033DC613915ED1FFFC4FD3FC46F800FFDC +:15385B002D25B4416F7FB508E30EFD7AD1C01CD1C83A455EA932 +:153870002CAC77E663AD63C0AC72FAA5741B32E916D5E0BD40AC +:1538850017740503FE7E0AD581323EF5457AFF2B33BFC82AC7C6 +:15389A0094174DE0783BE5CF75CD5B6AD1D4F59B6B45AC3048CA +:1538AF0079268AC0F35546428C936A314EE0DF0499FBE6F5749D +:1538C4003EFC750AE289466FB45A57D54AE3CA72A97994CAD023 +:1538D900382EF4BAEA2FB6CFD665ED55D598781B01B576EAA8ED +:1538EE005B39FF7B22D6307CB5B09624931C95A9BE2292F7E8B6 +:15390300C7C44303F50FD2337CAD64711EC8D603E0E3F536F634 +:15391800F82CF8E5D810C9A4170D712EDDD255D3C53407E3FBCC +:15392D0055B2FA8C69CB9300BE0D09F926C33FC2FEFEC424D5C1 +:15394200F3E318F1606CC85E334EA7FF6A6CB0D14FBF713687E5 +:1539570045DBF9F642969F5B4934B4EBFE2DF5DDE90BD67050D7 +:15396C008785AB230257F0FB0DB1458D4E7F0AA80F93158B9A3D +:1539810071CE7372162BACB8981D3F326414D96517C986FC2802 +:15399600FDC4FE9B809FF409C0E21D233B3B3A4A750D4057248D +:1539AB003C7467FC45BC946FB480E5DFA30276AB6F778D250892 +:1539C000B735A60337F611FFC7B19F1CC5FA83A82F84B58C55BA +:1539D50007A03FE3BD903D36BEEAA7ED4F59E36515B7F15B828E +:1539EA00FD0F3FE5298EC9CD9B73B26347C9AFC1B7BB047ED1E3 +:1539FF00D6BCB141D2A306B1A79816E71AE9AF3CF242E3453F3E +:153A140070F373DD194F23F6F95EE80781F1A7F4C0F9255AB02E +:153A2900BD419F97929A049F19DD7C07CDEFBE50360E0960AEE7 +:153A3E00639F6A862E3096EFD0CDEAFB6FD177AA0BF97136C947 +:153A53001FB3E28A20CDDBB448C46C9745DC120BA6BF2298E058 +:153A6800DF081AECC7593A9A0333F44D791BA103CAA9534601AC +:153A7D007BA57132ED6D9E97F23607A7F58164880F78925343FB +:153A920037A72BE1183038FCE84F9D30FA52DE9650D3908009B9 +:153AA7007066F4D570B5A08B22F42AC0FD29EC41091CCD8B0F3C +:153ABC00D43B78D94C32D76BD3CD473A5451A5D468F5CDC2C5E5 +:153AD10075C1E30306C64D89DDCE3F52F98FD3DF85D4DFAA4288 +:153AE600F437ABCF839FB723662FF1815F75F529F6B2D117930E +:153AFB00B27D52AD3E59F850459F9CF3D2363D44BF0CD798284B +:153B100076E10E7A01F0E6F4674EE84A2BC9419A7F7F6EE6B539 +:153B2500D3F852F6F0373C969E087C6C60D9710F19B839730EAD +:153B3A00D7D28BC4B96ABBDC412A071E49A28C4B9E857F379504 +:153B4F00FFFDEA51923983FC4F2343B5CA8E11D12F5FB2D374B5 +:153B6400FA0C79017E2F16B1E59F35DDB20973899C7CD6EC230E +:153B79005D5321FB3E4032DF9F841CE3A6D5CFE12C9D934346AA +:153B8E00A8E984C04788FA60AF6F171440BE8AF1C5752BEEFC13 +:153BA30015D1DEC2152FB8C697859FA2D38322FE2F70F7C8C3D1 +:153BB80096BF2BEAFF0EDB4B7C3068049A3A6DFE1FCCF0FF61C9 +:153BCD00E27FC0073B05EB7C820F62E003C3E683D10CDFCFCFB8 +:153BE2009FCAF747057F0E66E9AF8E18A82BCBD3832EFA774D11 +:153BF700A33FE0D96BF537293763ECB8C70C7ECB49C4324A1863 +:153C0C004F936CB360B6FAB98BF8DAE1E110C1574C7CEBC07AA5 +:153C21008D602D2758DB7C37F2ECABBF01BFBAE08D11BC311723 +:153C3600BCAA1B5E4B36BAF502A5A953C0EBC8216B6EE8123030 +:153C4B00CB31CB87CF8824DA8A5C7362EADA541EC4B91256DF0C +:153C60006BE0FB53B01DB5FF952ECCF01FD92E6F2256C061F98F +:153C75004E2566D92FC591A33AA972C52595724BE07CBFE6913D +:153C8A0058600EDE8D8F18CAF9A426930D739CE055C8E6958910 +:153C9F00C7B0AEE5F321561CE721A2A74AB64FFCA9DE960EA415 +:153CB40077FD33E6910EDFD953629FF44AC5DE3BD8F8A8618648 +:153CC900A516D4539ED88B98C1C1B988EF41E9896EEC77ED3513 +:153CDE0065AA0F7B61E237B52B8BB5FABDA62887B68CBD387FDC +:153CF3003CA73C2937B65B653AE26413E16C936F2DD785BF237A +:153D08007C526C9B08B0A2FE9DABB996B36E528FD370E9FD2C8B +:153D1D00D7D06799CA94278E6D02FC98CF010B60036F2E2318BE +:153D32004ACE9FD4E662CE7FFD59BD98719A2F92DAB7302FD91C +:153D470075E2FB086DD4579473FABE8BEAEFDA7742F851827F75 +:153D5C0044DEE84887AFFB9FF51460A33EA12F6CF220CE5EA6C6 +:153D71008107D29D39F0B9142C4BEF1D5C5CCCE0C16A2B830789 +:153D8600ACDF8D5B78087D576EEC5A873DC921DE4EE9BD185FB6 +:153D9B008413A4C13644AC330BDE538483631AEACF59F76B7D0D +:153DB00087C0C3312D40FD030E149C3BC6DA3BF4326A0B310BAB +:153DC500C3D47E39C941271EA1751E24CED93B8CED29EBD2DED5 +:153DDA0023DD754198FD61952ADFE5C45B1FFEBC88472874DE64 +:153DEF00D5C2AE5A7420286268EE16DF804059E2EB7CFA3D8C92 +:153E04007DC0F17F72C5B3251B113184845E087F7AF8A685976F +:153E190071863C4ADD01D249C6E2D5DE16C957A3CB91C5FA20AF +:153E2E00C18AF80B48AFD0FA750573907A6FA34FFDA346457D70 +:153E4300A0598EAA3ADEA54847C77DB3388FF4E722966149836F +:153E58006A5AF51E860E34B68CDE5568861E8E0F36D6501DD54A +:153E6D00544795FA40A35347A9783FB58DCBCB1F10F5FA45BD41 +:153E8200BFEA70F25ABF0F1B89E57D778A33DA0D13565B510BB7 +:153E97007EE0EAACF0EFAF36A3948E39F62A6385D2EAC5BA120B +:153EAC00818E68F793F20D8A7C61BE01E58DC526F28ECD90178A +:153EC1006D6F07ED92569E8337C9B30163D3CEB3FD2679C294B6 +:153ED600C76FE7D9302D4FAE522FBE37847CE095ADCB7F762708 +:153EEB006425FA21533F719F43F2DCA79AE64CEB596166FBCB27 +:153F0000638C2A8363D86F147A0B3DE34CAD88371B8D0BDE2D37 +:153F1500B1CECE67D68424C9E2B74CBD549FEAAC1F093F34B224 +:153F2A004F7F90C3B07E029FEF94A06FB6BC150BEB8881746A9C +:153F3F00D3AA9FDE958C3FA707CF3FA7C1462DA1B1126C1A1181 +:153F54006397F836A0B013F598673FF7560E53E3234B133497BD +:153F6900FBC9362A461F146E5A3E6FC233A400318BFDF1634B40 +:153F7E00A04B237F10F53B700839DE65C11749D48BEFFDD9F533 +:153F9300CE8F0F2EAD99566FC60EA6B941949F617DE61FEDF10C +:153FA800877EC15626788B2F63DC2855D9F2EE785B347E71160F +:153FBD00EB9F662877745A391A9F379C27B4CA1FE23F9FA1FCAC +:153FD200D68F50FEDD19CAD57F28BC87F89519CABDCF3EBCBDF5 +:153FE700D434FD0AFC1274F31FD6D5FFC9F54DBA19DEC7AF7EC8 +:153FFC00F0FB890F7BFFEF5DFFB4F77EF778F8A0F5D6FFFFFE71 +:154011005FF55E71E1BF789A7CFA7F077E9B3FA69D399A78FFE4 +:15402600C6F1F061F5B9F94D2A3BA2F779129B3F2ABF61BCCE52 +:15403B009155FE79711EAABAB553896D5E49C3DA1FF8828EF8BF +:1540500077F80EB8FFEE6E1D631E3A823FB0459FB5AA5B57D5B8 +:154065002FF15977B7EBC1755CF34B957AB0A8524F90CE66CB4D +:15407A00874DD7482F5102D53AEAFBD7D675680DD786E173B5CB +:15408F00AE4A877F33BC776435A7E57192F925FE4ABD605D8D23 +:1540A400FEF5358BB58A758BB5907FB3DE99F37B1AF6A316C828 +:1540B90031C4C70922AF2C7D4217EB40ABDA850C822CAA284A4F +:1540CE0068F08372DE178BF78B756F202EF4DA8A07E3BAF0CFA1 +:1540E3002438CFCED0FE4ABBFD426AFF10B55FE26A1BED9653F3 +:1540F800FBC827EAA5FADD6D5FB3EB9D70D59B4EFF34ED474C7B +:15410D00C55AD6B29E4C18D41DCF8971E022CDACBA6EA7297B4C +:154122002EE1C54F6DE6AF5D4CF8A9D416F86BF4F99F965BBC93 +:15413700AC7D63C51FCB2D87662704FEB12E457378106BA2B712 +:15414C0009DD240BBB881D01FD90C59F147D2398CEDA308DA2A4 +:15416100EFFE0D7AC5BEF5BA54E4C096BEEEC0D648B095FA2B21 +:15417600457A9C14638756F94535BA5FC0D4AD2D284AE83D3BB9 +:15418B00F764F80078FE6D3A6DC3C0443F71F6CEDA779D78128F +:1541A000ED8EDB7048655DF8269C6F36B76008ECABD203D41E5E +:1541B500FAD662FBB8C3394CE0252F8B970AE29BC2B54D7AC9E4 +:1541CA00BA7A01CFEE9C6EAD80F052E84FE8B92CB1718FCD975C +:1541DF000B45DFB3ED5EA1B60C7A17207C11DD8B1D1840FB8A9B +:1541F400D51B34D8DC15EB3668D3E94F83275020CE13B2828A7C +:154209003307C57BE95C8D5EF2604C97D997F45994E780C44203 +:15421E005EFB791F3D17AE23F8884F0A8BEA75FEBD06EDD0EB49 +:154233000D5AE1B9B57A09A7B47DAB74FED97B88DFEFD140FB92 +:1542480012C265C55A0B07724C6A51D9165E4F38F34A0FEBFE75 +:15425D00580E62F807F3B15753BEBA7596F4A8EE9757EAFE153F +:15427200D4D6DD8FEBFE55F7E87B73566A5823975764F3E7852A +:15428700AC3324227FA2D6CAFFDA1775FFAB0DFADE9DB59A97C5 +:15429C00E6ECC0F7366B159FCE69C177627CF1DA8DF9630D1B06 +:1542B1009FC6B78679AD5E71EE615D3ADBA073CA2BF9B2F8DF16 +:1542C60086311D12674E362176B4AF9DCA9D6ED828ECDA65ACCF +:1542DB00253710DE981758B6B1A26BBDB69B6401E982C5BBE8C3 +:1542F000FE879031FFF331DDBFAB41870DA1AA8F72B16F98F838 +:15430500A22EADFD922EDEBDD640EF6BF5BD842FD01C7C0DFB89 +:15431A00ABE09B524BC539C21F6FD74BCE7D512F3CDB2DE8DE86 +:15432F0043749F45F42E88F08D6E39045A835EC25FD7A623F818 +:15434400F06E82A505F0138E11377A1D3D2772B66AB3A81DC03C +:15435900DFB9D37ABEFB7ABA0472C8F98DBC34AF6C3A4869289B +:15436E000B7E36C98C04FE20E7C8BE9CE3F0D276CA237CAB09C3 +:1543830086ADF41CF8DE7CADE26C29E1B3549F896F7EC9B27C78 +:15439800F377CCE21BE0BD80F826E4DF2A70F1759B77C03725B1 +:1543AD009CD2A6F14E77FCBEC70A425B8826B1D66EF6E863B372 +:1543C20042D156C9FFB8EEFC2E8C3CFA186833AB7DFD46F67A95 +:1543D700CB46E75EF1AE477C1FA220BE7E63E158CB46299FE89F +:1543EC00FC894AEE25DC5F277A0367B70BFC7B5A0A7907E1FE98 +:1544010071C2FD1E21B7DDF8CFB1F19FB0BE4B11947C9FA0B6CC +:15441600A39BCE085A8057A29B46A7D102DF6D7BD0A605C9D76D +:15442B00E2F52E5ADCEAA2C57BC287303B8677D2F8ED75D106C1 +:15444000EB55A03BD277D8F4394FB471E8B1659AFFE787D1E3D1 +:15445500828B1E7F65D30363B8C4A6C50D7420DAB86991177966 +:15446A00E4B1DCC8FAC7D876D6E21F7B64E32C65CBC63CF69F69 +:15447F001F2B88FFC946FFD8A3E277C51F8B315AEC67F43BF207 +:15449400258177794725F7908CBD9E17E5050EDE696C16FA775A +:1544A900929CBB5F2F5CFBD414BC17CC84F7AE85A0B90BEF3177 +:1544BE008177A7BF6EFC936C2FBEDBC63FD67C30361CFC17BBB3 +:1544D300F0EF116B37167E7B6DFC164136D13BEC33BBF9DE2957 +:1544E800FF4B21FF2D9AA19C887B69D3C1C279FD14589E408C43 +:1544FD00AAA4D48273D5099237B954C72304C3A17B37EB15EBF0 +:154512009A34256789969773A7061EF693BC61AF376C3CF4031B +:154527007A776EAD569CF3592D3FE70FAC77D2CA8D6CCD3D1BF6 +:15453C0077C73C2D806B2170522ED6B603B9AA47CC8548473C72 +:1545510037C7A641FBD89BCA71E6687B9E403EF80E03AEB7C9AB +:15456600ECA43C99F1FE1A8D77CC5117D26905EB41D003684EA5 +:15457B000BBE6AE7FF163D57BC2BE35E7CD2EA77C1FF01EF9849 +:06459000C0E6B892000035 +:00000001FF diff --git a/drivers/atm/pca200e_ecd.data b/drivers/atm/pca200e_ecd.data new file mode 100644 index 000000000..eca84aa7e --- /dev/null +++ b/drivers/atm/pca200e_ecd.data @@ -0,0 +1,906 @@ +:150000001F8B0808AC5A10380203706361323030655F65636428 +:150015002E62696E327D00DC3A0D7054459AFD261333136278A4 +:15002A00192663E02479728060A10E9063213F64F0700F3DE05E +:15003F009E6CDC7B2F3514B35EF0A28B9A5A731E554B91474C5C +:1500540034E11AB6692618B7609D8404A2121CA8648D7551435D +:150069009DA578A56C8AF276A9AB829DF3AC92DD52CC5EB177A0 +:15007E00D4CA32F77DDD6F665E263FA25B775B7753D5E9F7BEA8 +:15009300FEFAFBEBEFFBFAEB7E79F4A91F6C270A21A1870849C1 +:1500A8007C974CFA8536C11F37B9A99FFEAD9C49302569258321 +:1500BD00D8EF4EEE6E14EF59E3B3EDFED3E3C735EC67E50822CC +:1500D200A9FE0FFD29BF7CEA97A26F4EC993D537AF13234A5E2D +:1500E7005EDE94F3BF245F4AFCF1F129E7CF9E866E0ADE2C3919 +:1500FC002BF0237F849F3240F688FEB5EC75792D39E3BCB43E9B +:15011100C9A9F54BDE24FFBC9C3C6987DDCD33F3938CB0674E4E +:1501260078D6F8D7D63FD9DC8CEEABDC4824B2F9DC949E391965 +:15013B00FED7BF11FF975E7267F17D1CFB4BE77E3625BFBC0C26 +:150150003F0FF9BFFF5372CB72671A1F3D3EF99DF51312ECCF0D +:15016500C070095C0E5FF8FFFE4B3A7E246851FDD31C5230FA46 +:15017A00FC0A35E009832F79ADB5E45140A3A4743C8CE3E39F62 +:15018F00C35BB09DEAFF05BD7A95BB3DADE6B56DADE538465425 +:1501A40052C90E11EF08B4773A8857FB013CB7112F090619CEAC +:1501B9005B125380AEB695F80197D874FE9A9022A5D554ADE572 +:1501CE002661CA73EE80B5F5F26AE22D7F9A78FC814838484AB5 +:1501E300E8B36DBD4D843D4C4930CE42B06FCC091861CFB9BDAD +:1501F8002621C3B438D010BE6DD7091AF29090DFEA334930C6AA +:15020D001187E86D9CB09E2EDF18033C8DD220A9BB6D57390DB4 +:1502220011D2D8B26F23C02CEA0FAC0EB76CBADB3C4F48F1BBF2 +:150237001157A5EBD25FC0FCCB804A3412ECA211D133EA167DD2 +:15024C003B8518510311A53A5FDD62226D9C4BD46AEA567ACCA9 +:15026100362DB78EE8A7683E21017F201E4E927EEAB6169944DB +:15027600AFE1ADE3AEBAC0C53534B0EE4194CF8AC2FE47C6065E +:15028B007960DD5253D1FA6834346000BC45C0D909BE0A681025 +:1502A000BDD7BA4BDBBA12ED8A7C09EB8EA79BDA6BF9816681AC +:1502B500F70EF3723259F4518D59F578B3AB0A66E7A3597F0E69 +:1502CA00BA90E04E5BEEC669E5765D2A33DD6762936427C1D5C0 +:1502DF005CDA40CA8A7AA03EA807AC0147BBA02E52A72974180E +:1502F4007B956F461DD851EB3EA14348C8A0EA9689F2332DA72B +:150309000E7B941FFB00D8FFD6801526637B69AB8FCC22A5F03C +:15031E00ACF65863355BCB4740B7F5A05B6A3CEC239954156CC1 +:15033300E7B09E9AA7F084F085DB760DD171378910B6285EA406 +:15034800F64A5F403DE05D8BB4C2F800BD8EE3418BAF06B8AA3D +:15035D00EE81F5E96393DE6D3B92E0385D564748698085091946 +:15037200A79EC256E0D34F49792B1D759310AC032BD6FBCDCEAF +:1503870038D845EFE5456A87F95932097ABB5B050D98BFE30F8A +:15039C009CDF2BE6B767E667E6C6EDC6D24DB7E7A56AA4888777 +:1503B1003626DE3B6D253EE5C5810BE19CD8095A7CFEB241D8BF +:1503C600765A663C6DAE8CBC4EF7B70D35420264F51833C16105 +:1503DB00A6438F32018C232C303A64E29A23DCADBDCAE604CE52 +:1503F000C2DAFC0BE48392B027D20C3E546386122FF0964DDB3D +:15040500C0A7BEC35A366D323B120AE8B357F8531ECA1ED46DF0 +:15041A007F6AE732A6800FFA49302E6321B8C48EB97E560BEFE0 +:15042F00458110CC6910FE9B84D825C10415992A67940623CBF7 +:15044400E9EC584E5DD1912DB4E84C9DA9C486689188ABB8F0F0 +:15045900BD43E494A124DEA49DE43503E75D87B4D6F9E7F81CCD +:15046E00E748EF05F296419A062866F84EF23AC04791363CBF24 +:150483000BCFC31CE5D213EF71C44759162BA4E81F2077148DF9 +:15049800DE677E1BF429501F117ABAB5A3E037FD527EFD21DE68 +:1504AD0072EB2653890C502FC844D803BC937403BD7E2113CE66 +:1504C20027FA51FE0EC4AAE7DCA04906DB38E62BF04FDB0E52E9 +:1504D700EFC24B09339A731CE3886F2C203A191CE0A344E0591A +:1504EC00183F514DC49F88258C471F213EC2FAAC68A8CFB85650 +:15050100D6535DAAB92A3CE7C0EFCB0728CC6BDC33EBBE3AF4E9 +:15051600E76BC964B19EF8949519FF64CE568E091F74150C995D +:15052B00885B1C83D82FEF43FCD0E167A306513B39C4E31CF4C7 +:150540000131A6FE965F4D26FD9E7387CD79E78E9AE46AAF90F1 +:1505550009FC2A0E7E2562E5D1C8C62AB40BFA87E7CCA98C1F9A +:15056A00E07CDB0F02E0079ED07A136DD5DEE892EB27D74DDAA8 +:15057F009075F0D47A1E222F1BA9F524FAABBC1763C2F6998923 +:15059400F69376FBD1FB4F007E4396CDFA85CD8A1BD166C3B678 +:1505A900CDE268B322323660755A03C6B5E64D2B053DCC1D2390 +:1505BE00D266445F1497ADAD0B68E03E15BF6D6448D8278AEB56 +:1505D300C80678BEF73EB0C30FE947E092E01FC585095735DAFE +:1505E800F671D7EE55CF245C958188AB5ADA037C046D01BEE121 +:1505FD00BAF4A9E9518E9B1D5AC626FE09B121732DAEABB48BBB +:150612008C15B459DAD7B3F32CC428FA34D7B6547ACE7D067369 +:15062700345B4F0631B39A266B102748855D9AEE95FAA9DD5677 +:15063C00D4EA35EAB4875792D2583897B499FE5D3F12FA91FA31 +:15065100A3343AFA18E487C7B823BF7489DC027E87B620FA20D5 +:150666004FD1F043DE9AE5B0C528F877AC664BD58D1BD21EFFFA +:15067B0059BA7B79AD423CD23EFF6EAE509A67B0CF7B609F6360 +:15069000FF23F63989F6D9BCD64CED8550E85072F557D21EB076 +:1506A5004745AD6EE339DB1EF3C922D37F7DA9B0478E5E629653 +:1506BA005AA5D57F827B8FBE9F46125FF04F66E1FE5412866761 +:1506CF0086F945D818ED469ECAF8A08A7BB46860BB6E87ED4EC3 +:1506E400F114BF6CDB45C1764D60BB8F6DDB5D00DB21FF8083E0 +:1506F9007F83CD7B22DFE3C67E6F5F26674C9F2BE638724555DF +:15070E001A0F7DDA111F0B20A778361F4BE710B11F8EC13CAB3F +:15072300CFB85A932B64C35C82792494788F611E51E60E9B4A3C +:1507380007E413987728E1C8273927219F0C603EF1E1B81893A8 +:15074D00F9A4D8B3F9A4F963E02D724A539F88D97980873AFBA5 +:150762001C3A37E59359CE5C33A1781D3BC1DC9B7BCDA235ED12 +:15077700A29E2C523E379B4988CE17BAF7F3909FE8EF821F7925 +:15078C000AB11608D25AE1474B445DF7FC5CCD20E5FB68A3A870 +:1507A100170E70A2DF010DFCFD7FBBF54429CA4C9ABEA016F86E +:1507B6008190DD315E0F7E5103E34F925FAF825A94A30ECFCD41 +:1507CB00EDC7BD45FA3FEA06F6167AA890B7BE6EEB8ED2E275F7 +:1507E0005F9819585F7C7324B932C5ABCC90B5C0CDF0B262939A +:1507F500695544DE16B4F419E647605EC90313E7DD13D9B652B6 +:15080A00AE1BE31B70DDEC7941C02DC8C25D1129B371352AEAA4 +:15081F003D7B5DDD02EF009F3F4EEA549887F684FAAA68452469 +:15083400AF42D45290DF570BFC56BA0BF015C4D73BF911F04B90 +:1508490037E243DE03FC62DCA7D1977CA206EDE5CEFA7063BDC6 +:15085E00A3BEDB4CC197290D617DA68BDC791A7B55055EA967AE +:150873000D7A477DD7EA98BF20E2AE48D57848C3FD00350F601C +:150888007C421EC69849CFB37FEA060FC6604F20B001CE496318 +:15089D00F45BB141FAE3B6A126DC2B99A8E7346641AFCCBD0C5D +:1508B200FC9F80B3D24E383761AD1C83FDE1320F41BEF0EFBA70 +:1508C7005F9C89FC501BE39EAAC2D98AE8F5D48775DE582DD4FD +:1508DC0079C130D653FB649EE04837404E899AD0B2CF592B7220 +:1508F10048F13F47DC707EFA7B13EB3699AF0DFBFCA4DB755C24 +:150906003B75477AA046AD605EF541B3E5D6BBCD36A0A978FFF8 +:15091B00C6DC8B750C9CBB3007DDB2E7553337827B40B7D80387 +:150930008A033190A792DF42FECCF4C379E3167106B1EBAEB1A5 +:150945001EEEC7F307D45D9DA1DE74BD05671CBE429CA18E43BC +:15095A00BE5B682CD0CC95E2ACA1F6C4DD381FFA828EE5E21D9F +:15096F00CF4F17DE36CBDB9B95EA476A72D279D11F53A6CF9FA5 +:150984002F7597077ACCF25BD6C49886A7633517D785EC80E7CC +:15099900C4DF12320AAD0BDA4E683AB425D008B40B301E87C6CB +:1509AE00A0E9625E4FDC6EB04FF43059BBFD16CF2CA13DDE56FB +:1509C30043BEDBB50EF83FC2317F3629F20C3409C7410F71268F +:1509D8008F2F88CBF60A4BF1D9381D5E9ADF82B8362D3FA475C3 +:1509ED00BA4BD293F8E3643ABE8067E39C2533D1CBD03A3C13A1 +:150A02009E8DD33425BF89326D9C964E46A68553D2C9D040BBF7 +:150A17007F55C31A995C3D2CF1C7A25CE40D8CB1E29881790360 +:150A2C00623586F12B629A58F412FA289C3F647C34424C9608E5 +:150A41007F9B2E4E5E8138715DFA8579CB9E939363247D66979D +:150A5600B181F1823501C620C60CC64E3A56ACA39958518FC96B +:150A6B00B3FA18D457D69F1A6B2156F09CCE223913E224153FF3 +:150A80001F431E9A8D7990EDA5175CF2ACFE817D7D38027114D6 +:150A950081380A7D8D38DA6CC751C3639938FA009E23DF07232E +:150AAA004223D0128F43850E8D416B8016825602ED1AE0753D49 +:150ABF0036318EC41D03C412CAEFD9DF938E27E09B965B03B992 +:150AD400F7BCFF8A21C70726C557AA05537E9F8DEBE047317E33 +:150AE900DEEF81F157441D23C75BE2B2C13A3649FEF5022F9BEF +:150AFE004E8B23CE5AE21F91E9F8B54C8AB35E320D3D874FEF6F +:150B13009A915E86969EC69B420F382B230E9D92DF4499668A69 +:150B28008D7A32959D60BE4D7FE194E3683F394E74A0F3154D74 +:150B3D00CE4DE17F988EBFD4BA8B38D4FBB846C8AC542C4EA83B +:150B520027713FDF91D98F156FABA86DB78CB65588BD1DFC5798 +:150B67007D286614EF1AA4BA479E078B77F5D28847D6AE88CF94 +:150B7C00B0C665526784B9B260E38E7DBC445B88674CB6E10A5C +:150B910021EE75DDA61F635A2DC718F12B780796AE33FA999E1D +:150BA60043484524B702756A8067E58101519721BC73FE108595 +:150BBB009862B92AE8AF77F3DBB513DC1D6B73DC635914F1AC84 +:150BD00087F12E56D25A75B3B4622F6768017E1CF67CBF1E338F +:150BE50015C85F985FE2F23B9EE0F375F4B11CFA743964B06EE9 +:150BFA00521FC48BD74A7D2C873E5F492B4B9FC12C7D06BFA10A +:150C0F003E71873E671D32C46F521FC44B7C47EA1377E8F3954C +:150C2400B4B2F419CED267F81BEAA35EC9E8B3E44A460684DF02 +:150C39008C3E88A7DAFAE0F3AA9BA595A5CF48963E230E7D4207 +:150C4E00F6FDA61A180DA77CBCCCA066BB897CA58FE0FB4EFBF0 +:150C63003D6EBF37D8EFC81FDF0DF11EA3C29781C7CE1CD1D360 +:150C780041FBBDDF7E1FB6DF2FD8EF23F6FB6AA0B3533BC6C47E +:150C8D007E0B63EDDA49BC1BE40C9EBBB49FE2F99F8FC273BFE6 +:150CA200F6160B698BA97DE6E61ACC2B857D695E24B73A10CB76 +:150CB700ADF62572AB3DB00E78DE451DCBB597059D7A98BB5EAC +:150CCC003B25E844E1B9567B83E1FC77A41C0C79D66B7B98A408 +:150CE1006BF18540B710724F0D394B4F6F3BB916715096422D36 +:150CF600B702613FD9F653011B75C0F66E7B4BC050A614EC99A4 +:150D0B006DCFAD4DD15FACC9F5433AF3C4733FABB7F9A34C0FC4 +:150D2000960DAC49D14CE122AD146E4A5694ADD4C645BAF768FE +:150D3500B9D5381EB56DAA3D216D1ABA22EF6F904789BD3FE19D +:150D4A00B8BEC3392EF9DD65D358286174F44989B3DEA681BC57 +:150D5F00FD4803C6C69FC88C55D9760CC3F846B01FDA8EC2739B +:150D7400583BC0F0DC392264BA2CE4DCA1BDC88E08FB76F1DBED +:150D8900AF0807F47DF7466E65D9853BCDCDA56F2C7F612C6631 +:150D9E007C7B2DCAD12E6C940F67B9556BDD952B4AF72C6730C3 +:150DB3007697188B0B79F363B915F3DE7257064A0F2CE7305641 +:150DC800B856CA8FF6CA8738B9F17B77E5EFE6BFB8FC208CFDBE +:150DDD0047756E753E9C577F7DF1F32AA4F9F17C5A85F3FFF557 +:150DF200C86015E29EBF78026AAD06C113E48F5BA22F113283A0 +:150E07009E715DF43B056D120CC555D1370A39E07C18C798B8BB +:150E1C00EDCC6553F93002F1F71A2D10DF7F625CCEBBCC6B45C5 +:150E31002F6D4482116E403F67DD5153D9F47DA8B3F6D15B712C +:150E4600AF04BB49BE31DE2AFA06DE2EFA2E61CFBC3D80BFEF5E +:150E5B0069C0BF9B16068280AF895C26F2ADE81BF9B0E8570B92 +:150E70009BCF3A03F81FFE10F037D1D9011DF0435CCA1DE37EDB +:150E8500E89F15EBB093975CC9EC6DA454033C43ACCD23B0367D +:150E9A008DDA7EA606C6007681AE96B6E141D15FE0E5D037AD30 +:150EAF00245E1674D52944A3FBAF277DE84B3B005EA01D83BA29 +:150EC400C112F6CB81B3F8ED77209E8C2BDC2B1FB171D1DE7613 +:150ED900BC517CDE0D3C55EF0766EB9A98FD6DB39F22BF48E2BF +:150EEE0067DCBF6B08EB5F529F789DC33BB340367FA8CF54BDFC +:150F0300782FF021776B43FC9315B63CDA1DF4C69792C76198CC +:150F1800AFDAF2305B1EAA65E4C1BDEEBC8D3BEA9067740679E9 +:150F2D0074873CB5200FBC3336853CB50E799EB4797C807164D6 +:150F4200CB336ACB73BD2C230FEE55F7D9B8E86F2979F0793A72 +:150F570079420E79D6833CF0CE6253C8F3CEF28C3C977E277943 +:150F6C002CBB827B9A940779A03C3B1CF2E05E735AE20A5E2E36 +:150F8100C8ADADD57DFC7A32994CE55867F917D10659443B01F6 +:150F960039BA96AA810DE1CE35FD14FF4FA873ECB821758973F1 +:150FAB00DDCE291BAFE0A505F1791CFB6658EB6539856F9A5A59 +:150FC00002CE58E939FD7C839D8F53B806E04521B67D901B9DD8 +:150FD500F3752DCA6A81BF017218DA61689FB1466D21DBA92DFB +:150FEA00039F2967ED5A15ACD57A56663C627272B07149A28F90 +:150FFF0046ADBEC62EC08F6923AC5FA3ACF3C8095A4C06CC398E +:151014005B8FD0F9173FA3AD5BEFA46DF397D2E7B62EA7CF1F57 +:151029005943DB2FAEA387E69FA6783FF357BFC8C198A6F8BFCB +:15103E00542F1C7993169CE9310F5CDC07F5C0BE554EB9CEDE5D +:1510530043BC85DAFAEA344C6FA1E5F712AFCF09130AB4D0C3DD +:15106800D3C06BAF2527C18D480BC37C89F6F12F9E621E6BA1D1 +:15107D00CBD64C01875AE093F9C4BB30D6C3704D312FD45EC9C3 +:15109200D405E99F3AC2884A995B13DF2FD855FCC78E2063D72D +:1510A70044DFC5AEBB64AD33EE92DF494812EAA2C23E336A0D67 +:1510BC0019F87D638EBBCF3C9433641C0A0D189DB0962F586F8B +:1510D100189E0F3E1777C9F825E280D561A81BA9897E90EF9079 +:1510E6000FCFF76E3A24E0CF440A2A3E49FD7B8D9D377E5E23CE +:1510FB00F7C7487A2F8D31947F01EC63F9B1DF97CF8BFD1DEE8E +:1511100023F65E382CEA18B97F0DCB5C073693FB1FB371BA04B5 +:151125004E43669F14F1F0A4CD6774129F5B27F091FBE5B0A8F2 +:15113A0087527CE2369FF5361F89D345651EEE67B171428E04DB +:15114F0095BABCFD7DA63FB4C83C06BAFA2277560560AFBA7A78 +:1511640043EA7B3E726FC56578F680FDCB0C3807E50E34C29EFD +:1511790055AD94F687550DBF8B04E9D8DB9027624A5DADF6326D +:15118E00DED9F9DCEADDB00F75B0D2D0BEAA0324DA48D43DD4DD +:1511A30055DA15762F851A4DFF0D5FA8FD86BB6C5B57691D3C31 +:1511B800A41DE0FE441F63B97D4DCBB46E8E79C51A053D12BD56 +:1511CD004C059A08276A94C281CBE3E4B9E527DDD5CEF965C6B7 +:1511E2004193DB34702E3E232D1D68B94B97844359F37D303FCA +:1511F700A4BDC8A186B0E747A79CAFFE23EE4D4BC2284B10C611 +:15120C0096419D11D43AC45D3427AD8D86F62B9EAB609E3B411A +:1512210039E96C74475AB90FF66017D6BB7A2FF744A2BC2032BB +:1512360022EE9C27FAF1B0EDC7D6043F4EFBEF689FA13AFCB79B +:15124B00106A85B48F821FE0FAA18FE6ED1F308BC92253EAB616 +:1512600044EA16EAAE76FAB35FEB608188BBD28DE768C2A807ED +:15127500D6A3E94EE2C5F7E7E7B61B259B89F7A5B93143D596FA +:15128A008AB5598FEB0073D9FAE876EC73578BFF21CABF23206C +:15129F0069AAAB3C61159E676A128F885E0BA4E4D620EECA880B +:1512B4005AB8CC6C752DDD9E6BC399CFDA9E1AC7FF6352430BCD +:1512C900BFE74ED10845BFE74B3DAFCBC0459C801EF81D11EF02 +:1512DE00CD0E6AEE3A96DE9BE4BDD916BCABB2EFA5314E08DEDD +:1512F300AFE9C75940AB2EC7B51570BD8F5DAFA95E29EEFB990A +:15130800BCE39FA37799F8BD016922CCA746CDB3C9A47F527EA9 +:15131D00B2F9D74EE2DF6EDF9D4B39EE127766BD71A4A3240E38 +:151332004BBA3A7E4790307C4E4C419FC571FF91F4D500F0620B +:1513470094E2BE68D3F4F9347FD50AADA02264E78D0AEDF66A05 +:15135C00A0C97C6A47FAEE1068B3A2ACF7F4B3CD8F8F1D355654 +:1513710068F757F8B4FBCB03DAA28AD47DEB0A6DBBA46DD35490 +:15138600BC8727D155DE9F19B638717B25D610F8EC4638D8F716 +:15139B00207ECF8950FC3E731ABFE72C4EB82B713D104791385F +:1513B000EC20E660C4D1FB38E2A0ACA501AC11A1B67B88903162 +:1513C5000236FE4BE255C5DD690CCF9BEA79D24FF15ED2F20E35 +:1513DA0088EF6B44AC7B4CE0FBD5D7E47730FBDC81304D1BA0C3 +:1513EF00E28CE280056D58A303B6CC8635E0D9B754F0E33B1C7E +:15140400E3E2FF0C865D648936C09D30DC971766C188CB4DCA55 +:1514190027C2583DF46A6488A910CBABB3C712CAF87016AC0146 +:15142E0060235930F7BF29E3A3593002B0771066AFF37F13F3E9 +:1514430084C1511569F6242F3203617CC0644C280C0F0C1AF656 +:15145800229960D0640871E2A297502C37025AEFB141264ADC60 +:15146D00E0A1CC4156D92DEE7CC144126CB07926122DDD9DB8D3 +:1514820099327844070F14B7425DEE8E73BD2D6A2B6559B7D497 +:151497009D52B355DE15578538BAE8B2559C73DFD7DD6FE6CDD5 +:1514AC006450F1F6EA7E4CBD37DDFDBEEFEBAFBFFEBEAFFBFBA7 +:1514C100BA31DE44D82DB80EE738919E4FBE9AF31B37FF6E8C0B +:1514D600D97D8E4A1BC19FE113CC3500EB7D15DAA8986B25E05C +:1514EB0087B471F62449D02133CEFDA473208FA0ED37A19F74B0 +:151500003663C7C458757D99E6E3144ABE9AA12F947C9BF50CD4 +:151515008CEBAB1D34234CD447180B4298111E57823AA4431D81 +:15152A006768C3D7CAB2AD92C6AD92463FE63CA91C16DF3FF7EC +:15153F00E1FF709CDAB90469291BFD5236446E9DE415D833C0CF +:151554000DBEEBAB6C10E61C105FC6F58DEC875B3ED5BCE799CF +:15156900AF3269B70EFEBE8AB2C2569792B0D97682E72DADE6FD +:15157E00717D5146D64D2F2B7296012DDCE704CDE492EFAB5527 +:15159300511E4ABE0134BEC1CA529CCF7E53D2C1CBC0E6F81BA9 +:1515A800C7A4FE495015BE293361DC608CF8337C825E8FF0D8F6 +:1515BD00B855A83D29D09E64DABF2DF80B65F06EEDC9F843208F +:1515D200770BC03B94FDC477DE271FD06EF709DE2FB9C6F8FCD9 +:1515E70009F8B2F5FBDAB2F576D9D305CA9475D3CB4A9C65796F +:1515FC00F1542EDF728EDAF3DFA91B7AF274033EA764DDD5BE7C +:15161100310B7C63D755E3F3FBD96FD1EE4ECD27B36CBD843CC7 +:1516260079CA9639785F78B6D748E4D5CF3A3766081863B4A142 +:15163B001CFCA948C92615F7A301D6853FCFEA38940F9C17769B +:15165000DD94B30E78E19670F8D301632C0F86CD032183A2CC22 +:15166500CC2F03787BED325FB6CC2C5036D39B5B867DEA73F4B0 +:15167A00D92EEB2D5056EC7596993451A9105621F9436214752A +:15168F0006CE4B1FC83CC6CA306EC2FFFBC7DACB1C6B51524A3A +:1516A400F89A13E5D7C7E5374E6D399F7910F72B13AC1DE6BA33 +:1516B9003F2474592118EA35C380BA700CDFB19DA53BD60968C7 +:1516CE001F501F6E475D02FFF1BB0315633A878FB2E223AC503C +:1516E300B9EA28A7CEF6E585CB5528EF92712E94FB7C7E617C84 +:1516F800B820BF7C85FB3AEB5CC21832C7A3072A123AD703DF1D +:15170D00866F7F4258D8CFAF1B037A2D747D6758B9E39A907AAE +:15172200DEB6FD421FE7F23A571F17A005BE11B48C51FE04D841 +:15173700D7233CF06F0AF2A1407B92699F4BDF1E87DCE1FC7519 +:15174C0079A7CF6FE29D3EBF8BBCD3E7322950B6DF337D7E97A8 +:1517610078A7CF6525AF0CDB3FE7FC36BB26E13ABB92CF716123 +:151776001B90A70B1DB60FE3E0DD72AF86386CA19A57A738EAD9 +:15178B007C79756E475D795E5DA9A36E812AED48204577F72309 +:1517A0005D268F1F667D8F380BDA7BE6DCDF88338C69E058640C +:1517B500FD8D98217C8BDCDC45A266737E547F75BBABAD8E9F57 +:1517CA0067C09C7AF516428A0E361AC9CFD31E5843EA53F054F3 +:1517DF00802798FB87FB643F03997A3EF6C77A726984BDD79F79 +:1517F4008DAFB70EFCFFFECEB7104F0DD0CA423DFAEA3B9555D3 +:1518090076EC09E339A4DB7C7312CFA274C7DE9CE2CF495CDB6C +:15181E00C033F9668A9F5101FFF25EB157E2F039A98B8C9F43E4 +:151833007E52807D39C4E339D2CEF6839D1D053B0BCFEF8FEA65 +:151848008277D59C77B6CD8D7D96F6106FAFCE3E93FC8BB8384D +:15185D00FF50FF35013C13CA3FBC53B903F1EDB957CC93DDF0B5 +:15187200447F12734E79CC08FEAFCFF137E36CCD771C7335E3A0 +:15188700FFA62CEC2BF024217992903C49489E249027C5B09E3B +:15189C00BE16FEE15CF26A4B0233B5BEC04BC58257A2EC562824 +:1518B1003B1018CB295B01654381E3765929969541D98D8149CF +:1518C6002CE3FBEE829F7A0AF8077C6C4D4DE7E3A53B89A721F4 +:1518DB00857CACBAE34FDD9FFE02F25024E5610FE03DDF9C4B45 +:1518F0006783423C473F853903B4BEF4E9745A5BE11BFA29D2CB +:151905005AF3AD69B5E391DF86DEED05E82D96F49E015A1B9ABF +:15191A00A7CBAF8939BE0564F7E38B694F11F4E3838BD3FB616C +:15192F00029CD317B11FBE6BEA47E63CEEB7EC4F5781FE28B23F +:151944003F5756114F17FCBE0BFEF73E813E69554CD56A18D73C +:15195900FDA0F35CCB09998472FCAF9056FA21BE0774AA017723 +:15196E00166886A56A2D2F22FE08E899B511DC0F8C51DC35426B +:151983009B98A262AD12DB0FB65831C11EF6F3FD2C0AEDCE4436 +:151998008E58A51DC7ACB512762F3CD3D79B74233C5DE2BFBBA6 +:1519AD00218F9E06D95687E746F0357D9AC04774810FF120BED8 +:1519C200E833B9F81640BBD28E23D65AC0F7E10501C327F17D8A +:1519D7007C41E083FF6E273F55C9CFA34D44D437919CFA39B6C6 +:1519EC00FE93F59756E6D6CF95F5DB65FD0779F5F364FD5A59A5 +:151A01007F9CD7A7A8EFD9ECF9A334F491913E1DF790DC68A32C +:151A1600F3CE1BF5833FC4F0CC47656C7333EE2F997D75959A13 +:151A2B0012D4A53E1BA838AF3787F6055B1DF1DCBD273B7E8D0B +:151A4000BC7ABCFBFDE680A3FCDC0BCF5CC1F2959B7FDDEC8CD9 +:151A5500FF9E7DEBA72F63F983FFF8AB665289B1C761DAFBDB56 +:151A6A00275A7C7E7373EC87C433761FF14CA3D391AF9B7A36C9 +:151A7F00D73E0B5F2365A10E7179C53A8C97A9B97DB3FD236C72 +:151A94003713647D3028721BB0ED40DBB83E33725F607F1BD7AA +:151AA900E5CCB47539D4719D0F3079591E3C5C6F52B02D5D5C15 +:151ABE0086ED35183306CD2A1DF7BDC16FF4F457C4F4BBC89216 +:151AD300A0972CA99BAFB98298233650C1F4756655F0BD0C5F2F +:151AE800C6F83EC46CCE0FB6177D9412F0F546F3EA3D8E7A059E +:151AFD00EA7BB37CED2F5248BF1BEA5DB5307EB2CD7C6ECFC40A +:151B1200B7D741FB8DB2FDF740FFFBB592805DE787BA0622E42F +:151B270009FF2F3C3B6254C3FFF98E360BCFC60D5F1E3DF7C0A8 +:151B3C0038252271CB0DBAB6FECBB4277625EDD9FA557A96EC0C +:151B5100DFAA49D0D3203F397AC527E574B491F079134A3E4B1F +:151B660093256416CA19FAC136EC27619E610C4775D0E5AA8842 +:151B7B0019C723DCFED2808C3FEF01B8D5C0FFDE45C493AA12E9 +:151B9000B27FB20160CB7D72226DF99364980E4E8EEA336F4273 +:151BA5009B1EA0C297D5E43E6D35C576459EB8F1AF8B7E50EF22 +:151BBA006B8CB1062BEB6F45E0BD669090283C1B9E23C484E70C +:151BCF0065F895C3FB65F885E0C79E13FB5D08A7F53FD29ED399 +:151BE400B82693FFDDE7D39EE3F89F8DB079303E181BA8E47B6F +:151BF9000929EBF4FD843C87B6818D58367FED75C669919FC22E +:151C0E0061281AC6285EC77C7A9ABA8F102FEA228C9B711FF33D +:151C230088E56AA306EE2763EC8AE7CAAB23B8B75AD6E4A0E3B9 +:151C3800AC9BCCC2D82AE2C7734FB857B100EAC73CD25E713CCB +:151C4D000798CA7535A326FC5FF05F609F501F89FC8B0C2D99AC +:151C6200B39958F63B570AF0F17D3CC5F18E7B97F63BEE59F2DD +:151C7700B80FFC1F73C4B96C783E76C4405D904A5FCFE71EC6BA +:151C8C004486FEF9282F23A9EB89EFDD51F10E7F701CB36D6341 +:151CA10016C65186268FEA650ADF43B1447C2566613CA5C94103 +:151CB600B7D8BF1CA60F4C3D30B5787234472E67A35C227D20D4 +:151CCB009BBB6F271E1EAF0C1F61E8F7EDD7560510861B73A2DD +:151CE00022A798163941FDFC9CD3179697E700279862EF075FF5 +:151CF50014F916FC5C82DAC3F74C791C397CCC7A5CCEC76BF51C +:151D0A00279B1CFCFA661A246E3CAB84F80BCC81F25560EBE5AC +:151D1F00FC60B8F7AC522E5764B288801D328662CA263C7B40E5 +:151D3400EFE5716FBFBD6E9B43460CD46BC85B2AE9C3EFCFDEF8 +:151D4900463CCAD45386FAFE53BA5347E2792466821EE76BBC5A +:151D5E007E9AFEBBD30AC626152EFBA6581F4D017FCCB87E3379 +:151D7300190DE299C5D496A3CDCE71B94EEA8BEE159C0779F150 +:151D8800175CBFD9704D0E374D4ED2CC99447594611CED7B66CF +:151D9D00BC20EC191276F90A92B38F9B858F79A4FD745FC5B0E0 +:151DB200CECFC7838E45FA63FCEC42DC5C8CEB03C0519C1C3729 +:151DC70095E409D35D1A37704F7026E09B1B66862B42E9A1A492 +:151DDC00B249D17AE90DEA2F8D33E9B4DF1B5382D9757098A279 +:151DF1005FBBDB85BAB015CAAAF9790D9EAE8B3EC3FD620D515C +:151E06008ECFCA06983B77BFC8D75A01ED4D727F017AC13E46AC +:151E1B000EA37D1CE6F6715FC549DD3BD9773BC737A5F4B2C6FC +:151E300031417B386E7AD1DF93E54591B8A9362678FF0E9103BC +:151E4500BA05F2EA5E07F38DC5AD9BC51955E68A8C67FA3737FD +:151E5A00341AB4BF15FA2AF33E8D9EF70E67F371F7817FE13540 +:151E6F00253DEC2AF440B90AFA176971E2748978EADE9C3334E2 +:151E8400A82741C648E549B18F20FD33E09DE08FC82DC8E5A33C +:151E9900DAF762CE7E3DCCBDC806EC036BC7791A4A1EDE5B29A3 +:151EAE00D681E683503E188EE96EAFD86B4B024DE78B4D3CA3AA +:151EC3003E0BEB03EB458E0CDAB0C572EDD8CA6564CCAC833ABB +:151ED8009B764E37B46F58CFFD6C1EC75F2BDB353ADAB5245FE1 +:151EED00DD0B3F13CBA3EB798CC4C43831F605D7AA48C7E05399 +:151F020071DD3729F704A1DCC6DB25E1FD5501BCBB1D78B7CB1C +:151F1700763F71B4BB0BF0623BD3D12E2ADBF514A0EFAEE41B6C +:151F2C0026CEB17E4EE3DF9B685FDC408B0AF43DCF65679CEF03 +:151F4100430FFE13D04AC4397EB783D66E097BA000ADCC41C374 +:151F56006ED9EE50015A871DEDF6C8762F7C0DAD38C636ADA5E6 +:151F6B00DF406BA983D6A484DDB1613AAD5D1BB2347C2CDB6D89 +:151F8000DB7095F1DC901D4FE52AE3A938F09EB7C7B300DEDD56 +:151F95000EBC17ECF1BC0ADED68D38BF2690074C75E2C5FECA8E +:151FAA00FB36B0DC96F935D0FE308967647E638990F92B2E21E2 +:151FBF00F3A18D59DCE11281BB65E3D7E006BC3E89D7C6E77309 +:151FD400F473A384D1561806C3396BEF7597E7EB3CD02FC75F90 +:151FE900CAEA3B3E9FF95D0A4719B767784F8E7A9CA11FE92EF7 +:151FFE00ED33F6815FAA826D53D79E32CAE909E32021739C3A1C +:15201300E86FA05F85748FFD9DDF15D70F9BE33ACA8B88271E8C +:15202800D0613DBC17D7BF77715859DBB01C6015815DC8E8D5B4 +:15203D00D0B8EE5E17E73A95EB53DB5E98A84FE35C9FAA6D40B2 +:152052003FE85197E33DA7BF9598AF31ACBB2A9881E7F178AE2F +:152067008CB0F9D23625047E26F5697848F8946063455F46F90A +:15207C00F9097E3E08ED52641CECD23B863B7682A26D2A684F28 +:152091005ECEAE1F193FC7D46BF8319C8E7B15F2FFA5747A5E1E +:1520A600FE5A52EC77F278BD359C02FDEA81B915AEA12CD41386 +:1520BB00455DEC2E163A59917E7C293CA37F486772FF588AE7B0 +:1520D000E79539F3C6944671EF4CABA31D5EF893DF0E6DC2F3A4 +:1520E5001A9E5B3AC910CE83987F510BFF8167E877BB2A13EDD1 +:1520FA00587F4368D4B821F40ECA8CD5CC7345C618C2C372FF1D +:15210F00E6B895FDFF8EC1CBFE3A8E3E0BF1B38421BE7F076D69 +:15212400BAAFC8DB631CFF324BD3608AFB4D0E9A12B4991C5B1C +:15213900E9D75C011B37DEBDC3F34230FF1ADAFB6FFCC2CABCBE +:15214E00AFFA228327B9F058535126EF07D6AB320F1BE92ABB9B +:15216300310E7EFE10B3F819D31A3A07F87D3BB24315B044DB21 +:152178003186FC07B368A9EAD330D6C7E19B414BD18E5BED0E8D +:15218D00BF12D6DDE411AD64E5844BAE8B0BE05983BE4B41D8DD +:1521A200555689FA16C09EA0840D594AEC94856704C4797E691E +:1521B700BB51BF15CBF98B396DF25C0091759305FD19915B88C8 +:1521CC0072746106D29560ED226798B9257D6E271D682B8B05AC +:1521E1005C7F30415522CF2AA8C72CA443FD6889C56D51868E26 +:1521F60014ED8A65E51BE11CBD4FC0194C09F8026E82F3A7EC3D +:15220B00A33EE68235223F8347C6753C138F3EB0F82661619B93 +:152220009C7900F03F8C65FD1FBBDF083F719FE89FC0339683D4 +:15223500C7DE73C0B69C8F49C1C71B36F75AFE7082D7259C38A8 +:15224A0033E7914354D0D24055CE975679875080BA653E202FCF +:15225F000F8FB28717A1EFFA0ACF4773D2E07B7909738E1DB4DE +:15227400B114F508C6FE992D27E80BE30D65CF935E9DDFD31477 +:15228900A69C2FFCAC05D42BD05FD660525C841797F61AECC022 +:15229E00ADC607FF96F690A911BEBEF7E118A96F1A8A768AF9BB +:1522B30023E24E017B0D535E3C7D1DD5D37624735E3EB39E9A77 +:1522C8003A66DD7EADEBA9F06B962D539847365C22D6BDB93243 +:1522DD002564086919967CE163128C7179E2EB5958C7A33D4393 +:1522F200794219E0BC32C51AFEA5AF44AE52A1F504CF1B0EC06E +:15230700DC6717E83C7FA01DF767BCDA92FAF7D19EC23AFC1118 +:15231C00EDD6E0659893CB93BE55DC36DE2FF37DEEC74B4F0E1C +:1523310070B9E3F960A2DCC2F2F7E4FA3622DB46F3DACA720B9E +:15234600CBEDF3B836FC5EF9CD60DE37B2DCC2F22E09BF5FB607 +:15235B008DE5B595E51696DBEBD4C512FE6AD916DBE1FB028718 +:15237000BE6975D4E13B9E6DC2334D6E90A362B0558A36622134 +:15238500BF1475BF81E31DD046F19EA9B9734343CD0AAC57CB16 +:15239A007A2E18A5DA116BBEF94993BFE55343891CB75E8E95C9 +:1523AF006C72C39A0BECF1BC9991192B95C805CB96D999A0DB1C +:1523C4009257709F2E3B077E0A3652E1E746D8B4F928E757464D +:1523D900AF200CF5E08831583CAA236D73375759F67CE632C014 +:1523EE00CFE58EF3BB8BF8592FA147ACFCF92CF2400127CC19EB +:15240300E73C796A76AF91F8ADD84754A54EFBA679F27480DF1E +:152418008D23E6C8C008CF89518BB3F98F8B31F7007C8D07F85F +:15242D00DE7E36AEB50EE4CD67CBCDFF36BEE9984FAD45FF072C +:152442003A3ACF9F086B23ACC4DBC7F9F912C06BFAD4E10B5CB6 +:15245700CCB3BB400BB611FB20A6C5F7472AC7DA4B0EC68D21C8 +:15246C009015B5294E93220662B9C57E29BF37096D33D66BB0B8 +:152481006E4FA17D97F0307EAB4716B1622FDE75D743272F66C3 +:1524960071AB05FC107704F0F23D0AD3C2F11A02BBAF4E8CD0AA +:1524AB00CB12278E6F0E4EA877E7E1CCED7F75FB4607FE900352 +:1524C000BF5600BFE2C0BFA000FEAA6BC48FFE456F6380DAB4A9 +:1524D500200D139F081A1600AE7CFCEAC4118E4B8B8CC0DA3C30 +:1524EA00D10E6B6F0B7D1F45E377CACC5B101961CF83DF833679 +:1524FF00ED92D3CFC1589F5A65F5B65103EF74BBF46455338FA4 +:152514002756DFB4B4AA6D6B50FB6143E366ED9EBF587FB7B6A6 +:15252900E127BBBA3B1FDDA5ADEFDCDED9B1AB33A8B56CB9679D +:15253E00C7CECE8D5D3B7EFCA3AEEE2DF5CB6E5B16D0AA1FD909 +:15255300D5B56DE7CE1D8F6DE978BC235457D75877DBD23F5BD6 +:15256800AE3DBC6D7BE72E2DD0585BD750DB7807BC04EB03C11A +:15257D00FADBB4AA4CFCCCC6575BBBB533BAA3BBF6A11D8F4646 +:152592006B3BB67644773D51FB68C7B6C76A77ED7CA8B6735700 +:1525A700B4F6E1276A3B3AB6F3B2ED3B764497EDBAA96E857601 +:1525BC00ABD6B9755BB7B6B5F3E18E1F6FEFD61EEAEA78EC478C +:1525D1009D5AF5EEEECEDDDD4B11CBB783BF75E7B6C73B77D624 +:1525E6003E0CDDDAD2D1FDE896AD3B1F5FF6D04D2B1AAE063F10 +:1525FB00039E9F6799E30FB7EFC77D42B58ACEF537B4576BF5C9 +:152610006C199EE5B1F3F423CACA85FA05E350E870B4880CD334 +:15262500F63FA63379FAEDDABDD67FFECEB552517F6054692D59 +:15263A00B40AE6DE39D0253E78BE85BA539ECBEEFA22ED797785 +:15264F009112DCA81D613550379F8C3787B401C6EBC3CAD30165 +:1526640028437DD3E428C3762AD8408069F56BA5AB6C9B500E21 +:15267900BA710611BE04FEBF02B0F7A9CF44D14F1CFE657A16F7 +:15268E00D2E5CC6B77E6B4C72E8B585C1F6F5F4DBBA03D513FA2 +:1526A300B77CF0CD04E68D39F0B328E1676797B9C85CA40FE9F8 +:1526B800F069C718F66106AC53317F8E4C2DC538ACCFDF72AB4E +:1526CD00817DC77B164BFEA1D1C02B54AA0096D8AF3A44C3DAC6 +:1526E2000BB4FE6DC00DFE940FBEB7F1E0391EBCB301CA2C2721 +:1526F700CE35E934C7C9EF6D04FFEA783A3DA732E2127B6AE153 +:15270C00017A1DD80584997C0BF3660350F60AA7AB04ECE521AB +:152721007E6FC47EDC972BB3C7CD3E6311FB038EDDE77CEC30F5 +:152736007EA36930EFD4BE845B5B6195B41C85F13EC061E33C5F +:15274B00C43958AABD6CD57CE56ACAFAAB620C6C7E3BC7C1F730 +:152760004EDAFD75F5574EA66739C703E951811E9F63BCA211D6 +:15277500378D257F65A920875A722431D7BF1BDA76515F7211DD +:15278A009B9D2CDEB43AB914E435DA8E776AE01D89782F0E0997 +:15279F00DF4DDF55709DA453F465947F79D0C07B36D662FC4621 +:1527B400C533BB61EE8B0E9ACBF5D74275ABD66845ABDE2F396E +:1527C9004FFDA15BF83E63EFEBE959975C765ED6009B9133FE04 +:1527DE006B29DE5D89EDDAA1DD19D92E906C01B8ADD66A11DF97 +:1527F30048F03B29E5B326B2860EF0BC9145D485F77F014FC4CC +:152808009D94B9CFBD2E71278EB8E76B047CE95AFD52B180EFB5 +:15281D00A523C603DAECE05C6D76DDEB8BCA82D6E21B83A7B1E3 +:152832000EE3BAE3E9598B355790D3A90E50DC8376C3BC3C0DA3 +:15284700F320137F9B7A45D8E7A957AC9F5754EB7CBF1874E630 +:15285C00A0840FDFF3BDD47E8065B7B5DB6D873607DBF0BEB4B9 +:1528710012DE07DCDFCDC7A57F21E6512B7CCFE358324E77F2F6 +:1528860028C233D982D251C3F7DF87190A4E6B12CF389FE7E720 +:15289B00A9ACD0ABFA10C09D5F5A632C07BEE2D9D81A729EF631 +:1528B00086DE88624C2D896B83B6A5860563751DC84EC99E710C +:1528C5008AB90441DCFF507F21C646CE65F4A915BE2ED380AECD +:1528DA00503BA75FFD85357129ED395A24FA79178C75538131D3 +:1528EF00857575597E9F7A2FA5790E09C2D92EBF9F0F73AE6456 +:15290400CA34F0BEBA2258A784928729FD4DDA637F8B730575F3 +:15291900E284E43BC66F911701E083DD6618EAF83B7B864652D2 +:15292E006911EF8436A54773798F325888569CC7E5C91EE6FB92 +:152943004CF0FC83BFCDFD6E02F98F72CE75C37E6AF37A1078EE +:15295800DD9A1CB1265E933E80B3DFB83724FB4D7F2FFA8D63CC +:15296D008FF0A200AF468E1997CD51219B788ED6D576B71186B2 +:15298200FA9B6DF9936321F89885D1F07B416B1464E2E3D78499 +:152997004CCC2FAD37FC23AEA02D1B78CC3B2AE2B952364EE849 +:1529AC00E8DF2D262756A15CF81A135C1E2C73B1EE1E386228C5 +:1529C100A073174B3910FB02B9E37E12F8EC575F0199EFA15EF8 +:1529D600900B5F4F9D91BA28F96DCF07C737181B2FC4EF6538A7 +:1529EB00DFA13DE7793E1E984F9837649F7FB9CE211BDD201B4B +:152A0000D13342365C781796940DCC8343DEF01C07CCEB782D44 +:152A15003B7E086F76B8CBD0FFFD2FEB41C759D5C936AB2AD9BA +:152A2A0062819EB3400FB202F909FC5E665CEF946A553CC61AE4 +:152A3F002BB00F06FA9BCEF00E1891728C1B8DB5A3DFE6F28C47 +:152A540018B89FA6CB73D6E8833FC0F79712FCAC18DFFF8275A5 +:152A69003B9E0FFB79C54958ABC6F95E981AEBB3300F7275EC6C +:152A7E0014F7FFCC581C65729EAAF559ABB553168367191B3372 +:152A93004E6BA29E2C8AD38FAFE21FBAC984E723A5B9F8B1A2B3 +:152AA800CF5D3F73FD4F7B4F1B1DC575DD9BD5AC342B0D627676 +:152ABD00D95D495848232C12C9519C5DB1C8922CC242A88FEC13 +:152AD20010654B9D744612F63AB603B19D84B634C7E784C42B00 +:152AE7005889058FF03015F65A266695480E6E209539909014D9 +:152AFC0092A5761C9152B2E1381C9AA4F638716C9AB8B6EC6293 +:152B110087A436DB7BEFCCAC56027F25ED39FDD13367CECCFB72 +:152B2600BEEFDEF7EEBBEFBDFBEEBB95BB86F37317D82FD98F5D +:152B3B00D9F7D9636C823DC40CB69D6D619BD917D84676275BBC +:152B5000CF6E6537B33EA6B04FB0B5ECE3EC63ECA3AC9B5DC784 +:152B650056B3556C255BC196C38CB29375B076D6C696B1085B45 +:152B7A00CA5A599885D887D8D5EC83AC059E0FB0AB58333C4D64 +:152B8F00ECFDF0BC8F2D81A7119E2BE1590C4F033C323CF5F4B3 +:152BA400D4C1B3889E5A7AAEA067A1FDD4D0536D3F558527687B +:152BB9003F81C2E32F7A16143DBE598F77CE235DF2CCBFE4A91D +:152BCE00BCEC33EF2D1FF16D9F8A777CCADFF5E379C747C0C3D7 +:152BE300535AF6BB963D6099CEB280EC52D7DE1F63F241F46BAC +:152BF800043FDDFE6F82FF9CFDDF02FF1207FFC863EA9A207EDC +:152C0D0054D359B7968349B2C4299A242F3E28C5E1CDC06B2E5B +:152C22003E487602C97E6C13D9BE9365DBCF63FB71E017B7FD26 +:152C3700CA6D3F17F8656CBF0ADBAF04FC303F2893CE264A2C4B +:152C4C0016B2F342BDE2909D07EA1187ECB4A8371C8234310E91 +:152C6100F768656DE3B751D0BA4A83D9F6A81BE41AF48BD1B952 +:152C7600FFB0EECB70ADC25433F081865161AA83EC1B26DE2674 +:152C8B006CF26DC2C81E0B84554218F81BE8CF9FE850A9EC5CF1 +:152CA000B3E1E0CEC139D62367C3983B4234D1659A8787749C89 +:152CB500F731AC27A509F5237E118792CB8A3F99B5C3813776CE +:152CCA00C98B0DDDC9E7B8E51F837831E49BD262831740067A12 +:152CDF008B6F8C9B89932BFA975C33FFBAED4FF8CFE6E7A36DBF +:152CF40009EB3CB7AC4D93FD5BD9D2E720DD4999743D4AED7F28 +:152D09003A37EB82B686F66043EDC03B5D2CE96A37CA609ECA75 +:152D1E00473BD4E9860E5A9F9BFEBE7B19E204DDB8469A857495 +:152D3300226B471D6CA30570018C5613E456A38C5D05B05F65E1 +:152D4800B883D1FEDC65FC24CEF263F2AB06F2DAA6B96B14217A +:152D5D0059273F6CDFF0BD49E65A79A099941868E571BE2C35E6 +:152D7200A03D4A18CFC35064BBDE42EB5061834908974CB0C425 +:152D87005CD55046B38EE5F353D5AA94688EE0574834B7E23778 +:152D9C008675CD8548A6C6B8D48ED15E6528A425A84FB46B511B +:152DB100D26D8AA27F3C3FBF1BE2C4C88E24CAD0D659D8B8163F +:152DC600A573001BAC33B1A18D961E14BBDBBE272065EB48E02C +:152DDB003AEF7C002A09F397A4AEB3A482FB3DE87E7505BF8CF3 +:152DF000E5B6E8A2CCB7B2D856FD3CD62B27EB96DD5C4B6FAAC7 +:152E0500C52C69A53C213F5A57C2FFD8889EAA49281CD9F31C8E +:152E1A00310A7A20B11FA4B17EB5F2FD3A2F9F30989E84791408 +:152E2F00BFEC9B377F13F27F328DFEE8D7027EA373FCAAC16F26 +:152E4400688EDFA6150097F47CFA7337BF1006815913E5A7F5FB +:152E5900BBD99456BBF205B5B7FE99F043EDE7ECB316093A3FF3 +:152E6E00BC287106EF0EA075B3452B4FA97C665C77C1B828CBA6 +:152E8300DF4A33FDBC21A44668AE836B6D4276775B10E7515087 +:152E98000ED3BF615CC1BDA0221ECAD933E1C99B5F6A031880EB +:152EAD00A64F035CA7744EDBA93EB4EE79ED8AA806ED68A70154 +:152EC200384B5C5CB13A2C6C87F2625B27D9BE52B42D3E2908A7 +:152ED70068EB74DBA8D0FD02F83F306AB9BF6EBBBF3D3A95CFC1 +:152EEC00073217E75CF311FB693AE99AD2116F77B3AC96F85E05 +:152F010069EB97BF5CDA8AFA10A3B9879485A71F504A4E3DA5BB +:152F16005EC7CE8417668FA964672DA4DB76067354D780F4F77E +:152F2B00EAF95B9E3616724F42F81943481C68C3392CE63D7D7E +:152F4000CB295DC894B61EBAA77419CA26C447A4B18349570694 +:152F5500E87C58C7BAFC61EF6024781CF2967EAD617D24843B52 +:152F6A00F6F8A4807B23D2B68312C1FFC383CF431F2C978753B1 +:152F7F0068DBBA4C1E4CEC4A680AD7A3411FFDA98E3657E38FD5 +:152F940031769F80FB095A6ABAE13503E2EE78496E591683F8DE +:152FA9009BE3AB5B518EA1BE251DD0F9CC578047BA5BE3D9FD8E +:152FBE00AD4C3FAC4F63DB8370EC3F6BC19FCF1C80F63348B612 +:152FD300299A6CDB31D4D7F461B20BDF44FD0C64DBCC30F4B3E3 +:152FE80084C6036D25A645F02B30AD15BFB85F266476431E596D +:152FFD00B2C55A9D49EA9C00380A65C9862AB643EC1FFBA6308D +:153012006CDC88A1CC9D491A572534F2CF803FBA512E9C6ED029 +:153027007431CEB77A4176C47E32DD306E2C0C66FA8F5E742F22 +:15303C00035C1A536FE40509E0E98232CE60BF0AA5B52CF0E088 +:153051002EC89765F6184F15CEF7A47411301002E09E1FD42243 +:153066004C3F9EA67929F0B3EDD153CAE9DB4B5BD36C504927FD +:15307B00762B171BF965E9E8B052951C51776DD5945D1D6749C3 +:15309000B694CCFBD39D4BEAAEA13DA3506212D762BD8B92B8B7 +:1530A50027A8D766A84ED69AB680F67513B466DDCEA32CFDBCA3 +:1530BA00CE75A38EE113C6AEACA6E07AA190D903E9B6219E69A5 +:1530CF006FAFDABCDFA8351F369A0037B550D75C298805108ECA +:1530E400FDB349DE46B63C280F49439B4E42B57C9F4E36F7D6B9 +:1530F900691AA4D39137F0F1437AC4FC1EC4DD66A00D4E616AB7 +:15310E008F8A79BA4E4E908E5AEC71C66A70BF3F74846C05F0F8 +:153123003D432AD469D4D5B3534D95B1D9FD23876BFB29ED8BE7 +:15313800FFC6FFF0618EE8427B1E7EF311D203A45B7670CD1FF4 +:15314D00FD5892F4B5B0CED6FE478AF63F8CEC88526D0EA543D0 +:15316200E6231969A5A60AD76B6AC91A4DE565CD1005DCD3DEE3 +:15317700A3354577B7E1B9B1C000B41F98B75627D07DD808DA47 +:15318C006E3CD36EF1FDDD86DF145BD18FEC8D16F643D2B4E610 +:1531A100EF42DCE446F446A28375C69963FB34D4CBB6CE365B69 +:1531B6007720FC02F2E2D6A0CE5E86E8C7A50EA8C14583C60317 +:1531CB0051EB5C2CAE9DBB7A2CDBCB3716D921E03EAA912D62AA +:1531E0000969AB7FED20D93284FAE33A346F022FCB9D277C7B31 +:1531F5004DBE57A4B9439AF6195CA46B6ADDB101F35C03ED4235 +:15320A0021BC9CF945ADC95C102EE6F1C8DB918EC4DF0BBC1DC8 +:15321F00F8FC86D25EBFF9BA4176DBFE11DBE190B1E5CD7CA012 +:15323400E54DECBB162D10D77E73A7EED246546FA7B5D7EF02FD +:153249001E81F7CB886C64A9086D65211B09231DB5A236AA591F +:15325E00F4D2D3A4F375AE9FDA18D00FDD3CB3F45F5336DD9182 +:15327300CE9806DD48D7B934251AD8F478271CBF5B5AFD4FD299 +:15328800A29C6891B6F7796668F28EB4281A6B1D3AE8DF477B45 +:15329D005995A1629AF8E2EF0F93DDEDD8C0E4857BDEDF26C538 +:1532B200CB605C1DD0D1B636F2AECD5F2C6D9DFA2F871F59FCB0 +:1532C700A31A68E65BA4191CF04DA421D6D5DAF3B1CAC0F230DC +:1532DC00EFC2B9A882BC64D1A5A688269B099E94657705C27175 +:1532F1005F5132771A9C9CA4F6846EA5C8BE40A4287DE4930561 +:153306007D5FD2134EB309D2DB6C42DA0F4C28A2EC26DE1C225F +:15331B003D404DAF895ABCA8D00FA1CEDC061C8FE17BFD29C2BE +:1533300001F45B7FEA0F567DCD39D76CA18DFBEA60AABF06645E +:153345000199650E8658F660949907AB7F9BF7C07712DC93E0AA +:15335A003FD96DA77FABF8CAB9D9F1ABEDF838AEEF7FBDA84C2E +:15336F00D4C780F947715AB2CF45771668FAC57BF8655DB87E3E +:153384002E1F4DDC37754C2985E9062F8FA4D04E49B9FC448ADD +:15339900EC86D37E5096CE544AF22198B72475D15CD27AE3FDB6 +:1533AE00790FE2417B30EF999B67316CA4770869BBE407F5F373 +:1533C300CF6A2023E96403C56A877F6750DBB56CAD4CEF0279DE +:1533D800B115E4A2F7D236A79F1DD193AE94CEF6F1BDD3CF6A0E +:1533ED0046D29536BAE45DC6EB17B17F24ECB9C980F11CCA42CA +:15340200407FDC5F95A18C629C5C787A363E717FD796672D5DEB +:15341700687D8F8EB23307FD0BEB086E63F5DF82BC188A914D54 +:15342C0074279FEC8F67F2697C2D2FD4E2D9A16035C8F103FAC1 +:153441004928F36E16D798194AE3BA986836E9A5C7C3EAB7121E +:15345600CDE1C1F6F659B26519C375E276EAF765DCADC067AE49 +:15346B00D765339666D22B862034A8B8D66CC9958BDBCA61EE8B +:15348000E2AA53A80CB4878769DC0361B5321A8E944399FBEB54 +:15349500AF6DAB3565181B9BF46A33A47362A73AF895B0E6CE17 +:1534AA00C23C31D76E387788A0EE07B374D041DE6C0CF3B8563E +:1534BF001DFBD424D36F191552B87FF857F43557B896CDACFF5A +:1534D40057DB7A174D363F0B013F6B5750AEF7C95C88E62A504F +:1534E9000FDEB11D937B64B226BB47ADB1EF6FF0C3388DE3317F +:1534FE00CB7DC7F072CFA9AD0D95D7B0BAA97EC6CE6912FB759A +:153513009B9F7B59DD29BB5B51560C01AFACE526D440F048BF54 +:1535280010FDF5D25AF8BA4EED26BBF4C827AB56A26EC011FBD2 +:15353D00BEA1843605E3BE2F7158F5D682DC52B0CFFCCE6F157A +:15355200C8E6F84DAF288BF8E2653067F98ECECC470E8E83CCE6 +:15356700556BDEAF23EFC276817BD85E18AF9FAA19591A05598C +:15357C0007C7A14FB875926FFEE9412DECC8346FBC997F4B99EA +:1535910026FDFBFC5BCA34ED6F25D3C45ED04CE77C39F21CC0B6 +:1535A60095D0707B5B39E93423DE8EB5F98FFF07E47F4C5B0B28 +:1535BB00B87BA05D776C76109E828943053C05CD2561E11CEEF2 +:1535D000296D99E44F1C437E1D5C68CE0B835BF79901FA969B53 +:1535E5008BE8AB035FBF5CFD619C8DB8BA5F564F5EC80B880779 +:1535FA00AC6B8B5D7766D7BDF63275C734E90BEFBDFE8B80EE1D +:15360F00D5C85763BBD2B1D7E7CC6FA08E747744113D5B8AE3A5 +:15362400C476EB37B0B47623C8F0CF3F35B254968F4F0297D654 +:153639007C1C8CB7D219C36FB74B1EF505A49F1B77B3B39A97FE +:15364E007B91EE4FB862E5CB6A28FBBDC8151D163EAF602F502E +:15366300DBC3FE7A05CE67426709A7D8E6703D17D784EB4C771E +:15367800AB13A7EAF8D305BC57415A491E48272A92BD18F72EE4 +:15368D005CB28D1D4AA32E4AC9D4310C1B759D3CA6EA799847E0 +:1536A2004178937C7B1B7E119EF32BCA966DBAF91990177FAEFD +:1536B7000BF263A32DF2BF1AD5E7ED3AC6862645D437CBACD512 +:1536CC00AC7F9C4B0D4D9E5B61A53F0278F3DB795D58B1BEED6D +:1536E1006AF6F5569A0B15C5C5B49847713AB4F7BEE5DE334AFE +:1536F60048FECBA5E88FE32588D21FC7FF0771CC8C0D65503E7B +:15370B00C5B4E5A8630FB8C4F361B5BBBE4A785D28838C60E796 +:153720005F39EBBF2AECB2FED3E5F2FC307C7557A525B763FE8C +:15373500AE8777A83437FA21F00A90BB8CE8238A144DAAD5302F +:15374A0096D079BD7761A31F5F1863525C6AAD8AFB984CDA4A08 +:15375F00E3901480F1C41E87684CC2B0F7301E3963913D2E5D94 +:15377400763CC2B108C7A408D9F4288C291A3B618D29563932C9 +:15378900AB965F3116A06C01E394206F37BA5FCD0BE5192D5589 +:15379E000E7047A2C956677E580DE31AC6697AD5A1F7A05EDB5A +:1537B3006ACD2B733FA0701DC343801F4CCF32CFE97417484EF5 +:1537C8008379654A2BCD24133E2847CA1C4A639F2B318F699847 +:1537DD0027B6356C734DF2B3A3D8A6CEBEE1C86B36CC00EBA1A5 +:1537F2005D5F813E3CA0D37959B439FA5D6B5CDDF3CA4CFFF2E4 +:1538070006ADF32F82BD5F3659C53C208B7AF62DB0DC719E794D +:15381C0036BB98670A5E4BCE6EB27993A523E2C6BB03FCCE58AA +:1538310098D136039EFCC73BD45520CFBA07C6D491DC98522753 +:15384600BB3B17CA1FFC30AE9D511AA9592D9C178D3540BBE016 +:15385B0086F87883EE96701D8E1B7A716F73849D1FD0CC1378F1 +:15387000B9D15C797276F9AB12CD4BFFA4722ED1BF09F53756D0 +:15388500B10A495AACA2BE2DEE75476A58855BFA06E9475E9528 +:15389A0079B30B75A7825F0AA3AC4B3A51645F00CFE5423CA71A +:1538AF003CF4EF02F78CCD6E9AEB94E3BEF81341B47DD3D4FF48 +:1538C4004610F36D253D9F5C35AB10E363C05797A8EF93B98E87 +:1538D90052482FC61B8C0BE0CF7F6940B7F412F921679DC02DFA +:1538EE006D517F0161685F6F04E340BD704F4F46DD29F0E3E3FC +:1539030063C651F487FF17618E7ED64E877B5BCF813F7EC78161 +:15391800C6783EF0A8CB3A53398234F74FA31D4656B60FEDE209 +:15392D00BDAC49A71F5450AFB51AE737D2214D100FA83D40DB6E +:153942000532DF5B66EE21BB48B5C00B8326C61FDEC26D1FA1AC +:15395700FBE170AE7355A66BA9245A672FD0F6C97CCA736254CD +:15396C0080388215C75F9DE19772FB2E4DCB6265A4EFAA03DE24 +:153981002201EB4C23EAB7A0DD41DCCF37C18F49C9C2FE1A2F08 +:153996009F37EE02BAF1801711FA66BCCABEA3720E7D437141CA +:1539AB008B9B3F3CC83F3DA0BEE177F2AD2DE49BB2F38DDBB65E +:1539C000677700AF385A86B695E47E964B18B4FE2E4534AEAEF2 +:1539D500BD9F379B0CC1443FA095D94EE5579BD306CA4392991B +:1539EA00813CE3FDB82EB9A3668342BCAA6E637FAD8967CCCFD0 +:1539FF00F6F3F2678DA341AB7D34429A263337DA02E923905F61 +:153A1400D702E609417A0BB63F4B236C68A77415CAA076FB725B +:153A2900D545FBA3E6EF8C1D3531254A792AFD317043FC83ABCF +:153A3E00E11B87BC4B614E70A3B9D7889A0FA4BB4D7D34065FA4 +:153A5300DCD38BC17F16C215282BE7B36DF1B20CE1009015D890 +:153A6800519351FACD8C711BE41B07D8FCD85E01572DF015E0BB +:153A7D008B362E6508AF85FFD590871FBE8D3077DB00FFE716D1 +:153A920060DB065C815F37F8F1C06F9E02BF50D0A2477C8E4D94 +:153AA7005FF7D30915DA5D854FE6979714D18B4378E47103D74A +:153ABC00A042F2B826E0FFE5F4E5E83C48448BB958C5D5995BCC +:153AD10022D86F4A3B642D4B3A81CD7A359E6991068C52DA2366 +:153AE600E6869C3C3250667D7A8CCE0570350975C67E4B14E2A1 +:153AFB00453406F90D215EFC4D05DEA69CC231AD5945BBE28BDE +:153B1000E5DEA56CD32B8353CF32E6E4C3360D68999FD8FB05AF +:153B25009BC63413FE51074328C0D3A12FC47105C39EB5F48CEF +:153B3A005B1CFE047ED99FA0AEDEB2E502C00A3207C1EDD09B26 +:153B4F00492097DBE9826CF972B6A983F277F46D310DE45551D0 +:153B6400C9BA280CF32A0B5E8A2FECDF7E6E461F5EC2BB96FCCD +:153B7900FB0A75ECFA31D6F1807A030C0DD29726F4F88F11604E +:153B8E00B44D64ADF7EBE0CEC03B096F16DE1CBC26BCD3787B99 +:153BA300758E0CAD3119DE50CE8ACB360D5A75B574E6C9CD7E81 +:153BB80039DB2DCF7147E7B8E373DC8939EECC1C77768EDB9CD5 +:153BCD00E366BF9A53FEAF8A74FA013FDDDC6CFB0393483BFFD1 +:153BE20064C16E531CEA161838AC56D2D9503B1F9873E3DCFA61 +:153BF70086F8BA48E0D8849ECE219D66F03605EEB3F09E83F799 +:153C0C0002BC02D0A71ADE2678DBE1ED86578177C34FACB8ECF6 +:153C2100D004E12DE3D01FDC8837BDC88D784B14B9116F1B8B77 +:153C3600DC88B778911BF1162B7223DEA2456EC45BA8C88D78AC +:153C4B00938BCBFFD58C5D442A1FDC818E8C816D1BF54BF97BFD +:153C6000D65DEB9C6B279C5DCE3E03E0576445F89D1BE74F0C29 +:153C750047DE7314E417908DF427E6310FEA1AC29CBA33CD31E8 +:153C8A008F00FFC0673A451823CBE545D73C05E3622DFC231DFB +:153C9F0079699B7A971778D67C5671076BEC8CCEB778DA4DF0DC +:153CB4001F996FF1B23AD6B8DCD11B91D1CE2F8CF93AE48138E6 +:153CC9009BAE84F11BD29FAB44D9E1D1193B0A20EF9DA91F80D0 +:153CDE0071793FCA08FAF40AF7F227208EECBDFCF8E48C73B8E8 +:153CF3009789E311A0D1531C4F8472B7DA67BC41DE597E16F2D1 +:153D0800F290FC3E9B8FD502BC9B251C0F51BED8AEEF88E3B99A +:153D1D009E47F52DD1FD547FCF87DCBD92DCAC23CF6F03B4794F +:153D320057EEC6B5306DE33C5CCF1FD399FEA81E80B97B271B90 +:153D4700A4F8839E0985AB6987B175CCC07B8078905BC9B66F83 +:153D5C006C587B6A3E8E637ABFE44D511E47459021218D203F57 +:153D7100AAF330167B2A715D6ECC401B0688E746C9923F10D617 +:153D86009C385BBEDB378F553C01F965E6E138D3A827696C6ACA +:153D9B00A2B109CF137235213A9F7EF662DE539E18E874C79ABA +:153DB00054596ED05F5CC12DBF0BD24CCDB76422070F3E5B5772 +:153DC5006B66FD43D6A7A7914F6D25BB6B98BF74FA030A9ED3D9 +:153DDA0040987DD1B1A53CC82A3CE4390D79F6824C85E7407863 +:153DEF00D265A57138407607A62D9BA17C7CC21065EBFED03C4A +:153E0400E9413FAA0580E7F3F26306C6AF043E4AF7A59780FC2C +:153E19008C770C16DDDF721EF2F8511CDA5E1C6D16587691BFD7 +:153E2E00CBC63A4570E33883B88C9633CFEBD0665F65039D0EF2 +:153E4300EC164EF6116FC23CE8CC045BD2E9C07D1EE046FD401A +:153E5800A04305DAF9C0B6C1A3DED985BCC7B1FB5D5CA7605144 +:153E6D009D9CF106EB45FBBCC0EF102E777618E039AA511DA462 +:153E8200319C7340BDB7CFD89D8D0F68231EE6B9016075D27CEB +:153E9700383AD8897BD4FF7CE0E7FB45B9C50890AEA70A7D760A +:153EAC00B5E1C0CECBFB691E86FF38C64B368ED6D8703A7A6FBD +:153EC100362E03B8BFD60261BE38BFDC5F32D337244FA36ADD4C +:153ED600E39AA6F28CE3E3CB5924827BD6796BEF219FFFF2F1E0 +:153EEB0008F82575BC5BC09BBB57F59EBE56918EAF54EB645735 +:153F000017E9B4E6B6A30E89C7533C6EDA70B6B225342E4F0ACC +:153F1500CCF334D4F167D0F6D8A6AF525E185F405E1F19A77B66 +:153F2A000BE8FC47570B9D7B00395CFF6662AC13CF44207E1FE7 +:153F3F00887374AF9C8D779FCF747756A1BC6E1ED3CFDFFC9DFD +:153F5400E53F0337D69937272EDFDE0047567BB3DA8F681ED6B2 +:153F6900779BEEDE60D7049587FDCCA2A74C3875F835DFB5043E +:153F7E00F729315CAFCB8E459CFAC6B8D9ED12F5122EC6B94E46 +:153F930084DBC1DB4BD971E201621C78825DCECF208F775BA70C +:153FA8003AD3BD3C543EBB2D76BF9EF7AC063A8AF1A2BAC88FA0 +:153FBD00E9A87F56A80BCC61ACFA3715EA8270F05D1FA4BA1001 +:153FD2009EE2636F8927B7D4A8DAEB1E79ACAF707C17E9FAE127 +:153FE700DC688FCBE6138003E0E99E82CDF1DC8076F2BF1C7DE8 +:153FFC00CB16AA13EACF3A696F837448EF34A429E63377BF6960 +:15401100B55751DEAFCBF171ED73D18930968D6D51DA7CD43A54 +:1540260057969B80F9C2A041F6E1A72D5EEEF415DE3C60489E81 +:15403B0009D50B3CF77E985B8926F215CDAEFF9199FA43BBA8E9 +:15405000EA3A46F5AF02BAD9F42D8C21E5C8EFA83F68AA6507E9 +:15406500DCEA0F17D1164AE4D0ACFEF09BEC21B28F82386BBD10 +:15407A00C53AEF8DE53CCC863BA12D5BFDA46BD06AC700EB5097 +:15408F0002CF30EBFDBBC9B6F9B139F4D62D7AD71F5D6E805B09 +:1540A4008C8F17D1F5908E6966E83A6ED72B45F5429EE3ED1A8C +:1540B900A63A2DCCF0CBB1ED3BB42CB45FF0E333686B3FA90FC2 +:1540CE0041FFB3ECEC5BF5F802B44FA72DFAD8D1CE4A281F618E +:1540E300B900B02C84B677A86C76DB3BF99FD0EEE422F8E200AC +:1540F8005FBC083ED981CFE24B84CFAE4182AF982F4C4F5B7B51 +:15410D00C8F8E5E3D69DB37A34B9B1B268CC49FCDE694B85B9DC +:15412200AB8F454608B768CB223D9DAF28B43D906D7E81BADD7A +:154137005FE5AF95E2D6FCDB17DDAF3E0969020D7CAFF7745A0A +:15414C007171CCBB00C3728774E97446E1610E7E10609570CC13 +:1541610081F683EB92828072A7A6058347FA65909112F78EF437 +:154176006E41FFD4EF90876F114E1EA37DF073F5C3CB58EEA8CC +:15418B006E84B85ECCA72E398C36C1FC5578BF10F827613ECE96 +:1541A000A4618387FC708F93DC502E4F7B2AC306A5C3B2F461E7 +:1541B500D4175D5097E13B07AC345B1230A7C77511618DA6D2CC +:1541CA00FDBCA87364CFE91156CC7F6BB7A694F49C5713F9BC33 +:1541DF006FE4239A8275E6214D5DF2C03A841FC74E840561C3C2 +:1541F4003D8476802170FA88521587BA9EF88AEA631AF0F08C51 +:15420900F22D1C17EC3CD1FE3CC8C03E4CE7D47D08F24FED3C5F +:15421E004CF7FE627BA1B8B1435B84EDBF534D840DEA8475C1C0 +:154233007B41912E8807A61FD3109F6DA83600E10E2ECE16F0E9 +:15424800609555C003AEBFE62C3C04BFCF77A67A70AF79421B7B +:15425D0000FF11EC2F8013F4C3B50D1C832D788F010E0E289865 +:154272007F49CF6BEA66C2C301C50BF5431C48782E05F74EF013 +:15428700CE0D280B6DDA86A0FCBAE0B97EC75EAD65DF04E6FFDB +:15429C00AF30B6A326A5BCCACE698B42ECD38D32FF61C79E62DB +:1542B100EE9364AF96ECCE74D31AC19251EB6C608AD245CD6D7D +:1542C6001AB46D0F7C711FCDC8BD36D3CEF13C18AE55611B6D33 +:1542DB00C1B934EA1E86DA35F61AE9B58DC2989B4D34B97B3965 +:1542F00021A2F289B0BA0760AD5726F19E385D977777D1FC14F6 +:15430500E248C03B44F9639D82FCD94E49FEC4723E26E3789DC3 +:15431A007D0EE461FCF6E35C2AF628D9BC0D74C886953FCA8CB7 +:15432F0063D91084B540FA2648DF08E9D1AF56FE44A79307B46F +:15434400A74E11C205087F6EC567293F91E666AF6C71E26CC493 +:154359007200267FC7B495B76EC18D388A60DF00385BE467BB1B +:15436E00F88E901183705C2FE882F934970AAB5202F7D2ACF8F1 +:15438300981FB481000FF9603CD2E77E0DCF015AF769601F6EDA +:1543980067F6FC1ADBBC346E97B3AF1F6D3254D3D97DCB0FE76F +:1543AD004CE8876D2260E9B05F325FE2388B9E057FC8BFD6990B +:1543C200FF901E1F944F7704650CF3B54BE75CD6D9C17D3A8668 +:1543D70021FF015E6B95057102B9AFA9FED35F53505EF5771D0F +:1543EC00B2EEE580303FCEFDD9611CDFB58FBF50C26AB387DBB4 +:1544010036C2B827DAF30C4B67D09273D066BC9038B0B40A64E3 +:154416004F3FE61BDA67C151E0932982CF1F4D46C83E04B8311D +:15442B00CFEAE8785B6D519E85B90BF05C4A6FF3CFDFD8ED19DF +:15444000EB81733B80CDF71CADE934CEA4293E8F48F76DDFA789 +:15445500FDF632E9F6CF4907ED5DBFDC7A52D4DCABFDFB65D2F4 +:15446A00DFF52ED2BF7C997491778477AF76EE32E9DE60EF5C67 +:15447F00DEF49B73F6D3707DA7B8FD01ADA65F9BBDBE31373CC9 +:15449400F1FADB874FBF53F8FF76FE73C2C5E2F6FF76EB03FFC6 +:1544A9001FFE47854B45F8F7CDE54BFF67E0B7DB47ECBDA5C765 +:1544BE00FEB580974916FB24D9B869EA1F94E2B7AD82AE287AF2 +:1544D3006F573508C7BB56C5EBB6AB74D607656EEF0675DEEA92 +:1544E800EDAA2CDFA9CDBB6E40F5F7688AC835A8FECA063509AF +:1544FD00728BDDA7D75D80B159F236A998DF1F9BD7DEEB35652F +:154512001275FF7A70EE12D7502389974B7A3F073C392036A83C +:15452700E53D2DEAC3D7372BF53DCD4A50BC4D1D2CF98082F66E +:15453C002017F17167AEE2C7F83C77A54A6B0FAB078877200F1F +:15455100A9AF4C2AA8DFE584FB28BC59757B1324DFD5DF9450C1 +:15456600697FC9BE2F7C2E0CAB6C182A0086BD0043A0A87C2C1D +:15457B00B70E60C078942FE45F5CF6053BDFE9A27CF3F967F20B +:15459000229E150FB3DEB578473AE49D28896B888F3CB3F2BAA4 +:1545A5009AB10555801B11CAF4AC69061C35288BC416B5F6430B +:1545BA007CAF9B0DF4D57F9EEFDD3B3F4934C0759110C0817BDE +:1545CF00705791DD9019D81126929358E21EAA1BC074D286E933 +:1545E40028D65DBC51ADDFB956E52A1DD8F2171DD83A01B66A62 +:1545F900B181FC1320203AF4F254B6A822C1B45D595499547755 +:15460E006DDD51680B88E73FE4F3360C8CEA893695ACFDE3E983 +:154623007BB0DC9C0D075793C2BBA784F99A05837767A3EA852E +:15463800F2B06EBDB62E3F2ABD115ECA66F0520F6DA7624D974C +:15464D001AE889103CDB4AB62BE580970A31A996B264DF0EBB47 +:154662006D2EA6BACF947B0ECAD221CC0BF802BAFB1C1890F65F +:15467700F5DD372A280BD5F7DCA8CCA53F74226F39ED1BCCF4C2 +:15468C00A7FAA93D148F3BD5A2066E8AAB3CBB539D07711FE630 +:1546A10058D06DFF1BF05FD10370427BA9A88CA8DAE31DCADEFE +:1546B600131D4AC5A9356A4003BF9DAB55ED233740DBBF41C1A6 +:1546CB003610009CD6AFB170C1C7B95E996DA0B60D729ADFCD92 +:1546E000DDA28AF112BCF7C4EFC1BD9ABAEEFE79DCADAAC8AF72 +:1546F50052C59550DE7577A8E2EA1BD4E192554A04D70156CE75 +:15470A00C42F0B5AE766287E326CC57FF233AAF844873ABC35B0 +:15471F00ACB861DCF53E7E9B52FFA1925EB48D2C24C27D9E6CDC +:1547340047DFFD684F4A0BABF5A76E51B9931DAA067139618691 +:15474900169BB08F07E99CCD3AB4A5220C40BAE31D7D34D76B64 +:15475E0067BDA5DE505F99B7BDAF3EB556D906BC4106FF21F8F1 +:154773007E1A79CE4FD6ABE250878A72B52CDF8AB29D20263FAF +:15478800A3726BEE5429ECC90E080FABC38033A43FB6719C93FD +:15479D0094FF03D75B7F0A70A80DA881539F512B4E6EA736B0B1 +:1547B2000BDAC03CA07D7954EB2BE64B4877A41DE928DB34C57B +:1547C70036791DC0D28BF0039EF16EBF1EF84F96DCA5CC837208 +:1547DC0010FEC1ADD6FFAA8BF900F225C78D71616C58B7278FDB +:1547F1006B3856DB36606A85F843BE0773AE054EBBBA1BE290E4 +:154806003E39C070D71CFD4AEFE3B54AFDC96AC06DB57AB97630 +:15481B00F4129B6947BF64563B421A94433B0A8A77115E1EB6C7 +:15483000DB12B6A380067E73DAD2F6C49FAF2F0F6E00FAC4FB9D +:15484500B7B35BD7CF0BC6FA39F10ED57157446F5D8F749A376F +:15485A00B0B68F9DE8ED73BEF52FBBE87E9DF2C4DABE8A6C6F1C +:15486F001FE7019A5FD9A0B9810E1781F688BFAB8916AEDE0ABE +:154884006D0BD0E10EA0C30EE2E9C5B428B16991B4EEF5F17365 +:15489900C29550766CDD14D105DB4D6CDDD13974019AF86EB218 +:1548AE00E9027CD7B7B6882EEF2BA2CBABA43339D3B7B742BF10 +:1548C3001E29A213D987863680FE9B6D5A9D063A39B4D9F01E37 +:1548D800E971A6881E3FB2E9817D3A60D3E2123A006D8A695101 +:1548ED0016FDD4FAD2E8DAF5EC6ED62B663FD5374FDAD057C62A +:15490200FE7A7D79E26FFAC4ECADE4AEFF3CF5579FC8C01DBD70 +:1549170093F0CE6F6ED05CC07B2F96C5B47207EFD04F2BC4AD95 +:15492C00C0FFFE42AD5873EF2CBC975F0EEFA9C548F322BCC7E7 +:1549410009EF4E7D8BF10F3CDF779D8D7F5C13C17EE2E0DF5732 +:15495600847F17AD6D58F81DB1F15B897C0AC2F0DEF0E23EE01F +:15496B00A47F89C6058B66988EECD3DB74B0701E9905CB97015C +:15498000CF6286EB7D12BE49E03DA59007DE9FBCF763B7A9F5A9 +:154995003D5D8A54B254292BB956C1362C02EF61273AFAF6FE68 +:1549AA000B849D5AA3F84A3EA2784A3E6A8571ABFAD8F537F4B0 +:1549BF006D8BBB7A11AEC5F69DF2D046BCA5B28BC648F4477B35 +:1549D40018CE1C05CB47BB9125CED86D8F1F180F75A511AEE79C +:1549E900F3793FC429F4FD27A1EFE3D87506A693B85E82F2017F +:1549FE008C75FE27ECF8DF82FFFA9779FCFA8E505E2975976B5E +:154A1300FC36D4D3629C7597298C2C795F74FC768369A4F38504 +:104A2800FEFE99F5D6F2FF06E2E5D1A4A89C0000A7 +:00000001FF diff --git a/drivers/atm/sba200e_ecd.data b/drivers/atm/sba200e_ecd.data new file mode 100644 index 000000000..d097e743b --- /dev/null +++ b/drivers/atm/sba200e_ecd.data @@ -0,0 +1,928 @@ +:150000001F8B0808AC5A10380203736261323030655F65636426 +:150015002E62696E327D00DC3A0D6C14D7996FD7B3F5AE71CCD4 +:15002A0078592F3F8DD70F0AA949E8DD022E07F61A1644AA40C3 +:15003F00012D88A433EE52268844E8924B571792229D1B0F8EB1 +:15005400013B7DD0C7608813E1640D5E58529C6C909D101DE4AC +:1500690016357749A4E4BA8A7227541DC9AA17295C4A2F76455E +:15007E00259438EC7DDF9B19EF7831C4A1524F772B8DDF9BF742 +:15009300BEF7FDBFEFFBDE1B3FFCD3BF7F88B808896E2484FED3 +:1500A8008890844A880EFD1CB4BBA00DB710128396439B8076CC +:1500BD0018DA4E68B51FC3036D16DA1DB8364E88026DE92FBA6D +:1500D2001EFE486452BF7C63D90D63AE825E0863FB54E1A984C2 +:1500E700782F999F6AB59F9E3C49B19D522690D8ED9FFB737D9F +:1500FC00FCD38F45DB66F353D2B6AD1433AEF2F2F209D77F491D +:15011100BE34E18787275C3FF52678EDF13693B20B7EE47FE17D +:15012600E71A20BB45FB4AA95D5E29DC72DD983C8589E52B4C68 +:15013B00927E7959B9A987A7DA6E4DCF24842D778E97CC7F63BA +:15015000F90B6D6DE8BEAEEBF97C299D49C95956A43F7A5BF4D5 +:150165005F7C512AA1FBB7D87EF4AFBF99905E79919E97FCDF83 +:15017A00FFB93C759E5BCDF3F48DEFDA29E89C2A8EA109DC0E0B +:15018F005FF8FFFE2B387E24ACB3FC6765A432BB6F911CF4C674 +:1501A400C1977CFA72F2308031121A8EE3BC3E026FE14E96FF67 +:1501B900025AF9AA21793BD46B5B3B1A708EC8A429FF1CF1557A +:1501CE003E4F7C81FDC4977802FA5DC447C2618EEBEA932EC057 +:1501E3004BB79000C012130F873C52EDEA50657DA14AB86BAFA6 +:1501F80014D4B75C5C467C1D4F126F20B8231E269759EF9EFE32 +:15020D009D846F61249CE1FA03844C0B6A716FD52F20EB9C6518 +:1502220035C1447C7AEB6916F59268404FA9249C341086C4F6C2 +:15023700182477ACC79FE300570FFC87E3FBC3A4657AEB6A1692 +:15024C0085F4D4BE7FB34AE4F5AC7D7DB3FA3C213546D2DD045F +:150261007C32C81F7230EF6A9E22B7A8B81EE7116EDFCCCB8A9D +:1502760067E549751FF5B490DC6C5641483010844C26EF66BEA1 +:15028B006067FCC3B9C4E721F3D53DC3EE1669F72655BAB04CF6 +:1502A00095B6AC654B008EF03EFD6EBA6531EA08F113F958A63E +:1502B500F8F4EB015853B966BE7AB950A8FEB04D8DB4FF933BA0 +:1502CA00021254BC2478DA75DB3C456FC2D306E429775C5F2546 +:1502DF0078A202FFB7626115F9D9AB95B5608BFC601B04DD5402 +:1502F4000575C0F90BA1C39DD5640A91FBF4DC8A2D0DE780D715 +:150309001DC0AB3D1FAB26E3C3487898BD07DA0F053964FC6180 +:15031E00B09F6E2C85F4EFDDC054B2B33F93978886ED30B49447 +:15033300768879E085CA723BCEF75CC37918AB1763BB718C8F81 +:15034800E218973A503F887F41CB78FCF545FC0256ACB3E8DA10 +:15035D0034052D8BEE84341DF8D924F1874DFC62BDC065D1B458 +:1503720069396575E2BF52823F5CC47F03AE9BF17F2BFD283F5C +:15038700BE7DFE1BC41863C362AC4325B1FE8C3D3EF66ED31296 +:15039C00F6BE39FF0257281DAF69ED17F8883C2F83386A5A1923 +:1503B1001BB5E418C30B73E3E48AF573539E9BF37F2BFCD76E07 +:1503C600827FCCEEB1FE1E1B7F838D9FA45929AE521C387FCD8B +:1503DB00E143B62C02A73CD433A10CE3F647A7B91FAAFA55D204 +:1503F00030CFB4AD06B685FE0DBED990327DD38903EC5BB9A572 +:15040500685F6F5587E09B3474B0AC44A2105B784D2CAD1ECE76 +:15041A00B85B80BE512D77A9570A85A0D33FD6FD99EB3BC4FAF6 +:15042F00CE09D78FAD053C57715DCCE12B18A2352F4BE4DF3E26 +:15044400A3E73F3562F9670D7FEEAC3AFD034D21B14BAC4EB966 +:15045900475D4C7FC5F6DC3B9020F2BF81EF26793FC4F5605035 +:15046E0089631EE0D00FC49222DEE3788D3E00FDB481E324B744 +:15048300A8470EEE8A93DC7B10B366C4F7CDDCA178E9E3ACFDEA +:15049800FD956A27C4B7F6F7D7837DE688787987152FBF0532CD +:1504AD00C87598AB92BC1BCF26E134E7D056692EE07F3ED0CF67 +:1504C20033CC96D2CAB56AA12CCB24D72A55EADDC8BAC949C5A3 +:1504D700A50DB0EEB2E30AC28C421A3D4C5E56C05E0CAB886E6F +:1504EC00F23A8C67712DF4FF45113C02DE68FE6D03E4309096C9 +:15050100DB45AABB203749D1BBD5BB80A7629CBF17F86C6701DD +:15051600E06D6788F8BC40FB933677C4BBE135950CFEDCC09CF9 +:15052B0087FC728B5FC455F5515EED2E3BA9A05ED65592181934 +:150540001C30B244C0E918E7BB519E705AC4FC2A42FC2496D294 +:1505550047B7F635873457A377C309F0B30106F089DD3F9C0F86 +:15056A00364FF16B85424D9DF26B359AFF9457B94EA8B1FCDB9D +:15057F009C84327177E57915E18379C83D202BD2385A0672CBE6 +:1505940003461053742C63CEC97F32C0F601EF8697D559078ED5 +:1505A900C3BE4D097EC0EE19B0BBD8136BE99A8829F3A21ECFAA +:1505BE00CAE3AAB013E634CB4601878D1EADB5725A02721ADA1A +:1505D30000748276C8A27FA15F800E9016D959D40FEAE5975DB2 +:1505E800DF079D844D9D583CD83A09002E874EAA854E56AC5F7D +:1505FD002CF0900C0BB60AF9C00FF764AC07F676126B984CB013 +:1506120055E82BFA3CD80FD619159837071F671F423DF547CC48 +:150627009D9ABBB94EF94FD5EDFED9920D9ABB2948DDCDE3ED05 +:15063C007B3FE4F1ACE201DD96CA8CF2A1DC1EB2006AA3679877 +:150651000CB2CABD9BD88E3B896FAFB6B1C9BBE105F0796ED6EE +:1506660014E1A5ACB002FD803221E3D52B26CFBC5F7F80DEBF28 +:15067B00988492F15AB2470D8C32C12FE9EF63DDD98560AF85B3 +:1506900006ECCF8CF5F4E05E053D0AD9486CD0C0F501D8C35394 +:1506A5001C72BD05754ABA6D6364519B29DBDD753F5B485DC4FE +:1506BA006BCAFA6BF53A79F216B2E641D6939396B5F5DBC477B6 +:1506CF004CC8FA30C8BAC39435047BBBE1F7A67CB1E3FA532095 +:1506E4005F6DF63BEAD4489390AD2C36430DE9A1E66F635D12CB +:1506F9003B20628096FFDC38EB2553A0E5B81F85AE5007644910 +:15070E00D12FE4BE8CF5801EFA8A7AC8BD6A209D523DF4801E4A +:1507230074D043D0D24325E80169074B68831F4E194FF38472E3 +:15073800C0972AEED189F7E6346B6F46C6E6D1C78027EC8760F4 +:15074D00EF3AF72BEE55C253FAB5151EC10BC417D8AF2761BF9D +:150762007ECADD9543AA6BE659D5D53524F6EC11C79EED297B45 +:15077700C5DEB37E9C3F52DCB335E8FFE8D7CE7D3B0BE05046FB +:15078C00BF4346AD9C4C71EEE7B1FC943BCDFDC1CBF1EA46B191 +:1507A1005788F48AD452BDAC53F4AB5DEB45BC8E06486C8EF056 +:1507B6005F6EE65EC88572F20A93D6ACC59C974940CE2B4C4D3A +:1507CB00B05EFDB8C2662694C06E880F77A4541FFA4FCCB0FC60 +:1507E00087C7671D931ABD55AB61BFC6581BD118FA4ADA05352E +:1507F50041586188A322F20CD3A03568598B1F7CEB04ACF36627 +:15080A008FA9011DF3FFEF0D51CBE01EF84BB6DB3E6764B09B53 +:15081F00E9E04BC89773FE51F0AD1524C1B6E9879693F065A3B1 +:150834001E6581396FB61DCE4A585F7C435A0F9AB4B278CE7380 +:15084900CCAD4A8E3621FE34B9357E5D33D7E74BD637265BC568 +:15085E00FAA513ACA7DA492677758B1C6DCF47110FCCDD958C37 +:1508730034A1FEEDB501FD984A61CE8BF0B1B9803B950925C1C8 +:15088800A6164C8305238BF5A9CC647C22F0A6D48CF11F7DAC82 +:15089D00167D35D76F94D64FEB1E76D43FA2AE642C8AB58F2916 +:1508B200DF196CCD7ACFEA53689DF58F63FD1C0D7D1060A1FEDC +:1508C700411CD21AA61EC43D0BF2E27E1A572BE3F1F93E2FEEED +:1508DC0053C31FCCC6F17C5BA75C51FF86BE06E7DDA19D24F6BF +:1508F10004C39C9E7B40D4893C8BF50E9C875D33CD9A270A7153 +:1509060003EB2B92DB8E7006C2C9C119702E7E5A9C8BA747FA68 +:15091B00C59938181D54B1CEC0F544AE15676212AA8F4F8F3447 +:150930008873309E89CB8066FBFEFBADF3F0BDEAF32EFB3CBC70 +:15094500D43C7BDE10C78B67CF89F2349E3DDFAA29397B62AE9C +:15095A00B6CFC3B992F33087986B3F373B0F7F4D8C7C4CDB1875 +:15096F00F11C3CA3BA601DC6BA3D10C776BF9B56BC55C7314647 +:150984008A5A40C43898C739A0853569CD9CA4A7C98449A13EBA +:15099900A222060A9B891858EDADFA15F8C48098DB4EACF36D2F +:1509AE0091DF1EC423D60B9D9B7024F62763F7BB19657A24259F +:1509C3006C00670103C726F7FCB3217C16EC1BA8492A585360D5 +:1509D8002C47BF7906F9224BD94BA843FB5EE0366C531F98D827 +:1509ED003613DD0B94C796AA28EB3EBC178056DC0B403BFE5E71 +:150A020060693CEEBAF15EE0EB6CD6FE17B0D944FAE413D8D15A +:150A17005B750FD830CA2C7939CAEB6D9D6DE290470CBF43DE6A +:150A2C00042153049FAD7D967D070C8499DC73613C3F729F6190 +:150A4100E39D01786D5BDBF1E9CE478AF1C5E5EB107ADA94DD30 +:150A5600D3689F51E58D49A5A67590C5800FAC0FF04CAA79CD1A +:150A6B003C8DF05CE80DFC0A748363EE92B161475C9A41E7F61F +:150A800060CCB93802B97A659F1AD0D07F1A18C81E708580C77E +:150A950031BED23C564648A3E66944597640DFB5C63C7FE1F838 +:150AAA00E1DA2106B508F7C82F412CEF33EEA4A70D29B9C7210B +:150ABF0097CE104EFF119EB74C5C4B268B2B79AA880BE087AD61 +:150AD40073A08BE8784634F0DDA6F34DE4D11DF2F43878D02783 +:150AE900290FC2651E30E5D11DF27C2DAE1279AE96C873F536FA +:150AFE00E5C938E479C7C1436692F2205CFE7E539E8C439EAFE6 +:150B1300C55522CFB51279AEDDA63CC991A23C67478A3CE0F891 +:150B280064E44138D99207FB4B268BAB449ED11279461DF2440C +:150B3D00ADFB0C19F3B9E5E3750A53EFFB09D2357D04DF975A45 +:150B5200EF19EBBDDE7A47FAF83E43BC2799F065A0B1AB4CB4FF +:150B6700ECAAF59EB6DEAF59EF17ADF751EBFD1DC0B38B9EE038 +:150B7C00D8D760AE93BECCC5BD03F47BE86B5CD403D04FD337E7 +:150B91007994DEC5CC73C5592303EBE05C51334BF33407939EC7 +:150BA600667FDED3EC053B606D8F3236D05302CF7658BB9ABEDF +:150BBB002AF074437F337D83E3FAB74C3E38D2DC4E777313AFA4 +:150BD0006E0C025EBC6B5841DE6167B6BEBC5CDC59004C15F5B9 +:150BE50034E2D80B5B5F136359C7D8335BDF1463C8933DF6E484 +:150BFA00D6BDCB6DFC7751D37E886796E8A7F9768B3EF2B4B65E +:150C0F006E60998DD386455C36ACCD2BF216B26011EF5F514FEF +:150C2400B3B84BB1743AFC88A9D39CF8EE61CA3EC3CE1F304F8C +:150C3900C7CD9BF4EEB6700C9A638CFF9D09F3A1850369071099 +:150C4E0007CC651F2DCE452C3DC6617E1DE80F75C7A01FA7072F +:150C6300399E8FCE099E2E0B3E1FA5CFF15EA1DF1EE3F48870DB +:150C780040FF03D73D4D7B67526543E88D85CFE692CA0F962315 +:150C8D001F9D424715509B2E592E352D0AED5EC861EE6E319754 +:150CA20011FC56243D8DB3DE949A82A1830B0D98AB5A6EF28FE3 +:150CB700FAAA807D72FD2BA9E98BDAE7161E82B93F367B9A2BEB +:150CCC00B4F2C6CF2EFD2182387F57CB22B8FEB7BD831184FDD0 +:150CE100E0D269C8FB3B044DE03FA38B7686E019E4CCC444BBDF +:150CF6004BE026E1682629DA84E0036A8E0CEE89E9172EABAEBD +:150D0B00F735D87FAFB0CA60268EFA31D75D36368BD6D41109F9 +:150D20006B8602EDB495C755D7FA47A0F6D9CFEEC05C097A3363 +:150D3500E9268D0ED1EE303A45DB23F4590EE705D7FEC701FEB1 +:150D4A007BAC2A1806782A6219C20F8A36619C15ED52A1F32969 +:150D5F001700FEFD7F10B5D5D4600CE0A386C977D2E887F6692B +:150D740061875D467AA498DB4808EAADB0226CB30D6C93A007C3 +:150D8900B81CCCC1D845B6B4CCBA2B17ED45A301DA9DDF273E14 +:150D9E001E76B7C0318F1D182DF8D1971E85F14A7A02EA055D0D +:150DB300E8AF0CCE160BBE8370E6BEC25CB9CD82457D5BFB8D79 +:150DC80061FF29A029FBDE533B9625AD6F6D507FC1B896FF8DAF +:150DDD0011681D62E8C0DBF3AF1BF0CE75E02D104DA9B20FCFF3 +:150DF20039EF1B121D323E69B0F8A1B3D9F52F4D1A4761BD6C70 +:150E0700F1C32D7E8ECE29F283B9EE030B36EBE0277B0B7E623A +:150E1C000E7E36033FF0CEF904FC6C76F0F39845E33DDC47160B +:150E31003F598B9F4A073F98AB5659B0E86F363FD8BF193F51AC +:150E4600073FAB811F78E7C909F8796B71919F8FBE30699C1BBB +:150E5B00C19C66F28334909FD6D9457E30D79C3161052D37C413 +:150E7000D68EE694310A676A3BC63A3F0F6874906BF434C4E84F +:150E8500CD4C0EDE173FBC2CCDF0FF560EE74E2AD65D9091B78B +:150E9A0062CA7F8CE0652EF17B1D79334EFB7959D57995E60779 +:150EAF0058714DDAB868C5631B5601B86ED8DB7E888DCEF53124 +:150EC400DACD37037D05F850E85178AEF0049DCB77D105E03353 +:150ED9000DBC9346C056AB799DB24D35C8A1447D3EC5BAF55427 +:150EEE00A207E093F41C4F53C60FF79E663564409DB6A597D514 +:150F03005EBAC23AB67C97EDA99DCFF66E59C8F6F52E639D97C5 +:150F180056B223B56718DED37CFCDB32DCD30CFFB7E7D9DEF32D +:150F2D00ACF2C231F5E0A5FD500FEC5FE2E4EB9D30F155D1D593 +:150F4200CD6363B176D6B090F8FCCE3121403B3B7A93F1CDD75E +:150F57000A378C2B5A3BC77889FA09D44FB08EB7B33B9B26184E +:150F6C00875AE06A1DF179434911ABC046F2DCE4318EF6C5F74D +:150F81004F46AC1A413EC789CCB844C51D2BBF8AFF6810E6FCBA +:150F96009A687BF8A8DBAC7586451B66A4007551554AEDD6878E +:150FAB00946EBD5F9926A5D4236543CA91E88072186CF9ACFEB4 +:150FC00086E27DEF0FAA8005E0837A9722AF632AFA4185833FB6 +:150FD500BC8390D890187F52AB6CFCC4FE770F2B6EFCFB0A33BF +:150FEA003F6A63B934C991E73990C72A925F35CC4A3E8179C4C6 +:150FFF00CA8567451D63E6AFB366AC039D99F98F5B303D026617 +:1510140047314F8AFDF09845277B039D3BC6D131F3E559510FD6 +:15102900D97432169D0F2D3A264C0F33E3709A87AF12D21B76BE +:15103E00B5941F48A981E83CBCDFF3FBB5EF468290ABAE5E372C +:15105300E5FD40FBEBC6CBD0F782FEEB14380779061290B39AFC +:151068005DA1745CA678DF1B66C92CC489A4AB65333D652C022E +:15107D001C92FC3DC8435D3C14DD1F3948BA13788676877AE21E +:15109200D23D50A3C5468CB974C4705BBA8ED02E234A0F1A8197 +:1510A7007C8A734F6AE702DA67605C895D0039F2FD5C069C38D8 +:1510BC000E276206072EAF93E6A617FA9A9DEBEB9443AA61E19E +:1510D100C0B5D8475C147049A1FA78B464BD1FD647E97306D4F3 +:1510E60010D6FAEE09D7E7FE1173537D1C7909C3DC02A833C232 +:1510FB00B48BE1DD96413A120AFD2FC3E3C238779A19E470422A +:15111000D23A0C3FE46037D6BBB17EC3AB751B95DA39718F365C +:15112500DE8FCF5A7EAC8FF3E331FFCDA614D9E1BF55502B8C04 +:15113A00F928F801DA0F7DB4FCC0805A43E6A9A66CF5A66CD11A +:15114F00BE66A73F0768170F6A529384E766C29917ECB1733E0C +:15116400F1E1FBBE999DCAC54DC4F7E2CCA422D3F9C236ABD16A +:151179000EB096AFEE7E085BCF52F13F2D15B383264E79893719 +:15118E002E43FF568F0947444B8336DF14F65D1D91AB16A81DE5 +:1511A300EEF90F79AC71EED71FB2E7F1FF6AE4E8DC07251B479E +:1511B800B4FB41BFDD5F591C17FB04E498438E36617E801A931D +:1511CD004E8BF5604D631CA2520BD51883B37A0061360998CB74 +:1511E200D6779F4EBCA3A0247692076973837DCF82DF034657E0 +:1511F700342F36BFD19B7797884F4E7633C487637EB95B7D077F +:15120C00713AE82F17B829C33B5949FE0CE87719B80EE95BEBFC +:1512210032B80EE89D71F62F3AF158BF83B9E39073F0FBEF1552 +:15123600568DF74FFC285B8BFB92DE1B09D2798DCC8A0F3FA1C4 +:15124B000F35EA629F778AEFE5BBA75C413ADC2F3F67DE75C28B +:1512600018E4AB1A1BBFA4CD6558B309D81F7EDE4272FD7C9ADA +:1512750003B6C2829520374F16EE10F0BA0AE2DD0B5A5D13D6FA +:15128A0008E677FE432A9C9E184473435AF339F8E46CD63B4C08 +:15129F00104FA67AF42893454EE83FF3BB42A11AEF06B789B5BD +:1512B40069B17681B69FD5C84FAB776AE759448333656C9E811D +:1512C900F489DC6F081EB09F4B19923C5745DC52FEA88DDBE4E5 +:1512DE0011F6DA589FA78C2CD058A44D6FACD2A6477EA04D6DF9 +:1512F30044BE376975CDB67C923C5B2D956F3273820F7BACC455 +:151308007E7C18BF7D9F03DB65E24B08A9C63AC6E53BA7BEE98E +:15131D00C2FBC734D64D747A10725E6CC8C0DA424A0E31D7BBE7 +:15133200E7D5FF065E7B5CC48BF6C77BF9465AD358456B227E15 +:151347007A47E366D0D32A5ADBB8CEB237E2A8965F1577D4E057 +:15135C000C34289F51CB80C60298AF86BE1BFA088773F6B90BB5 +:15137100E15DD638AE0F26E78571BD8CB2027D19F8284CA5ECCB +:1513860008E953189C8702AE3EF17DE059F17F5203D67D685A64 +:15139B009CD1719F797D57D4368823337C4755D7CC4EF57052CB +:1513B0006AA9B9705E9D23EE5933868EDF5E760E88EF34384755 +:1513C5008E0DB1CBE2FB0C65B3C8A9E508432C18F17DA56F880C +:1513DA00CDD2BE6A126B89398EDF4DF4248EFFBC89C883064DB6 +:1513EF00A6F03B8821AF1950A330EED79AC5B817DEA980AB6D72 +:1514040092F05E22F6BA7118FC026582FD5F8D7715B3A2A71B27 +:15141900C59D456ED038AC4942EF788FF70CC43C5BC6A0252368 +:15142E00CA11B1F27D7D01CF75FF43CC13064755A4D993BC91CC +:151443001988C3038611280C0F1CD6E045326894648038C168C9 +:151458002556E40688EE7B5CD089266EB450729055768B5B5FCA +:15146D003081041F5CF34C206BE1DE84CD94932B2203071A3D8B +:15148200ACCBDE79BB68A5AE721677C7D5B9DEECD69E4779615E +:151497008D6CDC65AB38E7BEAFBBDFCC9BC9A0E0DED5FD987AC3 +:1514AC006FBEEEF77D5F7FFDF5F77DDDFD7547F5F31B315A88AC +:1514C1001BB88ED10BB618607BCEF31C0253B2E941318E59B05A +:1514D600E751CCF18671A03F4CDCB28FC53814642D3F01387A39 +:1514EB00433155770FB3BC0699D9A328ABEF954FB03595493179 +:151500002F4698A20CB3BD8A291B2C2060E47206562A6057702E +:151515006D46C454576DDF30DD1B292025CAB0698761DCE8CF5F +:15152A00819102899467C3E8203CE5C8192A83AFA9C032D15E21 +:15153F00DC8F21F4769E6B22BEBFF4E59C7F70B1EFE3D4E291CB +:151554003FC5FFF019EAE881BE606BC0316AD10929C3F44592AE +:1515690030FAF4188BBB3F01BB07D1C3168CBB93E9B888CB7601 +:15157E00C1548AC935947C3DCD6728F916EDE819566B6CBC2309 +:151593004EF46F7DA14186B319437E5C0345D9C8C3B42F1C65B4 +:1515A800F07A019F12B1117B029F3EDC2F92193EA6035EFC1FE0 +:1515BD008E1956FFA7447F768BFE64BA60C90D6224A00FF3A197 +:1515D200D7696F826C29B2D96359B4C7259E72CEF3BD2FD3E9DE +:1515E700C559F685CBFB75B6CF555344C27ADD1915C74C0DDB68 +:1515FC0013E730B2613AACC00E2BC6711C376BC1E339C47B8D20 +:15161100CCE1A1E409E0F7049D3FC9E4EED3053F0C0636CD57B4 +:15162600191773BF8421C3372C8708FA8C3DC3678CD9888F0E7C +:15163B009BF9EA933CF549BAFE5B5CD600837773773ADE8E53ED +:151650006931CC3E443BF19DB5C90BBC5B6D82F729479CE97FDA +:15166500C09B29DF579729B7607BF3C0A40DD3614E3B2C67FFB1 +:15167A0091E9BB1863D6F8B58FED8E9CB18D4FE7C7710DCBAE50 +:15168F00F58D9EE71BABEC255B19C674ED8BC82CCBA6A03CAC55 +:1516A400727C5F72A1536BC8299F85B4EF47DA71A3028C776FB2 +:1516B900C4B945C6BD0EC0157E28639F5037702C5865E5F6325F +:1516CE0090834BE0614F1B8EA21C1C56FBB9FE71989E0B037C5D +:1516E3007B2C983703D3F3C0667AB261D8A62E5B9B2D58671E54 +:1516F80058A1C70ED38D4431D8B685423E246AA0FDC0F1E915CD +:15170D00FA1E4FEB3BC0D017D8D63A4811616B1AA8BF5EA6BF42 +:1517220031C3D2F39907713D3C418FC2B8F785B86DCB8743BE31 +:15173700611C5086397BF230D6331B6CF350B4EF681FB7A15DC2 +:15174C00C1B526F8EEC0C2B8CAF0839EC14490E683CB36B861D9 +:15176100AFBF203F5C0678AB43D8DF626E732D99615C500F659D +:1517760079E5E5CDDFD6591F27B43E7DB8EDC0C284CA7310AFE4 +:15178B00436EFF8BB8B09D5FD507C68DF0F58D7165F76B42D8B7 +:1517A0007BCB77737B9C2DEB6C7B9C8717F886F302710A3E0187 +:1517B500F76CC4C7F6C3F3C8214F7D92AE9FCDDF6E9BDEE11865 +:1517CA007678A68F71E2993EC60B3CD3C733C903DBEF9E3EC6AB +:1517DF009D9EE9E359CA8161FD57ECDF66E6BC221EC371CE7D03 +:1517F40003CA7489CDF7C15397785C62129B2F9473CA245B99AC +:1518090037A7CC652B5B905356642B5B2C0B3F129834E23DC8D7 +:15181E00972EF2CBAD582446838A3390893D6294E5EA425F6464 +:15183300628FA8C6E38C9CD853CEE4C8C8BE924647DD2AE853AA +:1518480098670742867C3B2105072B357D32E5763A3AD5367878 +:15185D004A20935E85AFC3FE0874EA70F4F7E5646A805EE941AA +:15187200044EC44576EDFFFFFDD5D610F7D86729370D75A835F8 +:15188700F749EBACBD4DDC2F24EDFA293667688F9E1A67CFD1D9 +:15189C00532CC7AA3D796A929DC989D2C446BE16678B410D07AF +:1518B10019FE18E539713F71ABF7F3BC65EE67BBC1CF0E829F2F +:1518C600051FC9E456C2E466F9EA1AE083783AD5F2CF84EC22A0 +:1518DB000E263BB47D51C0E307F847F749AB91D6D98D7C8C8CD2 +:1518F000C013D71B1D0A8B154DFCBF212BF68CD107BF617F17F3 +:15190500B179E0A4896D045924842C12421609218B04CAA2F079 +:15191A005E57A33D7EB95EF9E158F228CB033395AEC0D1422EFD +:15192F002B0EBB13600702F12CD83D00EB0B9CB66045089B0F62 +:15194400B05B03A30863FB3A5CA6572E810C4196172F4D9765C3 +:15195900C37AE2BE700965E95F7DBDEDBADEF69CCBA30F054261 +:15196E001F3EAA26EEDAEA6C3E2B24E2AE075E9CC0EBDA3CBC7E +:15198300C6A17E29E3B574F58DF4C1F5F27B3C0FBF8582DF525A +:15199800A0DD1F9AAEBFFA35F4B77322E52E8076B44F4C6F471A +:1519AD0012F0344F603BBCAB6F54976EA43DF13CED91447B1A71 +:1519C200818773F7417BBE01FDD6FF8236297E2A2BA594D97E0D +:1519D700B0798EBB0889001CFF4BA4D6D88DEF01D550403A8B99 +:1519EC0015CD9495EA57D91E33D899FA08AE37478DF001EE1352 +:151A010095837CAE32FE32F86249077FD8CDD64B0DA837161922 +:151A1600328B9A4E9A139F72DC7EC09B9AAD1B53F0DFC1FFBBA4 +:151A2B002E7C9ACDCF0551F70A3C1B20DEF42A9C1E51393DA4D7 +:151A400083F4D02BDBE92D867A454D43663DD0DB2D709CFE9440 +:151A5500D3EB14F4E0BFCB2E4F59C8B3086489E5ED5524AB7C94 +:151A6A008E65FFAA7879434EF95C513E26CACB73CAE789F2E328 +:151A7F00A2DCCBCA278D1A9A39CF92823652D2A5E2DE9D0B7DD7 +:151A940074CEF9956E888768D4B905E28CAD55B8AEA977AD2A29 +:151AA90056A4A02AE29A9E8517D5AAD0BE60AD2D5F60CF48D3BE +:151ABE000728ABE7DB3FAC0AD8E01FFFF0E5AB085FB3F5832A70 +:151AD3007B7EC18537BFFF1AC29FF8DB9F559162DCDBEE373A7F +:151AE800FFE5856AAF4FDF4A1E236E974ADCD3F8B4E58F2987E0 +:151AFD00B2FD338F35264DB4210E0F9FC331989CDD362B3EC2C4 +:151B12007A3341D7A7D6F2DC19ACDB5337ACCE8C3C12D85FC732 +:151B2700EC391DB5EC39945967724637E69FEF1B9FA7DCF14B5D +:151B3C002977661E46B55EDDAFE2BE0AC48DEEEE8551753D59D3 +:151B51001EF490E5AB16298EE0799045CF42AA6ED0FDC17369BF +:151B6600B9C4D99AC4CD4C1E740FC6284E88F50673CADDB672FB +:151B7B0009CA3B3372ED2E9048B70BCA1D65D07FA2CE22E6D307 +:151B9000F8B73741FD0651FF0EB0FF3EE1DFB0CC07651584EB9F +:151BA50013FE5F7261402B81FF8B6C75965C8869DE1C7E1E8494 +:151BBA007E4A4462A60B7C6CF96F53EEE8D594BBF9CBD42CD1C5 +:151BCF00BE7511B0D3A03F5976C52BF45442F9839E86927F6EF3 +:151BE400E84E320BF50CE3600B37AE5FE21EA16CE30B73854FA4 +:151BF90047980F360222BFA108F02E00F97B9712B7EEE7BABFE7 +:151C0E00600DE016FB3054F8F31749BFD13B3AA8BEB90CF7E984 +:151C230002068F654B0C561EA830D07717B863DA0F963E5CEE8D +:151C3800AD8CD2D65732F1168577A90F2255788EC2EF1CFC9498 +:151C4D005EB0AFF01B17BFD65EBEFE85F82EFE12D7BF94C6F455 +:151C6200BC4CC0A3FFC1E161012F009F5683EF7480CE837E2B7B +:151C770000FF50CCD618264DE9DB84BC823E830E9896DCADF9D7 +:151C8C000796596D9394037406B3ADD4083C4A48D17FA6DC93CD +:151CA100249BAEEE22B370AD1BF1FF33CC476702DD31A81376E8 +:151CB600733F65E191051EF932E76DF493947B90E7F5883A101A +:151CCB0007D1210DC7EC646A361B23B837D6F7F7C7198C4CCED0 +:151CE00026DE9F0EF277F883F2CED48D9AB89FD6377A5C9D2F99 +:151CF500B1F50E93EFB3454DDC575B6BA3C3D71DFB8DC7C61FD8 +:151D0A001B5F363A98A53F37A3FE209FA043814ADCA386B8203C +:151D1F003C443146DBAFAC0BB01C45CC8D8BBC4B95C819C3C77B +:151D340072E8BF303D7CED9BF68A7557BE8E3BC2F70C020ADF8D +:151D49002F40BA387EC227CDE7593FDC40FC373E8438D2F3B0B3 +:151D5E00AFE741D0065A69FA79F475DB3AF0CB69FB17A5E3B899 +:151D7300D62B1BEC9C14192D20E037D8FA3EE0A0631B591E841D +:151D8800CF9A67CD2103EC0C12CA784CD834FCBEFB5EE296C690 +:151D9D005FD2E40F5F52ED362D6D77D99C6CC448FDD57B923824 +:151DB2003324A32D66F3191AA37790C120E6EA4FFDFB7095BD05 +:151DC7006F6E1263BBA482E45D1FE56B9BBAC03B22F026742EFA +:151DDC003FC0ABC738DE25C7B3F0CE1078C757E7E0457B08F1E8 +:151DF100D5BE85FD2A3BAF0F3610F126393E7D19EEC9CB83B482 +:151E06003039AC4BC933BAAB28C6D6F966029DB961AA3922869F +:151E1B007128296D91944EE316F91D6D2C95F279A25230334FC2 +:151E30000D1B1877EE72A0ADAA6DB4CEDD635E358B4B587EE23F +:151E4500A4A9E2B3B8A291C80FBCCAE64201E554E8D13CED0713 +:151E5A00FF15E847FFD5CFFCD7BE8523AA67B4EB5E466F5CEA4B +:151E6F00A49571CE7B38A67B301E13F082484C972B13AC7D8726 +:151E8400C801D584B1ECDA30C8F6D1BE85361EFAC411194EB76D +:151E99006F6E6830687DCBED46FA7D1A3FFDFD997CEC7DE0FFB5 +:151EAE003DBAE0875E831F80CB601F91173B4D07DF4FDF9375AB +:151EC3002604ED1501BE8B47F83C5FC44F203B2E1F9E4F922D53 +:151ED80047B9EBD5ACFD0B186FC88303FA1AD73F43C9237B8A4E +:151EED00F95C4DFF25C07BC351D5E5116B64C0D3C5421DCF3873 +:151F0200CFC2F2B64D3C470A7DCC3231BFAB653A12D7FF14CA3C +:151F17002CDE19DF507FD7261607B33C8E7A51EF7BB67AD5C94A +:151F2C00D7F7C04F47786213DBD3D0314F00DB82F349E4A3F77A +:151F4100A598EA1DE5FC20DCA2DB2AF09DCC4377C446779BA8EC +:151F5600F7B6ADDE7AA08BF5466DF5DA44BD9FE4E16F7DF2845B +:151F6B008EE3EA1CE3F16F74F403B5789E06F83BCC746798AD4C +:151F800015F7FE1DF04A0619AFB5365EDB05EEF7F3F03A6EE3A1 +:151F95006197A8F78F7978BD60ABB75BD4FBD7AFE035BA39C326 +:151FAA006BFDD7F05A6FE33529700F6C9ECE6B7C7386875F8943 +:151FBF007A439BAFD19F9B33FD59738DFEACB1D1BD68F5671EA7 +:151FD400BA2336BA13567F5E836E77038EAFB328031AB6D3C5F7 +:151FE900F68AFB3F106EE9FC7EA87F84C4D23ADFE0E43A7FD59C +:151FFE00C1755E6FC8D00E3B39ED8E86AFA00D741B045D8B5E7B +:1520130083AD9D0D02474F7E1C14C7ACB516ADE6DA3C3C4FF630 +:152028005AC6DEB1F18CE771E5E394F92FBCB7473E4D31CE73E4 +:15203D00157569FB206E94C197C9F5EF6A0B8C33DA41DCA3B7F4 +:15205200D9A01F40BBF2D91EEB3B9F23A61ED18755D417BEF704 +:15206700774085F9EA1E9C9FAE67B832BEE12EC055007E216DFF +:15207C005743C3AA6B438CD954664F2D7FA1A33D8D317B2AD7C5 +:1520910001FF60471DB6F7ACF61663BE4EBFEA5848B514E65951 +:1520A600E0BAEF659EFBC57D5382D3A7C29E86FB786C07BE8FF4 +:1520BB00B765909DE791C3BA46D12F4586C12FBDADB9A2670C99 +:1520D000F44D79FDC98F32F33B9ECFD0A9F970BB1AD712C4FFBC +:1520E500A9546A5EEE5C8FAF47B2FD70B3640AECAB1BC656B88C +:1520FA00D4A0A18E36B4C5AE426E93252BCEC6F32DBF4BA57368 +:15210F003F9529969F39DF9E372855F27B70545B3DBC8028B73B +:152124001EFA84C30A9EA11AA188E7093C4355E6C0DBD558FC4D +:15213900EB284E3462F92DA141ED96D0DBA8336615D6C19800DF +:15214E00F3A901EEDB1A3333FFDFD618ECCF6218A3101F4D680E +:15216300FCFBB7D1A77B0B3C1DDA7BBFCDF0E49F6271928DA775 +:152178008451454EAEF1298E80451BEF02BA83D18C52ACEFBB81 +:15218D00F50B33FDBEEE8B349DE492936B0BD2795F309F147980 +:1521A200F8C8D7FC5B3127A28F9AEC2C5729CB19BA17C5217371 +:1521B7005CBC6E9CA2FCC12D9AB2BC17FAFA347CD36B4ACA69E7 +:1521CC00B3D1164F5E7C84906714E79AB30E316FCD43E7218C26 +:1521E1005DF2E2F69B4EF94DC07DD620B4CF94A2EF9A986F8196 +:1521F600EB9F69DF8DF38A42317E11EFB7C57D14A20CFFE7B9AD +:15220B00EF83E596A21E4DCC40BE127482E78C5397E0CF65E79A +:1522200003FA1BF945BCBE6082E51BB1BC0FF9A4897CC83F5F73 +:152235008EBC73DD13EBF1150319FD463C138F703CFE298E9FB9 +:15224A00E34D30F9CCFF791775C01C0EEFAFE823C32A9EA3C3D2 +:15225F0098977F9330B14ED63800FCC707ECF7C9F07623FEC926 +:152274004778FB389D78161D6B4D00EB323926B91C6FD9DA6987 +:15228900E23D116C4E63A7993E5F1B32382F1586CCE4526BF06A +:15229E009C8480E112F9A00C1E1EA44F2DC5D8F518CB47B4F334 +:1522B300E07D6D39B5F71DD431257908F7E6A9A5272CC606DB7A +:1522C8007A9874AAECDEA8B0C1E4827C61B904EDA515BA819379 +:1522DD00E4C2A24E8D1EB8533B7F21E526E3036CFEEDC53E92E8 +:1522F2004F6992F22EF545F8F9796BEEB2A070FAFCA9A36E8876 +:15230700CDE7B2E650E327CD7B6F740E15FE4BD3D229CC23ECDB +:15231C0077F2F969B64E711D425E4A845C589F04A33C7F4D1EC1 +:1523310030713E8DFE0CF5097580C94AE773E9A35FA6E6D8F47E +:15234600384B9F59DE7800C63E9D30E6F9028DB87EE2519697DC +:15235B007F88FE14E6E9CF287706AFC098BC2BE965E7B07B1FA4 +:15237000E5F4E38FE2251B0798DE610E97809B083F27E6B551F3 +:152385005137915357C04D841F15E3DDC2FF9EF8E67CCE37023B +:15239A006E22BC55E03F27EA2673EA0AB889F0B502FF3281BF77 +:1523AF0053D4C57AF8BED8666FBA6D65F88E67DBF04C9B0BF426 +:1523C400A8107C95A40C98282F49DEAFA19F092883788676EE70 +:1523D900DC505F9504F3D3F91D135A9132642ED22FADF5557FB6 +:1523EE00A64991D3E66B51E71617CFFB9C373332638D14993002 +:152403002D9D9D09B62D7915D7D13263E0FBE02325766E884EE9 +:152418001B8F627CA5ED0AE2900F0E68BD85832AF23677ABDF7C +:15242D00B4C633D301B409101B3892EFB2FD46FEFD88993B9E8E +:1524420079FE24D08431631F272FDDDCA925FE89AFF3C9C2A6AC +:152457007DDD38D98BB9A2D618E91960392BB2F0A7385696619D +:15246C006E00C41A8FB1B5F7CCDED306C51910E7A9FEF0FD47F0 +:15248100DB78AA2DF83FB0D139F1445819A04E4F17936729E02E +:15249600ABFF2CE377E9E7397E1778C13A44EEC03326265B170D +:1524AB00298E373A0FC6B43ED015796D8CDFCF00B8703D05C6F8 +:1524C000E33C764700F8662CC77BC33087D8F2BFB8BFAA46965F +:1524D500D2420FDEBDD7618CFF3A435BCE1387B8224097AF4988 +:1524EA0098D85F7DE0F7E5B303C6154113FB378B2694BB7268E4 +:1524FF0066B7BFA4B1C1463F6CA3AFE4A12FD9E82FCE43DF7F80 +:1525140083F431BEE8AC0C18162FC8C3D825CEC362A0954B5FF5 +:152529003E3BC46829910103EF4082B9B789B18FA4F03B8F16DC +:15253E004706E861887BD0A74DD9E31C5C7393FD66679DA1E108 +:152553005D60532FFAABD87E5FC96D2BFC75CD41E54F2A2AB7BB +:152568002A0FFEF1A60794CDDFDBD9DEF2EC4E6553CBB696A616 +:15257D009D2D41A5FAF107B7EF686968DDFEDDEFB4B63F5EBE5C +:15259200F2EE9501A5E4999DAD4FEFD8B1FDB9C79B9E6F0AADAF +:1525A7005A55B9EAEE157F7497F2D4D3DB5A762A81CAB255156B +:1525BC006595ABE125581E0896DFADF8D3FB5B16BDB2B2E696EB +:1525D100B6EDED654F6E7FB6ADACA9B9A96DE70B65CF363DFDA7 +:1525E6005CD9CE1D4F96B5EC6C2B7BEA85B2A6A66D0CB66DFB24 +:1525FB00F6B6953B6F5B758F72A7D2D2FC74BBD2DCF254D3775B +:15261000B7B52B4FB6363DF79D16A564577BCBAEF61548E5FA76 +:15262500F037EF78FAF9961D654F41B31E6F6A7FF6F1E61DCF95 +:15263A00AF7CF2B67B2AAE853F8D9E9D679AE30B37EE67F71A4D +:15264F00F88DB9BE8AC612A59CAEC4B35CD6398D88B406EFD1B8 +:1526640038143AD25640FA8DC6DFA7D2E7341A958DE627BF703B +:15267900AC91E48735BF526DF861EC7D0CB6C40BCF37D176E26F +:15268E003E09DD6FB47E9172FF74A9146C50866829942D22C3C6 +:1526A3005521A587B2F2B0B4370030B4376B6D30AC27830F04B5 +:1526B8009C66B752B4CEF2090BC036CE203C96C0FF5701F73E78 +:1526CD00F9E5368C13CFFD756A16F2653FD7603FD310BDC2F71F +:1526E200CABA58FD12A31FEA13F9B2E9856FCE027D3B4FB48D99 +:1526F700B0B3D32B1D642EF2877C78959314DB3003E6A998E3FD +:15270C0046C657E03EA9D7577DA7866DEF02393A7F52A9E1B5D5 +:152721006A7EC0C5D7AB0E1961E58746CD08D08678CA0BDF5BC8 +:1527360074F01C97B77A850630D34EF3A1548AD1EC62FD72CC9E +:15274B003C9D4ACDC1FBC4F8BA738F7113F805C439F916AEE733 +:152760000700768CF1E5047F7908F90AEFC775B9F956BF5967CC +:152775006CA2BFC3BEBBCCFA0EF7571405C69DDC957029F7980F +:15278A00CEEAE3D0DF07186E1C8738068B94D7CCD22F1D6BED4A +:15279F00EBBF28734BDEF67EA87927E5FAAAF2D27752B3ECFD49 +:1527B40081FCC8C08FD7D65F6D1197114DFEEC556C93121D4848 +:1527C900CCC13BE7E8622314ED4890E2B6464F926CF14697828B +:1527DE003F3EC7EEC3F3F96AA1ED0F18787F29CE1DDF9470BE3A +:1527F300A41A18D348EF3FA3E11D51F5B8CF12C6B3DB611693D4 +:15280800F6EA41D50C55AEDBA414ACFBD079D1F0856E67EB8DA0 +:15281D00462235EB23B12F128AF6D09BB2F4A01EF3BFE763BD01 +:1528320066A8773ABDAF1231F07EEE40B49A12F915EA666D83D9 +:15284700793795F63ADCEB35DC4767F617BEDFE3C0F58C8BFC2C +:15285C00CEAAE601889DCB204E78925E29242ECFD880F69872A0 +:152871007370AE72F3AA3796CE0FBEBAECD6E018C091DED4894A +:15288600D4AC658A23C8F8917B0C5C7376C1383C0F7A9FDE0F44 +:15289B001B3FC6FDF1F831F32F1696A86C7D186CE4D142116F97 +:1528B000290EB6761A075C565DAB5E3BD4395837A0E29DA7C812 +:1528C5002FAEE7E6D2C2F18BDFB7C2F7EF39385FB8A679E10D71 +:1528DA001C3F7BE9E2A241CDFBDF47282A4A6D14CFB45F64E72D +:1528EF00E7CCD0EB6A1FE05D5454AADD8577C28E47D55272D174 +:15290400E80C9D68C33D2E05FBA96E8566429FA0AE38770F1B8D +:15291900B8B71FC4F58EF08F791F88B18B31B4C4E6610AF015FA +:15292E006A64FC877F6C8E4DA5DCA70B783BD7439FAECDD37719 +:15294300308F9E9FDBA6DEA914CBE9403CEDE2FB4530C69CE3B3 +:152958003A8C83FD4601CC4B42C923863196725BDFCE80B1811F +:15296D0036F0AC903BEEA7A22CC22007AB4E3F94B1F7F1970D63 +:15298200CCA762FB8F50A7F48D6CD95F0539E6E315C7ED82680B +:1529970007F57FCE653E359CFD1D933FEA33B305FB0D4BD6BDC7 +:1529AC0020EBDAE88079F5B8F0F9F676A34E8A761FFD0D6F378E +:1529C100F63DE2DB05F84A599F458C5D2C6E133AFA2BAEA378CF +:1529D6007EDA51F780867B86DFB2F450F40997670657E8379C5D +:1529EB00E736D00DE083E9C6A2A2B59AEF178EA0A523783CBFC9 +:152A00008DEFB30A1D39A3625CB78C9C5987FAE1AD4C30BD3021 +:152A1500F565AAEBFD214D025BBB4CE8035F0FC8EEFF1190B788 +:152A2A004F3EC6E29DD9A01F5EB0BF577E2DE46E8D0BDB37B8AA +:152A3F00679D4FEE2B717C437D94FD343A30AE7A218EAC17FDA3 +:152A54003EC3A623EDA023AD1F701D71809C25A123E597B99C53 +:152A690059EE01F6FFF14C3F223E4FB84D6BFDB7B672B0676627 +:152A7E0049B4CEF447FFA7BDEF8F8EE2B8F3AC1EF54833D22015 +:152A93005AC3CC20B0905A443892A33833625024598481B05E2D +:152AA8009910769673B2DD92B0C7B1BD109B64B93B6E1FEF85E7 +:152ABD00C42318890137B8E913589615337224AF7C0B398507C9 +:152AD200397C4F24E2C239B021DC2C211C9764F1388FD8BAACE3 +:152AE700CF283E62E3C466EEFBA9EE1E8D846CECDDBDF7EE8F21 +:152AFC009B7EF3BAEBF7B7BEDF6F557DABEA5BDF5A69AC4D3DC0 +:152B110064AC4ED519D4075AF65353DC2E34E6371EB9869F2B10 +:152B26000ACEB2EE45FDB55654BA5B0DDE817DA2914EC869824F +:152B3B007B50C5FAD98475AE1E32F7037C3D69949F0DE4EB5DA3 +:152B5000B09131CED8A10527686E3ACCD7BEA454B701BDC4D514 +:152B6500A9935CDE8BA786C193F324B9DB582D9F34747AFBF5F8 +:152B7A0011F5B46C86B3EA61EDEA07C8832E36E6FE07F17305BB +:152B8F005F77BC253C273C2C7C56F00937D8AFD97F633F64DFE9 +:152BA40063C3EC5966B0DD6C07DBCEFE9A6D618FB38DEC61F62A +:152BB90020EB600AFB125BCFFE8C7D917D81B5B17BD96AB68A61 +:152BCE00AD642BD8729A41B6B066D6C41AD93216664B59030BD8 +:152BE300B120FB0CBB9B7D9AD5D3F3297617ABA3A7967D929E0F +:152BF8003BD9127A6AE8F9043D8BE9A9A647A6A78A3F95F42CC7 +:152C0D00E24F057FEEE0CF42EB59C09F72EB999F7B02D6E3CFE1 +:152C22003DBEBC675EDEE39DF694CD78A45B9EB9B73CA5B33E15 +:152C3700733EF0F17CE85372DBA7F8233FEEDB3E2E6E3B338E52 +:152C4C00F3B1C15A4DE6674B4856A96CEA8C32F928FC6AC84FD6 +:152C6100B7BE6BE93B6D7DD7D3B724D037FA96CA5A8A1FD17442 +:152C7600D6A6A569522C098A26C98B8F4A31FAA7E89F597C1419 +:152C8B00E598B6496BB90D3659B6FCDC969F407E31CBAFD8F202 +:152CA00073905FCAF22BB1FC0AC80FF95199FC2CAAC4A2412BC1 +:152CB5002FE8F906AD3CA0D71BB4D2428F374869A202F66465D7 +:152CCA002D880E49BE4BA3D975BF93E469F845B99D8790EE4D6B +:152CDF00090DAE3375D4FEABFB5D679A558E9F0F091BFD90302C +:152CF4006E7F87C24A298CFC0DF88B679B555E76BACEB07167CF +:152D0900E31CF5485B30EA2F719AE8329F770775CCF318EAC994 +:152D1E00D3043B815FE0507298F1E3A7AC70EA135BE5C5866EE7 +:152D3300E593FA2FA67F94E245D15F4A8B0DD105BBA3B3BFA3AF +:152D4800C2549C74DEB7E498FAD62D7F8EFFF1EC5CE82698E770 +:152D5D00F7656DD2B4C76AEA6D705D4699EB74145ADFFC9CB4E6 +:152D720083788DD11C34D8447DA783251C4D4611ECA1469AD5B9 +:152D8700C9EA66BE1E37F943E732E0046EAC898E533A0F6B8218 +:152D9C004EB4514FB8A08E5673C90D4611BB8B60BFCB700622DC +:152DB1009DE959FC24C1F463F25B06FADADA996B124159E77EE0 +:152DC600E0EF029CCB151A44A29914EF6A10313F96AAF537A019 +:152DDB003B2F85A8C826BD9EAF3BC17E6C33D7C9803BEA28A727 +:152DF00032EA74942F9E2957A5785D186F57BCAE01EF28EA9AFF +:152E05000E72191A71391FC3DE6230A8C5799B68D2225CD728D1 +:152E1A0002FF58766E1BC58972FB879095CD33CF312DC2F5F20E +:152E2F0037F133A82CB8C53C03CDB659F714242D5D08ACEBCEA1 +:152E440025A012345F49E83A4B28D8DF81FBAD15E23296DEA113 +:152E59007B64B1814577C2AE9C8BA565DDB4FF6AEA31D5670A9B +:152E6E001A789E941F5F47C277B4574F2E882B42AA17DF464EDC +:152E8300CF23FA5FFB50BF0AF9A02ECA670DA62768DE242EFB76 +:152E9800EE83DFA5FC5FEE833FFCEAC9AF7F865F39F9F5CCF080 +:152EAD00DBBA82E0925EEBFBFA83AF874860D63CF2157D1B3BFC +:152EC200A355AC7C5D6DAF7A25F46CD3045FB75814BF44F57999 +:152ED7004A5BB4F2BCEABA4FE336CACB2DBBF3934F88CBC4D496 +:152EEC0090EEA0F15196BFDFC7F4EB862B69DAE3E476D4C70FBC +:152F01003406307FA2F298FEB7C61DC2EB2AF051CC5E098D3CFA +:152F1600F86623C142B4BD42F09DD7056D9FFAEC86D7B43B22A6 +:152F2B005486B4CF20DCC56FAE581D72ED46F93B47D94821CDB2 +:152F4000E3BE33EA725DA3F05DFDAEB6D7C9FFE97ED3FD3796FB +:152F5500FB3FF59FC966FD7DF679C0E8CFFB128E333AF0B68DCF +:152F6A008D6BF11F14367CEB5B850DD07FE84F3FAB2CBCF0B4B0 +:152F7F005270FEA2BA865D0A2D1C3FA9422748F8C900F4F5CCDC +:152F94003A120D70EED52FFD07F5FA43578C85C2CB14E792E1D4 +:152FA9008A1F69C4BC15F94F3E745E77A50A1B469F285CC6F5AF +:152FBE00645FE26BDE47138E14D1FAB88E7AFCE1507738708AB3 +:152FD300F2977EA3A12E12608EFE68D485FD1069D75189C3FEC9 +:152FE800E3A3AF513B2C96F726B3244F16C9DDF1FD714D11D6BF +:152FFD0069D44E7FAEC36E288D00EC2917F610B4E464F5EF0D02 +:153012008ABBE74DB97E5994E26F8FAD6EE0EBAF05E6594D31D5 +:15302700F56DEA279D0DB1F1C30D4C3FAE4F82FFB0BE47E1EB7B +:15303C00C95F4C1D211EEAE6F6486A2D7B41BCBDE97BB9DDF0EB +:153051005ADED648AE4DEDA5B616D744A2ABC4B430DE2EA635C4 +:15306600E08D3D3257EA00EC1D733BA2E5A9842EB85EC63C93F4 +:15307B00DB0B052FA28DB8CE216CC88842EE4E258CBBE21AF7B7 +:153090007FEF27541EB921134ED2D4D013131BCA486E445B997A +:1530A500AC1E321606529D63379DCB0897C6E9F7B22E89E06916 +:1530BA00A5322EA16D05FB349DFAE156CA97A5068C8BBC7E4946 +:1530CF009DDAA91424C0DEEED6C24C3F053BDAA3E82F7747CE85 +:1530E4002BBF7EB4B0A18F752B7DF1034AE91271595F64AF3217 +:1530F9003FD1ABEEDFA929FB9B2F73D952CA1CEC5BB3A4F2B3DC +:15310E007C8F28181FC5DA6BD9A204F600F58A14AF8FB986EDC6 +:1531230032EDF5E3BB4D24193AF39A2EB411EFEAA78DFDE39A1A +:1531380082F541576A80D2ED028EF95E5E79E6A0519179CEA8B5 +:15314D0025BC54503D338524165038DA67ADBC8BDB6EE1794811 +:153162009A7191E6A1E5F2533AB7B1B841D3289D8EBE418C1DA2 +:15317700D3C3991F50DC5DD4467A699C1B509167762EF4786000 +:15318C004B80BAFC7327D583F15EC5BBB257756843AA6B7CB87A +:1531A10011E7E87DA78E98F6BC4F33B6003A00D029A39FB8AE2A +:1531B60047A57AF73BD6ED53134579776CA4B1D69FD4BEF10F46 +:1531CB00E28F0F0A9C667C0FC4977981EB03F25B806033057EB2 +:1531E0002CC1F5B78013733F24C9F7438CF15EA53CD3D317CC90 +:1531F500BC9092566ABC0F2958ABA9A2AC191E17F6B807B4DAA8 +:15320A00C881469CF3F277116FD1BCB63C0EF7712360B985B33F +:15321F0003AA392E1C307C194F03FCB0B6EFCAED8FF4F13D009A +:15323400077097EED56B389DCCF3C9021BD1A0476D9E4B1EE5BE +:153249007DE9AF282F612DFAB214A7AF903CA20616751B4F47B0 +:15325E00CC73AC584B17BEA071BBBA12A7B3693B5AE23CFF9D4E +:15327300A35761D392EA8DF56831437D5BFA3AA7435946C4B92C +:15328800E57980A79CDB5F4A76DA773430FD4903F6C100A7902A +:15329D00F986569B9917CAEFFBD1E783BEBCDFCFF5F9D4FF6FB5 +:1532B2002A6CF765DEC638C06DAB48991EE3B1F7B37EDFFBE0EC +:1532C700779306C0B12FB34F7768BD6A598BB9E7EFA07E03F7AF +:1532DC00DE7858EF520FF1D042D61B02FDCE7D798A77CF59B649 +:1532F1007F2F73DDAF894ECE7B4437B845BEDF11E7FB58A037C4 +:15330600E8CB6D5EA19D133D67D292E3DEA2C3ED70FB9169045F +:15331B001AE4E3DEA6C7C7A04131A7419FB5CF33458BDBD220BD +:153330006FECB5F11F1B87BDB4D2603E2DBCB14F86605F8345EF +:15334500BB466F3CF1C946295644E36C972E901FFAB1CDDF28C2 +:15335A006C38F147FB3CA0D99F9413ADBC8B3443A03A8176A8A8 +:15336F00A3B9E7639681F290B77DBE7D4A7E32E9B1208F16DB67 +:15338400393C49D3EE0E85635F51CAEC3304EBBE1BB8953CFDD8 +:15339900E3AD79E9B77E39A7E7CBF583FBD830D7DBDC049A7748 +:1533AE000D2B1ED9C9FBE92D5C0F50D31744CCBE29D7EEA8CE2A +:1533C300C2268CCBF4BEEF3CC701B553DFB63F98F5CDCCB8F661 +:1533D8000BF6DCCB03C9CE052413C82C7534C8C68F4658E668BC +:1533ED00F93F66DDF41E25F728F98F3659E93F28BE32313DBE77 +:15340200CB8A8F717EE0EDBC32B1DF48F391FCB4A80F9F7B51F9 +:153417007D6E92FCD28AF573792CFED499934A2189F6A2DC9BBD +:15342C00849D9A62F97412679ECDFDA0717EE651928FD13C2606 +:15344100A17B324B1A4E1FC8BA81878167B3EE9979E6C3C6F7CB +:1534560031296DABFC8C7EFD558D64259C19485A7CF8EF0DCEEC +:15346B00BB416EB37E723FC98F0D241F7D1CDE9C7CB5574F3836 +:15348000481E1D11DB275FD58C84A3CF6895F71B6FDF44FB88C7 +:153495005B73952EE32A6422A23FF657652A231F2737AE4CC7E0 +:1534AA0027F6772DF9D6D47FD60774C8D202B52FD491DC46F8DA +:1534BF00DF91FC188C72BBDF763E727A2A1FDFEFB3AE0A9CED31 +:1534D4000994C32EB47E91CADC06BBF91968DC46344FA6562FE1 +:1534E9003C15527F10AF0B753735F13EAB88D1DC287D9F562434 +:1534FE003C4C7DCB9A19B2A6639928DFA7CB99681FEC1CBB5C2A +:15351300D514DE66C9998B1B8B694EE3A8547859B08B0879DDE3 +:15352800D915524B23A17031953D54754F634546A631B3562FB7 +:15353D00CF0475C1D3A2767F3BA439C769FE986E326C7BD4D0FD +:1535520001E132BFD445F2674D4874134CD1AF8C32FDA17E5706 +:1535670012FB88FF9ABF332B1CCB6ED5BF29B7F4306AAD7E2D55 +:15357C0048FD5A9302B9DF2B0B413E9709364DD94049BF30BA8B +:15359100607C405D60DD59E0A3711C63314BBF64940957D55FDC +:1535A60057977E96914CCED88426B1DF34FA846B6A69B5B301F8 +:1535BB0072648464F60A6158D593DD4A39E618D46FA29F14DD49 +:1535D000AF73FB344CDA31FA00FBEF212ECBC1760CB91792FC9F +:1535E5008DB7FD5F2817B5E7DC83669A8FF23F9CCD06642ABF7B +:1535FA00D1CA9FDBF69F257FFB1F4F4DE57DA7FCA73C0DEC3F98 +:15360F0049B566F92E8259B6E250BF1E58287F32945F1FF84BF5 +:15362400DC864D11CDA95ED259E685A33E6AE7C998735945E6DD +:15363900A08EFE14BC8A7DF5329219DA16F42E8D903C8631F194 +:15364E004B4E9DCB608DCF68215BEEDAF47EF603E52ECFBBD91D +:153663000F94BB9A6691BB1CE78EA890BD206FD9F2574EEE8AAB +:153678000C37E28CBB6F25CEBABFAE35DD9CDE1FF23E9368DB97 +:15368D0056FD686331D7C99ED03CEC64A3EFD4FF22584E6A8B1D +:1536A200334B7278704D38DB6D3CC006D104E1E9DECC1C93BEB6 +:1536B700382B6386EB62F2B87A37A1A1006E2B0C7E080B4085CD +:1536CC006486DF091AAF3E088F243B841D6DD7D41BEF645DC0D6 +:1536E1002770566FE1B0E63D138715B3E010694EBFF32F8B4708 +:1536F6003FE457C2E3A2C089CECBC063747F5FECF733AE95B49A +:15370B007065F3FFEDDCF2CCF4D103FA1AD6A7DD4FF39DEFFF58 +:15372000AC77A92C9F1AA5514CF30A24A74A970C9FD54E45E8FD +:153735005348BF34B6B1CB5A99F0867AC7CA6BEA216A87341F91 +:15374A006FC01AB85466A898FBB2F401CD357E90DE07B53B5395 +:15375F00628397E6805EF6BAEA3D754515F8BD15A3DCBE14B79D +:15377400AFF4438C1B716D60FC07E13B28DE1D142F30DE13B21D +:153789006D3F4994066D54A638B63F6C3FC11FEDAB32736F4889 +:15379E009A28E434E736A7CE5EE16D0AF76905327786A6EC5777 +:1537B3005DE1FD43F0D5D2507EF9F2AB81696EE9D5CA696EE8E9 +:1537C8005BCDA7B2E673B8BAF3E03A990757771E5C272DB8FEA1 +:1537DD0084E072E6C175320FAE25A19976B582164FE7E0CAF8FC +:1537F200A7C3955934CD0D9EA9A0B1B531833E90DF11C9F8DC00 +:153807004700EF8C111DC61AE711CFCC3F457C263F63283769B9 +:15381C009E9E7E5E0F73FB865D7DF192443BDCDBF85D55C7FA7E +:15383100A00F5570866091BBFA1DE7BECD797284AFDD3CAF0766 +:15384600E5471BCDB897B5EB2B8A96791E7885E629BFD45DF29A +:15385B00F7FAEBE5FF61C47F37939F7A463DD07F4CADD7CC6F34 +:15387000CCF37B46275698F98C52BE3E2BCF1B2B3636DECDFE86 +:15388500A681CFD3F3E2222DF2C84F778EE2EC78F2921294FFC4 +:15389A006229FC21BFD134EECFF0FD0C64B8684F0AF323A42D33 +:1538AF00C6990FE25D9C27ACD8FF3CE763F4AFA2957FE9B4EFA6 +:1538C400F92187F9DD572CCF0DD15B7770BD769DE7EF786E8FEB +:1538D900CA714CF3761FC9FF46E405458A24D472C23F3FDF2953 +:1538EE009936FF6FF72799272924D7ABD85767D24E2E1749FE99 +:15390300B862CB455C4642D8C7908F6CD9C8929366958F201BEC +:1539180041460A731B30391947D3CF99328E598ECCCAE5DF195D +:15392D00F320EB92DCE492771B23D7B2AEE294962C26B8C3914D +:153942004483BD76514E7216E224AF8166DD3AAB15DBB75F33B8 +:15395700E5AEF11FF3701DE141C20FD2B3D4555D583041E3BBD3 +:15396C00466D21A915A612712F9523A58EF5A19F04DF214FCC1D +:15398100DFC17FB5F2ABFDE6BC7E265FF7F2FE653EC9C5DE53D5 +:153996007B492619D3C08315046BEB1FF3E55FAB8E54B7792958 +:1539AB00677BE6CDACBF96E4DD6DBF356556BE1741F09D79D3A5 +:1539C0004C531630CF6FB9ACFDDFD1F9CC4D7329F7C83CD38DB4 +:1539D500F3A3DB1DCC7D86FEE6FCB0D6B28F62EA383953423B4C +:1539EA00F33569F6D962CF4F894F4E35ABAB683EE6EC1A547BD6 +:1539FF00D3834AA5EC6C59287FFA73580BE669A43A35771E3916 +:153A14005A4D7C24F488B16ADD29615D59E879E3505D985DEFCD +:153A2900D2B6FC149750CD9C0F4D2F7F55BC6EE93FAB9C5BF459 +:153A3E00C7829D35F35989242D56A12F0E5D0DD843724A7FCB73 +:153A5300F57BEF4ABDDF0ADDBFC03743E8C3B84E1FB761111D23 +:153A680036D6523CBB3CF8B7927BEACE013E472F96024D9DA766 +:153A7D0003B0AF54DBF95E00F936987A72E5ACC4131BA4B1734E +:153A9200897AA72C34632FD513AB366E90BFF8CD2EDDD4AB1599 +:153AA7007B2E5AF32BA7B443FD1585C13E682FE250BDB0372D1B +:153ABC0043F78FFCC4D8A031067FFA7EA390B92F5BE98AC87D98 +:153AD10095FCF11E221AC35ED698C33CB3DB0B9AFB26614796E4 +:153AE600158DC02EE7354DBAF08C02BDEC729C75938E692ECFE7 +:153AFB0011751DD1769E2CB6176506349CF3A8A07E349041FC40 +:153B1000BD3B30C60996EDC0BB52AD4B258F797608B675E6F2B3 +:153B25003C87FB711F93CB8CE32B4F894B85915BD3B26811D7DC +:153B3A00D7D6096F61BF797616FA59B09B0A3D948C1F77C324AA +:153B4F0072F73188F2756333D14D24BC78A82DC7E89BCDB21F0F +:153B64001B8CB9B458E6C747C52B5DEA7B3E3BDF8A5CBE492BCA +:153B7900DF98653B7B0FF52D63458C9F1966E9B8C1F793A4B0E2 +:153B8E00265436758A995AC395811FD12AD3C4CB2FCF4C92FB54 +:153BA3004CA79449519EB14EACB3EF59B049E17D5BE596CE8A23 +:153BB8000C6C185CEE14E5AF196301933F6A284D6D26DD5F4F2A +:153BCD00E9C3945FEB3CE60E527A13B63FE9036CB0B3BC0A7361 +:153BE20028669F5B8E744632EF187B16449508CF53E98C929B8F +:153BF700E21F5D4DEF18E55D4873DAFB33878C48E6E9BEB68CD8 +:153C0C00DE1FA537F6A8A3F43D4EE10A9595F65AB6C4598AE365 +:153C210000F64B61F3B13393321EA17C63049B0FFC4AB8AAA7B5 +:153C3600B78BDEB0D12B5378057DAFA63C7CF4AEA1F9DA26FA1D +:153C4B009E9807DE265C915F1BF989D4D75C24BF60C0A4476CD9 +:153C6000864D72E795B84A7C57E295C5E50579F412008F3C64E5 +:153C7500604D35280F515F3764CC464FF33C53588B3A58C9DDD8 +:153C8A00A987C2683785CDB216E53AAD757A39BF43A8CB30756C +:153C9F001D841E3B8F149559D537C8CFB5080BE2EA947DA00895 +:153CB400C50B6B8CF2EB015E7CB5B9BE6DE2EF3106D6A9B8178D +:153CC90061B1DCBE946DFD5DB7F21BC6EC7CD8D62E2DF8736B0E +:153CDE00FF6BEBA0B685BE7B6467BB2B074FB3BE10E310C27EAD +:153CF30063EAC9D7DBFD13F9457F0E5DD365CB5D046B8C997058 +:153D0800DBF4E6772A5AE9026CF972B6B599E76FEB8B230DE54F +:153D1D005552CA5A7918F22A0ADC8A2FB46F9F30759E439A7424 +:153D3200501D4772753C7701753CA2AE8149D46F0EEB9317007C +:153D4700306C5F99FB57F2CF281AFD23F48FD23F46FF2DF48FD5 +:153D5C00D35FA77F8AFEA3F41FFF9919976DED36EB6A9EF9E018 +:153D71006E7D867B74863B3DC33D39C32DBD36DD1D9CE18ECEF0 +:153D8600706F99E1D667B8475FCB3B9342F86913A6DBB78880A5 +:153D9B0076BED19C5DB049AA97BFEBB85ACACF365BF9548E74A6 +:153DB000626D684D6C43D87F7258AFBD083A4DE14D21F726FA49 +:153DC5006FA37F92FE7DF41FA1FF09FA9FA1FF65FA4FD0FFC613 +:153DDA0045332E3B36CCF196B2E94F6EE04DCF73036FF13C37CD +:153DEF00F0B625CF0DBCC5F2DCC05B34CF0DBC45F2DCC05B3084 +:153E0400CF0DBCC9F9E5BF36657F93974F6E7F73CA006F433FFD +:153E19005A7C62C33DB67D048EB3D9EC7F107E3D2C0FBF33E3C5 +:153E2E00FC33C3D1F78C91FC42B2947E7A0E734357B658165B92 +:153E4300FA04E676D137F5332D1E1A238BE5459FBD48E36205B5 +:153E58007D838EA2B44BDD5C467DD65C56F218AB6989CC35FBFF +:153E6D00B407E83B3CD7ECCB2A59CD725BFF49869D72DCFB4582 +:153E820079006793A5347E53FA8952C80E2F4ED9E92019F152A8 +:153E970055178DCB872123E8932B9CCB4F531CB96CF6F1C91EC9 +:153EAC00E7B0378FF1689299363AEC781E2A77A7659780E49DE9 +:153EC100E597292F3797F7A7F7631504EF7609E321E48BDDFA81 +:153ED6009E18CEA5BDA8EF881CE6F5777FC6D92EC9753AFA7C2A +:153EEB009C112A5B79006BB9DA9639D89F1AD499FEA2EE178621 +:153F0000D516D6CDE377BB87156141138DAD83460DD54D243929 +:153F150097DB268FEED52ECEC538A6774A65499EC7988764486F +:153F2A004AE3925FD4451A8BDDA558571EA4BEFC450378AE91FA +:153F3F004CF903B0A63DD3E5BB9139ACE434E5979A8371A6469B +:153F54004FF0B1A9968F4D380F2B2C08727B0A976F66DDC5F1B1 +:153F6900AE1667B45695E56AFD8D15C2F2CD94E6CC5C5326B23D +:153F7E00F1E0B5740FA7F477653D4EBC29A57772BB7EC85FBA96 +:153F9300F02905E78C00B33732B854245945A43C2729CF769297 +:153FA800A9708E49E4BAD87C1C862D490379A0BD8BB161C323AE +:153FBD009BF7BA66B91EFF8B9A9FFA7C51FE9E81F8B8FB976419 +:153FD200B00D1305243FE3CEC7BCFBA71294C7DFC588F762B02A +:153FE700B561DA75FFCF6CB0C5436E8C33C065A498B9DF269E84 +:153FFC007D8B75B5D8B09B3819E17D13F2E0677ED892161BEE59 +:15401100EB0437F45D890E25B02303DE100907176F64DDF6BD19 +:1540260005F9750AE4D5C91E6F502FAEB740FD1DE0728ED39C6C +:15403B00233AA6F13A4883FD34F7A07AEF9EB2731CEBD27ADD53 +:15405000CCBD8660B5D37C2ED2DD029D8B9F1CF9E5618F5C6F8D +:15406500F8B9AEB24A6D76B561C32ECA87F9BC0DDF18E3250BE4 +:15407A00476B2D386D3D4E0B977EEC15D7539837262EF7154C5C +:15408F00B50DC95DA39AF7EBF6F1F28C5343CB59380C1D8CAC5D +:1540A400B96796CD7EEB5498FC123AEE46294B3FA9965DB84765 +:1540B900914EAD542B65472BD7C94EEF864E94DB9D3F6E5A70DC +:1540CE0036B0257C5C1E7531F715AAE32F88F7D8D6E7795E88FB +:1540E300EF425F1F1EE2F7AEF0F34BADF5FCDC0EC9E1FA77E3C0 +:1540F800832D38D303FC3E8D7B0B49A6B5F0EEF5669C2DF321EE +:15410D00AF674EEAD71F7C69F92FC88D3A8B99E1D9F98D706485 +:15412200F29BC93F9ECC71FD40C6D91E681DE6E5A19D99F4946F +:15413700394EEDFE5A6C5D82B51884EB95E38361BBBE51613A5F +:15414C005F42CFE6664C6801DC36DEDE1C1FE27D8027467D8299 +:1541610055CE2F288F8F5AA7CA8C7379B0783A2FB6BD9D75AFA9 +:15417600263A7A62797591BFA7439F3257179AC398F5AFCDD556 +:15418B00057088AD9FE675E1788A0D7E209E9C528D6AAD9364C6 +:1541A000515FD7A9FD5C671573A30187D54F100EA84F77E7EEE2 +:1541B5004C487769E7FE68EB0FD7F33A411FDC4EFB08A503BD44 +:1541CA00FB284D7E3FB3ED7D935F3DF2615D8E0D695F8F0C8732 +:1541DF0050367851DA3E669E8B4C0FD37CA11BFB9D567D877409 +:1541F400BBAD88992386E41E56CBA8CF3D48732B4F06FD8A6685 +:15420900D5FFC454FD892FE6B79EE4F59F4F74B3E89B1B438A6B +:15421E00D1DFF1F6A0C1DE7FAE3DDC840D9FF0B169EDE1B7E3CD +:15423300C7B85D1FE0ACE121D35E01CA798EED6D215E36DB49B7 +:154248006BB7C9C7046B4F1C67F0F5CE03B8B3217A7206BD7508 +:15425D0093DE5563CB0D727B624379743DA623CD145D87AC7ADB +:154272002579BDD0E794B5EEE5755A98129783F76D5AE6F89743 +:15428700FCC414EE0A49E83DD4FECC7B42CC7AFC35F1A7CD8B26 +:15429C005E36D6524AE503961B04CB42E2BD6345D379EFDCFF00 +:1542B10026BE93F3E08B117CB13CF8641B3EB35FE2F86CEDE6C9 +:1542C600F0E5F70BF1EBA6CE03DE62CCBC07588F24B694E68D22 +:1542DB0039F1776D5ECACD5DBD2CDCCB710B5B2C7D93D9921C44 +:1542F000EF916CF32B9C55785EBC478A99F36F6FE4B0FA32A58C +:15430500F1578BED6517FA1487C0CAE6212C7D4C972EA414DCF3 +:15431A00F17094609530E610FF6C06AFBA20776A5A2070A253C4 +:15432F00261929FE646FFB0EF827DF411FBEC375EE24D7DB9887 +:15434400A8DABB8CA5C7742328B4239FCAC45ED89CF3CDC7FD16 +:1543590068E49FC07AB5B4D710293FECCD7337952BF23DC1BDA2 +:15436E00064F87B2F4BDD07F9E87BB95BBCC343BE234A7C7BA03 +:15438300886BAD063D0E3FD7A1B3E6F412BF4F604CDFD9A6299D +:1543980005EBAEABF16CD6DBFB794D419D454A539938B201F0C4 +:1543AD0063EC042C80CD4F75692218FC174E28F36354D7B3DF2C +:1543C20056BD4CA33E3CA57C1FE38295A77876402519D88B7446 +:1543D70076DD7B28FFE4BEE3FC1E66F00B8F1B3DB6C3B5FB1DAF +:1543EC003503D8A84EA80BBB3EA0812EC003D34F6AC06723D44E +:154401005C28DCC6C5E51C1ECCB27278C07A6DDAC443E08762E3 +:154416004B721D742486B52EF2EF457B219CC00F6B1B18834D1B +:15442B00784F120E8E28C8BF60DDEFD5ED1C0F479432AA1F70F9 +:1544400020E15C15D5DB853B83A82CD84C0E52F99581894EDBE9 +:154455001EB2699F27AEE9C4837B162495B7D884B628C8FEB2C2 +:15446A0046163F97B3D7F917DC1E32B79BD4C6D70896F49B67EE +:15447F005B933C5D24B30B7756B8E98D7D6023F6EE149FE33C0E +:1544940023D6AAC0A3F5984B439736D8A4E937B89E663F8DB948 +:1544A900E3F15A67BBE00AAB623CA40E10AC55CA28EEB9D475D6 +:1544BE00F9402B9F9F521C89FA0E8FFCC51697FCB51649FED26B +:1544D30072312A63BC1EBF4AF230DE9D984B455FE43695FDCD24 +:1544E800B261E60F9971703C4861F594BE96D2D7507AF855C8F3 +:1544FD005F6AB1F3207E6AF150B88BC2AFAEF81ACFCFC3E766D2 +:15451200BFDB61C7D9827208265FF3A499B76EC20D1C85D136AC +:1545270008CE7AF9D556B1396864281CEB05AD349F1692215583 +:15453C008A630FD88C8FFC8807FC22E58378FC7C020EA4C7CC33 +:15455100FB80D0869B9835BF06CF4B435639239DB02952CE6D45 +:154566004F987E9833C18FEB1B9A67316E992F098249CF9C3FD4 +:15457B00E55F61CF7FB85E2A95CFEF384B195BDEBD75CE659ECD +:154590007D1DD11186FE07772CF8ADFEC69FFE8EEABBF01D0521 +:1545A500F2AAAFF59879AF1085F930F767C731BE6BAFFCB680E3 +:1545BA00558C1F6FDC42E39EC79A67983AB0A69C833B095CF13E +:1545CF00234BE793ECE943BEC111138E5C3F99E4F0F9228930CA +:1545E400B76F426EE4591E196AACC8CB333777A13E97A7B7FA20 +:1545F900CFDF5AFC8C7A606E47B079AFF2359D9AA934F9E76932 +:15460E00F9FDE74F69FF384BBAC333D211BFEBB3AD27453287BE +:15462300B4FF394BFACD1F21FDB559D2856F0BEF216D6296747F +:15463800EFB1DB9737F9FE8CFD27ACEFE4F31FD6FCDF9DBEBE22 +:15464D0031335CFAC38787C76F17FE7F3BFF19E19E7CFEFFB008 +:15466200F581FF1FFE4F0A97F2F0EF9DD92FFD3F03BFC51FD198 +:154677008F971EED6B9E287359ECCBDC46536D67B7147B641541 +:15468C0035454FD9A3AA46E1B82BDA73EF6E15ED14E3A4A76CC6 +:1546A100933A67F56E55961FD7E6DCDBA5FAD6698A47A8567DC5 +:1546B600A5D56A82E416AB4D6FB84163B35456AB22BF7F6A5E9C +:1546CB0087EED314EC110BEB30778969D0A813E582F6AF539F69 +:1546E000ECF754ABC5EBEAD5E7EEAB53AAD6D52901CF236A774F +:1546F500C1A714DCC5B8488CD973151FE28BC22754BEF6B0BABF +:15470A008BF71DE843AA4A130AF413ED702F0FAF539D65712E7A +:15471F00DF553D1057F9FE1264E459605865C15042301C22180D +:15473400FC79E5A3DC4A8201F178BE947F7ED937AC7C27F3F2CE +:15474900CD665FC97A60EB20C4DAD7331640DEF18298067C644E +:15475E009999D7DD8CCD9B4FB8F15099EEB57584A36A6591A745 +:154773005EADF88CD8EE645D1D557F25B61F9A9BE034C0BA4825 +:1547880090E0C01EDC5DDC76DA14EC5EAE07833DB8F813BC6EA9 +:15479D0004D3390BA631D4DD73BF5AB56FBD2A94DAB0656FDA01 +:1547B200B0B5106CE59E6AEE1F2701D1A697BBB45EF5709876A1 +:1547C7002B8B4A13EAFE9D7B72BC003CFF219BB56060BC9EB026 +:1547DC000966EE374F3E8172D3161CB81FEC0C7DCFD54C18CA91 +:1547F100F6D5A865541EEAD66E9D4D81D226C74BD1145EAA8851 +:15480600774AD6B6AAFE75610ECFAE82DD4A31E1A5C493500B35 +:15481B0059A2638FC59B8B79DDA7CA9DA0B2740A2B237C11DDC4 +:15483000BD360CA07D55DBFD0A64A1AA75F72B33E94F8DA8AC8E +:1548450098EF1B4CB5A7AA33033C9E70BE5EF53F105345F6B844 +:15485A003A87E23E27B080D3FA36E8BB641DC149FC52521A56D0 +:15486F00B51F352B87CE362B25E7D7AA7E8DFCF6AD56B5CFAF8A +:1548840021DE5FA38007FC84D3AAB5262EC498D02EB34D9CB7E4 +:15489900494EF3398587544FAC0077EBF8DCD8ABA96CEB9C2374 +:1548AE003CAC7AC455AA67259577EF63AA67F51A756FC12A05F2 +:1548C300FA1EE2CAA9F84501F31C188F9F0899F15FFEAAEA3924 +:1548D800DDACEEDD19529C34EE96FDE811A5EA3305EDB0BDEDB4 +:1548ED008A873ADCE3CD1D07610F4D0BA955E71F528573CDAA2E +:15490200467105D7142DB6A28D07F8B9B10DB005E4EAA274A731 +:154917009A3BF85CAF89B51796053B8ACA9A3AAA92EB955DD473 +:15492C0037C8E4DF43EFBF449FF3F71B554F4FB30AB95A961F63 +:15494100866CE7F224BEAA0A6B1F5779D8CBCD141E52F712CEDB +:15495600407FF038E624C5FF5168AF3A4F38D4BA54FFF9AFAA3B +:15496B0025E776731ED84F3C3087685F1CD13AF2FB25D01DB469 +:15498000E33AF5164DC193F7122CED809FF08CBB49D7D177A2D7 +:1549950060B33287CA01FCDD3BCDEF5537B37EF44BB61B7169FF +:1549AA006CD83090C51A8EC9DB064DAD803FF47B34E79A67F3A6 +:1549BF00D5368AC3CF47100C9B67E80797FDA842A93A574EB8AA +:1549D4002D5767E3A337D9141FFD9A997C041A14131F053C9B2E +:1549E900395E9EB378097CE4D7C86F062FED8EFFF9C6E2C026AC +:1549FE00A24FAC73377B78E39C40B453F03CA6DAEE92C8C31BD2 +:154A130041A7395DEB3BD8D9F60EFB5D75CDC1EF702A8EAFEF25 +:154A280028196FEF10DC44F34F546B4EA2C34DA23DF07737A785 +:154A3D0085A3BD44DB4174788CE8B087F7E9F9B428B0689130FA +:154A5200EF8EF209AE4F50D9D10D67385DC037D10D6333E84242 +:154A670034F13E60D185FA5DEFFA3CBADC994797B7B8CEEF5418 +:154A7C00DBDE49EDBA378F4EDCFE38F100FCB75BB4BA803BFF2F +:154A91002CDA6CFA98F4B894478FBFB3E88136EDB768710B1D40 +:154AA6008836F9B4288A7C65636164FD46B68DB57BC6BFD23197 +:154ABB0047DAD451C4FECDC6E2F8BFEDF08C3FCCDD557FC5DBED +:154AD000ABD7C3C81D799CE35DDC5EAD39A8EFBD5914D58A6DA5 +:154AE500BC533B2DF1ECA4FEEF5FA9256B9F9C86F7E2D9F09E3E +:154AFA005C0C9AE7E13DC6F16ED7371FFFD4E77BEFB5F08F35C1 +:154B0F0011B4131BFFDE3CFC3BF8DA8689DF5E0BBFA5E8A7280A +:154B2400AC92E65AF96DC04EFF261F174C9A211DE8A658743081 +:154B3900711E9E06CBB708CF9E94D0FE32BD13D4F714521EB8D2 +:154B4E00FFFDD0171F51ABD6B52A52C152A5A8E01E053CECA121 +:154B6300BE879D6DEE38F4530A3BBF56F1167C5E71177CC10C75 +:154B7800135675B0FBD674EC8A39DA01D762E084CA261E292BCC +:154B8D00941D7C8C843FECB9D87314940FBBA705F6D86D8D1FA2 +:154BA20088075D7FC0F55A36EBA338B9B6FF32B57D8C5D9768CE +:154BB7003A89F512C80734D6F94E5BF1BF4FDF55D744BCBD27B6 +:154BCC00785E4975BF63E8117EC65230EF62A69125EB8D0C3DF1 +:154BE1006A308DEB88C1DF37B5DE5AFC7F00E871AED038A00037 +:014BF60000BE +:00000001FF diff --git a/drivers/atm/zatm.c b/drivers/atm/zatm.c index 11cd3e6ca..26c8c9d90 100644 --- a/drivers/atm/zatm.c +++ b/drivers/atm/zatm.c @@ -636,12 +636,12 @@ printk("dummy: 0x%08lx, 0x%08lx\n",dummy[0],dummy[1]); event_dump(); } if (!size) { - kfree_skb(skb); + dev_kfree_skb_irq(skb); if (vcc) vcc->stats->rx_err++; continue; } if (!atm_charge(vcc,skb->truesize)) { - kfree_skb(skb); + dev_kfree_skb_irq(skb); continue; } skb->len = size; @@ -854,7 +854,7 @@ printk("NONONONOO!!!!\n"); uPD98401_TXBD_SIZE*ATM_SKB(skb)->iovcnt,GFP_ATOMIC); if (!dsc) { if (vcc->pop) vcc->pop(vcc,skb); - else dev_kfree_skb(skb); + else dev_kfree_skb_irq(skb); return -EAGAIN; } /* @@@ should check alignment */ @@ -908,7 +908,7 @@ if (*ZATM_PRV_DSC(skb) != (uPD98401_TXPD_V | uPD98401_TXPD_DP | *ZATM_PRV_DSC(skb) = 0; /* mark as invalid */ zatm_vcc->txing--; if (vcc->pop) vcc->pop(vcc,skb); - else dev_kfree_skb(skb); + else dev_kfree_skb_irq(skb); while ((skb = skb_dequeue(&zatm_vcc->backlog))) if (do_tx(skb) == RING_BUSY) { skb_queue_head(&zatm_vcc->backlog,skb); @@ -1395,7 +1395,7 @@ static int __init zatm_init(struct atm_dev *dev) command | PCI_COMMAND_IO | PCI_COMMAND_MASTER))) { printk(KERN_ERR DEV_LABEL "(itf %d): can't enable IO (0x%02x)" "\n",dev->number,error); - return error; + return -EIO; } eprom_get_esi(dev); printk(KERN_NOTICE DEV_LABEL "(itf %d): rev.%d,base=0x%x,irq=%d,", @@ -1741,7 +1741,6 @@ static int zatm_send(struct atm_vcc *vcc,struct sk_buff *skb) if (!skb) { printk(KERN_CRIT "!skb in zatm_send ?\n"); if (vcc->pop) vcc->pop(vcc,skb); - else dev_kfree_skb(skb); return -EINVAL; } ATM_SKB(skb)->vcc = vcc; diff --git a/drivers/block/Config.in b/drivers/block/Config.in index 01fc28943..d4ba3f06b 100644 --- a/drivers/block/Config.in +++ b/drivers/block/Config.in @@ -44,6 +44,7 @@ else bool ' RZ1000 chipset bugfix/support' CONFIG_BLK_DEV_RZ1000 bool ' Generic PCI IDE chipset support' CONFIG_BLK_DEV_IDEPCI if [ "$CONFIG_BLK_DEV_IDEPCI" = "y" ]; then + bool ' Sharing PCI IDE interrupts support' CONFIG_IDEPCI_SHARE_IRQ bool ' Generic PCI bus-master DMA support' CONFIG_BLK_DEV_IDEDMA_PCI if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" ]; then bool ' Use PCI DMA by default when available' CONFIG_IDEDMA_PCI_AUTO @@ -54,38 +55,43 @@ else define_bool CONFIG_IDEDMA_PCI_EXPERIMENTAL n fi fi + if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then + bool ' ATA Work(s) In Progress (EXPERIMENTAL)' CONFIG_IDEDMA_PCI_WIP + fi bool ' Boot off-board chipsets first support' CONFIG_BLK_DEV_OFFBOARD bool ' AEC6210 chipset support' CONFIG_BLK_DEV_AEC6210 - if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" -a "$CONFIG_BLK_DEV_AEC6210" = "y" ]; then - bool ' AEC6210 Tuning support (EXPERIMENTAL)' CONFIG_BLK_DEV_AEC6210_TUNING + if [ "$CONFIG_IDEDMA_PCI_WIP" = "y" -a "$CONFIG_BLK_DEV_AEC6210" = "y" ]; then + bool ' AEC6210 Tuning support (WIP)' CONFIG_AEC6210_TUNING fi if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" ]; then bool ' ALI M15x3 chipset support' CONFIG_BLK_DEV_ALI15X3 - if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then - bool ' AMD Viper support (EXPERIMENTAL)' CONFIG_BLK_DEV_AMD7409 + bool ' AMD Viper support' CONFIG_BLK_DEV_AMD7409 + if [ "$CONFIG_IDEDMA_PCI_WIP" = "y" -a "$CONFIG_BLK_DEV_AMD7409" = "y" ]; then + bool ' AMD Viper ATA-66 Override (WIP)' CONFIG_AMD7409_OVERRIDE fi fi bool ' CMD64X chipset support' CONFIG_BLK_DEV_CMD64X - if [ "$CONFIG_BLK_DEV_CMD64X" = "y" -a "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then - bool ' CMD64X chipset RAID support (EXPERIMENTAL) (WIP)' CONFIG_BLK_DEV_CMD64X_RAID + if [ "$CONFIG_IDEDMA_PCI_WIP" = "y" -a "$CONFIG_BLK_DEV_CMD64X" = "y" ]; then + bool ' CMD64X chipset RAID (WIP)' CONFIG_CMD64X_RAID fi if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then bool ' CY82C693 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_CY82C693 fi + bool ' Cyrix CS5530 MediaGX chipset support' CONFIG_BLK_DEV_CS5530 if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" ]; then bool ' HPT34X chipset support' CONFIG_BLK_DEV_HPT34X - if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" -a "$CONFIG_BLK_DEV_HPT34X" = "y" ]; then - bool ' HPT34X DMA support (EXPERIMENTAL)' CONFIG_BLK_DEV_HPT34X_DMA + if [ "$CONFIG_IDEDMA_PCI_WIP" = "y" -a "$CONFIG_BLK_DEV_HPT34X" = "y" ]; then + bool ' HPT34X AUTODMA support (WIP)' CONFIG_HPT34X_AUTODMA fi bool ' HPT366 chipset support' CONFIG_BLK_DEV_HPT366 - if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" -a "$CONFIG_BLK_DEV_HPT366" = "y" ]; then - bool ' HPT366 Fast Interrupt support (EXPERIMENTAL) (WIP)' CONFIG_HPT366_FAST_IRQ_PREDICTION - bool ' HPT366 mode three unsupported (EXPERIMENTAL) (WIP)' CONFIG_HPT366_MODE3 + if [ "$CONFIG_IDEDMA_PCI_WIP" = "y" -a "$CONFIG_BLK_DEV_HPT366" = "y" ]; then + bool ' HPT366 Fast Interrupts (WIP)' CONFIG_HPT366_FIP + bool ' HPT366 mode Three (WIP)' CONFIG_HPT366_MODE3 fi - if [ "$CONFIG_X86" = "y" ]; then + if [ "$CONFIG_X86" = "y" -o "$CONFIG_IA64" = "y" ]; then bool ' Intel PIIXn chipsets support' CONFIG_BLK_DEV_PIIX if [ "$CONFIG_BLK_DEV_PIIX" = "y" -a "$CONFIG_IDEDMA_PCI_AUTO" = "y" ]; then - bool ' PIIXn Tuning support' CONFIG_BLK_DEV_PIIX_TUNING + bool ' PIIXn Tuning support' CONFIG_PIIX_TUNING fi fi fi @@ -98,21 +104,18 @@ else if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" ]; then bool ' PROMISE PDC20246/PDC20262 support' CONFIG_BLK_DEV_PDC202XX if [ "$CONFIG_BLK_DEV_PDC202XX" = "y" ]; then - bool ' Special UDMA Feature' CONFIG_PDC202XX_FORCE_BURST_BIT - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - bool ' Special Mode Feature (EXPERIMENTAL)' CONFIG_PDC202XX_FORCE_MASTER_MODE + bool ' Special UDMA Feature' CONFIG_PDC202XX_BURST + if [ "$CONFIG_IDEDMA_PCI_WIP" = "y" ]; then + bool ' Special Mode Feature (WIP)' CONFIG_PDC202XX_MASTER fi fi if [ "$CONFIG_X86" = "y" ]; then bool ' SiS5513 chipset support' CONFIG_BLK_DEV_SIS5513 fi - bool ' Cyrix CS5530 MediaGX chipset support' CONFIG_BLK_DEV_CS5530 fi if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then bool ' Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290 - if [ "$CONFIG_X86" = "y" ]; then - bool ' VIA82CXXX chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_VIA82CXXX - fi + bool ' VIA82CXXX chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_VIA82CXXX fi fi if [ "$CONFIG_PPC" = "y" -o "$CONFIG_ARM" = "y" ]; then @@ -232,6 +235,7 @@ if [ "$CONFIG_IDE_CHIPSETS" = "y" -o \ "$CONFIG_BLK_DEV_AMD7409" = "y" -o \ "$CONFIG_BLK_DEV_CMD640" = "y" -o \ "$CONFIG_BLK_DEV_CMD64X" = "y" -o \ + "$CONFIG_BLK_DEV_CS5530" = "y" -o \ "$CONFIG_BLK_DEV_CY82C693" = "y" -o \ "$CONFIG_BLK_DEV_HPT34X" = "y" -o \ "$CONFIG_BLK_DEV_HPT366" = "y" -o \ @@ -240,7 +244,6 @@ if [ "$CONFIG_IDE_CHIPSETS" = "y" -o \ "$CONFIG_BLK_DEV_PDC202XX" = "y" -o \ "$CONFIG_BLK_DEV_PIIX" = "y" -o \ "$CONFIG_BLK_DEV_SIS5513" = "y" -o \ - "$CONFIG_BLK_DEV_CS5530" = "y" -o \ "$CONFIG_BLK_DEV_SL82C105" = "y" ]; then define_bool CONFIG_BLK_DEV_IDE_MODES y else diff --git a/drivers/block/Makefile b/drivers/block/Makefile index 9f313de8f..be158ca1a 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -130,6 +130,10 @@ ifeq ($(CONFIG_BLK_DEV_CMD64X),y) IDE_OBJS += cmd64x.o endif +ifeq ($(CONFIG_BLK_DEV_CS5530),y) +IDE_OBJS += cs5530.o +endif + ifeq ($(CONFIG_BLK_DEV_CY82C693),y) IDE_OBJS += cy82c693.o endif @@ -198,10 +202,6 @@ ifeq ($(CONFIG_BLK_DEV_PDC202XX),y) IDE_OBJS += pdc202xx.o endif -ifeq ($(CONFIG_BLK_DEV_CS5530),y) -IDE_OBJS += cs5530.o -endif - ifeq ($(CONFIG_BLK_DEV_PDC4030),y) IDE_OBJS += pdc4030.o endif diff --git a/drivers/block/README.buddha b/drivers/block/README.buddha deleted file mode 100644 index d3b7bc73f..000000000 --- a/drivers/block/README.buddha +++ /dev/null @@ -1,210 +0,0 @@ - -The Amiga Buddha and Catweasel IDE Driver (part of ide.c) was written by -Geert Uytterhoeven based on the following specifications: - ------------------------------------------------------------------------- - -Register map of the Buddha IDE controller and the -Buddha-part of the Catweasel Zorro-II version - -The Autoconfiguration has been implemented just as Commodore -described in their manuals, no tricks have been used (for -example leaving some address lines out of the equations...). -If you want to configure the board yourself (for example let -a Linux kernel configure the card), look at the Commodore -Docs. Reading the nibbles should give this information: - -Vendor number: 4626 ($1212) -product number: 0 (42 for Catweasel Z-II) -Serial number: 0 -Rom-vector: $1000 - -The card should be a Z-II board, size 64K, not for freemem -list, Rom-Vektor is valid, no second Autoconfig-board on the -same card, no space preferrence, supports "Shutup_forever". - -Setting the base address should be done in two steps, just -as the Amiga Kickstart does: The lower nibble of the 8-Bit -address is written to $4a, then the whole Byte is written to -$48, while it doesn't matter how often you're writing to $4a -as long as $48 is not touched. After $48 has been written, -the whole card disappears from $e8 and is mapped to the new -addrress just written. Make shure $4a is written befor $48, -otherwise your chance is only 1:16 to find the board :-). - -The local memory-map is even active when mapped to $e8: - -$0-$7e Autokonfig-space, see Z-II docs. - -$80-$7fd reserved - -$7fe Speed-select Register: Read & Write - (description see further down) - -$800-$8ff IDE-Select 0 (Port 0, Register set 0) - -$900-$9ff IDE-Select 1 (Port 0, Register set 1) - -$a00-$aff IDE-Select 2 (Port 1, Register set 0) - -$b00-$bff IDE-Select 3 (Port 1, Register set 1) - -$c00-$cff IDE-Select 4 (Port 2, Register set 0, - Catweasel only!) - -$d00-$dff IDE-Select 5 (Port 3, Register set 1, - Catweasel only!) - -$e00-$eff local expansion port, on Catweasel Z-II the - Catweasel registers are also mapped here. - Never touch, use multidisk.device! - -$f00 read only, Byte-access: Bit 7 shows the - level of the IRQ-line of IDE port 0. - -$f01-$f3f mirror of $f00 - -$f40 read only, Byte-access: Bit 7 shows the - level of the IRQ-line of IDE port 1. - -$f41-$f7f mirror of $f40 - -$f80 read only, Byte-access: Bit 7 shows the - level of the IRQ-line of IDE port 2. - (Catweasel only!) - -$f81-$fbf mirror of $f80 - -$fc0 write-only: Writing any value to this - register enables IRQs to be passed from the - IDE ports to the Zorro bus. This mechanism - has been implemented to be compatible with - harddisks that are either defective or have - a buggy firmware and pull the IRQ line up - while starting up. If interrupts would - always be passed to the bus, the computer - might not start up. Once enabled, this flag - can not be disabled again. The level of the - flag can not be determined by software - (what for? Write to me if it's necessary!). - -$fc1-$fff mirror of $fc0 - -$1000-$ffff Buddha-Rom with offset $1000 in the rom - chip. The addresses $0 to $fff of the rom - chip cannot be read. Rom is Byte-wide and - mapped to even addresses. - -The IDE ports issue an INT2. You can read the level of the -IRQ-lines of the IDE-ports by reading from the three (two -for Buddha-only) registers $f00, $f40 and $f80. This way -more than one I/O request can be handled and you can easily -determine what driver has to serve the INT2. Buddha and -Catweasel expansion boards can issue an INT6. A seperate -memory map is available for the I/O module and the sysop's -I/O module. - -The IDE ports are fed by the address lines A2 to A4, just as -the Amiga 1200 and Amiga 4000 IDE ports are. This way -existing drivers can be easily ported to Buddha. A move.l -polls two words out of the same address of IDE port since -every word is mirrored once. movem is not possible, but -it's not necessary either, because you can only speedup -68000 systems with this technique. A 68020 system with -fastmem is faster with move.l. - -If you're using the mirrored registers of the IDE-ports with -A6=1, the Buddha doesn't care about the speed that you have -selected in the speed register (see further down). With -A6=1 (for example $840 for port 0, register set 0), a 780ns -access is being made. These registers should be used for a -command access to the harddisk/CD-Rom, since command -accesses are Byte-wide and have to be made slower according -to the ATA-X3T9 manual. - -Now for the speed-register: The register is byte-wide, and -only the upper three bits are used (Bits 7 to 5). Bit 4 -must always be set to 1 to be compatible with later Buddha -versions (if I'll ever update this one). I presume that -I'll never use the lower four bits, but they have to be set -to 1 by definition. - The values in this table have to be shifted 5 bits to the -left and or'd with $1f (this sets the lower 5 bits). - -All the timings have in common: Select and IOR/IOW rise at -the same time. IOR and IOW have a propagation delay of -about 30ns to the clocks on the Zorro bus, that's why the -values are no multiple of 71. One clock-cycle is 71ns long -(exactly 70,5 at 14,18 Mhz on PAL systems). - -value 0 (Default after reset) - -497ns Select (7 clock cycles) , IOR/IOW after 172ns (2 clock cycles) -(same timing as the Amiga 1200 does on it's IDE port without -accelerator card) - -value 1 - -639ns Select (9 clock cycles), IOR/IOW after 243ns (3 clock cycles) - -value 2 - -781ns Select (11 clock cycles), IOR/IOW after 314ns (4 clock cycles) - -value 3 - -355ns Select (5 clock cycles), IOR/IOW after 101ns (1 clock cycle) - -value 4 - -355ns Select (5 clock cycles), IOR/IOW after 172ns (2 clock cycles) - -value 5 - -355ns Select (5 clock cycles), IOR/IOW after 243ns (3 clock cycles) - -value 6 - -1065ns Select (15 clock cycles), IOR/IOW after 314ns (4 clock cycles) - -value 7 - -355ns Select, (5 clock cycles), IOR/IOW after 101ns (1 clock cycle) - -When accessing IDE registers with A6=1 (for example $84x), -the timing will always be mode 0 8-bit compatible, no matter -what you have selected in the speed register: - -781ns select, IOR/IOW after 4 clock cycles (=314ns) aktive. - -All the timings with a very short select-signal (the 355ns -fast accesses) depend on the accelerator card used in the -system: Sometimes two more clock cycles are inserted by the -bus interface, making the whole access 497ns long. This -doesn't affect the reliability of the controller nor the -performance of the card, since this doesn't happen very -often. - -All the timings are calculated and only confirmed by -measurements that allowed me to count the clock cycles. If -the system is clocked by an oscillator other than 28,37516 -Mhz (for example the NTSC-frequency 28,63636 Mhz), each -clock cycle is shortened to a bit less than 70ns (not worth -mentioning). You could think of a small performance boost -by overclocking the system, but you would either need a -multisync monitor, or a graphics card, and your internal -diskdrive would go crazy, that's why you shouldn't tune your -Amiga this way. - -Giving you the possibility to write software that is -compatible with both the Buddha and the Catweasel Z-II, The -Buddha acts just like a Catweasel Z-II with no device -connected to the third IDE-port. The IRQ-register $f80 -always shows a "no IRQ here" on the Buddha, and accesses to -the third IDE port are going into data's Nirwana on the -Buddha. - - Jens Schönfeld february 19th, 1997 - updated may 27th, 1997 - eMail: sysop@nostlgic.tng.oche.de - diff --git a/drivers/block/README.fd b/drivers/block/README.fd deleted file mode 100644 index 38f0b85a5..000000000 --- a/drivers/block/README.fd +++ /dev/null @@ -1,222 +0,0 @@ -This Readme file describes the floppy driver. - -FAQ list: -========= - - A FAQ list may be found in the fdutils package (see below), and also -at http://fdutils.linux.lu/FAQ.html - - -LILO configuration options (Thinkpad users, read this) -====================================================== - - The floppy driver is configured using the 'floppy=' option in -lilo. This option can be typed at the boot prompt, or entered in the -lilo configuration file. - Example: If your kernel is called linux-2.2.13, type the following line -at the lilo boot prompt (if you have a thinkpad): - linux-2.2.13 floppy=thinkpad -You may also enter the following line in /etc/lilo.conf, in the description -of linux-2.2.13: - append = "floppy=thinkpad" - - Several floppy related options may be given, example: - linux-2.2.13 floppy=daring floppy=two_fdc - append = "floppy=daring floppy=two_fdc" - - If you give options both in the lilo config file and on the boot -prompt, the option strings of both places are concatenated, the boot -prompt options coming last. That's why there are also options to -restore the default behavior. - - If you use the floppy driver as a module, use the following syntax: - insmod floppy - -Example: - insmod floppy daring two_fdc - - Some versions of insmod are buggy in one way or another. If you have -any problems (options not being passed correctly, segfaults during -insmod), first check whether there is a more recent version. - - The floppy related options include: - - floppy=asus_pci - Sets the bit mask to allow only units 0 and 1. (default) - - floppy=daring - Tells the floppy driver that you have a well behaved floppy controller. - This allows more efficient and smoother operation, but may fail on - certain controllers. This may speed up certain operations. - - floppy=0,daring - Tells the floppy driver that your floppy controller should be used - with caution. - - floppy=one_fdc - Tells the floppy driver that you have only one floppy controller. - (default) - - floppy=two_fdc - floppy=
,two_fdc - Tells the floppy driver that you have two floppy controllers. - The second floppy controller is assumed to be at
. - This option is not needed if the second controller is at address - 0x370, and if you use the 'cmos' option. - - floppy=thinkpad - Tells the floppy driver that you have a Thinkpad. Thinkpads use an - inverted convention for the disk change line. - - floppy=0,thinkpad - Tells the floppy driver that you don't have a Thinkpad. - - floppy=omnibook - floppy=nodma - Tells the floppy driver not to use Dma for data transfers. - This is needed on HP Omnibooks, which don't have a workable - DMA channel for the floppy driver. This option is also useful - if you frequently get "Unable to allocate DMA memory" messages. - Indeed, dma memory needs to be continuous in physical memory, - and is thus harder to find, whereas non-dma buffers may be - allocated in virtual memory. However, I advise against this if - you have an FDC without a FIFO (8272A or 82072). 82072A and - later are OK. You also need at least a 486 to use nodma. - If you use nodma mode, I suggest you also set the FIFO - threshold to 10 or lower, in order to limit the number of data - transfer interrupts. - - If you have a FIFO-able FDC, the floppy driver automatically - falls back on non DMA mode if no DMA-able memory can be found. - If you want to avoid this, explicitely ask for 'yesdma'. - - floppy=yesdma - Tells the floppy driver that a workable DMA channel is available. - (default) - - floppy=nofifo - Disables the FIFO entirely. This is needed if you get "Bus - master arbitration error" messages from your Ethernet card (or - from other devices) while accessing the floppy. - - floppy=fifo - Enables the FIFO. (default) - - floppy=,fifo_depth - Sets the FIFO threshold. This is mostly relevant in DMA - mode. If this is higher, the floppy driver tolerates more - interrupt latency, but it triggers more interrupts (i.e. it - imposes more load on the rest of the system). If this is - lower, the interrupt latency should be lower too (faster - processor). The benefit of a lower threshold is less - interrupts. - To tune the fifo threshold, switch on over/underrun messages - using 'floppycontrol --messages'. Then access a floppy - disk. If you get a huge amount of "Over/Underrun - retrying" - messages, then the fifo threshold is too low. Try with a - higher value, until you only get an occasional Over/Underrun. - It is a good idea to compile the floppy driver as a module - when doing this tuning. Indeed, it allows to try different - fifo values without rebooting the machine for each test. Note - that you need to do 'floppycontrol --messages' every time you - re-insert the module. - Usually, tuning the fifo threshold should not be needed, as - the default (0xa) is reasonable. - - floppy=,,cmos - Sets the CMOS type of to . This is mandatory if - you have more than two floppy drives (only two can be - described in the physical CMOS), or if your BIOS uses - non-standard CMOS types. The CMOS types are: - 0 - Use the value of the physical CMOS - 1 - 5 1/4 DD - 2 - 5 1/4 HD - 3 - 3 1/2 DD - 4 - 3 1/2 HD - 5 - 3 1/2 ED - 6 - 3 1/2 ED - 16 - unknown or not installed - (Note: there are two valid types for ED drives. This is because 5 was - initially chosen to represent floppy *tapes*, and 6 for ED drives. - AMI ignored this, and used 5 for ED drives. That's why the floppy - driver handles both.) - - floppy=unexpected_interrupts - Print a warning message when an unexpected interrupt is received. - (default) - - floppy=no_unexpected_interrupts - floppy=L40SX - Don't print a message when an unexpected interrupt is received. This - is needed on IBM L40SX laptops in certain video modes. (There seems - to be an interaction between video and floppy. The unexpected - interrupts affect only performance, and can be safely ignored.) - - floppy=broken_dcl - Don't use the disk change line, but assume that the disk was - changed whenever the device node is reopened. Needed on some - boxes where the disk change line is broken or unsupported. - This should be regarded as a stopgap measure, indeed it makes - floppy operation less efficient due to unneeded cache - flushings, and slightly more unreliable. Please verify your - cable, connection and jumper settings if you have any DCL - problems. However, some older drives, and also some laptops - are known not to have a DCL. - - floppy=debug - Print debugging messages. - - floppy=messages - Print informational messages for some operations (disk change - notifications, warnings about over and underruns, and about - autodetection). - - floppy=silent_dcl_clear - Uses a less noisy way to clear the disk change line (which - doesn't involve seeks). Implied by 'daring' option. - - floppy=,irq - Sets the floppy IRQ to instead of 6. - - floppy=,dma - Sets the floppy DMA channel to instead of 2. - - floppy=slow - Use PS/2 stepping rate: - " PS/2 floppies have much slower step rates than regular floppies. - It's been recommended that take about 1/4 of the default speed - in some more extreme cases." - - - -Supporting utilities and additional documentation: -================================================== - - Additional parameters of the floppy driver can be configured at -runtime. Utilities which do this can be found in the fdutils package. -This package also contains a new version of mtools which allows to -access high capacity disks (up to 1992K on a high density 3 1/2 disk!). -It also contains additional documentation about the floppy driver. - -The latest version can be found at fdutils homepage: - http://fdutils.linux.lu - -The fdutils-5.3 release can be found at: - http://fdutils.linux.lu/fdutils-5.3.src.tar.gz - http://www.tux.org/pub/knaff/fdutils/fdutils-5.3.src.tar.gz - ftp://tsx-11.mit.edu/pub/linux/sources/sbin/fdutils-5.3.src.tar.gz - ftp://metalab.unc.edu/pub/Linux/utils/disk-management/fdutils-5.3.src.tar.gz - -Reporting problems about the floppy driver -========================================== - - If you have a question or a bug report about the floppy driver, mail -me at Alain.Knaff@poboxes.com . If you post to Usenet, preferably use -comp.os.linux.hardware. As the volume in these groups is rather high, -be sure to include the word "floppy" (or "FLOPPY") in the subject -line. If the reported problem happens when mounting floppy disks, be -sure to mention also the type of the filesystem in the subject line. - - Be sure to read the FAQ before mailing/posting any bug reports! - - Alain diff --git a/drivers/block/README.lvm b/drivers/block/README.lvm deleted file mode 100644 index 3d652457f..000000000 --- a/drivers/block/README.lvm +++ /dev/null @@ -1,8 +0,0 @@ - -This is the Logical Volume Manager driver for Linux, - -Tools, library that manage logical volumes can be found -at . - -There you can obtain actual driver versions too. - diff --git a/drivers/block/README.md b/drivers/block/README.md deleted file mode 100644 index 6ad19ac99..000000000 --- a/drivers/block/README.md +++ /dev/null @@ -1,4 +0,0 @@ -Tools that manage md devices can be found at sweet-smoke.ufr-info-p7.ibp.fr -in public/Linux/md035.tar.gz. - - Marc ZYNGIER diff --git a/drivers/block/aec6210.c b/drivers/block/aec6210.c index f74103d9a..30be6a7cc 100644 --- a/drivers/block/aec6210.c +++ b/drivers/block/aec6210.c @@ -1,7 +1,7 @@ /* - * linux/drivers/block/aec6210.c Version 0.04 Dec. 13, 1999 + * linux/drivers/block/aec6210.c Version 0.05 Feb. 10, 2000 * - * Copyright (C) 1998-99 Andre Hedrick (andre@suse.com) + * Copyright (C) 1998-2000 Andre Hedrick (andre@suse.com) * May be copied or modified under the terms of the GNU General Public License * * pio 0 :: 40: 00 07 00 00 00 00 00 00 02 07 a6 04 00 02 00 02 @@ -56,7 +56,52 @@ #define ACARD_DEBUG_DRIVE_INFO 1 -#ifdef CONFIG_BLK_DEV_AEC6210_TUNING +#define DISPLAY_AEC6210_TIMINGS + +#if defined(DISPLAY_AEC6210_TIMINGS) && defined(CONFIG_PROC_FS) +#include +#include + +static int aec6210_get_info(char *, char **, off_t, int); +extern int (*aec6210_display_info)(char *, char **, off_t, int); /* ide-proc.c */ +extern char *ide_media_verbose(ide_drive_t *); +static struct pci_dev *bmide_dev; + +static int aec6210_get_info (char *buffer, char **addr, off_t offset, int count) +{ + char *p = buffer; + + u32 bibma = bmide_dev->resource[4].start; + u8 c0 = 0, c1 = 0; + + p += sprintf(p, "\n AEC6210 Chipset.\n"); + + /* + * at that point bibma+0x2 et bibma+0xa are byte registers + * to investigate: + */ + c0 = inb_p((unsigned short)bibma + 0x02); + c1 = inb_p((unsigned short)bibma + 0x0a); + + p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n"); + p += sprintf(p, " %sabled %sabled\n", + (c0&0x80) ? "dis" : " en", + (c1&0x80) ? "dis" : " en"); + p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n"); + p += sprintf(p, "DMA enabled: %s %s %s %s\n", + (c0&0x20) ? "yes" : "no ", (c0&0x40) ? "yes" : "no ", + (c1&0x20) ? "yes" : "no ", (c1&0x40) ? "yes" : "no " ); + + p += sprintf(p, "UDMA\n"); + p += sprintf(p, "DMA\n"); + p += sprintf(p, "PIO\n"); + return p-buffer;/* => must be less than 4k! */ +} +#endif /* defined(DISPLAY_AEC6210_TIMINGS) && defined(CONFIG_PROC_FS) */ + +byte aec6210_proc = 0; + +#ifdef CONFIG_AEC6210_TUNING struct chipset_bus_clock_list_entry { byte xfer_speed; @@ -269,7 +314,7 @@ int aec6210_dmaproc (ide_dma_action_t func, ide_drive_t *drive) } return ide_dmaproc(func, drive); /* use standard DMA stuff */ } -#endif /* CONFIG_BLK_DEV_AEC6210_TUNING */ +#endif /* CONFIG_AEC6210_TUNING */ unsigned int __init pci_init_aec6210 (struct pci_dev *dev, const char *name) { @@ -277,12 +322,19 @@ unsigned int __init pci_init_aec6210 (struct pci_dev *dev, const char *name) pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE); printk("%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start); } + +#if defined(DISPLAY_AEC6210_TIMINGS) && defined(CONFIG_PROC_FS) + aec6210_proc = 1; + bmide_dev = dev; + aec6210_display_info = &aec6210_get_info; +#endif /* DISPLAY_AEC6210_TIMINGS && CONFIG_PROC_FS */ + return dev->irq; } void __init ide_init_aec6210 (ide_hwif_t *hwif) { -#ifdef CONFIG_BLK_DEV_AEC6210_TUNING +#ifdef CONFIG_AEC6210_TUNING hwif->tuneproc = &aec6210_tune_drive; if (hwif->dma_base) { @@ -291,7 +343,7 @@ void __init ide_init_aec6210 (ide_hwif_t *hwif) hwif->drives[0].autotune = 1; hwif->drives[1].autotune = 1; } -#endif /* CONFIG_BLK_DEV_AEC6210_TUNING */ +#endif /* CONFIG_AEC6210_TUNING */ } void __init ide_dmacapable_aec6210 (ide_hwif_t *hwif, unsigned long dmabase) diff --git a/drivers/block/ali14xx.c b/drivers/block/ali14xx.c index e86fe61db..e7fd203b4 100644 --- a/drivers/block/ali14xx.c +++ b/drivers/block/ali14xx.c @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ali14xx.c Version 0.03 Feb 09, 1996 + * linux/drivers/block/ali14xx.c Version 0.03 Feb 09, 1996 * * Copyright (C) 1996 Linus Torvalds & author (see below) */ @@ -55,12 +55,12 @@ /* port addresses for auto-detection */ #define ALI_NUM_PORTS 4 -static int ports[ALI_NUM_PORTS] = {0x074, 0x0f4, 0x034, 0x0e4}; +static int __init ports[ALI_NUM_PORTS] = {0x074, 0x0f4, 0x034, 0x0e4}; /* register initialization data */ typedef struct { byte reg, data; } RegInitializer; -static RegInitializer initData[] = { +static RegInitializer __init initData[] = { {0x01, 0x0f}, {0x02, 0x00}, {0x03, 0x00}, {0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x2b}, {0x0a, 0x0f}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00}, {0x28, 0x00}, @@ -150,7 +150,7 @@ static void ali14xx_tune_drive (ide_drive_t *drive, byte pio) /* * Auto-detect the IDE controller port. */ -static int findPort (void) +static int __init findPort (void) { int i; byte t; @@ -183,7 +183,7 @@ static int findPort (void) /* * Initialize controller registers with default values. */ -static int initRegisters (void) { +static int __init initRegisters (void) { RegInitializer *p; byte t; unsigned long flags; @@ -200,7 +200,7 @@ static int initRegisters (void) { return t; } -void init_ali14xx (void) +void __init init_ali14xx (void) { /* auto-detect IDE controller port */ if (!findPort()) { diff --git a/drivers/block/alim15x3.c b/drivers/block/alim15x3.c index 4b9b28e3b..bc3d2b9e3 100644 --- a/drivers/block/alim15x3.c +++ b/drivers/block/alim15x3.c @@ -1,5 +1,5 @@ /* - * linux/drivers/block/alim15x3.c Version 0.08 Jan. 14, 2000 + * linux/drivers/block/alim15x3.c Version 0.08 Jan. 14, 2000 * * Copyright (C) 1998-2000 Michel Aubry, Maintainer * Copyright (C) 1998-2000 Andrzej Krzysztofowicz, Maintainer @@ -493,7 +493,6 @@ static int ali15x3_dmaproc (ide_dma_action_t func, ide_drive_t *drive) default: break; } - return ide_dmaproc(func, drive); /* use standard DMA stuff */ } @@ -518,6 +517,13 @@ unsigned int __init pci_init_ali15x3 (struct pci_dev *dev, const char *name) if (inb(fixdma_base+2) & 0x80) printk("%s: simplex device: DMA will fail!!\n", name); } + +#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) + ali_proc = 1; + bmide_dev = dev; + ali_display_info = &ali_get_info; +#endif /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */ + return 0; } @@ -666,22 +672,11 @@ void __init ide_init_ali15x3 (ide_hwif_t *hwif) */ hwif->dmaproc = &ali15x3_dmaproc; hwif->autodma = 1; - hwif->drives[0].autotune = 0; - hwif->drives[1].autotune = 0; } else { hwif->autodma = 0; hwif->drives[0].autotune = 1; hwif->drives[1].autotune = 1; } - -#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) - if (!ali_proc) { - ali_proc = 1; - bmide_dev = hwif->pci_dev; - ali_display_info = &ali_get_info; - } -#endif /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */ - return; } diff --git a/drivers/block/amd7409.c b/drivers/block/amd7409.c index 46d5f36af..b12847843 100644 --- a/drivers/block/amd7409.c +++ b/drivers/block/amd7409.c @@ -1,5 +1,5 @@ /* - * linux/drivers/block/amd7409.c Version 0.01 Jan. 10, 2000 + * linux/drivers/block/amd7409.c Version 0.03 Feb. 10, 2000 * * Copyright (C) 2000 Andre Hedrick * May be copied or modified under the terms of the GNU General Public License @@ -24,6 +24,51 @@ #include "ide_modes.h" +#define DISPLAY_VIPER_TIMINGS + +#if defined(DISPLAY_VIPER_TIMINGS) && defined(CONFIG_PROC_FS) +#include +#include + +static int amd7409_get_info(char *, char **, off_t, int); +extern int (*amd7409_display_info)(char *, char **, off_t, int); /* ide-proc.c */ +extern char *ide_media_verbose(ide_drive_t *); +static struct pci_dev *bmide_dev; + +static int amd7409_get_info (char *buffer, char **addr, off_t offset, int count) +{ + char *p = buffer; + u32 bibma = bmide_dev->resource[4].start; + u8 c0 = 0, c1 = 0; + + /* + * at that point bibma+0x2 et bibma+0xa are byte registers + * to investigate: + */ + c0 = inb_p((unsigned short)bibma + 0x02); + c1 = inb_p((unsigned short)bibma + 0x0a); + + p += sprintf(p, "\n AMD 7409 VIPER Chipset.\n"); + p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n"); + p += sprintf(p, " %sabled %sabled\n", + (c0&0x80) ? "dis" : " en", + (c1&0x80) ? "dis" : " en"); + p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n"); + p += sprintf(p, "DMA enabled: %s %s %s %s\n", + (c0&0x20) ? "yes" : "no ", (c0&0x40) ? "yes" : "no ", + (c1&0x20) ? "yes" : "no ", (c1&0x40) ? "yes" : "no " ); + p += sprintf(p, "UDMA\n"); + p += sprintf(p, "DMA\n"); + p += sprintf(p, "PIO\n"); + + return p-buffer; /* => must be less than 4k! */ +} +#endif /* defined(DISPLAY_VIPER_TIMINGS) && defined(CONFIG_PROC_FS) */ + +byte amd7409_proc = 0; + +extern char *ide_xfer_verbose (byte xfer_rate); + /* * Here is where all the hard work goes to program the chipset. * @@ -33,11 +78,13 @@ static int amd7409_tune_chipset (ide_drive_t *drive, byte speed) ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; int err = 0; - int drive_number = ((HWIF(drive)->channel ? 2 : 0) + - (drive->select.b.unit & 0x01)); + byte unit = (drive->select.b.unit & 0x01); + int drive_number = ((HWIF(drive)->channel ? 2 : 0) + unit); + unsigned long dma_base = hwif->dma_base; byte drive_pci = 0x00; byte drive_pci2 = 0x00; - byte drive_timing = 0x00; + byte ultra_timing = 0x00; + byte dma_pio_timing = 0x00; byte pio_timing = 0x00; switch (drive_number) { @@ -49,54 +96,99 @@ static int amd7409_tune_chipset (ide_drive_t *drive, byte speed) return ((int) ide_dma_off_quietly); } - pci_read_config_byte(dev, drive_pci, &drive_timing); - pci_read_config_byte(dev, drive_pci2, &pio_timing); + pci_read_config_byte(dev, drive_pci, &ultra_timing); + pci_read_config_byte(dev, drive_pci2, &dma_pio_timing); + pci_read_config_byte(dev, 0x4c, &pio_timing); - printk("%s: UDMA 0x%02x PIO 0x%02x ", - drive->name, drive_timing, pio_timing); +#ifdef DEBUG + printk("%s: UDMA 0x%02x DMAPIO 0x%02x PIO 0x%02x ", + drive->name, ultra_timing, dma_pio_timing, pio_timing); +#endif + + ultra_timing &= ~0xC7; + dma_pio_timing &= ~0xFF; + pio_timing &= ~(0x03 << drive_number); + +#ifdef DEBUG + printk(":: UDMA 0x%02x DMAPIO 0x%02x PIO 0x%02x ", + ultra_timing, dma_pio_timing, pio_timing); +#endif switch(speed) { case XFER_UDMA_4: - drive_timing &= ~0xC7; - drive_timing |= 0x45; - pci_write_config_byte(dev, drive_pci, drive_timing); + ultra_timing |= 0x45; + dma_pio_timing |= 0x20; + pio_timing |= (0x03 << drive_number); break; case XFER_UDMA_3: - drive_timing &= ~0xC7; - drive_timing |= 0x44; - pci_write_config_byte(dev, drive_pci, drive_timing); + ultra_timing |= 0x44; + dma_pio_timing |= 0x20; + pio_timing |= (0x03 << drive_number); break; case XFER_UDMA_2: - drive_timing &= ~0xC7; - drive_timing |= 0x40; - pci_write_config_byte(dev, drive_pci, drive_timing); + ultra_timing |= 0x40; + dma_pio_timing |= 0x20; + pio_timing |= (0x03 << drive_number); break; case XFER_UDMA_1: - drive_timing &= ~0xC7; - drive_timing |= 0x41; - pci_write_config_byte(dev, drive_pci, drive_timing); + ultra_timing |= 0x41; + dma_pio_timing |= 0x20; + pio_timing |= (0x03 << drive_number); break; case XFER_UDMA_0: - drive_timing &= ~0xC7; - drive_timing |= 0x42; - pci_write_config_byte(dev, drive_pci, drive_timing); + ultra_timing |= 0x42; + dma_pio_timing |= 0x20; + pio_timing |= (0x03 << drive_number); + break; + case XFER_MW_DMA_2: + dma_pio_timing |= 0x20; + pio_timing |= (0x03 << drive_number); + break; + case XFER_MW_DMA_1: + dma_pio_timing |= 0x21; + pio_timing |= (0x03 << drive_number); + break; + case XFER_MW_DMA_0: + dma_pio_timing |= 0x77; + pio_timing |= (0x03 << drive_number); + break; + case XFER_PIO_4: + dma_pio_timing |= 0x20; + pio_timing |= (0x03 << drive_number); + break; + case XFER_PIO_3: + dma_pio_timing |= 0x22; + pio_timing |= (0x03 << drive_number); + break; + case XFER_PIO_2: + dma_pio_timing |= 0x42; + pio_timing |= (0x03 << drive_number); + break; + case XFER_PIO_1: + dma_pio_timing |= 0x65; + pio_timing |= (0x03 << drive_number); + break; + case XFER_PIO_0: + default: + dma_pio_timing |= 0xA8; + pio_timing |= (0x03 << drive_number); break; - case XFER_MW_DMA_2:break; - case XFER_MW_DMA_1:break; - case XFER_MW_DMA_0:break; - case XFER_SW_DMA_2:break; - case XFER_SW_DMA_1:break; - case XFER_SW_DMA_0:break; - case XFER_PIO_4:break; - case XFER_PIO_3:break; - case XFER_PIO_2:break; - case XFER_PIO_1:break; - case XFER_PIO_0:break; - default: break; } - printk(":: UDMA 0x%02x PIO 0x%02x\n", drive_timing, pio_timing); + pci_write_config_byte(dev, drive_pci, ultra_timing); + pci_write_config_byte(dev, drive_pci2, dma_pio_timing); + pci_write_config_byte(dev, 0x4c, pio_timing); + +#ifdef DEBUG + printk(":: UDMA 0x%02x DMAPIO 0x%02x PIO 0x%02x\n", + ultra_timing, dma_pio_timing, pio_timing); +#endif + if (speed > XFER_PIO_4) { + outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2); + } else { + outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2); + } err = ide_config_drive_speed(drive, speed); return (err); } @@ -109,12 +201,14 @@ static int amd7409_tune_chipset (ide_drive_t *drive, byte speed) static int config_chipset_for_dma (ide_drive_t *drive) { struct hd_driveid *id = drive->id; + byte udma_66 = ((id->hw_config & 0x2000) && + (HWIF(drive)->udma_four)) ? 1 : 0; byte speed = 0x00; int rval; - if ((id->dma_ultra & 0x0010) && (HWIF(drive)->udma_four)) { + if ((id->dma_ultra & 0x0010) && (udma_66)) { speed = XFER_UDMA_4; - } else if ((id->dma_ultra & 0x0008) && (HWIF(drive)->udma_four)) { + } else if ((id->dma_ultra & 0x0008) && (udma_66)) { speed = XFER_UDMA_3; } else if (id->dma_ultra & 0x0004) { speed = XFER_UDMA_2; @@ -128,12 +222,6 @@ static int config_chipset_for_dma (ide_drive_t *drive) speed = XFER_MW_DMA_1; } else if (id->dma_mword & 0x0001) { speed = XFER_MW_DMA_0; - } else if (id->dma_1word & 0x0004) { - speed = XFER_SW_DMA_2; - } else if (id->dma_1word & 0x0002) { - speed = XFER_SW_DMA_1; - } else if (id->dma_1word & 0x0001) { - speed = XFER_SW_DMA_0; } else { return ((int) ide_dma_off_quietly); } @@ -143,7 +231,6 @@ static int config_chipset_for_dma (ide_drive_t *drive) rval = (int)( ((id->dma_ultra >> 11) & 3) ? ide_dma_on : ((id->dma_ultra >> 8) & 7) ? ide_dma_on : ((id->dma_mword >> 8) & 7) ? ide_dma_on : - ((id->dma_1word >> 8) & 7) ? ide_dma_on : ide_dma_off_quietly); return rval; @@ -222,8 +309,7 @@ static int config_drive_xfer_rate (ide_drive_t *drive) } } else if (id->field_valid & 2) { try_dma_modes: - if ((id->dma_mword & 0x0007) || - (id->dma_1word & 0x0007)) { + if (id->dma_mword & 0x0007) { /* Force if Capable regular DMA modes */ dma_func = config_chipset_for_dma(drive); if (dma_func != ide_dma_on) @@ -265,16 +351,45 @@ int amd7409_dmaproc (ide_dma_action_t func, ide_drive_t *drive) return ide_dmaproc(func, drive); /* use standard DMA stuff */ } +unsigned int __init pci_init_amd7409 (struct pci_dev *dev, const char *name) +{ + unsigned long fixdma_base = dev->resource[4].start; + + if (!fixdma_base || fixdma_base == PCI_BASE_ADDRESS_IO_MASK) { + /* + * + */ + } else { + /* + * enable DMA capable bit, and "not" simplex only + */ + outb(inb(fixdma_base+2) & 0x60, fixdma_base+2); + + if (inb(fixdma_base+2) & 0x80) + printk("%s: simplex device: DMA will fail!!\n", name); + } +#if defined(DISPLAY_VIPER_TIMINGS) && defined(CONFIG_PROC_FS) + amd7409_proc = 1; + bmide_dev = dev; + amd7409_display_info = &amd7409_get_info; +#endif /* DISPLAY_VIPER_TIMINGS && CONFIG_PROC_FS */ + + return 0; +} + unsigned int __init ata66_amd7409 (ide_hwif_t *hwif) { -#if 0 +#ifdef CONFIG_AMD7409_OVERRIDE + byte ata66 = 1; +#else byte ata66 = 0; +#endif /* CONFIG_AMD7409_OVERRIDE */ +#if 0 pci_read_config_byte(hwif->pci_dev, 0x48, &ata66); return ((ata66 & 0x02) ? 0 : 1); -#else - return 0; #endif + return ata66; } void __init ide_init_amd7409 (ide_hwif_t *hwif) @@ -288,3 +403,8 @@ void __init ide_init_amd7409 (ide_hwif_t *hwif) hwif->drives[1].autotune = 1; } } + +void ide_dmacapable_amd7409 (ide_hwif_t *hwif, unsigned long dmabase) +{ + ide_setup_dma(hwif, dmabase, 8); +} diff --git a/drivers/block/buddha.c b/drivers/block/buddha.c index e5862cd31..3e1cfcd33 100644 --- a/drivers/block/buddha.c +++ b/drivers/block/buddha.c @@ -42,7 +42,7 @@ #define BUDDHA_BASE2 0xa00 #define BUDDHA_BASE3 0xc00 -static const u_int buddha_bases[CATWEASEL_NUM_HWIFS] = { +static const u_int __init buddha_bases[CATWEASEL_NUM_HWIFS] = { BUDDHA_BASE1, BUDDHA_BASE2, BUDDHA_BASE3 }; @@ -61,7 +61,7 @@ static const u_int buddha_bases[CATWEASEL_NUM_HWIFS] = { #define BUDDHA_STATUS 0x1e /* see status-bits */ #define BUDDHA_CONTROL 0x11a -static int buddha_offsets[IDE_NR_PORTS] = { +static int __init buddha_offsets[IDE_NR_PORTS] = { BUDDHA_DATA, BUDDHA_ERROR, BUDDHA_NSECTOR, BUDDHA_SECTOR, BUDDHA_LCYL, BUDDHA_HCYL, BUDDHA_SELECT, BUDDHA_STATUS, BUDDHA_CONTROL }; @@ -75,7 +75,7 @@ static int buddha_offsets[IDE_NR_PORTS] = { #define BUDDHA_IRQ2 0xf40 /* interrupt */ #define BUDDHA_IRQ3 0xf80 -static const int buddha_irqports[CATWEASEL_NUM_HWIFS] = { +static const int __init buddha_irqports[CATWEASEL_NUM_HWIFS] = { BUDDHA_IRQ1, BUDDHA_IRQ2, BUDDHA_IRQ3 }; @@ -109,7 +109,7 @@ static int buddha_ack_intr(ide_hwif_t *hwif) * Any Buddha or Catweasel boards present? */ -static int find_buddha(void) +static int __init find_buddha(void) { struct zorro_dev *z = NULL; @@ -143,7 +143,7 @@ static int find_buddha(void) * We support only _one_ of them, no multiple boards! */ -void buddha_init(void) +void __init buddha_init(void) { hw_regs_t hw; int i, index; diff --git a/drivers/block/cmd640.c b/drivers/block/cmd640.c index 3e5f56cec..b2077df6d 100644 --- a/drivers/block/cmd640.c +++ b/drivers/block/cmd640.c @@ -1,5 +1,5 @@ /* - * linux/drivers/block/cmd640.c Version 1.02 Sep 01, 1996 + * linux/drivers/block/cmd640.c Version 1.02 Sep 01, 1996 * * Copyright (C) 1995-1996 Linus Torvalds & authors (see below) */ @@ -290,7 +290,7 @@ static byte get_cmd640_reg_vlb (unsigned short reg) return b; } -static int match_pci_cmd640_device (void) +static int __init match_pci_cmd640_device (void) { const byte ven_dev[4] = {0x95, 0x10, 0x40, 0x06}; unsigned int i; @@ -310,7 +310,7 @@ static int match_pci_cmd640_device (void) /* * Probe for CMD640x -- pci method 1 */ -static int probe_for_cmd640_pci1 (void) +static int __init probe_for_cmd640_pci1 (void) { get_cmd640_reg = get_cmd640_reg_pci1; put_cmd640_reg = put_cmd640_reg_pci1; @@ -324,7 +324,7 @@ static int probe_for_cmd640_pci1 (void) /* * Probe for CMD640x -- pci method 2 */ -static int probe_for_cmd640_pci2 (void) +static int __init probe_for_cmd640_pci2 (void) { get_cmd640_reg = get_cmd640_reg_pci2; put_cmd640_reg = put_cmd640_reg_pci2; @@ -338,7 +338,7 @@ static int probe_for_cmd640_pci2 (void) /* * Probe for CMD640x -- vlb */ -static int probe_for_cmd640_vlb (void) +static int __init probe_for_cmd640_vlb (void) { byte b; @@ -359,7 +359,7 @@ static int probe_for_cmd640_vlb (void) * Returns 1 if an IDE interface/drive exists at 0x170, * Returns 0 otherwise. */ -static int secondary_port_responding (void) +static int __init secondary_port_responding (void) { unsigned long flags; @@ -403,7 +403,7 @@ void cmd640_dump_regs (void) * Check whether prefetch is on for a drive, * and initialize the unmask flags for safe operation. */ -static void check_prefetch (unsigned int index) +static void __init check_prefetch (unsigned int index) { ide_drive_t *drive = cmd_drives[index]; byte b = get_cmd640_reg(prefetch_regs[index]); @@ -424,7 +424,7 @@ static void check_prefetch (unsigned int index) /* * Figure out which devices we control */ -static void setup_device_ptrs (void) +static void __init setup_device_ptrs (void) { unsigned int i; @@ -507,7 +507,7 @@ inline static byte pack_nibbles (byte upper, byte lower) /* * This routine retrieves the initial drive timings from the chipset. */ -static void retrieve_drive_counts (unsigned int index) +static void __init retrieve_drive_counts (unsigned int index) { byte b; @@ -694,7 +694,7 @@ static void cmd640_tune_drive (ide_drive_t *drive, byte mode_wanted) /* * Probe for a cmd640 chipset, and initialize it if found. Called from ide.c */ -int ide_probe_for_cmd640x (void) +int __init ide_probe_for_cmd640x (void) { #ifdef CONFIG_BLK_DEV_CMD640_ENHANCED int second_port_toggled = 0; diff --git a/drivers/block/cmd64x.c b/drivers/block/cmd64x.c index 8f5f04aea..4e98893ec 100644 --- a/drivers/block/cmd64x.c +++ b/drivers/block/cmd64x.c @@ -1,4 +1,4 @@ -/* $Id: cmd64x.c,v 1.20 1999/12/30 03:48:37 +/* $Id: cmd64x.c,v 1.21 2000/01/30 23:23:16 * * cmd64x.c: Enable interrupts at initialization time on Ultra/PCI machines. * Note, this driver is not used at all on other systems because @@ -8,7 +8,7 @@ * * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) * Copyright (C) 1998 David S. Miller (davem@redhat.com) - * Copyright (C) 1999 Andre Hedrick (andre@suse.com) + * Copyright (C) 1999-2000 Andre Hedrick (andre@suse.com) */ #include @@ -18,8 +18,10 @@ #include #include +#include "ide_modes.h" #define CMD_DEBUG 0 +#undef NO_WRITE #if CMD_DEBUG #define cmdprintk(x...) printk(##x) @@ -27,6 +29,235 @@ #define cmdprintk(x...) #endif +/* + * CMD64x specific registers definition. + */ + +#define CNTRL 0x51 +#define CNTRL_DIS_RA0 0x40 +#define CNTRL_DIS_RA1 0x80 +#define CNTRL_ENA_2ND 0x08 + +#define CMDTIM 0x52 +#define ARTTIM0 0x53 +#define DRWTIM0 0x54 +#define ARTTIM1 0x55 +#define DRWTIM1 0x56 +#define ARTTIM23 0x57 +#define ARTTIM23_DIS_RA2 0x04 +#define ARTTIM23_DIS_RA3 0x08 +#define DRWTIM23 0x58 +#define DRWTIM2 0x58 +#define BRST 0x59 +#define DRWTIM3 0x5b + +#define MRDMODE 0x71 + +#define DISPLAY_CMD64X_TIMINGS + +#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS) +#include +#include + +static int cmd64x_get_info(char *, char **, off_t, int); +extern int (*cmd64x_display_info)(char *, char **, off_t, int); /* ide-proc.c */ +extern char *ide_media_verbose(ide_drive_t *); +static struct pci_dev *bmide_dev; + +static int cmd64x_get_info (char *buffer, char **addr, off_t offset, int count) +{ + char *p = buffer; + u32 bibma = bmide_dev->resource[4].start; + u8 c0 = 0, c1 = 0; + + switch(bmide_dev->device) { + case PCI_DEVICE_ID_CMD_648: + p += sprintf(p, "\n CMD648 Chipset.\n"); + break; + case PCI_DEVICE_ID_CMD_646: + p += sprintf(p, "\n CMD646 Chipset.\n"); + break; + case PCI_DEVICE_ID_CMD_643: + p += sprintf(p, "\n CMD643 Chipset.\n"); + break; + default: + p += sprintf(p, "\n CMD64? Chipse.\n"); + break; + } + + /* + * at that point bibma+0x2 et bibma+0xa are byte registers + * to investigate: + */ + c0 = inb_p((unsigned short)bibma + 0x02); + c1 = inb_p((unsigned short)bibma + 0x0a); + p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n"); + p += sprintf(p, " %sabled %sabled\n", + (c0&0x80) ? "dis" : " en", + (c1&0x80) ? "dis" : " en"); + p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n"); + p += sprintf(p, "DMA enabled: %s %s %s %s\n", + (c0&0x20) ? "yes" : "no ", (c0&0x40) ? "yes" : "no ", + (c1&0x20) ? "yes" : "no ", (c1&0x40) ? "yes" : "no " ); + + p += sprintf(p, "UDMA\n"); + p += sprintf(p, "DMA\n"); + p += sprintf(p, "PIO\n"); + + return p-buffer; /* => must be less than 4k! */ +} +#endif /* defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS) */ + +byte cmd64x_proc = 0; + +/* + * Registers and masks for easy access by drive index: + */ +#if 0 +static byte prefetch_regs[4] = {CNTRL, CNTRL, ARTTIM23, ARTTIM23}; +static byte prefetch_masks[4] = {CNTRL_DIS_RA0, CNTRL_DIS_RA1, ARTTIM23_DIS_RA2, ARTTIM23_DIS_RA3}; +#endif + +/* + * This routine writes the prepared setup/active/recovery counts + * for a drive into the cmd646 chipset registers to active them. + */ +static void program_drive_counts (ide_drive_t *drive, int setup_count, int active_count, int recovery_count) +{ + unsigned long flags; + ide_drive_t *drives = HWIF(drive)->drives; + byte temp_b; + static const byte setup_counts[] = {0x40, 0x40, 0x40, 0x80, 0, 0xc0}; + static const byte recovery_counts[] = + {15, 15, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0}; + static const byte arttim_regs[2][2] = { + { ARTTIM0, ARTTIM1 }, + { ARTTIM23, ARTTIM23 } + }; + static const byte drwtim_regs[2][2] = { + { DRWTIM0, DRWTIM1 }, + { DRWTIM2, DRWTIM3 } + }; + int channel = (int) HWIF(drive)->channel; + int slave = (drives != drive); /* Is this really the best way to determine this?? */ + + cmdprintk("program_drive_count parameters = s(%d),a(%d),r(%d),p(%d)\n", setup_count, + active_count, recovery_count, drive->present); + /* + * Set up address setup count registers. + * Primary interface has individual count/timing registers for + * each drive. Secondary interface has one common set of registers, + * for address setup so we merge these timings, using the slowest + * value. + */ + if (channel) { + drive->drive_data = setup_count; + setup_count = IDE_MAX(drives[0].drive_data, drives[1].drive_data); + cmdprintk("Secondary interface, setup_count = %d\n", setup_count); + } + + /* + * Convert values to internal chipset representation + */ + setup_count = (setup_count > 5) ? 0xc0 : (int) setup_counts[setup_count]; + active_count &= 0xf; /* Remember, max value is 16 */ + recovery_count = (int) recovery_counts[recovery_count]; + + cmdprintk("Final values = %d,%d,%d\n", setup_count, active_count, recovery_count); + + /* + * Now that everything is ready, program the new timings + */ + __save_flags (flags); + __cli(); + /* + * Program the address_setup clocks into ARTTIM reg, + * and then the active/recovery counts into the DRWTIM reg + */ + (void) pci_read_config_byte(HWIF(drive)->pci_dev, arttim_regs[channel][slave], &temp_b); +#ifndef NO_WRITE + (void) pci_write_config_byte(HWIF(drive)->pci_dev, arttim_regs[channel][slave], + ((byte) setup_count) | (temp_b & 0x3f)); + (void) pci_write_config_byte(HWIF(drive)->pci_dev, drwtim_regs[channel][slave], + (byte) ((active_count << 4) | recovery_count)); +#endif + cmdprintk ("Write %x to %x\n", ((byte) setup_count) | (temp_b & 0x3f), arttim_regs[channel][slave]); + cmdprintk ("Write %x to %x\n", (byte) ((active_count << 4) | recovery_count), drwtim_regs[channel][slave]); + __restore_flags(flags); +} + +/* + * Attempts to set the interface PIO mode. + * The preferred method of selecting PIO modes (e.g. mode 4) is + * "echo 'piomode:4' > /proc/ide/hdx/settings". Special cases are + * 8: prefetch off, 9: prefetch on, 255: auto-select best mode. + * Called with 255 at boot time. + */ +static void cmd64x_tuneproc (ide_drive_t *drive, byte mode_wanted) +{ + int setup_time, active_time, recovery_time, clock_time, pio_mode, cycle_time; + byte recovery_count2, cycle_count; + int setup_count, active_count, recovery_count; + int bus_speed = ide_system_bus_speed(); + /*byte b;*/ + ide_pio_data_t d; + + switch (mode_wanted) { + case 8: /* set prefetch off */ + case 9: /* set prefetch on */ + mode_wanted &= 1; + /*set_prefetch_mode(index, mode_wanted);*/ + cmdprintk("%s: %sabled cmd640 prefetch\n", drive->name, mode_wanted ? "en" : "dis"); + return; + } + + (void) ide_get_best_pio_mode (drive, mode_wanted, 5, &d); + pio_mode = d.pio_mode; + cycle_time = d.cycle_time; + + /* + * I copied all this complicated stuff from cmd640.c and made a few minor changes. + * For now I am just going to pray that it is correct. + */ + if (pio_mode > 5) + pio_mode = 5; + setup_time = ide_pio_timings[pio_mode].setup_time; + active_time = ide_pio_timings[pio_mode].active_time; + recovery_time = cycle_time - (setup_time + active_time); + clock_time = 1000 / bus_speed; + cycle_count = (cycle_time + clock_time - 1) / clock_time; + + setup_count = (setup_time + clock_time - 1) / clock_time; + + active_count = (active_time + clock_time - 1) / clock_time; + + recovery_count = (recovery_time + clock_time - 1) / clock_time; + recovery_count2 = cycle_count - (setup_count + active_count); + if (recovery_count2 > recovery_count) + recovery_count = recovery_count2; + if (recovery_count > 16) { + active_count += recovery_count - 16; + recovery_count = 16; + } + if (active_count > 16) + active_count = 16; /* maximum allowed by cmd646 */ + + /* + * In a perfect world, we might set the drive pio mode here + * (using WIN_SETFEATURE) before continuing. + * + * But we do not, because: + * 1) this is the wrong place to do it (proper is do_special() in ide.c) + * 2) in practice this is rarely, if ever, necessary + */ + program_drive_counts (drive, setup_count, active_count, recovery_count); + + printk ("%s: selected cmd646 PIO mode%d (%dns)%s, clocks=%d/%d/%d\n", + drive->name, pio_mode, cycle_time, + d.overridden ? " (overriding vendor mode)" : "", + setup_count, active_count, recovery_count); +} + static int config_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ultra_66) { struct hd_driveid *id = drive->id; @@ -123,7 +354,7 @@ static int config_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ul static void config_chipset_for_pio (ide_drive_t *drive, unsigned int rev) { - /* FIXME!! figure out some PIOing junk.... */ + cmd64x_tuneproc(drive, 5); } static int cmd64x_config_drive_for_dma (ide_drive_t *drive) @@ -198,7 +429,7 @@ fast_ata_pio: no_dma_set: config_chipset_for_pio(drive, class_rev); } - return hwif->dmaproc(dma_func, drive); + return HWIF(drive)->dmaproc(dma_func, drive); } static int cmd64x_dmaproc (ide_dma_action_t func, ide_drive_t *drive) @@ -277,9 +508,9 @@ unsigned int __init pci_init_cmd64x (struct pci_dev *dev, const char *name) #endif /* Setup interrupts. */ - (void) pci_read_config_byte(dev, 0x71, &mrdmode); + (void) pci_read_config_byte(dev, MRDMODE, &mrdmode); mrdmode &= ~(0x30); - (void) pci_write_config_byte(dev, 0x71, mrdmode); + (void) pci_write_config_byte(dev, MRDMODE, mrdmode); /* Use MEMORY READ LINE for reads. * NOTE: Although not mentioned in the PCI0646U specs, @@ -287,16 +518,26 @@ unsigned int __init pci_init_cmd64x (struct pci_dev *dev, const char *name) * back as set or not. The PCI0646U2 specs clarify * this point. */ - (void) pci_write_config_byte(dev, 0x71, mrdmode | 0x02); - + (void) pci_write_config_byte(dev, MRDMODE, mrdmode | 0x02); +#if 0 /* Set reasonable active/recovery/address-setup values. */ - (void) pci_write_config_byte(dev, 0x53, 0x40); - (void) pci_write_config_byte(dev, 0x54, 0x3f); - (void) pci_write_config_byte(dev, 0x55, 0x40); - (void) pci_write_config_byte(dev, 0x56, 0x3f); - (void) pci_write_config_byte(dev, 0x57, 0x5c); - (void) pci_write_config_byte(dev, 0x58, 0x3f); - (void) pci_write_config_byte(dev, 0x5b, 0x3f); + (void) pci_write_config_byte(dev, ARTTIM0, 0x40); + (void) pci_write_config_byte(dev, DRWTIM0, 0x3f); + (void) pci_write_config_byte(dev, ARTTIM1, 0x40); + (void) pci_write_config_byte(dev, DRWTIM1, 0x3f); + (void) pci_write_config_byte(dev, ARTTIM23, 0x5c); + (void) pci_write_config_byte(dev, DRWTIM23, 0x3f); + (void) pci_write_config_byte(dev, DRWTIM3, 0x3f); +#else + (void) pci_write_config_byte(dev, ARTTIM23, 0x1c); +#endif + +#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS) + cmd64x_proc = 1; + bmide_dev = dev; + cmd64x_display_info = &cmd64x_get_info; +#endif /* DISPLAY_CMD64X_TIMINGS && CONFIG_PROC_FS */ + return 0; } @@ -317,8 +558,13 @@ void __init ide_init_cmd64x (ide_hwif_t *hwif) pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); class_rev &= 0xff; - if (!hwif->dma_base) + hwif->tuneproc = &cmd64x_tuneproc; + + if (!hwif->dma_base) { + hwif->drives[0].autotune = 1; + hwif->drives[1].autotune = 1; return; + } switch(dev->device) { case PCI_DEVICE_ID_CMD_643: diff --git a/drivers/block/cs5530.c b/drivers/block/cs5530.c index 3e26b8006..0f2f04990 100644 --- a/drivers/block/cs5530.c +++ b/drivers/block/cs5530.c @@ -1,5 +1,5 @@ /* - * linux/drivers/block/cs5530.c Version 0.5 Feb 13, 2000 + * linux/drivers/block/cs5530.c Version 0.5 Feb 13, 2000 * * Copyright (C) 2000 Mark Lord * May be copied or modified under the terms of the GNU General Public License @@ -24,130 +24,63 @@ #include #include "ide_modes.h" -/* - * Return the mode name for a drive transfer mode value: - */ -static const char *strmode (byte mode) +#define DISPLAY_CS5530_TIMINGS + +#if defined(DISPLAY_CS5530_TIMINGS) && defined(CONFIG_PROC_FS) +#include +#include + +static int cs5530_get_info(char *, char **, off_t, int); +extern int (*cs5530_display_info)(char *, char **, off_t, int); /* ide-proc.c */ +extern char *ide_media_verbose(ide_drive_t *); +static struct pci_dev *bmide_dev; + +static int cs5530_get_info (char *buffer, char **addr, off_t offset, int count) { - switch (mode) { - case XFER_UDMA_4: return("UDMA4"); - case XFER_UDMA_3: return("UDMA3"); - case XFER_UDMA_2: return("UDMA2"); - case XFER_UDMA_1: return("UDMA1"); - case XFER_UDMA_0: return("UDMA0"); - case XFER_MW_DMA_2: return("MDMA2"); - case XFER_MW_DMA_1: return("MDMA1"); - case XFER_MW_DMA_0: return("MDMA0"); - case XFER_SW_DMA_2: return("SDMA2"); - case XFER_SW_DMA_1: return("SDMA1"); - case XFER_SW_DMA_0: return("SDMA0"); - case XFER_PIO_4: return("PIO4"); - case XFER_PIO_3: return("PIO3"); - case XFER_PIO_2: return("PIO2"); - case XFER_PIO_1: return("PIO1"); - case XFER_PIO_0: return("PIO0"); - default: return("???"); - } + char *p = buffer; + u32 bibma = bmide_dev->resource[4].start; + u8 c0 = 0, c1 = 0; + + /* + * at that point bibma+0x2 et bibma+0xa are byte registers + * to investigate: + */ + + c0 = inb_p((unsigned short)bibma + 0x02); + c1 = inb_p((unsigned short)bibma + 0x0a); + + p += sprintf(p, "\n Cyrix 5530 Chipset.\n"); + p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n"); + p += sprintf(p, " %sabled %sabled\n", + (c0&0x80) ? "dis" : " en", + (c1&0x80) ? "dis" : " en"); + p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n"); + p += sprintf(p, "DMA enabled: %s %s %s %s\n", + (c0&0x20) ? "yes" : "no ", (c0&0x40) ? "yes" : "no ", + (c1&0x20) ? "yes" : "no ", (c1&0x40) ? "yes" : "no " ); + + p += sprintf(p, "UDMA\n"); + p += sprintf(p, "DMA\n"); + p += sprintf(p, "PIO\n"); + + return p-buffer; } +#endif /* DISPLAY_CS5530_TIMINGS && CONFIG_PROC_FS */ + +byte cs5530_proc = 0; + +extern char *ide_xfer_verbose (byte xfer_rate); /* * Set a new transfer mode at the drive */ int cs5530_set_xfer_mode (ide_drive_t *drive, byte mode) { - int i, error = 1; - byte stat; - ide_hwif_t *hwif = HWIF(drive); - - printk("%s: cs5530_set_xfer_mode(%s)\n", drive->name, strmode(mode)); - /* - * If this is a DMA mode setting, then turn off all DMA bits. - * We will set one of them back on afterwards, if all goes well. - * - * Not sure why this is needed (it looks very silly), - * but other IDE chipset drivers also do this fiddling. ???? -ml - */ - switch (mode) { - case XFER_UDMA_4: - case XFER_UDMA_3: - case XFER_UDMA_2: - case XFER_UDMA_1: - case XFER_UDMA_0: - case XFER_MW_DMA_2: - case XFER_MW_DMA_1: - case XFER_MW_DMA_0: - case XFER_SW_DMA_2: - case XFER_SW_DMA_1: - case XFER_SW_DMA_0: - drive->id->dma_ultra &= ~0xFF00; - drive->id->dma_mword &= ~0x0F00; - drive->id->dma_1word &= ~0x0F00; - } + int error = 0; - /* - * Select the drive, and issue the SETFEATURES command - */ - disable_irq(hwif->irq); - udelay(1); - SELECT_DRIVE(HWIF(drive), drive); - udelay(1); - if (IDE_CONTROL_REG) - OUT_BYTE(drive->ctl | 2, IDE_CONTROL_REG); - OUT_BYTE(mode, IDE_NSECTOR_REG); - OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG); - OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG); - udelay(1); /* spec allows drive 400ns to assert "BUSY" */ + printk("%s: cs5530_set_xfer_mode(%s)\n", drive->name, ide_xfer_verbose(mode)); + error = ide_config_drive_speed(drive, mode); - /* - * Wait for drive to become non-BUSY - */ - if ((stat = GET_STAT()) & BUSY_STAT) { - unsigned long flags, timeout; - __save_flags(flags); /* local CPU only */ - ide__sti(); /* local CPU only -- for jiffies */ - timeout = jiffies + WAIT_CMD; - while ((stat = GET_STAT()) & BUSY_STAT) { - if (0 < (signed long)(jiffies - timeout)) - break; - } - __restore_flags(flags); /* local CPU only */ - } - - /* - * Allow status to settle, then read it again. - * A few rare drives vastly violate the 400ns spec here, - * so we'll wait up to 10usec for a "good" status - * rather than expensively fail things immediately. - */ - for (i = 0; i < 10; i++) { - udelay(1); - if (OK_STAT((stat = GET_STAT()), DRIVE_READY, BUSY_STAT|DRQ_STAT|ERR_STAT)) { - error = 0; - break; - } - } - enable_irq(hwif->irq); - - /* - * Turn dma bit on if all is okay - */ - if (error) { - (void) ide_dump_status(drive, "cs5530_set_xfer_mode", stat); - } else { - switch (mode) { - case XFER_UDMA_4: drive->id->dma_ultra |= 0x1010; break; - case XFER_UDMA_3: drive->id->dma_ultra |= 0x0808; break; - case XFER_UDMA_2: drive->id->dma_ultra |= 0x0404; break; - case XFER_UDMA_1: drive->id->dma_ultra |= 0x0202; break; - case XFER_UDMA_0: drive->id->dma_ultra |= 0x0101; break; - case XFER_MW_DMA_2: drive->id->dma_mword |= 0x0404; break; - case XFER_MW_DMA_1: drive->id->dma_mword |= 0x0202; break; - case XFER_MW_DMA_0: drive->id->dma_mword |= 0x0101; break; - case XFER_SW_DMA_2: drive->id->dma_1word |= 0x0404; break; - case XFER_SW_DMA_1: drive->id->dma_1word |= 0x0202; break; - case XFER_SW_DMA_0: drive->id->dma_1word |= 0x0101; break; - } - } return error; } @@ -302,8 +235,10 @@ int cs5530_dmaproc (ide_dma_action_t func, ide_drive_t *drive) case ide_dma_check: return cs5530_config_dma(drive); default: - return ide_dmaproc(func, drive); + break; } + /* Other cases are done by generic IDE-DMA code. */ + return ide_dmaproc(func, drive); } /* @@ -384,6 +319,13 @@ unsigned int __init pci_init_cs5530 (struct pci_dev *dev, const char *name) pci_write_config_byte(master_0, 0x43, 0xc1); restore_flags(flags); + +#if defined(DISPLAY_CS5530_TIMINGS) && defined(CONFIG_PROC_FS) + cs5530_proc = 1; + bmide_dev = dev; + cs5530_display_info = &cs5530_get_info; +#endif /* DISPLAY_CS5530_TIMINGS && CONFIG_PROC_FS */ + return 0; } diff --git a/drivers/block/cy82c693.c b/drivers/block/cy82c693.c index 412f403c3..cfff0381c 100644 --- a/drivers/block/cy82c693.c +++ b/drivers/block/cy82c693.c @@ -1,5 +1,5 @@ /* - * linux/drivers/block/cy82c693.c Version 0.34 Dec. 13, 1999 + * linux/drivers/block/cy82c693.c Version 0.34 Dec. 13, 1999 * * Copyright (C) 1998-99 Andreas S. Krebs (akrebs@altavista.net), Maintainer * Copyright (C) 1998-99 Andre Hedrick, Integrater @@ -54,7 +54,7 @@ #include "ide_modes.h" /* the current version */ -#define CY82_VERSION "CY82C693U driver v0.34 99-09-03 Andreas S. Krebs (akrebs@altavista.net)" +#define CY82_VERSION "CY82C693U driver v0.34 99-13-12 Andreas S. Krebs (akrebs@altavista.net)" /* * The following are used to debug the driver. @@ -439,4 +439,3 @@ void __init ide_init_cy82c693(ide_hwif_t *hwif) hwif->drives[1].autotune = 1; } } - diff --git a/drivers/block/dtc2278.c b/drivers/block/dtc2278.c index d805dec75..d8838e111 100644 --- a/drivers/block/dtc2278.c +++ b/drivers/block/dtc2278.c @@ -1,5 +1,5 @@ /* - * linux/drivers/block/dtc2278.c Version 0.02 Feb 10, 1996 + * linux/drivers/block/dtc2278.c Version 0.02 Feb 10, 1996 * * Copyright (C) 1996 Linus Torvalds & author (see below) */ @@ -95,7 +95,7 @@ static void tune_dtc2278 (ide_drive_t *drive, byte pio) HWIF(drive)->drives[!drive->select.b.unit].io_32bit = 1; } -void init_dtc2278 (void) +void __init init_dtc2278 (void) { unsigned long flags; diff --git a/drivers/block/falconide.c b/drivers/block/falconide.c index 321569eb1..7bce07517 100644 --- a/drivers/block/falconide.c +++ b/drivers/block/falconide.c @@ -40,7 +40,7 @@ #define ATA_HD_STATUS 0x1d /* see status-bits */ #define ATA_HD_CONTROL 0x39 -static int falconide_offsets[IDE_NR_PORTS] = { +static int __init falconide_offsets[IDE_NR_PORTS] = { ATA_HD_DATA, ATA_HD_ERROR, ATA_HD_NSECTOR, ATA_HD_SECTOR, ATA_HD_LCYL, ATA_HD_HCYL, ATA_HD_SELECT, ATA_HD_STATUS, ATA_HD_CONTROL, -1 }; @@ -50,7 +50,7 @@ static int falconide_offsets[IDE_NR_PORTS] = { * Probe for a Falcon IDE interface */ -void falconide_init(void) +void __init falconide_init(void) { if (MACH_IS_ATARI && ATARIHW_PRESENT(IDE)) { hw_regs_t hw; diff --git a/drivers/block/gayle.c b/drivers/block/gayle.c index 920f2ee0a..29cceb20e 100644 --- a/drivers/block/gayle.c +++ b/drivers/block/gayle.c @@ -41,7 +41,7 @@ #define GAYLE_STATUS 0x1e /* see status-bits */ #define GAYLE_CONTROL 0x101a -static int gayle_offsets[IDE_NR_PORTS] = { +static int __init gayle_offsets[IDE_NR_PORTS] = { GAYLE_DATA, GAYLE_ERROR, GAYLE_NSECTOR, GAYLE_SECTOR, GAYLE_LCYL, GAYLE_HCYL, GAYLE_SELECT, GAYLE_STATUS, -1, -1 }; @@ -105,7 +105,7 @@ static int gayle_ack_intr_a1200(ide_hwif_t *hwif) * Probe for a Gayle IDE interface (and optionally for an IDE doubler) */ -void gayle_init(void) +void __init gayle_init(void) { int a4000, i; diff --git a/drivers/block/hpt34x.c b/drivers/block/hpt34x.c index 10fe3ebc1..7a077368e 100644 --- a/drivers/block/hpt34x.c +++ b/drivers/block/hpt34x.c @@ -1,7 +1,7 @@ /* - * linux/drivers/block/hpt34x.c Version 0.28 Dec. 13, 1999 + * linux/drivers/block/hpt34x.c Version 0.29 Feb. 10, 2000 * - * Copyright (C) 1998-99 Andre Hedrick (andre@suse.com) + * Copyright (C) 1998-2000 Andre Hedrick (andre@suse.com) * May be copied or modified under the terms of the GNU General Public License * * @@ -16,6 +16,12 @@ * hdg: DMA 1 (0x0012 0x0052) (0x0030 0x0070) * hdh: DMA 1 (0x0052 0x0252) (0x0070 0x00f0) * + * ide-pci.c reference + * + * Since there are two cards that report almost identically, + * the only discernable difference is the values reported in pcicmd. + * Booting-BIOS card or HPT363 :: pcicmd == 0x07 + * Non-bootable card or HPT343 :: pcicmd == 0x05 */ #include @@ -27,7 +33,6 @@ #include #include #include - #include #include #include @@ -35,16 +40,56 @@ #include #include - #include "ide_modes.h" #ifndef SPLIT_BYTE #define SPLIT_BYTE(B,H,L) ((H)=(B>>4), (L)=(B-((B>>4)<<4))) #endif -#define HPT343_DEBUG_DRIVE_INFO 0 -#define HPT343_DISABLE_ALL_DMAING 0 -#define HPT343_DMA_DISK_ONLY 0 +#define HPT343_DEBUG_DRIVE_INFO 1 + +#define DISPLAY_HPT34X_TIMINGS +#if defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS) +#include +#include + +static int hpt34x_get_info(char *, char **, off_t, int); +extern int (*hpt34x_display_info)(char *, char **, off_t, int); /* ide-proc.c */ +extern char *ide_media_verbose(ide_drive_t *); +static struct pci_dev *bmide_dev; + +static int hpt34x_get_info (char *buffer, char **addr, off_t offset, int count) +{ + char *p = buffer; + u32 bibma = bmide_dev->resource[4].start; + u8 c0 = 0, c1 = 0; + + /* + * at that point bibma+0x2 et bibma+0xa are byte registers + * to investigate: + */ + c0 = inb_p((unsigned short)bibma + 0x02); + c1 = inb_p((unsigned short)bibma + 0x0a); + + p += sprintf(p, "\n HPT34X Chipset.\n"); + p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n"); + p += sprintf(p, " %sabled %sabled\n", + (c0&0x80) ? "dis" : " en", + (c1&0x80) ? "dis" : " en"); + p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n"); + p += sprintf(p, "DMA enabled: %s %s %s %s\n", + (c0&0x20) ? "yes" : "no ", (c0&0x40) ? "yes" : "no ", + (c1&0x20) ? "yes" : "no ", (c1&0x40) ? "yes" : "no " ); + + p += sprintf(p, "UDMA\n"); + p += sprintf(p, "DMA\n"); + p += sprintf(p, "PIO\n"); + + return p-buffer; /* => must be less than 4k! */ +} +#endif /* defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS) */ + +byte hpt34x_proc = 0; extern char *ide_xfer_verbose (byte xfer_rate); @@ -109,12 +154,8 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra) struct hd_driveid *id = drive->id; byte speed = 0x00; -#if HPT343_DISABLE_ALL_DMAING - return ((int) ide_dma_off); -#elif HPT343_DMA_DISK_ONLY if (drive->media != ide_disk) return ((int) ide_dma_off_quietly); -#endif /* HPT343_DISABLE_ALL_DMAING */ hpt34x_clear_chipset(drive); @@ -249,14 +290,13 @@ try_dma_modes: fast_ata_pio: dma_func = ide_dma_off_quietly; no_dma_set: - config_chipset_for_pio(drive); } -#if 0 +#ifndef CONFIG_HPT34X_AUTODMA if (dma_func == ide_dma_on) dma_func = ide_dma_off; -#endif +#endif /* CONFIG_HPT34X_AUTODMA */ return HWIF(drive)->dmaproc(dma_func, drive); } @@ -273,18 +313,10 @@ int hpt34x_dmaproc (ide_dma_action_t func, ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); unsigned long dma_base = hwif->dma_base; - byte unit = (drive->select.b.unit & 0x01); unsigned int count, reading = 0; byte dma_stat; switch (func) { - case ide_dma_off: - case ide_dma_off_quietly: - outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2); - break; - case ide_dma_on: - outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2); - break; case ide_dma_check: return config_drive_xfer_rate(drive); case ide_dma_read: @@ -357,11 +389,16 @@ unsigned int __init pci_init_hpt34x (struct pci_dev *dev, const char *name) pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, dev->resource[1].start); pci_write_config_dword(dev, PCI_BASE_ADDRESS_2, dev->resource[2].start); pci_write_config_dword(dev, PCI_BASE_ADDRESS_3, dev->resource[3].start); - pci_write_config_word(dev, PCI_COMMAND, cmd); __restore_flags(flags); /* local CPU only */ +#if defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS) + hpt34x_proc = 1; + bmide_dev = dev; + hpt34x_display_info = &hpt34x_get_info; +#endif /* DISPLAY_HPT34X_TIMINGS && CONFIG_PROC_FS */ + return dev->irq; } @@ -372,11 +409,7 @@ void __init ide_init_hpt34x (ide_hwif_t *hwif) unsigned short pcicmd = 0; pci_read_config_word(hwif->pci_dev, PCI_COMMAND, &pcicmd); -#ifdef CONFIG_BLK_DEV_HPT34X_DMA -#if 0 hwif->autodma = (pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0; -#endif -#endif /* CONFIG_BLK_DEV_HPT34X_DMA */ hwif->dmaproc = &hpt34x_dmaproc; } else { hwif->drives[0].autotune = 1; diff --git a/drivers/block/hpt366.c b/drivers/block/hpt366.c index 7328ea7b8..02c9c16dd 100644 --- a/drivers/block/hpt366.c +++ b/drivers/block/hpt366.c @@ -1,7 +1,7 @@ /* - * linux/drivers/block/hpt366.c Version 0.15 Dec. 22, 1999 + * linux/drivers/block/hpt366.c Version 0.16 Feb. 10, 2000 * - * Copyright (C) 1999 Andre Hedrick + * Copyright (C) 1999-2000 Andre Hedrick * May be copied or modified under the terms of the GNU General Public License * * Thanks to HighPoint Technologies for their assistance, and hardware. @@ -30,6 +30,13 @@ #include "ide_modes.h" +#define DISPLAY_HPT366_TIMINGS + +#if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) +#include +#include +#endif /* defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) */ + const char *bad_ata66_4[] = { "WDC AC310200R", NULL @@ -120,6 +127,48 @@ struct chipset_bus_clock_list_entry twenty_five_base [] = { #define HPT366_ALLOW_ATA66_4 1 #define HPT366_ALLOW_ATA66_3 1 +#if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) +static int hpt366_get_info(char *, char **, off_t, int); +extern int (*hpt366_display_info)(char *, char **, off_t, int); /* ide-proc.c */ +extern char *ide_media_verbose(ide_drive_t *); +static struct pci_dev *bmide_dev; +static struct pci_dev *bmide2_dev; + +static int hpt366_get_info (char *buffer, char **addr, off_t offset, int count) +{ + char *p = buffer; + u32 bibma = bmide_dev->resource[4].start; + u32 bibma2 = bmide2_dev->resource[4].start; + u8 c0 = 0, c1 = 0; + + /* + * at that point bibma+0x2 et bibma+0xa are byte registers + * to investigate: + */ + c0 = inb_p((unsigned short)bibma + 0x02); + if (bmide2_dev) + c1 = inb_p((unsigned short)bibma2 + 0x02); + + p += sprintf(p, "\n HPT366 Chipset.\n"); + p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n"); + p += sprintf(p, " %sabled %sabled\n", + (c0&0x80) ? "dis" : " en", + (c1&0x80) ? "dis" : " en"); + p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n"); + p += sprintf(p, "DMA enabled: %s %s %s %s\n", + (c0&0x20) ? "yes" : "no ", (c0&0x40) ? "yes" : "no ", + (c1&0x20) ? "yes" : "no ", (c1&0x40) ? "yes" : "no " ); + + p += sprintf(p, "UDMA\n"); + p += sprintf(p, "DMA\n"); + p += sprintf(p, "PIO\n"); + + return p-buffer;/* => must be less than 4k! */ +} +#endif /* defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) */ + +byte hpt366_proc = 0; + extern char *ide_xfer_verbose (byte xfer_rate); byte hpt363_shared_irq = 0; byte hpt363_shared_pin = 0; @@ -263,20 +312,20 @@ static int config_chipset_for_dma (ide_drive_t *drive) pci_read_config_byte(HWIF(drive)->pci_dev, 0x51, ®51h); -#ifdef CONFIG_HPT366_FAST_IRQ_PREDICTION +#ifdef CONFIG_HPT366_FIP /* * Some drives prefer/allow for the method of handling interrupts. */ if (!(reg51h & 0x80)) pci_write_config_byte(HWIF(drive)->pci_dev, 0x51, reg51h|0x80); -#else /* ! CONFIG_HPT366_FAST_IRQ_PREDICTION */ +#else /* ! CONFIG_HPT366_FIP */ /* * Disable the "fast interrupt" prediction. * Instead, always wait for the real interrupt from the drive! */ if (reg51h & 0x80) pci_write_config_byte(HWIF(drive)->pci_dev, 0x51, reg51h & ~0x80); -#endif /* CONFIG_HPT366_FAST_IRQ_PREDICTION */ +#endif /* CONFIG_HPT366_FIP */ /* * Preserve existing PIO settings: @@ -420,7 +469,6 @@ no_dma_set: * This is specific to the HPT366 UDMA bios chipset * by HighPoint|Triones Technologies, Inc. */ - int hpt366_dmaproc (ide_dma_action_t func, ide_drive_t *drive) { byte reg50h = 0; @@ -434,7 +482,6 @@ int hpt366_dmaproc (ide_dma_action_t func, ide_drive_t *drive) pci_read_config_byte(HWIF(drive)->pci_dev, 0x50, ®50h); /* ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL); */ case ide_dma_timeout: - break; default: break; } @@ -464,6 +511,17 @@ unsigned int __init pci_init_hpt366 (struct pci_dev *dev, const char *name) if (test != 0x08) pci_write_config_byte(dev, PCI_MAX_LAT, 0x08); +#if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) + if (!hpt366_proc) { + hpt366_proc = 1; + bmide_dev = dev; + hpt366_display_info = &hpt366_get_info; + } + if ((hpt366_proc) && ((dev->devfn - bmide_dev->devfn) == 1)) { + bmide2_dev = dev; + } +#endif /* DISPLAY_HPT366_TIMINGS && CONFIG_PROC_FS */ + return dev->irq; } @@ -482,18 +540,6 @@ unsigned int __init ata66_hpt366 (ide_hwif_t *hwif) void __init ide_init_hpt366 (ide_hwif_t *hwif) { -#if 0 - if ((PCI_FUNC(hwif->pci_dev->devfn) & 1) && (hpt363_shared_irq)) { - hwif->mate = &ide_hwifs[hwif->index-1]; - hwif->mate->mate = hwif; - hwif->serialized = hwif->mate->serialized = 1; - } - - if ((PCI_FUNC(hwif->pci_dev->devfn) & 1) && (hpt363_shared_pin)) { - - } -#endif - hwif->tuneproc = &hpt366_tune_drive; if (hwif->dma_base) { hwif->dmaproc = &hpt366_dmaproc; diff --git a/drivers/block/ht6560b.c b/drivers/block/ht6560b.c index d9fb885c2..6b7d5af72 100644 --- a/drivers/block/ht6560b.c +++ b/drivers/block/ht6560b.c @@ -1,7 +1,7 @@ /* - * linux/drivers/block/ht6580.c Version 0.04 Mar 19, 1996 + * linux/drivers/block/ht6560b.c Version 0.07 Feb 1, 2000 * - * Copyright (C) 1995-1996 Linus Torvalds & author (see below) + * Copyright (C) 1995-2000 Linus Torvalds & author (see below) */ /* @@ -12,42 +12,31 @@ * * Version 0.03 Some cleanups * - * I reviewed some assembler source listings of htide drivers and found - * out how they setup those cycle time interfacing values, as they at Holtek - * call them. IDESETUP.COM that is supplied with the drivers figures out - * optimal values and fetches those values to drivers. I found out that - * they use IDE_SELECT_REG to fetch timings to the ide board right after - * interface switching. After that it was quite easy to add code to - * ht6560b.c. + * Version 0.05 PIO mode cycle timings auto-tune using bus-speed * - * IDESETUP.COM gave me values 0x24, 0x45, 0xaa, 0xff that worked fine - * for hda and hdc. But hdb needed higher values to work, so I guess - * that sometimes it is necessary to give higher value than IDESETUP - * gives. [see cmd640.c for an extreme example of this. -ml] + * Version 0.06 Prefetch mode now defaults no OFF. To set + * prefetch mode OFF/ON use "hdparm -p8/-p9". + * Unmask irq is disabled when prefetch mode + * is enabled. * - * Perhaps I should explain something about these timing values: - * The higher nibble of value is the Recovery Time (rt) and the lower nibble - * of the value is the Active Time (at). Minimum value 2 is the fastest and - * the maximum value 15 is the slowest. Default values should be 15 for both. - * So 0x24 means 2 for rt and 4 for at. Each of the drives should have - * both values, and IDESETUP gives automatically rt=15 st=15 for CDROMs or - * similar. If value is too small there will be all sorts of failures. - * - * Port 0x3e6 bit 0x20 sets these timings on/off. If 0x20 bit is set - * these timings are disabled. + * Version 0.07 Trying to fix CD-ROM detection problem. + * "Prefetch" mode bit OFF for ide disks and + * ON for anything else. * - * Mikko Ala-Fossi * - * More notes: + * HT-6560B EIDE-controller support + * To activate controller support use kernel parameter "ide0=ht6560b". + * Use hdparm utility to enable PIO mode support. * - * There's something still missing from the initialization code, though. - * If I have booted to dos sometime after power on, I can get smaller - * timing values working. Perhaps I could soft-ice the initialization. + * Author: Mikko Ala-Fossi + * Jan Evert van Grootheest * - * -=- malafoss@snakemail.hut.fi -=- searching the marvels of universe -=- + * Try: http://www.maf.iki.fi/~maf/ht6560b/ */ -#undef REALLY_SLOW_IO /* most systems can safely undef this */ +#define HT6560B_VERSION "v0.07" + +#undef REALLY_SLOW_IO /* most systems can safely undef this */ #include #include @@ -63,175 +52,291 @@ #include "ide_modes.h" -/* - * This routine handles interface switching for the peculiar hardware design - * on the F.G.I./Holtek HT-6560B VLB IDE interface. - * The HT-6560B can only enable one IDE port at a time, and requires a - * silly sequence (below) whenever we switch between primary and secondary. - * - * This stuff is courtesy of malafoss@snakemail.hut.fi - * (or maf@nemesis.tky.hut.fi) - * - * At least one user has reported that this code can confuse the floppy - * controller and/or driver -- perhaps this should be changed to use - * a read-modify-write sequence, so as not to disturb other bits in the reg? - */ +/* #define DEBUG */ /* remove comments for DEBUG messages */ /* - * The special i/o-port that HT-6560B uses to select interfaces: + * The special i/o-port that HT-6560B uses to configuration: + * bit0 (0x01): "1" selects secondary interface + * bit2 (0x04): "1" enables FIFO function + * bit5 (0x20): "1" enables prefetched data read function (???) + * + * The special i/o-port that HT-6560A uses to configuration: + * bit0 (0x01): "1" selects secondary interface + * bit1 (0x02): "1" enables prefetched data read function + * bit2 (0x04): "0" enables multi-master system (?) + * bit3 (0x08): "1" 3 cycle time, "0" 2 cycle time (?) */ -#define HT_SELECT_PORT 0x3e6 - +#define HT_CONFIG_PORT 0x3e6 +#define HT_CONFIG(drivea) (byte)(((drivea)->drive_data & 0xff00) >> 8) /* - * We don't know what all of the bits are for, but we *do* know about these: - * bit5 (0x20): "1" selects slower speed by disabling use of timing values - * bit0 (0x01): "1" selects second interface + * FIFO + PREFETCH (both a/b-model) */ -static byte ht6560b_selects [2][MAX_DRIVES] = {{0x3c,0x3c}, {0x3d,0x3d}}; +#define HT_CONFIG_DEFAULT 0x1c /* no prefetch */ +/* #define HT_CONFIG_DEFAULT 0x3c */ /* with prefetch */ +#define HT_SECONDARY_IF 0x01 +#define HT_PREFETCH_MODE 0x20 /* - * VLB ht6560b Timing values: + * ht6560b Timing values: + * + * I reviewed some assembler source listings of htide drivers and found + * out how they setup those cycle time interfacing values, as they at Holtek + * call them. IDESETUP.COM that is supplied with the drivers figures out + * optimal values and fetches those values to drivers. I found out that + * they use IDE_SELECT_REG to fetch timings to the ide board right after + * interface switching. After that it was quite easy to add code to + * ht6560b.c. + * + * IDESETUP.COM gave me values 0x24, 0x45, 0xaa, 0xff that worked fine + * for hda and hdc. But hdb needed higher values to work, so I guess + * that sometimes it is necessary to give higher value than IDESETUP + * gives. [see cmd640.c for an extreme example of this. -ml] + * + * Perhaps I should explain something about these timing values: + * The higher nibble of value is the Recovery Time (rt) and the lower nibble + * of the value is the Active Time (at). Minimum value 2 is the fastest and + * the maximum value 15 is the slowest. Default values should be 15 for both. + * So 0x24 means 2 for rt and 4 for at. Each of the drives should have + * both values, and IDESETUP gives automatically rt=15 st=15 for CDROMs or + * similar. If value is too small there will be all sorts of failures. * * Timing byte consists of - * High nibble: Recovery Time (rt) - * The valid values range from 2 to 15. The default is 15. + * High nibble: Recovery Cycle Time (rt) + * The valid values range from 2 to 15. The default is 15. * - * Low nibble: Active Time (at) - * The valid values range from 2 to 15. The default is 15. + * Low nibble: Active Cycle Time (at) + * The valid values range from 2 to 15. The default is 15. * * You can obtain optimized timing values by running Holtek IDESETUP.COM * for DOS. DOS drivers get their timing values from command line, where * the first value is the Recovery Time and the second value is the * Active Time for each drive. Smaller value gives higher speed. * In case of failures you should probably fall back to a higher value. - * - * Here's an example to make it clearer: - * - * DOS: DEVICE=C:\bin\HTIDE\HTIDE.SYS /D0=2,4 /D1=4,5 /D2=10,10 /D3=15,15 - * Linux: byte ht6560b_timings [][] = {{0x24, 0x45}, {0xaa, 0xff}}; - * - * Note: There are no ioctls to change these values directly, - * but settings can be approximated as PIO modes, using "hdparm": - * - * rc.local: hdparm -p3 /dev/hda -p2 /dev/hdb -p1 /dev/hdc -p0 /dev/hdd */ +#define HT_TIMING(drivea) (byte)((drivea)->drive_data & 0x00ff) +#define HT_TIMING_DEFAULT 0xff -static byte ht6560b_timings [2][MAX_DRIVES] = {{0xff,0xff}, {0xff,0xff}}; - -static byte pio_to_timings[6] = {0xff, 0xaa, 0x45, 0x24, 0x13, 0x12}; +/* + * This routine handles interface switching for the peculiar hardware design + * on the F.G.I./Holtek HT-6560B VLB IDE interface. + * The HT-6560B can only enable one IDE port at a time, and requires a + * silly sequence (below) whenever we switch between primary and secondary. + */ /* * This routine is invoked from ide.c to prepare for access to a given drive. */ static void ht6560b_selectproc (ide_drive_t *drive) { - byte t; unsigned long flags; static byte current_select = 0; static byte current_timing = 0; - byte select = ht6560b_selects[HWIF(drive)->index][drive->select.b.unit]; - byte timing = ht6560b_timings[HWIF(drive)->index][drive->select.b.unit]; - + byte select, timing; + + __save_flags (flags); /* local CPU only */ + __cli(); /* local CPU only */ + + select = HT_CONFIG(drive); + timing = HT_TIMING(drive); + if (select != current_select || timing != current_timing) { current_select = select; current_timing = timing; - __save_flags (flags); /* local CPU only */ - __cli(); /* local CPU only */ - (void) inb(HT_SELECT_PORT); - (void) inb(HT_SELECT_PORT); - (void) inb(HT_SELECT_PORT); + if (drive->media != ide_disk || !drive->present) + select |= HT_PREFETCH_MODE; + (void) inb(HT_CONFIG_PORT); + (void) inb(HT_CONFIG_PORT); + (void) inb(HT_CONFIG_PORT); + (void) inb(HT_CONFIG_PORT); + outb(select, HT_CONFIG_PORT); /* - * Note: input bits are reversed to output bits!! + * Set timing for this drive: */ - t = inb(HT_SELECT_PORT) ^ 0x3f; - t &= (~0x21); - t |= (current_select & 0x21); - outb(t, HT_SELECT_PORT); - /* - * Set timing for this drive: - */ - outb (timing, IDE_SELECT_REG); - (void) inb (IDE_STATUS_REG); - __restore_flags (flags); /* local CPU only */ + outb(timing, IDE_SELECT_REG); + (void) inb(IDE_STATUS_REG); #ifdef DEBUG - printk("ht6560b: %s: select=%#x timing=%#x\n", drive->name, t, timing); + printk("ht6560b: %s: select=%#x timing=%#x\n", drive->name, select, timing); #endif } + __restore_flags (flags); /* local CPU only */ } /* * Autodetection and initialization of ht6560b */ -int try_to_init_ht6560b(void) +static int __init try_to_init_ht6560b(void) { byte orig_value; int i; - + /* Autodetect ht6560b */ - if ((orig_value=inb(HT_SELECT_PORT)) == 0xff) + if ((orig_value=inb(HT_CONFIG_PORT)) == 0xff) return 0; - + for (i=3;i>0;i--) { - outb(0x00, HT_SELECT_PORT); - if (!( (~inb(HT_SELECT_PORT)) & 0x3f )) { - outb(orig_value, HT_SELECT_PORT); - return 0; + outb(0x00, HT_CONFIG_PORT); + if (!( (~inb(HT_CONFIG_PORT)) & 0x3f )) { + outb(orig_value, HT_CONFIG_PORT); + return 0; } } - outb(0x00, HT_SELECT_PORT); - if ((~inb(HT_SELECT_PORT))& 0x3f) { - outb(orig_value, HT_SELECT_PORT); + outb(0x00, HT_CONFIG_PORT); + if ((~inb(HT_CONFIG_PORT))& 0x3f) { + outb(orig_value, HT_CONFIG_PORT); return 0; } /* - * Ht6560b autodetected: - * reverse input bits to output bits - * initialize bit1 to 0 + * Ht6560b autodetected */ - outb((orig_value ^ 0x3f) & 0xfd, HT_SELECT_PORT); - - printk("\nht6560b: detected and initialized"); + outb(HT_CONFIG_DEFAULT, HT_CONFIG_PORT); + outb(HT_TIMING_DEFAULT, 0x1f6); /* IDE_SELECT_REG */ + (void) inb(0x1f7); /* IDE_STATUS_REG */ + + printk("\nht6560b " HT6560B_VERSION + ": chipset detected and initialized" +#ifdef DEBUG + " with debug enabled" +#endif + ); return 1; } -static void tune_ht6560b (ide_drive_t *drive, byte pio) +static byte ht_pio2timings(ide_drive_t *drive, byte pio) { - unsigned int hwif, unit; + int bus_speed, active_time, recovery_time; + int active_cycles, recovery_cycles; + ide_pio_data_t d; + + if (pio) { + pio = ide_get_best_pio_mode(drive, pio, 5, &d); + + /* + * Just like opti621.c we try to calculate the + * actual cycle time for recovery and activity + * according system bus speed. + */ + bus_speed = ide_system_bus_speed(); + active_time = ide_pio_timings[pio].active_time; + recovery_time = d.cycle_time + - active_time + - ide_pio_timings[pio].setup_time; + /* + * Cycle times should be Vesa bus cycles + */ + active_cycles = (active_time * bus_speed + 999) / 1000; + recovery_cycles = (recovery_time * bus_speed + 999) / 1000; + /* + * Upper and lower limits + */ + if (active_cycles < 2) active_cycles = 2; + if (recovery_cycles < 2) recovery_cycles = 2; + if (active_cycles > 15) active_cycles = 15; + if (recovery_cycles > 15) recovery_cycles = 0; /* 0==16 */ + +#ifdef DEBUG + printk("ht6560b: drive %s setting pio=%d recovery=%d (%dns) active=%d (%dns)\n", drive->name, pio, recovery_cycles, recovery_time, active_cycles, active_time); +#endif + + return (byte)((recovery_cycles << 4) | active_cycles); + } else { + +#ifdef DEBUG + printk("ht6560b: drive %s setting pio=0\n", drive->name); +#endif + + return HT_TIMING_DEFAULT; /* default setting */ + } +} + +/* + * Enable/Disable so called prefetch mode + */ +static void ht_set_prefetch(ide_drive_t *drive, byte state) +{ + unsigned long flags; + int t = HT_PREFETCH_MODE << 8; + + save_flags (flags); /* all CPUs */ + cli(); /* all CPUs */ + + /* + * Prefetch mode and unmask irq seems to conflict + */ + if (state) { + drive->drive_data |= t; /* enable prefetch mode */ + drive->no_unmask = 1; + drive->unmask = 0; + } else { + drive->drive_data &= ~t; /* disable prefetch mode */ + drive->no_unmask = 0; + } + + restore_flags (flags); /* all CPUs */ + +#ifdef DEBUG + printk("ht6560b: drive %s prefetch mode %sabled\n", drive->name, (state ? "en" : "dis")); +#endif +} - if (pio == 255) { /* auto-tune */ - if (drive->media != ide_disk) - pio = 0; /* some CDROMs don't like fast modes (?) */ - else - pio = ide_get_best_pio_mode(drive, pio, 5, NULL); +static void tune_ht6560b (ide_drive_t *drive, byte pio) +{ + unsigned long flags; + byte timing; + + switch (pio) { + case 8: /* set prefetch off */ + case 9: /* set prefetch on */ + ht_set_prefetch(drive, pio & 1); + return; } - unit = drive->select.b.unit; - hwif = HWIF(drive)->index; - ht6560b_timings[hwif][unit] = pio_to_timings[pio]; - if (pio == 0) - ht6560b_selects[hwif][unit] |= 0x20; - else - ht6560b_selects[hwif][unit] &= ~0x20; + + timing = ht_pio2timings(drive, pio); + + save_flags (flags); /* all CPUs */ + cli(); /* all CPUs */ + + drive->drive_data &= 0xff00; + drive->drive_data |= timing; + + restore_flags (flags); /* all CPUs */ + +#ifdef DEBUG + printk("ht6560b: drive %s tuned to pio mode %#x timing=%#x\n", drive->name, pio, timing); +#endif } -void init_ht6560b (void) +void __init init_ht6560b (void) { - if (check_region(HT_SELECT_PORT,1)) { - printk("\nht6560b: PORT 0x3e6 ALREADY IN USE\n"); + int t; + + if (check_region(HT_CONFIG_PORT,1)) { + printk(KERN_ERR "ht6560b: PORT %#x ALREADY IN USE\n", HT_CONFIG_PORT); } else { if (try_to_init_ht6560b()) { - request_region(HT_SELECT_PORT, 1, ide_hwifs[0].name); + request_region(HT_CONFIG_PORT, 1, ide_hwifs[0].name); ide_hwifs[0].chipset = ide_ht6560b; ide_hwifs[1].chipset = ide_ht6560b; ide_hwifs[0].selectproc = &ht6560b_selectproc; ide_hwifs[1].selectproc = &ht6560b_selectproc; ide_hwifs[0].tuneproc = &tune_ht6560b; ide_hwifs[1].tuneproc = &tune_ht6560b; - ide_hwifs[0].serialized = 1; - ide_hwifs[1].serialized = 1; + ide_hwifs[0].serialized = 1; /* is this needed? */ + ide_hwifs[1].serialized = 1; /* is this needed? */ ide_hwifs[0].mate = &ide_hwifs[1]; ide_hwifs[1].mate = &ide_hwifs[0]; ide_hwifs[1].channel = 1; + + /* + * Setting default configurations for drives + */ + t = (HT_CONFIG_DEFAULT << 8); + t |= HT_TIMING_DEFAULT; + ide_hwifs[0].drives[0].drive_data = t; + ide_hwifs[0].drives[1].drive_data = t; + t |= (HT_SECONDARY_IF << 8); + ide_hwifs[1].drives[0].drive_data = t; + ide_hwifs[1].drives[1].drive_data = t; } else - printk("\nht6560b: not found\n"); + printk(KERN_ERR "ht6560b: not found\n"); } } diff --git a/drivers/block/ide-cd.h b/drivers/block/ide-cd.h index 8891205ed..1eb48ef6c 100644 --- a/drivers/block/ide-cd.h +++ b/drivers/block/ide-cd.h @@ -1,11 +1,11 @@ -#ifndef _IDE_CD_H -#define _IDE_CD_H /* * linux/drivers/block/ide_cd.h * - * Copyright (C) 1996, 1997, 1998 Erik Andersen - * Copyright (C) 1998, 1999 Jens Axboe + * Copyright (C) 1996-98 Erik Andersen + * Copyright (C) 1998-2000 Jens Axboe */ +#ifndef _IDE_CD_H +#define _IDE_CD_H #include #include diff --git a/drivers/block/ide-disk.c b/drivers/block/ide-disk.c index e62295241..f766605bc 100644 --- a/drivers/block/ide-disk.c +++ b/drivers/block/ide-disk.c @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide-disk.c Version 1.09 April 23, 1999 + * linux/drivers/block/ide-disk.c Version 1.09 April 23, 1999 * * Copyright (C) 1994-1998 Linus Torvalds & authors (see below) */ diff --git a/drivers/block/ide-dma.c b/drivers/block/ide-dma.c index 3b6f5e56a..751424831 100644 --- a/drivers/block/ide-dma.c +++ b/drivers/block/ide-dma.c @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide-dma.c Version 4.09 April 23, 1999 + * linux/drivers/block/ide-dma.c Version 4.09 April 23, 1999 * * Copyright (c) 1999 Andre Hedrick * May be copied or modified under the terms of the GNU General Public License @@ -91,6 +91,8 @@ #include #include +extern char *ide_dmafunc_verbose(ide_dma_action_t dmafunc); + #ifdef CONFIG_IDEDMA_NEW_DRIVE_LISTINGS struct drive_list_entry { @@ -401,6 +403,7 @@ int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); unsigned long dma_base = hwif->dma_base; + byte unit = (drive->select.b.unit & 0x01); unsigned int count, reading = 0; byte dma_stat; @@ -408,8 +411,11 @@ int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive) case ide_dma_off: printk("%s: DMA disabled\n", drive->name); case ide_dma_off_quietly: + outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2); case ide_dma_on: drive->using_dma = (func == ide_dma_on); + if (drive->using_dma) + outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2); return 0; case ide_dma_check: return config_drive_for_dma (drive); @@ -424,7 +430,7 @@ int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive) drive->waiting_for_dma = 1; if (drive->media != ide_disk) return 0; - ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);/* issue cmd to drive */ + ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL); /* issue cmd to drive */ OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG); case ide_dma_begin: /* Note that this is done *after* the cmd has @@ -449,12 +455,10 @@ int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive) return check_drive_lists(drive, (func == ide_dma_good_drive)); case ide_dma_lostirq: case ide_dma_timeout: - /* - * printk("ide_dmaproc: chipset supported func only: %d\n", func); - */ + printk("ide_dmaproc: chipset supported %s func only: %d\n", ide_dmafunc_verbose(func), func); return 1; default: - printk("ide_dmaproc: unsupported func: %d\n", func); + printk("ide_dmaproc: unsupported %s func: %d\n", ide_dmafunc_verbose(func), func); return 1; } } @@ -541,14 +545,15 @@ unsigned long __init ide_get_or_set_dma_base (ide_hwif_t *hwif, int extra, const } } if (dma_base) { - if (extra) /* PDC20246, PDC20262, & HPT343 */ + if (extra) /* PDC20246, PDC20262, HPT343, & HPT366 */ request_region(dma_base+16, extra, name); dma_base += hwif->channel ? 8 : 0; hwif->dma_extra = extra; switch(dev->device) { - case PCI_DEVICE_ID_CMD_643: case PCI_DEVICE_ID_AL_M5219: + case PCI_DEVICE_ID_AMD_VIPER_7409: + case PCI_DEVICE_ID_CMD_643: outb(inb(dma_base+2) & 0x60, dma_base+2); if (inb(dma_base+2) & 0x80) { printk("%s: simplex device: DMA forced\n", name); diff --git a/drivers/block/ide-features.c b/drivers/block/ide-features.c index 87b7cacb4..3f29ed591 100644 --- a/drivers/block/ide-features.c +++ b/drivers/block/ide-features.c @@ -1,16 +1,15 @@ /* - * linux/drivers/block/ide-features.c + * linux/drivers/block/ide-features.c Version 0.03 Feb. 10, 2000 * - * Copyright (C) 1999 Linus Torvalds & authors (see below) + * Copyright (C) 1999-2000 Linus Torvalds & authors (see below) * - * Andre Hedrick + * Copyright (C) 1999-2000 Andre Hedrick * * Extracts if ide.c to address the evolving transfer rate code for - * the SETFEATURES_XFER callouts. Below are original authors of some or - * various parts of any given function below. + * the SETFEATURES_XFER callouts. Various parts of any given function + * are credited to previous ATA-IDE maintainers. * - * Mark Lord - * Gadi Oxman + * May be copied or modified under the terms of the GNU General Public License */ #define __NO_VERSION__ @@ -36,12 +35,15 @@ #include #include +#define SETFEATURES_CONTROL_REG (0) /* some arch's may need */ + /* - * + * A Verbose noise maker for debugging on the attempted transfer rates. */ char *ide_xfer_verbose (byte xfer_rate) { switch(xfer_rate) { + case XFER_UDMA_7: return("UDMA 7"); case XFER_UDMA_6: return("UDMA 6"); case XFER_UDMA_5: return("UDMA 5"); case XFER_UDMA_4: return("UDMA 4"); @@ -71,14 +73,42 @@ char *ide_xfer_verbose (byte xfer_rate) char *ide_media_verbose (ide_drive_t *drive) { switch (drive->media) { - case ide_disk: return("disk "); - case ide_cdrom: return("cdrom "); - case ide_tape: return("tape "); - case ide_floppy: return("floppy"); - default: return("??????"); + case ide_scsi: return("scsi "); + case ide_disk: return("disk "); + case ide_optical: return("optical"); + case ide_cdrom: return("cdrom "); + case ide_tape: return("tape "); + case ide_floppy: return("floppy "); + default: return("???????"); } } +/* + * A Verbose noise maker for debugging on the attempted dmaing calls. + */ +char *ide_dmafunc_verbose (ide_dma_action_t dmafunc) +{ + switch (dmafunc) { + case ide_dma_read: return("ide_dma_read"); + case ide_dma_write: return("ide_dma_write"); + case ide_dma_begin: return("ide_dma_begin"); + case ide_dma_end: return("ide_dma_end:"); + case ide_dma_check: return("ide_dma_check"); + case ide_dma_on: return("ide_dma_on"); + case ide_dma_off: return("ide_dma_off"); + case ide_dma_off_quietly: return("ide_dma_off_quietly"); + case ide_dma_test_irq: return("ide_dma_test_irq"); + case ide_dma_bad_drive: return("ide_dma_bad_drive"); + case ide_dma_good_drive: return("ide_dma_good_drive"); + case ide_dma_lostirq: return("ide_dma_lostirq"); + case ide_dma_timeout: return("ide_dma_timeout"); + default: return("unknown"); + } +} + +/* + * Update the + */ int ide_driveid_update (ide_drive_t *drive) { /* @@ -128,50 +158,6 @@ int ide_driveid_update (ide_drive_t *drive) return 1; } -/* - * Similar to ide_wait_stat(), except it never calls ide_error internally. - * This is a kludge to handle the new ide_config_drive_speed() function, - * and should not otherwise be used anywhere. Eventually, the tuneproc's - * should be updated to return ide_startstop_t, in which case we can get - * rid of this abomination again. :) -ml - */ -int ide_wait_noerr (ide_drive_t *drive, byte good, byte bad, unsigned long timeout) -{ - byte stat; - int i; - unsigned long flags; - - udelay(1); /* spec allows drive 400ns to assert "BUSY" */ - if ((stat = GET_STAT()) & BUSY_STAT) { - __save_flags(flags); /* local CPU only */ - ide__sti(); /* local CPU only */ - timeout += jiffies; - while ((stat = GET_STAT()) & BUSY_STAT) { - if (0 < (signed long)(jiffies - timeout)) { - __restore_flags(flags); /* local CPU only */ - (void)ide_dump_status(drive, "ide_wait_noerr", stat); - return 1; - } - } - __restore_flags(flags); /* local CPU only */ - } - /* - * Allow status to settle, then read it again. - * A few rare drives vastly violate the 400ns spec here, - * so we'll wait up to 10usec for a "good" status - * rather than expensively fail things immediately. - * This fix courtesy of Matthew Faupel & Niccolo Rigacci. - */ - for (i = 0; i < 10; i++) { - udelay(1); - if (OK_STAT((stat = GET_STAT()), good, bad)) - return 0; - } - (void)ide_dump_status(drive, "ide_wait_noerr", stat); - return 1; -} - - /* * Verify that we are doing an approved SETFEATURES_XFER with respect * to the hardware being able to support request. Since some hardware @@ -213,70 +199,96 @@ int set_transfer (ide_drive_t *drive, int cmd, int nsect, int feature) return 0; } -#if 0 -ide_startstop_t set_drive_speed_intr (ide_drive_t *drive) -{ - byte stat; - - if (!OK_STAT(stat=GET_STAT(),READY_STAT,BAD_STAT)) /* - * if (!OK_STAT(stat=GET_STAT(),DRIVE_READY,BAD_STAT)) - * if (stat != DRIVE_READY) + * Similar to ide_wait_stat(), except it never calls ide_error internally. + * This is a kludge to handle the new ide_config_drive_speed() function, + * and should not otherwise be used anywhere. Eventually, the tuneproc's + * should be updated to return ide_startstop_t, in which case we can get + * rid of this abomination again. :) -ml + * + * It is gone.......... + * + * const char *msg == consider adding for verbose errors. */ - (void) ide_dump_status(drive, "set_drive_speed_status", stat); - - return ide_stopped; -} -#endif - int ide_config_drive_speed (ide_drive_t *drive, byte speed) { - unsigned long flags; - int err; + ide_hwif_t *hwif = HWIF(drive); + int i, error = 1; + byte unit = (drive->select.b.unit & 0x01); byte stat; - __save_flags(flags); /* local CPU only */ - __cli(); /* local CPU only */ - /* * Don't use ide_wait_cmd here - it will * attempt to set_geometry and recalibrate, * but for some reason these don't work at * this point (lost interrupt). */ + /* + * Select the drive, and issue the SETFEATURES command + */ + disable_irq(hwif->irq); /* disable_irq_nosync ?? */ + udelay(1); SELECT_DRIVE(HWIF(drive), drive); + udelay(1); if (IDE_CONTROL_REG) OUT_BYTE(drive->ctl | 2, IDE_CONTROL_REG); OUT_BYTE(speed, IDE_NSECTOR_REG); OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG); OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG); - - err = ide_wait_noerr(drive, DRIVE_READY, BUSY_STAT|DRQ_STAT|ERR_STAT, WAIT_CMD); - -#if 0 - if (IDE_CONTROL_REG) + if ((IDE_CONTROL_REG) && (SETFEATURES_CONTROL_REG)) OUT_BYTE(drive->ctl, IDE_CONTROL_REG); -#endif + udelay(1); + /* + * Wait for drive to become non-BUSY + */ + if ((stat = GET_STAT()) & BUSY_STAT) { + unsigned long flags, timeout; + __save_flags(flags); /* local CPU only */ + ide__sti(); /* local CPU only -- for jiffies */ + timeout = jiffies + WAIT_CMD; + while ((stat = GET_STAT()) & BUSY_STAT) { + if (0 < (signed long)(jiffies - timeout)) + break; + } + __restore_flags(flags); /* local CPU only */ + } - __restore_flags(flags); /* local CPU only */ + /* + * Allow status to settle, then read it again. + * A few rare drives vastly violate the 400ns spec here, + * so we'll wait up to 10usec for a "good" status + * rather than expensively fail things immediately. + * This fix courtesy of Matthew Faupel & Niccolo Rigacci. + */ + for (i = 0; i < 10; i++) { + udelay(1); + if (OK_STAT((stat = GET_STAT()), DRIVE_READY, BUSY_STAT|DRQ_STAT|ERR_STAT)) { + error = 0; + break; + } + } -#if 0 - ide_set_handler(drive, &set_drive_speed_intr, WAIT_CMD, NULL); -#endif + enable_irq(hwif->irq); - stat = GET_STAT(); - if (stat != DRIVE_READY) + if (error) { (void) ide_dump_status(drive, "set_drive_speed_status", stat); + return error; + } drive->id->dma_ultra &= ~0xFF00; drive->id->dma_mword &= ~0x0F00; drive->id->dma_1word &= ~0x0F00; + if (speed > XFER_PIO_4) { + outb(inb(hwif->dma_base+2)|(1<<(5+unit)), hwif->dma_base+2); + } else { + outb(inb(hwif->dma_base+2) & ~(1<<(5+unit)), hwif->dma_base+2); + } + switch(speed) { -#if 0 - case XFER_UDMA_6: drive->id->dma_ultra |= 0x1010; break; - case XFER_UDMA_5: drive->id->dma_ultra |= 0x1010; break; -#endif + case XFER_UDMA_7: drive->id->dma_ultra |= 0x8080; break; + case XFER_UDMA_6: drive->id->dma_ultra |= 0x4040; break; + case XFER_UDMA_5: drive->id->dma_ultra |= 0x2020; break; case XFER_UDMA_4: drive->id->dma_ultra |= 0x1010; break; case XFER_UDMA_3: drive->id->dma_ultra |= 0x0808; break; case XFER_UDMA_2: drive->id->dma_ultra |= 0x0404; break; @@ -290,11 +302,10 @@ int ide_config_drive_speed (ide_drive_t *drive, byte speed) case XFER_SW_DMA_0: drive->id->dma_1word |= 0x0101; break; default: break; } - return(err); + return error; } EXPORT_SYMBOL(ide_driveid_update); -EXPORT_SYMBOL(ide_wait_noerr); EXPORT_SYMBOL(ide_ata66_check); EXPORT_SYMBOL(set_transfer); EXPORT_SYMBOL(ide_config_drive_speed); diff --git a/drivers/block/ide-floppy.c b/drivers/block/ide-floppy.c index e2977c754..bee6a4c6c 100644 --- a/drivers/block/ide-floppy.c +++ b/drivers/block/ide-floppy.c @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide-floppy.c Version 0.9 Jul 4, 1999 + * linux/drivers/block/ide-floppy.c Version 0.9 Jul 4, 1999 * * Copyright (C) 1996 - 1999 Gadi Oxman */ @@ -1264,8 +1264,11 @@ static int idefloppy_get_capacity (ide_drive_t *drive) blocks = descriptor->blocks = ntohl (descriptor->blocks); length = descriptor->length = ntohs (descriptor->length); if (!i && descriptor->dc == CAPACITY_CURRENT) { - if (memcmp (descriptor, &floppy->capacity, sizeof (idefloppy_capacity_descriptor_t))) - printk (KERN_INFO "%s: %dkB, %d blocks, %d sector size\n", drive->name, blocks * length / 1024, blocks, length); + if (memcmp (descriptor, &floppy->capacity, sizeof (idefloppy_capacity_descriptor_t))) { + printk (KERN_INFO "%s: %dkB, %d blocks, %d sector size, %s \n", + drive->name, blocks * length / 1024, blocks, length, + drive->using_dma ? ", DMA":""); + } floppy->capacity = *descriptor; if (!length || length % 512) printk (KERN_ERR "%s: %d bytes block size not supported\n", drive->name, length); diff --git a/drivers/block/ide-pci.c b/drivers/block/ide-pci.c index a5593dffb..2ddbbc8bd 100644 --- a/drivers/block/ide-pci.c +++ b/drivers/block/ide-pci.c @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide-pci.c Version 1.04 July 27, 1999 + * linux/drivers/block/ide-pci.c Version 1.04 July 27, 1999 * * Copyright (c) 1998-1999 Andre Hedrick * @@ -31,6 +31,7 @@ #define DEVID_PIIX4 ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB}) #define DEVID_PIIX4E ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_1}) #define DEVID_PIIX4U ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_1}) +#define DEVID_PIIX4U2 ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82372FB_1}) #define DEVID_VIA_IDE ((ide_pci_devid_t){PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C561}) #define DEVID_VP_IDE ((ide_pci_devid_t){PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1}) #define DEVID_PDC20246 ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20246}) @@ -95,13 +96,19 @@ extern void ide_dmacapable_ali15x3(ide_hwif_t *, unsigned long); #endif #ifdef CONFIG_BLK_DEV_AMD7409 +extern unsigned int pci_init_amd7409(struct pci_dev *, const char *); extern unsigned int ata66_amd7409(ide_hwif_t *); extern void ide_init_amd7409(ide_hwif_t *); +extern void ide_dmacapable_amd7409(ide_hwif_t *, unsigned long); +#define PCI_AMD7409 &pci_init_amd7409 #define ATA66_AMD7409 &ata66_amd7409 #define INIT_AMD7409 &ide_init_amd7409 +#define DMA_AMD7409 &ide_dmacapable_amd7409 #else +#define PCI_AMD7409 NULL #define ATA66_AMD7409 NULL #define INIT_AMD7409 NULL +#define DMA_AMD7409 NULL #endif #ifdef CONFIG_BLK_DEV_CMD64X @@ -135,11 +142,11 @@ extern void ide_init_cy82c693(ide_hwif_t *); #ifdef CONFIG_BLK_DEV_CS5530 extern unsigned int pci_init_cs5530(struct pci_dev *, const char *); extern void ide_init_cs5530(ide_hwif_t *); -#define INIT_CS5530 &ide_init_cs5530 #define PCI_CS5530 &pci_init_cs5530 +#define INIT_CS5530 &ide_init_cs5530 #else -#define INIT_CS5530 NULL #define PCI_CS5530 NULL +#define INIT_CS5530 NULL #endif #ifdef CONFIG_BLK_DEV_HPT34X @@ -149,7 +156,7 @@ extern void ide_init_hpt34x(ide_hwif_t *); #define INIT_HPT34X &ide_init_hpt34x #else #define PCI_HPT34X NULL -#define INIT_HPT34X NULL +#define INIT_HPT34X IDE_IGNORE #endif #ifdef CONFIG_BLK_DEV_HPT366 @@ -289,6 +296,7 @@ static ide_pci_device_t ide_pci_chipsets[] __initdata = { {DEVID_PIIX4, "PIIX4", PCI_PIIX, NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, {DEVID_PIIX4E, "PIIX4", PCI_PIIX, NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, {DEVID_PIIX4U, "PIIX4", PCI_PIIX, ATA66_PIIX, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, + {DEVID_PIIX4U2, "PIIX4", PCI_PIIX, ATA66_PIIX, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, {DEVID_VIA_IDE, "VIA_IDE", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, {DEVID_VP_IDE, "VP_IDE", PCI_VIA82CXXX, ATA66_VIA82CXXX,INIT_VIA82CXXX, DMA_VIA82CXXX, {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, ON_BOARD, 0 }, {DEVID_PDC20246,"PDC20246", PCI_PDC202XX, NULL, INIT_PDC202XX, NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, OFF_BOARD, 16 }, @@ -318,7 +326,7 @@ static ide_pci_device_t ide_pci_chipsets[] __initdata = { {DEVID_CY82C693,"CY82C693", PCI_CY82C693, NULL, INIT_CY82C693, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, {DEVID_HINT, "HINT_IDE", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, {DEVID_CS5530, "CS5530", PCI_CS5530, NULL, INIT_CS5530, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_AMD7409, "AMD7409", NULL, ATA66_AMD7409, INIT_AMD7409, NULL, {{0x40,0x01,0x01}, {0x40,0x02,0x02}}, ON_BOARD, 0 }, + {DEVID_AMD7409, "AMD7409", PCI_AMD7409, ATA66_AMD7409, INIT_AMD7409, DMA_AMD7409, {{0x40,0x01,0x01}, {0x40,0x02,0x02}}, ON_BOARD, 0 }, {IDE_PCI_DEVID_NULL, "PCI_IDE", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }}; /* @@ -329,27 +337,6 @@ static ide_pci_device_t ide_pci_chipsets[] __initdata = { static unsigned int __init ide_special_settings (struct pci_dev *dev, const char *name) { switch(dev->device) { - case PCI_DEVICE_ID_TTI_HPT343: - { - int i; - unsigned long hpt34xIoBase = dev->resource[4].start; - unsigned short pcicmd = 0; - - pci_write_config_byte(dev, 0x80, 0x00); - pci_read_config_word(dev, PCI_COMMAND, &pcicmd); - if (!(pcicmd & PCI_COMMAND_MEMORY)) { - pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20); - } else { - pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xF0); - } - - dev->resource[0].start = (hpt34xIoBase + 0x20); - dev->resource[1].start = (hpt34xIoBase + 0x34); - dev->resource[2].start = (hpt34xIoBase + 0x28); - dev->resource[3].start = (hpt34xIoBase + 0x3c); - for(i=0; i<4; i++) - dev->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO; - } case PCI_DEVICE_ID_TTI_HPT366: case PCI_DEVICE_ID_PROMISE_20246: case PCI_DEVICE_ID_PROMISE_20262: @@ -535,17 +522,8 @@ check_if_enabled: #endif } if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT34X)) { - /* - * Since there are two cards that report almost identically, - * the only discernable difference is the values - * reported in pcicmd. - * Booting-BIOS card or HPT363 :: pcicmd == 0x07 - * Non-bootable card or HPT343 :: pcicmd == 0x05 - */ - if (pcicmd & PCI_COMMAND_MEMORY) { - printk("%s: is IDE Express HPT363.\n", d->name); - d->bootable = OFF_BOARD; - } + /* see comments in hpt34x.c on why..... */ + d->bootable = (pcicmd & PCI_COMMAND_MEMORY) ? OFF_BOARD : NEVER_BOARD; } /* * Set up the IDE ports @@ -618,9 +596,7 @@ check_if_enabled: if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20246) || IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20262) || IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6210) || -#ifdef CONFIG_BLK_DEV_HPT34X IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT34X) || -#endif /* CONFIG_BLK_DEV_HPT34X */ IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366) || IDE_PCI_DEVID_EQ(d->devid, DEVID_CS5530) || IDE_PCI_DEVID_EQ(d->devid, DEVID_CY82C693) || diff --git a/drivers/block/ide-probe.c b/drivers/block/ide-probe.c index b57fa28da..24eef80b7 100644 --- a/drivers/block/ide-probe.c +++ b/drivers/block/ide-probe.c @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide-probe.c Version 1.05 July 3, 1999 + * linux/drivers/block/ide-probe.c Version 1.05 July 3, 1999 * * Copyright (C) 1994-1998 Linus Torvalds & authors (see below) */ @@ -57,7 +57,7 @@ static inline void do_identify (ide_drive_t *drive, byte cmd) ide__sti(); /* local CPU only */ ide_fix_driveid(id); if (!drive->forced_lun) - drive->last_lun = id->word126 & 0x7; + drive->last_lun = id->last_lun & 0x7; #if defined (CONFIG_SCSI_EATA_DMA) || defined (CONFIG_SCSI_EATA_PIO) || defined (CONFIG_SCSI_EATA) /* * EATA SCSI controllers do a hardware ATA emulation: @@ -394,6 +394,56 @@ static inline byte probe_for_drive (ide_drive_t *drive) return 1; /* drive was found */ } +/* + * Calculate the region that this interface occupies, + * handling interfaces where the registers may not be + * ordered sanely. We deal with the CONTROL register + * separately. + */ +static int hwif_check_regions (ide_hwif_t *hwif) +{ + int region_errors = 0; + + region_errors = ide_check_region(hwif->io_ports[IDE_DATA_OFFSET], 1); + region_errors += ide_check_region(hwif->io_ports[IDE_ERROR_OFFSET], 1); + region_errors += ide_check_region(hwif->io_ports[IDE_NSECTOR_OFFSET], 1); + region_errors += ide_check_region(hwif->io_ports[IDE_SECTOR_OFFSET], 1); + region_errors += ide_check_region(hwif->io_ports[IDE_LCYL_OFFSET], 1); + region_errors += ide_check_region(hwif->io_ports[IDE_HCYL_OFFSET], 1); + region_errors += ide_check_region(hwif->io_ports[IDE_SELECT_OFFSET], 1); + region_errors += ide_check_region(hwif->io_ports[IDE_STATUS_OFFSET], 1); + if (hwif->io_ports[IDE_CONTROL_OFFSET]) + region_errors += ide_check_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1); + if (hwif->io_ports[IDE_IRQ_OFFSET]) + region_errors += ide_check_region(hwif->io_ports[IDE_IRQ_OFFSET], 1); + + return(region_errors); +} + +static void hwif_register (ide_hwif_t *hwif) +{ + if (hwif->io_ports[IDE_DATA_OFFSET]) + ide_request_region(hwif->io_ports[IDE_DATA_OFFSET], 1, hwif->name); + if (hwif->io_ports[IDE_ERROR_OFFSET]) + ide_request_region(hwif->io_ports[IDE_ERROR_OFFSET], 1, hwif->name); + if (hwif->io_ports[IDE_NSECTOR_OFFSET]) + ide_request_region(hwif->io_ports[IDE_NSECTOR_OFFSET], 1, hwif->name); + if (hwif->io_ports[IDE_SECTOR_OFFSET]) + ide_request_region(hwif->io_ports[IDE_SECTOR_OFFSET], 1, hwif->name); + if (hwif->io_ports[IDE_LCYL_OFFSET]) + ide_request_region(hwif->io_ports[IDE_LCYL_OFFSET], 1, hwif->name); + if (hwif->io_ports[IDE_HCYL_OFFSET]) + ide_request_region(hwif->io_ports[IDE_HCYL_OFFSET], 1, hwif->name); + if (hwif->io_ports[IDE_SELECT_OFFSET]) + ide_request_region(hwif->io_ports[IDE_SELECT_OFFSET], 1, hwif->name); + if (hwif->io_ports[IDE_STATUS_OFFSET]) + ide_request_region(hwif->io_ports[IDE_STATUS_OFFSET], 1, hwif->name); + if (hwif->io_ports[IDE_CONTROL_OFFSET]) + ide_request_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1, hwif->name); + if (hwif->io_ports[IDE_IRQ_OFFSET]) + ide_request_region(hwif->io_ports[IDE_IRQ_OFFSET], 1, hwif->name); +} + /* * This routine only knows how to look for drive units 0 and 1 * on an interface, so any setting of MAX_DRIVES > 2 won't work here. @@ -403,12 +453,6 @@ static void probe_hwif (ide_hwif_t *hwif) unsigned int unit; unsigned long flags; - ide_ioreg_t ide_control_reg = hwif->io_ports[IDE_CONTROL_OFFSET]; - ide_ioreg_t region_low = hwif->io_ports[IDE_DATA_OFFSET]; - ide_ioreg_t region_high = region_low; - unsigned int region_request = 8; - int i; - if (hwif->noprobe) return; if (hwif->io_ports[IDE_DATA_OFFSET] == HD_DATA) { @@ -417,30 +461,11 @@ static void probe_hwif (ide_hwif_t *hwif) probe_cmos_for_drives (hwif); } - /* - * Calculate the region that this interface occupies, - * handling interfaces where the registers may not be - * ordered sanely. We deal with the CONTROL register - * separately. - */ - for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) { - if (hwif->io_ports[i]) { - if (hwif->io_ports[i] < region_low) - region_low = hwif->io_ports[i]; - if (hwif->io_ports[i] > region_high) - region_high = hwif->io_ports[i]; - } - } - region_request = (region_high - region_low); - if (region_request == 0x0007) - region_request++; if ((hwif->chipset != ide_4drives || !hwif->mate->present) && #if CONFIG_BLK_DEV_PDC4030 (hwif->chipset != ide_pdc4030 || hwif->channel == 0) && #endif /* CONFIG_BLK_DEV_PDC4030 */ - (ide_check_region(region_low, region_request) || - (ide_control_reg && ide_check_region(ide_control_reg,1)))) - { + (hwif_check_regions(hwif))) { int msgout = 0; for (unit = 0; unit < MAX_DRIVES; ++unit) { ide_drive_t *drive = &hwif->drives[unit]; @@ -467,20 +492,18 @@ static void probe_hwif (ide_hwif_t *hwif) if (drive->present && !hwif->present) { hwif->present = 1; if (hwif->chipset != ide_4drives || !hwif->mate->present) { - ide_request_region(region_low, region_request, hwif->name); - if (ide_control_reg) - ide_request_region(ide_control_reg, 1, hwif->name); + hwif_register(hwif); } } } - if (ide_control_reg && hwif->reset) { + if (hwif->io_ports[IDE_CONTROL_OFFSET] && hwif->reset) { unsigned long timeout = jiffies + WAIT_WORSTCASE; byte stat; printk("%s: reset\n", hwif->name); - OUT_BYTE(12, ide_control_reg); + OUT_BYTE(12, hwif->io_ports[IDE_CONTROL_OFFSET]); udelay(10); - OUT_BYTE(8, ide_control_reg); + OUT_BYTE(8, hwif->io_ports[IDE_CONTROL_OFFSET]); do { ide_delay_50ms(); stat = IN_BYTE(hwif->io_ports[IDE_STATUS_OFFSET]); @@ -594,7 +617,11 @@ static int init_irq (ide_hwif_t *hwif) * Allocate the irq, if not already obtained for another hwif */ if (!match || match->irq != hwif->irq) { +#ifdef CONFIG_IDEPCI_SHARE_IRQ + int sa = (hwif->chipset == ide_pci) ? SA_SHIRQ : SA_INTERRUPT; +#else /* !CONFIG_IDEPCI_SHARE_IRQ */ int sa = (hwif->chipset == ide_pci) ? SA_INTERRUPT|SA_SHIRQ : SA_INTERRUPT; +#endif /* CONFIG_IDEPCI_SHARE_IRQ */ if (ide_request_irq(hwif->irq, &ide_intr, sa, hwif->name, hwgroup)) { if (!match) kfree(hwgroup); @@ -784,20 +811,18 @@ static int hwif_init (ide_hwif_t *hwif) return (hwif->present = 0); } - if (init_irq (hwif)) { + if (init_irq(hwif)) { int i = hwif->irq; /* * It failed to initialise. Find the default IRQ for * this port and try that. */ - if (!(hwif->irq = ide_default_irq(hwif->io_ports[IDE_DATA_OFFSET]))) - { + if (!(hwif->irq = ide_default_irq(hwif->io_ports[IDE_DATA_OFFSET]))) { printk("%s: Disabled unable to get IRQ %d.\n", hwif->name, i); (void) unregister_blkdev (hwif->major, hwif->name); return (hwif->present = 0); } - if(init_irq (hwif)) - { + if (init_irq(hwif)) { printk("%s: probed IRQ %d and default IRQ %d failed.\n", hwif->name, i, hwif->irq); (void) unregister_blkdev (hwif->major, hwif->name); @@ -863,7 +888,8 @@ int ideprobe_init (void) for (index = 0; index < MAX_HWIFS; ++index) if (probe[index]) hwif_init(&ide_hwifs[index]); - ide_register_module(&ideprobe_module); + if (!ide_probe) + ide_probe = &ideprobe_module; MOD_DEC_USE_COUNT; return 0; } @@ -882,6 +908,6 @@ int init_module (void) void cleanup_module (void) { - ide_unregister_module(&ideprobe_module); + ide_probe = NULL; } #endif /* MODULE */ diff --git a/drivers/block/ide-proc.c b/drivers/block/ide-proc.c index 66e45001c..90977c959 100644 --- a/drivers/block/ide-proc.c +++ b/drivers/block/ide-proc.c @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide-proc.c Version 1.03 January 2, 1998 + * linux/drivers/block/ide-proc.c Version 1.03 January 2, 1998 * * Copyright (C) 1997-1998 Mark Lord */ @@ -73,21 +73,46 @@ #define MIN(a,b) (((a) < (b)) ? (a) : (b)) #endif +#ifdef CONFIG_BLK_DEV_AEC6210 +extern byte aec6210_proc; +int (*aec6210_display_info)(char *, char **, off_t, int) = NULL; +#endif /* CONFIG_BLK_DEV_AEC6210 */ #ifdef CONFIG_BLK_DEV_ALI15X3 extern byte ali_proc; int (*ali_display_info)(char *, char **, off_t, int) = NULL; #endif /* CONFIG_BLK_DEV_ALI15X3 */ - +#ifdef CONFIG_BLK_DEV_AMD7409 +extern byte amd7409_proc; +int (*amd7409_display_info)(char *, char **, off_t, int) = NULL; +#endif /* CONFIG_BLK_DEV_AMD7409 */ +#ifdef CONFIG_BLK_DEV_CMD64X +extern byte cmd64x_proc; +int (*cmd64x_display_info)(char *, char **, off_t, int) = NULL; +#endif /* CONFIG_BLK_DEV_CMD64X */ +#ifdef CONFIG_BLK_DEV_CS5530 +extern byte cs5530_proc; +int (*cs5530_display_info)(char *, char **, off_t, int) = NULL; +#endif /* CONFIG_BLK_DEV_CS5530 */ +#ifdef CONFIG_BLK_DEV_HPT34X +extern byte hpt34x_proc; +int (*hpt34x_display_info)(char *, char **, off_t, int) = NULL; +#endif /* CONFIG_BLK_DEV_HPT34X */ +#ifdef CONFIG_BLK_DEV_HPT366 +extern byte hpt366_proc; +int (*hpt366_display_info)(char *, char **, off_t, int) = NULL; +#endif /* CONFIG_BLK_DEV_HPT366 */ +#ifdef CONFIG_BLK_DEV_PDC202XX +extern byte pdc202xx_proc; +int (*pdc202xx_display_info)(char *, char **, off_t, int) = NULL; +#endif /* CONFIG_BLK_DEV_PDC202XX */ #ifdef CONFIG_BLK_DEV_PIIX extern byte piix_proc; int (*piix_display_info)(char *, char **, off_t, int) = NULL; #endif /* CONFIG_BLK_DEV_PIIX */ - #ifdef CONFIG_BLK_DEV_SIS5513 extern byte sis_proc; int (*sis_display_info)(char *, char **, off_t, int) = NULL; #endif /* CONFIG_BLK_DEV_SIS5513 */ - #ifdef CONFIG_BLK_DEV_VIA82CXXX extern byte via_proc; int (*via_display_info)(char *, char **, off_t, int) = NULL; @@ -229,7 +254,7 @@ static int proc_ide_write_config #endif /* CONFIG_BLK_DEV_IDEPCI */ if (for_real) { #if 0 - printk("proc_ide_write_config: type=%c, reg=0x%x, val=0x%x, digits=%d\n", is_pci ? 'PCI' : 'non-PCI', reg, val, digits); + printk("proc_ide_write_config: type=%c, reg=0x%x, val=0x%x, digits=%d\n", is_pci ? "PCI" : "non-PCI", reg, val, digits); #endif if (is_pci) { #ifdef CONFIG_BLK_DEV_IDEPCI @@ -349,7 +374,7 @@ static int proc_ide_read_drivers while (p) { driver = (ide_driver_t *) p->info; - if (p->type == IDE_DRIVER_MODULE && driver) + if (driver) out += sprintf(out, "%s version %s\n", driver->name, driver->version); p = p->next; } @@ -775,10 +800,38 @@ void proc_ide_create(void) create_proc_read_entry("drivers",0,proc_ide_root, proc_ide_read_drivers, NULL); +#ifdef CONFIG_BLK_DEV_AEC6210 + if ((aec6210_display_info) && (aec6210_proc)) + create_proc_info_entry("aec6210", 0, proc_ide_root, aec6210_display_info); +#endif /* CONFIG_BLK_DEV_AEC6210 */ #ifdef CONFIG_BLK_DEV_ALI15X3 if ((ali_display_info) && (ali_proc)) create_proc_info_entry("ali", 0, proc_ide_root, ali_display_info); #endif /* CONFIG_BLK_DEV_ALI15X3 */ +#ifdef CONFIG_BLK_DEV_AMD7409 + if ((amd7409_display_info) && (amd7409_proc)) + create_proc_info_entry("amd7409", 0, proc_ide_root, amd7409_display_info); +#endif /* CONFIG_BLK_DEV_AMD7409 */ +#ifdef CONFIG_BLK_DEV_CMD64X + if ((cmd64x_display_info) && (cmd64x_proc)) + create_proc_info_entry("cmd64x", 0, proc_ide_root, cmd64x_display_info); +#endif /* CONFIG_BLK_DEV_CMD64X */ +#ifdef CONFIG_BLK_DEV_CS5530 + if ((cs5530_display_info) && (cs5530_proc)) + create_proc_info_entry("cs5530", 0, proc_ide_root, cs5530_display_info); +#endif /* CONFIG_BLK_DEV_CS5530 */ +#ifdef CONFIG_BLK_DEV_HPT34X + if ((hpt34x_display_info) && (hpt34x_proc)) + create_proc_info_entry("", 0, proc_ide_root, hpt34x_display_info); +#endif /* CONFIG_BLK_DEV_HPT34X */ +#ifdef CONFIG_BLK_DEV_HPT366 + if ((hpt366_display_info) && (hpt366_proc)) + create_proc_info_entry("", 0, proc_ide_root, hpt366_display_info); +#endif /* CONFIG_BLK_DEV_HPT366 */ +#ifdef CONFIG_BLK_DEV_PDC202XX + if ((pdc202xx_display_info) && (pdc202xx_proc)) + create_proc_info_entry("pdc202xx", 0, proc_ide_root, pdc202xx_display_info); +#endif /* CONFIG_BLK_DEV_PDC202XX */ #ifdef CONFIG_BLK_DEV_PIIX if ((piix_display_info) && (piix_proc)) create_proc_info_entry("piix", 0, proc_ide_root, piix_display_info); @@ -799,10 +852,38 @@ void proc_ide_destroy(void) * Mmmm.. does this free up all resources, * or do we need to do a more proper cleanup here ?? */ +#ifdef CONFIG_BLK_DEV_AEC6210 + if ((aec6210_display_info) && (aec6210_proc)) + remove_proc_entry("ide/aec6210",0); +#endif /* CONFIG_BLK_DEV_AEC6210 */ #ifdef CONFIG_BLK_DEV_ALI15X3 if ((ali_display_info) && (ali_proc)) remove_proc_entry("ide/ali",0); #endif /* CONFIG_BLK_DEV_ALI15X3 */ +#ifdef CONFIG_BLK_DEV_AMD7409 + if ((amd7409_display_info) && (amd7409_proc)) + remove_proc_entry("ide/amd7409",0); +#endif /* CONFIG_BLK_DEV_AMD7409 */ +#ifdef CONFIG_BLK_DEV_CMD64X + if ((cmd64x_display_info) && (cmd64x_proc)) + remove_proc_entry("ide/cmd64x",0); +#endif /* CONFIG_BLK_DEV_CMD64X */ +#ifdef CONFIG_BLK_DEV_CS5530 + if ((cs5530_display_info) && (cs5530_proc)) + remove_proc_entry("ide/cs5530",0); +#endif /* CONFIG_BLK_DEV_CS5530 */ +#ifdef CONFIG_BLK_DEV_HPT34X + if ((hpt34x_display_info) && (hpt34x_proc)) + remove_proc_entry("ide/hpt34x",0); +#endif /* CONFIG_BLK_DEV_HPT34X */ +#ifdef CONFIG_BLK_DEV_HPT366 + if ((hpt366_display_info) && (hpt366_proc)) + remove_proc_entry("ide/hpt366",0); +#endif /* CONFIG_BLK_DEV_HPT366 */ +#ifdef CONFIG_BLK_DEV_PDC202XX + if ((pdc202xx_display_info) && (pdc202xx_proc)) + remove_proc_entry("ide/pdc202xx",0); +#endif /* CONFIG_BLK_DEV_PDC202XX */ #ifdef CONFIG_BLK_DEV_PIIX if ((piix_display_info) && (piix_proc)) remove_proc_entry("ide/piix",0); diff --git a/drivers/block/ide-tape.c b/drivers/block/ide-tape.c index 1e1b6e44e..95e780abf 100644 --- a/drivers/block/ide-tape.c +++ b/drivers/block/ide-tape.c @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide-tape.c Version 1.16f Dec 15, 1999 + * linux/drivers/block/ide-tape.c Version 1.16f Dec 15, 1999 * * Copyright (C) 1995 - 1999 Gadi Oxman * @@ -411,12 +411,12 @@ #include -#define NO_LONGER_REQUIRE (1) +#define NO_LONGER_REQUIRED (1) /* * OnStream support */ -#define ONSTREAM_DEBUG (1) +#define ONSTREAM_DEBUG (0) #define OS_CONFIG_PARTITION (0xff) #define OS_DATA_PARTITION (0) #define OS_PARTITION_VERSION (1) @@ -543,6 +543,7 @@ typedef struct os_header_s { /* * The following are used to debug the driver: * + * Setting IDETAPE_DEBUG_INFO to 1 will report device capabilities. * Setting IDETAPE_DEBUG_LOG to 1 will log driver flow control. * Setting IDETAPE_DEBUG_BUGS to 1 will enable self-sanity checks in * some places. @@ -557,7 +558,9 @@ typedef struct os_header_s { * is verified to be stable enough. This will make it much more * esthetic. */ +#define IDETAPE_DEBUG_INFO 0 #define IDETAPE_DEBUG_LOG 1 +#define IDETAPE_DEBUG_LOG_VERBOSE 0 #define IDETAPE_DEBUG_BUGS 1 /* @@ -700,9 +703,10 @@ typedef struct idetape_packet_command_s { */ typedef struct { unsigned page_code :6; /* Page code - Should be 0x2a */ - unsigned reserved1_67 :2; - u8 page_length; /* Page Length - Should be 0x12 */ - u8 reserved2, reserved3; + __u8 reserved0_6 :1; + __u8 ps :1; /* parameters saveable */ + __u8 page_length; /* Page Length - Should be 0x12 */ + __u8 reserved2, reserved3; unsigned ro :1; /* Read Only Mode */ unsigned reserved4_1234 :4; unsigned sprev :1; /* Supports SPACE in the reverse direction */ @@ -716,7 +720,8 @@ typedef struct { unsigned locked :1; /* The volume is locked */ unsigned prevent :1; /* The device defaults in the prevent state after power up */ unsigned eject :1; /* The device can eject the volume */ - unsigned reserved6_45 :2; /* Reserved */ + __u8 disconnect :1; /* The device can break request > ctl */ + __u8 reserved6_5 :1; unsigned ecc :1; /* Supports error correction */ unsigned cmprs :1; /* Supports data compression */ unsigned reserved7_0 :1; @@ -726,12 +731,12 @@ typedef struct { unsigned blk32768 :1; /* slowb - the device restricts the byte count for PIO */ /* transfers for slow buffer memory ??? */ /* Also 32768 block size in some cases */ - u16 max_speed; /* Maximum speed supported in KBps */ - u8 reserved10, reserved11; - u16 ctl; /* Continuous Transfer Limit in blocks */ - u16 speed; /* Current Speed, in KBps */ - u16 buffer_size; /* Buffer Size, in 512 bytes */ - u8 reserved18, reserved19; + __u16 max_speed; /* Maximum speed supported in KBps */ + __u8 reserved10, reserved11; + __u16 ctl; /* Continuous Transfer Limit in blocks */ + __u16 speed; /* Current Speed, in KBps */ + __u16 buffer_size; /* Buffer Size, in 512 bytes */ + __u8 reserved18, reserved19; } idetape_capabilities_page_t; /* @@ -741,8 +746,8 @@ typedef struct { unsigned page_code :6; /* Page code - Should be 0x30 */ unsigned reserved1_6 :1; unsigned ps :1; - u8 page_length; /* Page Length - Should be 2 */ - u8 reserved2; + __u8 page_length; /* Page Length - Should be 2 */ + __u8 reserved2; unsigned play32 :1; unsigned play32_5 :1; unsigned reserved2_23 :2; @@ -768,23 +773,23 @@ typedef struct idetape_stage_s { typedef struct { unsigned error_code :7; /* Current of deferred errors */ unsigned valid :1; /* The information field conforms to QIC-157C */ - u8 reserved1 :8; /* Segment Number - Reserved */ + __u8 reserved1 :8; /* Segment Number - Reserved */ unsigned sense_key :4; /* Sense Key */ unsigned reserved2_4 :1; /* Reserved */ unsigned ili :1; /* Incorrect Length Indicator */ unsigned eom :1; /* End Of Medium */ unsigned filemark :1; /* Filemark */ - u32 information __attribute__ ((packed)); - u8 asl; /* Additional sense length (n-7) */ - u32 command_specific; /* Additional command specific information */ - u8 asc; /* Additional Sense Code */ - u8 ascq; /* Additional Sense Code Qualifier */ - u8 replaceable_unit_code; /* Field Replaceable Unit Code */ + __u32 information __attribute__ ((packed)); + __u8 asl; /* Additional sense length (n-7) */ + __u32 command_specific; /* Additional command specific information */ + __u8 asc; /* Additional Sense Code */ + __u8 ascq; /* Additional Sense Code Qualifier */ + __u8 replaceable_unit_code; /* Field Replaceable Unit Code */ unsigned sk_specific1 :7; /* Sense Key Specific */ unsigned sksv :1; /* Sense Key Specific information is valid */ - u8 sk_specific2; /* Sense Key Specific */ - u8 sk_specific3; /* Sense Key Specific */ - u8 pad[2]; /* Padding to 20 bytes */ + __u8 sk_specific2; /* Sense Key Specific */ + __u8 sk_specific3; /* Sense Key Specific */ + __u8 pad[2]; /* Padding to 20 bytes */ } idetape_request_sense_result_t; @@ -1247,13 +1252,13 @@ typedef struct { unsigned reserved3_45 :2; /* Reserved */ unsigned reserved3_6 :1; /* TrmIOP - Reserved */ unsigned reserved3_7 :1; /* AENC - Reserved */ - u8 additional_length; /* Additional Length (total_length-4) */ - u8 rsv5, rsv6, rsv7; /* Reserved */ - u8 vendor_id[8]; /* Vendor Identification */ - u8 product_id[16]; /* Product Identification */ - u8 revision_level[4]; /* Revision Level */ - u8 vendor_specific[20]; /* Vendor Specific - Optional */ - u8 reserved56t95[40]; /* Reserved - Optional */ + __u8 additional_length; /* Additional Length (total_length-4) */ + __u8 rsv5, rsv6, rsv7; /* Reserved */ + __u8 vendor_id[8]; /* Vendor Identification */ + __u8 product_id[16]; /* Product Identification */ + __u8 revision_level[4]; /* Revision Level */ + __u8 vendor_specific[20]; /* Vendor Specific - Optional */ + __u8 reserved56t95[40]; /* Reserved - Optional */ /* Additional information may be returned */ } idetape_inquiry_result_t; @@ -1287,10 +1292,25 @@ typedef struct { * Mode Parameter Header for the MODE SENSE packet command */ typedef struct { - u8 mode_data_length; /* Length of the following data transfer */ - u8 medium_type; /* Medium Type */ - u8 dsp; /* Device Specific Parameter */ - u8 bdl; /* Block Descriptor Length */ + __u8 mode_data_length; /* Length of the following data transfer */ + __u8 medium_type; /* Medium Type */ + __u8 dsp; /* Device Specific Parameter */ + __u8 bdl; /* Block Descriptor Length */ +#if 0 + /* data transfer page */ + __u8 page_code :6; + __u8 reserved0_6 :1; + __u8 ps :1; /* parameters saveable */ + __u8 page_length; /* page Length == 0x02 */ + __u8 reserved2; + __u8 read32k :1; /* 32k blk size (data only) */ + __u8 read32k5 :1; /* 32.5k blk size (data&AUX) */ + __u8 reserved3_23 :2; + __u8 write32k :1; /* 32k blk size (data only) */ + __u8 write32k5 :1; /* 32.5k blk size (data&AUX) */ + __u8 reserved3_6 :1; + __u8 streaming :1; /* streaming mode enable */ +#endif } idetape_mode_parameter_header_t; /* @@ -1299,10 +1319,10 @@ typedef struct { * Support for block descriptors is optional. */ typedef struct { - u8 density_code; /* Medium density code */ - u8 blocks[3]; /* Number of blocks */ - u8 reserved4; /* Reserved */ - u8 length[3]; /* Block Length */ + __u8 density_code; /* Medium density code */ + __u8 blocks[3]; /* Number of blocks */ + __u8 reserved4; /* Reserved */ + __u8 length[3]; /* Block Length */ } idetape_parameter_block_descriptor_t; /* @@ -1312,16 +1332,16 @@ typedef struct { unsigned page_code :6; /* Page Code - Should be 0xf */ unsigned reserved0 :1; /* Reserved */ unsigned ps :1; - u8 page_length; /* Page Length - Should be 14 */ + __u8 page_length; /* Page Length - Should be 14 */ unsigned reserved2 :6; /* Reserved */ unsigned dcc :1; /* Data Compression Capable */ unsigned dce :1; /* Data Compression Enable */ unsigned reserved3 :5; /* Reserved */ unsigned red :2; /* Report Exception on Decompression */ unsigned dde :1; /* Data Decompression Enable */ - u32 ca; /* Compression Algorithm */ - u32 da; /* Decompression Algorithm */ - u8 reserved[4]; /* Reserved */ + __u32 ca; /* Compression Algorithm */ + __u32 da; /* Decompression Algorithm */ + __u8 reserved[4]; /* Reserved */ } idetape_data_compression_page_t; /* @@ -1331,16 +1351,16 @@ typedef struct { unsigned page_code :6; /* Page Code - Should be 0x11 */ unsigned reserved1_6 :1; /* Reserved */ unsigned ps :1; - u8 page_length; /* Page Length - Should be 6 */ - u8 map; /* Maximum Additional Partitions - Should be 0 */ - u8 apd; /* Additional Partitions Defined - Should be 0 */ + __u8 page_length; /* Page Length - Should be 6 */ + __u8 map; /* Maximum Additional Partitions - Should be 0 */ + __u8 apd; /* Additional Partitions Defined - Should be 0 */ unsigned reserved4_012 :3; /* Reserved */ unsigned psum :2; /* Should be 0 */ unsigned idp :1; /* Should be 0 */ unsigned sdp :1; /* Should be 0 */ unsigned fdp :1; /* Fixed Data Partitions */ - u8 mfr; /* Medium Format Recognition */ - u8 reserved[2]; /* Reserved */ + __u8 mfr; /* Medium Format Recognition */ + __u8 reserved[2]; /* Reserved */ } idetape_medium_partition_page_t; /* @@ -1359,6 +1379,53 @@ typedef struct { static idetape_chrdev_t idetape_chrdevs[MAX_HWIFS * MAX_DRIVES]; static int idetape_chrdev_present = 0; +#if IDETAPE_DEBUG_LOG_VERBOSE + +/* + * DO NOT REMOVE, BUILDING A VERBOSE DEBUG SCHEME FOR ATAPI + */ + +char *idetape_sense_key_verbose (byte idetape_sense_key) +{ + switch (idetape_sense_key) { + default: { + char buf[22]; + sprintf(buf, "IDETAPE_SENSE (0x%02x)", idetape_sense_key); + return(buf); + } + + } +} + +char *idetape_command_key_verbose (byte idetape_command_key) +{ + switch (idetape_command_key) { + case IDETAPE_TEST_UNIT_READY_CMD: return("TEST_UNIT_READY_CMD"); + case IDETAPE_REWIND_CMD: return("REWIND_CMD"); + case IDETAPE_REQUEST_SENSE_CMD: return("REQUEST_SENSE_CMD"); + case IDETAPE_READ_CMD: return("READ_CMD"); + case IDETAPE_WRITE_CMD: return("WRITE_CMD"); + case IDETAPE_WRITE_FILEMARK_CMD: return("WRITE_FILEMARK_CMD"); + case IDETAPE_SPACE_CMD: return("SPACE_CMD"); + case IDETAPE_INQUIRY_CMD: return("INQUIRY_CMD"); + case IDETAPE_ERASE_CMD: return("ERASE_CMD") + case IDETAPE_MODE_SENSE_CMD: return("MODE_SENSE_CMD"); + case IDETAPE_MODE_SELECT_CMD: return("MODE_SELECT_CMD"); + case IDETAPE_LOAD_UNLOAD_CMD: return("LOAD_UNLOAD_CMD"); + case IDETAPE_PREVENT_CMD: return("PREVENT_CMD"); + case IDETAPE_LOCATE_CMD: return("LOCATE_CMD"); + case IDETAPE_READ_POSITION_CMD: return("READ_POSITION_CMD"); + case IDETAPE_READ_BUFFER_CMD: return("READ_BUFFER_CMD"); + case IDETAPE_SET_SPEED_CMD: return("SET_SPEED_CMD"); + default: { + char buf[20]; + sprintf(buf, "CMD (0x%02x)", idetape_command_key); + return(buf); + } + } +} +#endif /* IDETAPE_DEBUG_LOG_VERBOSE */ + /* * Too bad. The drive wants to send us data which we are not ready to accept. * Just throw it away. @@ -1523,6 +1590,14 @@ static void idetape_analyze_error (ide_drive_t *drive,idetape_request_sense_resu */ if (tape->debug_level >= 1) printk (KERN_INFO "ide-tape: pc = %x, sense key = %x, asc = %x, ascq = %x\n",pc->c[0],result->sense_key,result->asc,result->ascq); +#if IDETAPE_DEBUG_LOG_VERBOSE + if (tape->debug_level >= 1) + printk (KERN_INFO "ide-tape: pc = %s, sense key = %x, asc = %x, ascq = %x\n", + idetape_command_key_verbose((byte) pc->c[0]), + result->sense_key, + result->asc, + result->ascq); +#endif /* IDETAPE_DEBUG_LOG_VERBOSE */ #endif /* IDETAPE_DEBUG_LOG */ if (tape->onstream && result->sense_key == 2 && result->asc == 0x53 && result->ascq == 2) { @@ -3833,7 +3908,7 @@ static int idetape_get_logical_blk (ide_drive_t *drive, int logical_blk_num, int if (tape->onstream) { #if ONSTREAM_DEBUG if (tape->debug_level >= 1) - printk(KERN_INFO "ide-tape: %s: first_stage == NULL, pipeline error %d\n", tape->name, test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags)); + printk(KERN_INFO "ide-tape: %s: first_stage == NULL, pipeline error %ld\n", tape->name, (long)test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags)); #endif clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags); position = idetape_read_position(drive); @@ -5280,16 +5355,16 @@ static int idetape_chrdev_release (struct inode *inode, struct file *filp) static int idetape_identify_device (ide_drive_t *drive,struct hd_driveid *id) { struct idetape_id_gcw gcw; -#if IDETAPE_DEBUG_LOG +#if IDETAPE_DEBUG_INFO unsigned short mask,i; -#endif /* IDETAPE_DEBUG_LOG */ +#endif /* IDETAPE_DEBUG_INFO */ if (!id) return 0; *((unsigned short *) &gcw) = id->config; -#if IDETAPE_DEBUG_LOG +#if IDETAPE_DEBUG_INFO printk (KERN_INFO "ide-tape: Dumping ATAPI Identify Device tape parameters\n"); printk (KERN_INFO "ide-tape: Protocol Type: "); switch (gcw.protocol) { @@ -5377,7 +5452,7 @@ static int idetape_identify_device (ide_drive_t *drive,struct hd_driveid *id) } else printk (KERN_INFO "ide-tape: According to the device, fields 64-70 are not valid.\n"); -#endif /* IDETAPE_DEBUG_LOG */ +#endif /* IDETAPE_DEBUG_INFO */ /* Check that we can support this device */ @@ -5462,12 +5537,12 @@ static void idetape_onstream_configure_block_size (ide_drive_t *drive) header = (idetape_mode_parameter_header_t *) pc.buffer; bs = (idetape_block_size_page_t *) (pc.buffer + sizeof(idetape_mode_parameter_header_t) + header->bdl); -#if IDETAPE_DEBUG_LOG +#if IDETAPE_DEBUG_INFO printk(KERN_INFO "ide-tape: 32KB play back: %s\n", bs->play32 ? "Yes" : "No"); printk(KERN_INFO "ide-tape: 32.5KB play back: %s\n", bs->play32_5 ? "Yes" : "No"); printk(KERN_INFO "ide-tape: 32KB record: %s\n", bs->record32 ? "Yes" : "No"); printk(KERN_INFO "ide-tape: 32.5KB record: %s\n", bs->record32_5 ? "Yes" : "No"); -#endif +#endif /* IDETAPE_DEBUG_INFO */ /* * Configure default auto columns mode, 32.5KB block size @@ -5587,7 +5662,7 @@ static void idetape_get_mode_sense_results (ide_drive_t *drive) else if (tape->onstream && capabilities->blk32768) tape->tape_block_size = 32768; -#if IDETAPE_DEBUG_LOG +#if IDETAPE_DEBUG_INFO printk (KERN_INFO "ide-tape: Dumping the results of the MODE SENSE packet command\n"); printk (KERN_INFO "ide-tape: Mode Parameter Header:\n"); printk (KERN_INFO "ide-tape: Mode Data Length - %d\n",header->mode_data_length); @@ -5615,7 +5690,7 @@ static void idetape_get_mode_sense_results (ide_drive_t *drive) printk (KERN_INFO "ide-tape: Continuous transfer limits in blocks - %d\n",capabilities->ctl); printk (KERN_INFO "ide-tape: Current speed in KBps - %d\n",capabilities->speed); printk (KERN_INFO "ide-tape: Buffer size - %d\n",capabilities->buffer_size*512); -#endif /* IDETAPE_DEBUG_LOG */ +#endif /* IDETAPE_DEBUG_INFO */ } static void idetape_add_settings (ide_drive_t *drive) diff --git a/drivers/block/ide.c b/drivers/block/ide.c index 93da9bea2..b82092452 100644 --- a/drivers/block/ide.c +++ b/drivers/block/ide.c @@ -186,6 +186,7 @@ static int ide_lock = 0; * ide_modules keeps track of the available IDE chipset/probe/driver modules. */ ide_module_t *ide_modules = NULL; +ide_module_t *ide_probe = NULL; /* * This is declared extern in ide.h, for access by other IDE modules: @@ -281,7 +282,7 @@ static void init_hwif_data (unsigned int index) * for the max possible number (MAX_HWIFS * MAX_DRIVES) of them. */ #define MAGIC_COOKIE 0x12345678 -static void init_ide_data (void) +static void __init init_ide_data (void) { unsigned int index; static unsigned long magic_cookie = MAGIC_COOKIE; @@ -1093,13 +1094,18 @@ static ide_startstop_t start_request (ide_drive_t *drive) #endif block = rq->sector; blockend = block + rq->nr_sectors; - if ((blockend < block) || (blockend > drive->part[minor&PARTN_MASK].nr_sects)) { - printk("%s%c: bad access: block=%ld, count=%ld\n", drive->name, - (minor&PARTN_MASK)?'0'+(minor&PARTN_MASK):' ', block, rq->nr_sectors); - goto kill_rq; +#if 0 + if ((rq->cmd == READ || rq->cmd == WRITE) && + (drive->media == ide_disk || drive->media == ide_floppy)) +#endif + { + if ((blockend < block) || (blockend > drive->part[minor&PARTN_MASK].nr_sects)) { + printk("%s%c: bad access: block=%ld, count=%ld\n", drive->name, + (minor&PARTN_MASK)?'0'+(minor&PARTN_MASK):' ', block, rq->nr_sectors); + goto kill_rq; + } + block += drive->part[minor&PARTN_MASK].start_sect + drive->sect0; } - block += drive->part[minor&PARTN_MASK].start_sect + drive->sect0; - /* Yecch - this will shift the entire interval, possibly killing some innocent following sector */ if (block == 0 && drive->remap_0_to_1 == 1) @@ -1409,9 +1415,9 @@ void ide_timer_expiry (unsigned long data) } } else { ide_drive_t *drive = hwgroup->drive; - hwgroup->handler = NULL; if (!drive) { printk("ide_timer_expiry: hwgroup->drive was NULL\n"); + hwgroup->handler = NULL; } else { ide_hwif_t *hwif; ide_startstop_t startstop; @@ -1429,6 +1435,7 @@ void ide_timer_expiry (unsigned long data) return; } } + hwgroup->handler = NULL; /* * We need to simulate a real interrupt when invoking * the handler() function, which means we need to globally @@ -1436,7 +1443,7 @@ void ide_timer_expiry (unsigned long data) */ spin_unlock(&io_request_lock); hwif = HWIF(drive); - disable_irq(hwif->irq); + disable_irq(hwif->irq); /* disable_irq_nosync ?? */ __cli(); /* local CPU only, as if we were handling an interrupt */ if (hwgroup->poll_timeout != 0) { startstop = handler(drive); @@ -1802,23 +1809,33 @@ static void revalidate_drives (void) } } -static void ide_init_module (int type) +static void ide_probe_module (void) +{ + if (!ide_probe) { +#ifdef CONFIG_KMOD + (void) request_module("ide-probe-mod"); +#endif /* CONFIG_KMOD */ + } else { + (void) ide_probe->init(); + } + revalidate_drives(); +} + +static void ide_driver_module (void) { - int found = 0; + int index; ide_module_t *module = ide_modules; - + + for (index = 0; index < MAX_HWIFS; ++index) + if (ide_hwifs[index].present) + goto search; + ide_probe_module(); +search: while (module) { - if (module->type == type) { - found = 1; - (void) module->init(); - } + (void) module->init(); module = module->next; } revalidate_drives(); -#ifdef CONFIG_KMOD - if (!found && type == IDE_PROBE_MODULE) - (void) request_module("ide-probe-mod"); -#endif /* CONFIG_KMOD */ } static int ide_open (struct inode * inode, struct file * filp) @@ -1830,7 +1847,7 @@ static int ide_open (struct inode * inode, struct file * filp) return -ENXIO; MOD_INC_USE_COUNT; if (drive->driver == NULL) - ide_init_module(IDE_DRIVER_MODULE); + ide_driver_module(); #ifdef CONFIG_KMOD if (drive->driver == NULL) { if (drive->media == ide_disk) @@ -1881,9 +1898,9 @@ int ide_replace_subdriver (ide_drive_t *drive, const char *driver) if (drive->driver != NULL && DRIVER(drive)->cleanup(drive)) goto abort; strncpy(drive->driver_req, driver, 9); - ide_init_module(IDE_DRIVER_MODULE); + ide_driver_module(); drive->driver_req[0] = 0; - ide_init_module(IDE_DRIVER_MODULE); + ide_driver_module(); if (DRIVER(drive) && !strcmp(DRIVER(drive)->name, driver)) return 0; abort: @@ -1897,6 +1914,35 @@ ide_proc_entry_t generic_subdriver_entries[] = { }; #endif +/* + * Note that we only release the standard ports, + * and do not even try to handle any extra ports + * allocated for weird IDE interface chipsets. + */ +void hwif_unregister (ide_hwif_t *hwif) +{ + if (hwif->io_ports[IDE_DATA_OFFSET]) + ide_release_region(hwif->io_ports[IDE_DATA_OFFSET], 1); + if (hwif->io_ports[IDE_ERROR_OFFSET]) + ide_release_region(hwif->io_ports[IDE_ERROR_OFFSET], 1); + if (hwif->io_ports[IDE_NSECTOR_OFFSET]) + ide_release_region(hwif->io_ports[IDE_NSECTOR_OFFSET], 1); + if (hwif->io_ports[IDE_SECTOR_OFFSET]) + ide_release_region(hwif->io_ports[IDE_SECTOR_OFFSET], 1); + if (hwif->io_ports[IDE_LCYL_OFFSET]) + ide_release_region(hwif->io_ports[IDE_LCYL_OFFSET], 1); + if (hwif->io_ports[IDE_HCYL_OFFSET]) + ide_release_region(hwif->io_ports[IDE_HCYL_OFFSET], 1); + if (hwif->io_ports[IDE_SELECT_OFFSET]) + ide_release_region(hwif->io_ports[IDE_SELECT_OFFSET], 1); + if (hwif->io_ports[IDE_STATUS_OFFSET]) + ide_release_region(hwif->io_ports[IDE_STATUS_OFFSET], 1); + if (hwif->io_ports[IDE_CONTROL_OFFSET]) + ide_release_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1); + if (hwif->io_ports[IDE_IRQ_OFFSET]) + ide_release_region(hwif->io_ports[IDE_IRQ_OFFSET], 1); +} + void ide_unregister (unsigned int index) { struct gendisk *gd, **gdp; @@ -1967,9 +2013,7 @@ void ide_unregister (unsigned int index) * and do not even try to handle any extra ports * allocated for weird IDE interface chipsets. */ - ide_release_region(hwif->io_ports[IDE_DATA_OFFSET], 8); - if (hwif->io_ports[IDE_CONTROL_OFFSET]) - ide_release_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1); + hwif_unregister(hwif); /* * Remove us from the hwgroup, and free @@ -2036,23 +2080,28 @@ void ide_unregister (unsigned int index) kfree (gd->flags); kfree(gd); } - old_hwif = *hwif; + old_hwif = *hwif; init_hwif_data (index); /* restore hwif data to pristine status */ - hwif->hwgroup = old_hwif.hwgroup; - hwif->tuneproc = old_hwif.tuneproc; - hwif->resetproc = old_hwif.resetproc; - hwif->dmaproc = old_hwif.dmaproc; - hwif->dma_base = old_hwif.dma_base; - hwif->dma_extra = old_hwif.dma_extra; - hwif->config_data = old_hwif.config_data; - hwif->select_data = old_hwif.select_data; - hwif->irq = old_hwif.irq; - hwif->major = old_hwif.major; - hwif->proc = old_hwif.proc; - hwif->udma_four = old_hwif.udma_four; - hwif->chipset = old_hwif.chipset; - hwif->pci_dev = old_hwif.pci_dev; - hwif->pci_devid = old_hwif.pci_devid; + hwif->hwgroup = old_hwif.hwgroup; + hwif->tuneproc = old_hwif.tuneproc; + hwif->selectproc = old_hwif.selectproc; + hwif->resetproc = old_hwif.resetproc; + hwif->dmaproc = old_hwif.dmaproc; + hwif->dma_base = old_hwif.dma_base; + hwif->dma_extra = old_hwif.dma_extra; + hwif->config_data = old_hwif.config_data; + hwif->select_data = old_hwif.select_data; + hwif->proc = old_hwif.proc; + hwif->irq = old_hwif.irq; + hwif->major = old_hwif.major; + hwif->chipset = old_hwif.chipset; + hwif->autodma = old_hwif.autodma; + hwif->udma_four = old_hwif.udma_four; +#ifdef CONFIG_BLK_DEV_IDEPCI + hwif->pci_dev = old_hwif.pci_dev; + hwif->pci_devid = old_hwif.pci_devid; +#endif /* CONFIG_BLK_DEV_IDEPCI */ + abort: restore_flags(flags); /* all CPUs */ } @@ -2087,6 +2136,7 @@ void ide_setup_ports ( hw_regs_t *hw, } } hw->irq = irq; + hw->dma = NO_DMA; hw->ack_intr = ack_intr; } @@ -2126,11 +2176,11 @@ found: hwif->noprobe = 0; if (!initializing) { - ide_init_module(IDE_PROBE_MODULE); + ide_probe_module(); #ifdef CONFIG_PROC_FS create_proc_ide_interfaces(); #endif - ide_init_module(IDE_DRIVER_MODULE); + ide_driver_module(); } if (hwifp) @@ -2750,7 +2800,7 @@ int __init ide_setup (char *s) if (!strcmp(s, "ide=doubler")) { extern int ide_doubler; - printk("ide: Enabled support for IDE doublers\n"); + printk(" : Enabled support for IDE doublers\n"); ide_doubler = 1; return 0; } @@ -2759,12 +2809,14 @@ int __init ide_setup (char *s) #ifdef CONFIG_BLK_DEV_IDEPCI if (!strcmp(s, "ide=reverse")) { ide_scan_direction = 1; - printk("ide: Enabled support for IDE inverse scan order.\n"); + printk(" : Enabled support for IDE inverse scan order.\n"); return 0; } #endif /* CONFIG_BLK_DEV_IDEPCI */ +#ifndef CONFIG_BLK_DEV_IDEPCI init_ide_data (); +#endif /* CONFIG_BLK_DEV_IDEPCI */ /* * Look for drive options: "hdx=" @@ -3176,7 +3228,7 @@ void __init ide_init_builtin_drivers (void) #if defined(__mc68000__) || defined(CONFIG_APUS) if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET]) { ide_get_lock(&ide_lock, NULL, NULL); /* for atari only */ - disable_irq(ide_hwifs[0].irq); + disable_irq(ide_hwifs[0].irq); /* disable_irq_nosync ?? */ } #endif /* __mc68000__ || CONFIG_APUS */ @@ -3293,10 +3345,6 @@ ide_drive_t *ide_scan_devices (byte media, const char *name, ide_driver_t *drive { unsigned int unit, index, i; - for (index = 0; index < MAX_HWIFS; ++index) - if (ide_hwifs[index].present) goto search; - ide_init_module(IDE_PROBE_MODULE); -search: for (index = 0, i = 0; index < MAX_HWIFS; ++index) { ide_hwif_t *hwif = &ide_hwifs[index]; if (!hwif->present) @@ -3327,8 +3375,16 @@ int ide_register_subdriver (ide_drive_t *drive, ide_driver_t *driver, int versio setup_driver_defaults(drive); restore_flags(flags); /* all CPUs */ if (drive->autotune != 2) { - if (driver->supports_dma && HWIF(drive)->dmaproc != NULL) + if (driver->supports_dma && HWIF(drive)->dmaproc != NULL) { + /* + * Force DMAing for the beginning of the check. + * Some chipsets appear to do interesting things, + * if not checked and cleared. + * PARANOIA!!! + */ + (void) (HWIF(drive)->dmaproc(ide_dma_off_quietly, drive)); (void) (HWIF(drive)->dmaproc(ide_dma_check, drive)); + } drive->dsc_overlap = (drive->next != drive && driver->supports_dsc_overlap); drive->nice1 = 1; } @@ -3400,6 +3456,7 @@ EXPORT_SYMBOL(ide_spin_wait_hwgroup); /* * Probe module */ +EXPORT_SYMBOL(ide_probe); EXPORT_SYMBOL(drive_is_flashcard); EXPORT_SYMBOL(ide_timer_expiry); EXPORT_SYMBOL(ide_intr); @@ -3474,7 +3531,7 @@ EXPORT_SYMBOL(ide_register_hw); EXPORT_SYMBOL(ide_register); EXPORT_SYMBOL(ide_unregister); EXPORT_SYMBOL(ide_setup_ports); - +EXPORT_SYMBOL(hwif_unregister); EXPORT_SYMBOL(get_info_ptr); EXPORT_SYMBOL(current_capacity); @@ -3539,13 +3596,9 @@ void cleanup_module (void) { int index; - for (index = 0; index < MAX_HWIFS; ++index) { + for (index = 0; index < MAX_HWIFS; ++index) ide_unregister(index); -#ifdef CONFIG_BLK_DEV_IDEDMA - if (ide_hwifs[index].dma_base) - (void) ide_release_dma(&ide_hwifs[index]); -#endif /* CONFIG_BLK_DEV_IDEDMA */ - } + #ifdef CONFIG_PROC_FS proc_ide_destroy(); #endif diff --git a/drivers/block/ide_modes.h b/drivers/block/ide_modes.h index d8c8a7144..b6c28e6ab 100644 --- a/drivers/block/ide_modes.h +++ b/drivers/block/ide_modes.h @@ -1,11 +1,12 @@ -#ifndef _IDE_MODES_H -#define _IDE_MODES_H /* * linux/drivers/block/ide_modes.h * * Copyright (C) 1996 Linus Torvalds, Igor Abramov, and Mark Lord */ +#ifndef _IDE_MODES_H +#define _IDE_MODES_H + #include /* diff --git a/drivers/block/linear.c b/drivers/block/linear.c index 1c3305bae..978d75b80 100644 --- a/drivers/block/linear.c +++ b/drivers/block/linear.c @@ -121,14 +121,15 @@ static int linear_stop (mddev_t *mddev) return 0; } -static int linear_make_request (mddev_t *mddev, int rw, struct buffer_head * bh) +static int linear_make_request (request_queue_t *q, mddev_t *mddev, + int rw, struct buffer_head * bh) { linear_conf_t *conf = mddev_to_conf(mddev); struct linear_hash *hash; dev_info_t *tmp_dev; long block; - block = bh->b_blocknr * (bh->b_size >> 10); + block = bh->b_rsector >> 1; hash = conf->hash_table + (block / conf->smallest->size); if (block >= (hash->dev0->size + hash->dev0->offset)) { @@ -149,8 +150,7 @@ static int linear_make_request (mddev_t *mddev, int rw, struct buffer_head * bh) bh->b_rdev = tmp_dev->dev; bh->b_rsector = (block - tmp_dev->offset) << 1; - generic_make_request(rw, bh); - return 0; + return 1; } static int linear_status (char *page, mddev_t *mddev) diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index 808878b3e..a0ac26a49 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -952,96 +952,122 @@ end_io: bh->b_end_io(bh, test_bit(BH_Uptodate, &bh->b_state)); } -void generic_make_request(int rw, struct buffer_head * bh) +static inline void buffer_IO_error(struct buffer_head * bh) +{ + mark_buffer_clean(bh); + /* + * b_end_io has to clear the BH_Uptodate bitflag in the error case! + */ + bh->b_end_io(bh, 0); +} + +int generic_make_request (request_queue_t *q, int rw, struct buffer_head * bh) { - request_queue_t * q; unsigned long flags; + int ret; - q = blk_get_queue(bh->b_rdev); + /* + * Resolve the mapping until finished. (drivers are + * still free to implement/resolve their own stacking + * by explicitly returning 0) + */ + while (q->make_request_fn) { + ret = q->make_request_fn(q, rw, bh); + if (ret > 0) { + q = blk_get_queue(bh->b_rdev); + continue; + } + return ret; + } + /* + * Does the block device want us to queue + * the IO request? (normal case) + */ __make_request(q, rw, bh); - spin_lock_irqsave(&io_request_lock,flags); if (q && !q->plugged) (q->request_fn)(q); spin_unlock_irqrestore(&io_request_lock,flags); -} + return 0; +} /* This function can be used to request a number of buffers from a block device. Currently the only restriction is that all buffers must belong to the same device */ -static void __ll_rw_block(int rw, int nr, struct buffer_head * bh[],int haslock) +static void __ll_rw_block(int rw, int nr, struct buffer_head * bhs[], + int haslock) { + struct buffer_head *bh; + request_queue_t *q; unsigned int major; int correct_size; - request_queue_t *q; int i; - major = MAJOR(bh[0]->b_dev); - q = blk_get_queue(bh[0]->b_dev); + major = MAJOR(bhs[0]->b_dev); + q = blk_get_queue(bhs[0]->b_dev); if (!q) { printk(KERN_ERR "ll_rw_block: Trying to read nonexistent block-device %s (%ld)\n", - kdevname(bh[0]->b_dev), bh[0]->b_blocknr); + kdevname(bhs[0]->b_dev), bhs[0]->b_blocknr); goto sorry; } /* Determine correct block size for this device. */ correct_size = BLOCK_SIZE; if (blksize_size[major]) { - i = blksize_size[major][MINOR(bh[0]->b_dev)]; + i = blksize_size[major][MINOR(bhs[0]->b_dev)]; if (i) correct_size = i; } /* Verify requested block sizes. */ for (i = 0; i < nr; i++) { - if (bh[i]->b_size != correct_size) { + bh = bhs[i]; + if (bh->b_size != correct_size) { printk(KERN_NOTICE "ll_rw_block: device %s: " "only %d-char blocks implemented (%u)\n", - kdevname(bh[0]->b_dev), - correct_size, bh[i]->b_size); + kdevname(bhs[0]->b_dev), + correct_size, bh->b_size); goto sorry; } } - if ((rw & WRITE) && is_read_only(bh[0]->b_dev)) { + if ((rw & WRITE) && is_read_only(bhs[0]->b_dev)) { printk(KERN_NOTICE "Can't write to read-only device %s\n", - kdevname(bh[0]->b_dev)); + kdevname(bhs[0]->b_dev)); goto sorry; } for (i = 0; i < nr; i++) { + bh = bhs[i]; + /* Only one thread can actually submit the I/O. */ if (haslock) { - if (!buffer_locked(bh[i])) + if (!buffer_locked(bh)) BUG(); } else { - if (test_and_set_bit(BH_Lock, &bh[i]->b_state)) + if (test_and_set_bit(BH_Lock, &bh->b_state)) continue; } - set_bit(BH_Req, &bh[i]->b_state); + set_bit(BH_Req, &bh->b_state); - if (q->make_request_fn) - q->make_request_fn(rw, bh[i]); - else { - bh[i]->b_rdev = bh[i]->b_dev; - bh[i]->b_rsector = bh[i]->b_blocknr*(bh[i]->b_size>>9); + /* + * First step, 'identity mapping' - RAID or LVM might + * further remap this. + */ + bh->b_rdev = bh->b_dev; + bh->b_rsector = bh->b_blocknr * (bh->b_size>>9); - generic_make_request(rw, bh[i]); - } + generic_make_request(q, rw, bh); } - return; sorry: - for (i = 0; i < nr; i++) { - mark_buffer_clean(bh[i]); /* remeber to refile it */ - clear_bit(BH_Uptodate, &bh[i]->b_state); - bh[i]->b_end_io(bh[i], 0); - } + for (i = 0; i < nr; i++) + buffer_IO_error(bhs[i]); return; } @@ -1176,10 +1202,7 @@ int __init blk_dev_init(void) #ifdef CONFIG_BLK_DEV_FD floppy_init(); #else -#if !defined(CONFIG_SGI_IP22) && !defined(CONFIG_SGI_IP27) && \ - !defined (__mc68000__) && !defined(CONFIG_PPC) && !defined(__sparc__) && \ - !defined(CONFIG_APUS) && !defined(CONFIG_DECSTATION) && \ - !defined(CONFIG_BAGET_MIPS) && !defined(__sh__) && !defined(__ia64__) +#if defined(__i386__) /* Do we even need this? */ outb_p(0xc, 0x3f2); #endif #endif diff --git a/drivers/block/lvm.c b/drivers/block/lvm.c index 6d2f2743e..9f58a48d5 100644 --- a/drivers/block/lvm.c +++ b/drivers/block/lvm.c @@ -192,7 +192,7 @@ extern int lvm_init(void); static void lvm_dummy_device_request(request_queue_t *); #define DEVICE_REQUEST lvm_dummy_device_request -static void lvm_make_request_fn(int, struct buffer_head*); +static int lvm_make_request_fn(request_queue_t *, int, struct buffer_head*); static int lvm_blk_ioctl(struct inode *, struct file *, uint, ulong); static int lvm_blk_open(struct inode *, struct file *); @@ -1292,14 +1292,14 @@ static int lvm_proc_get_info(char *page, char **start, off_t pos, int count) */ static int lvm_map(struct buffer_head *bh, int rw) { - int minor = MINOR(bh->b_dev); + int minor = MINOR(bh->b_rdev); int ret = 0; ulong index; ulong pe_start; ulong size = bh->b_size >> 9; - ulong rsector_tmp = bh->b_blocknr * size; + ulong rsector_tmp = bh->b_rsector; ulong rsector_sav; - kdev_t rdev_tmp = bh->b_dev; + kdev_t rdev_tmp = bh->b_rdev; kdev_t rdev_sav; lv_t *lv = vg[VG_BLK(minor)]->lv[LV_BLK(minor)]; @@ -1513,11 +1513,10 @@ static void lvm_dummy_device_request(request_queue_t * t) /* * make request function */ -static void lvm_make_request_fn(int rw, struct buffer_head *bh) +static int lvm_make_request_fn(request_queue_t *q, int rw, struct buffer_head *bh) { lvm_map(bh, rw); - if (bh->b_rdev != MD_MAJOR) generic_make_request(rw, bh); - return; + return 1; } diff --git a/drivers/block/macide.c b/drivers/block/macide.c index 4f6febd28..46a14ba19 100644 --- a/drivers/block/macide.c +++ b/drivers/block/macide.c @@ -1,5 +1,5 @@ /* - * linux/drivers/block/macide.c -- Macintosh IDE Driver + * linux/drivers/ide/macide.c -- Macintosh IDE Driver * * Copyright (C) 1998 by Michael Schmitz * @@ -43,7 +43,7 @@ #define MAC_HD_STATUS 0x1c /* see status-bits */ #define MAC_HD_CONTROL 0x38 /* control/altstatus */ -static int macide_offsets[IDE_NR_PORTS] = { +static int __init macide_offsets[IDE_NR_PORTS] = { MAC_HD_DATA, MAC_HD_ERROR, MAC_HD_NSECTOR, MAC_HD_SECTOR, MAC_HD_LCYL, MAC_HD_HCYL, MAC_HD_SELECT, MAC_HD_STATUS, MAC_HD_CONTROL }; @@ -84,7 +84,7 @@ static int mac_ack_intr(ide_hwif_t* hwif) * Probe for a Macintosh IDE interface */ -void macide_init(void) +void __init macide_init(void) { hw_regs_t hw; int index = -1; diff --git a/drivers/block/md.c b/drivers/block/md.c index b258fc6c5..171b3b659 100644 --- a/drivers/block/md.c +++ b/drivers/block/md.c @@ -75,16 +75,16 @@ static devfs_handle_t devfs_handle = NULL; static struct gendisk md_gendisk= { - MD_MAJOR, - "md", - 0, - 1, - md_hd_struct, - md_size, - MAX_MD_DEVS, - NULL, - NULL, - &md_fops, + major: MD_MAJOR, + major_name: "md", + minor_shift: 0, + max_p: 1, + part: md_hd_struct, + sizes: md_size, + nr_real: MAX_MD_DEVS, + real_devices: NULL, + next: NULL, + fops: &md_fops, }; void md_plug_device (request_queue_t *mdqueue, kdev_t dev) @@ -178,17 +178,16 @@ static void do_md_request (request_queue_t * q) return; } -void md_make_request (int rw, struct buffer_head * bh) +static int md_make_request (request_queue_t *q, int rw, struct buffer_head * bh) { - mddev_t *mddev = kdev_to_mddev(bh->b_dev); + mddev_t *mddev = kdev_to_mddev(bh->b_rdev); - if (!mddev || !mddev->pers) - bh->b_end_io(bh, 0); + if (mddev && mddev->pers) + return mddev->pers->make_request(q, mddev, rw, bh); else { - if ((rw == READ || rw == READA) && buffer_uptodate(bh)) - bh->b_end_io(bh, 1); - else - mddev->pers->make_request(mddev, rw, bh); + mark_buffer_clean(bh); + bh->b_end_io(bh, 0); + return -1; } } @@ -234,28 +233,6 @@ static mddev_t * alloc_mddev (kdev_t dev) return mddev; } -static void free_mddev (mddev_t *mddev) -{ - if (!mddev) { - MD_BUG(); - return; - } - - /* - * Make sure nobody else is using this mddev - * (careful, we rely on the global kernel lock here) - */ - while (md_atomic_read(&mddev->resync_sem.count) != 1) - schedule(); - while (md_atomic_read(&mddev->recovery_sem.count) != 1) - schedule(); - - del_mddev_mapping(mddev, MKDEV(MD_MAJOR, mdidx(mddev))); - md_list_del(&mddev->all_mddevs); - MD_INIT_LIST_HEAD(&mddev->all_mddevs); - kfree(mddev); -} - struct gendisk * find_gendisk (kdev_t dev) { struct gendisk *tmp = gendisk_head; @@ -757,6 +734,32 @@ static void export_array (mddev_t *mddev) MD_BUG(); } +static void free_mddev (mddev_t *mddev) +{ + if (!mddev) { + MD_BUG(); + return; + } + + export_array(mddev); + md_size[mdidx(mddev)] = 0; + md_hd_struct[mdidx(mddev)].nr_sects = 0; + + /* + * Make sure nobody else is using this mddev + * (careful, we rely on the global kernel lock here) + */ + while (md_atomic_read(&mddev->resync_sem.count) != 1) + schedule(); + while (md_atomic_read(&mddev->recovery_sem.count) != 1) + schedule(); + + del_mddev_mapping(mddev, MKDEV(MD_MAJOR, mdidx(mddev))); + md_list_del(&mddev->all_mddevs); + MD_INIT_LIST_HEAD(&mddev->all_mddevs); + kfree(mddev); +} + #undef BAD_CSUM #undef BAD_MAGIC #undef OUT_OF_MEM @@ -1723,13 +1726,7 @@ static int do_md_stop (mddev_t * mddev, int ro) printk (STILL_MOUNTED, mdidx(mddev)); OUT(-EBUSY); } - - /* - * complain if it's already stopped - */ - if (!mddev->nb_dev) - OUT(-ENXIO); - + if (mddev->pers) { /* * It is safe to call stop here, it only frees private @@ -1796,9 +1793,6 @@ static int do_md_stop (mddev_t * mddev, int ro) * Free resources if final stop */ if (!ro) { - export_array(mddev); - md_size[mdidx(mddev)] = 0; - md_hd_struct[mdidx(mddev)].nr_sects = 0; free_mddev(mddev); printk (KERN_INFO "md%d stopped.\n", mdidx(mddev)); @@ -3279,15 +3273,15 @@ static void md_geninit (void) { int i; - blksize_size[MD_MAJOR] = md_blocksizes; - max_readahead[MD_MAJOR] = md_maxreadahead; - for(i = 0; i < MAX_MD_DEVS; i++) { md_blocksizes[i] = 1024; + md_size[i] = 0; md_maxreadahead[i] = MD_READAHEAD; register_disk(&md_gendisk, MKDEV(MAJOR_NR,i), 1, &md_fops, 0); - } + blksize_size[MD_MAJOR] = md_blocksizes; + blk_size[MAJOR_NR] = md_size; + max_readahead[MD_MAJOR] = md_maxreadahead; printk("md.c: sizeof(mdp_super_t) = %d\n", (int)sizeof(mdp_super_t)); diff --git a/drivers/block/ns87415.c b/drivers/block/ns87415.c index 8b8bb3f60..0e5675fde 100644 --- a/drivers/block/ns87415.c +++ b/drivers/block/ns87415.c @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ns87415.c Version 1.00 December 7, 1997 + * linux/drivers/block/ns87415.c Version 1.00 December 7, 1997 * * Copyright (C) 1997-1998 Mark Lord * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) diff --git a/drivers/block/opti621.c b/drivers/block/opti621.c index 0885ed49e..cc2aa567c 100644 --- a/drivers/block/opti621.c +++ b/drivers/block/opti621.c @@ -1,5 +1,5 @@ /* - * linux/drivers/block/opti621.c Version 0.6 Jan 02, 1999 + * linux/drivers/block/opti621.c Version 0.6 Jan 02, 1999 * * Copyright (C) 1996-1998 Linus Torvalds & authors (see below) */ diff --git a/drivers/block/pdc202xx.c b/drivers/block/pdc202xx.c index c5a0c4924..bce80650c 100644 --- a/drivers/block/pdc202xx.c +++ b/drivers/block/pdc202xx.c @@ -1,7 +1,7 @@ /* - * linux/drivers/block/pdc202xx.c Version 0.28 Dec. 13, 1999 + * linux/drivers/block/pdc202xx.c Version 0.29 Feb. 10, 2000 * - * Copyright (C) 1998-99 Andre Hedrick (andre@suse.com) + * Copyright (C) 1998-2000 Andre Hedrick (andre@suse.com) * May be copied or modified under the terms of the GNU General Public License * * Promise Ultra33 cards with BIOS v1.20 through 1.28 will need this @@ -14,7 +14,7 @@ * 8 are UDMA supported and 4 are limited to DMA mode 2 multi-word. * The 8/4 ratio is a BIOS code limit by promise. * - * UNLESS you enable "CONFIG_PDC202XX_FORCE_BURST_BIT" + * UNLESS you enable "CONFIG_PDC202XX_BURST" * * There is only one BIOS in the three contollers. * @@ -100,6 +100,61 @@ #define PDC202XX_DEBUG_DRIVE_INFO 0 #define PDC202XX_DECODE_REGISTER_INFO 0 +#define DISPLAY_PDC202XX_TIMINGS +#if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS) +#include +#include + +static int pdc202xx_get_info(char *, char **, off_t, int); +extern int (*pdc202xx_display_info)(char *, char **, off_t, int); /* ide-proc.c */ +extern char *ide_media_verbose(ide_drive_t *); +static struct pci_dev *bmide_dev; + +static int pdc202xx_get_info (char *buffer, char **addr, off_t offset, int count) +{ + char *p = buffer; + + u32 bibma = bmide_dev->resource[4].start; + u8 c0 = 0, c1 = 0; + + /* + * at that point bibma+0x2 et bibma+0xa are byte registers + * to investigate: + */ + c0 = inb_p((unsigned short)bibma + 0x02); + c1 = inb_p((unsigned short)bibma + 0x0a); + + switch(bmide_dev->device) { + case PCI_DEVICE_ID_PROMISE_20262: + p += sprintf(p, "\n PDC20262 Chipset.\n"); + break; + case PCI_DEVICE_ID_PROMISE_20246: + p += sprintf(p, "\n PDC20246 Chipset.\n"); + break; + default: + p += sprintf(p, "\n PDC202XX Chipset.\n"); + break; + } + + p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n"); + p += sprintf(p, " %sabled %sabled\n", + (c0&0x80) ? "dis" : " en", + (c1&0x80) ? "dis" : " en"); + p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n"); + p += sprintf(p, "DMA enabled: %s %s %s %s\n", + (c0&0x20) ? "yes" : "no ", (c0&0x40) ? "yes" : "no ", + (c1&0x20) ? "yes" : "no ", (c1&0x40) ? "yes" : "no " ); + + p += sprintf(p, "UDMA\n"); + p += sprintf(p, "DMA\n"); + p += sprintf(p, "PIO\n"); + + return p-buffer; /* => must be less than 4k! */ +} +#endif /* defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS) */ + +byte pdc202xx_proc = 0; + extern char *ide_xfer_verbose (byte xfer_rate); /* A Register */ @@ -620,15 +675,15 @@ unsigned int __init pci_init_pdc202xx (struct pci_dev *dev, const char *name) (primary_mode & 1) ? "MASTER" : "PCI", (secondary_mode & 1) ? "MASTER" : "PCI" ); -#ifdef CONFIG_PDC202XX_FORCE_BURST_BIT +#ifdef CONFIG_PDC202XX_BURST if (!(udma_speed_flag & 1)) { printk("%s: FORCING BURST BIT 0x%02x -> 0x%02x ", name, udma_speed_flag, (udma_speed_flag|1)); outb(udma_speed_flag|1, high_16 + 0x001f); printk("%sCTIVE\n", (inb(high_16 + 0x001f) & 1) ? "A" : "INA"); } -#endif /* CONFIG_PDC202XX_FORCE_BURST_BIT */ +#endif /* CONFIG_PDC202XX_BURST */ -#ifdef CONFIG_PDC202XX_FORCE_MASTER_MODE +#ifdef CONFIG_PDC202XX_MASTER if (!(primary_mode & 1)) { printk("%s: FORCING PRIMARY MODE BIT 0x%02x -> 0x%02x ", name, primary_mode, (primary_mode|1)); @@ -642,7 +697,14 @@ unsigned int __init pci_init_pdc202xx (struct pci_dev *dev, const char *name) outb(secondary_mode|1, high_16 + 0x001b); printk("%s\n", (inb(high_16 + 0x001b) & 1) ? "MASTER" : "PCI"); } -#endif /* CONFIG_PDC202XX_FORCE_MASTER_MODE */ +#endif /* CONFIG_PDC202XX_MASTER */ + +#if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS) + pdc202xx_proc = 1; + bmide_dev = dev; + pdc202xx_display_info = &pdc202xx_get_info; +#endif /* DISPLAY_PDC202XX_TIMINGS && CONFIG_PROC_FS */ + return dev->irq; } diff --git a/drivers/block/pdc4030.c b/drivers/block/pdc4030.c index 0b682645c..f42c4946f 100644 --- a/drivers/block/pdc4030.c +++ b/drivers/block/pdc4030.c @@ -1,5 +1,5 @@ /* -*- linux-c -*- - * linux/drivers/block/pdc4030.c Version 0.90 May 27, 1999 + * linux/drivers/ide/pdc4030.c Version 0.90 May 27, 1999 * * Copyright (C) 1995-1999 Linus Torvalds & authors (see below) */ diff --git a/drivers/block/pdc4030.h b/drivers/block/pdc4030.h index 9f08da5aa..551785c36 100644 --- a/drivers/block/pdc4030.h +++ b/drivers/block/pdc4030.h @@ -1,5 +1,5 @@ /* - * linux/drivers/block/pdc4030.h + * linux/drivers/ide/pdc4030.h * * Copyright (C) 1995-1998 Linus Torvalds & authors */ diff --git a/drivers/block/piix.c b/drivers/block/piix.c index 64cf45853..4c2d94c99 100644 --- a/drivers/block/piix.c +++ b/drivers/block/piix.c @@ -1,8 +1,8 @@ /* - * linux/drivers/block/piix.c Version 0.28 Dec. 13, 1999 + * linux/drivers/block/piix.c Version 0.30 Feb. 26, 2000 * * Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer - * Copyright (C) 1998-1999 Andre Hedrick (andre@suse.com) + * Copyright (C) 1998-2000 Andre Hedrick (andre@suse.com) * May be copied or modified under the terms of the GNU General Public License * * PIO mode setting function for Intel chipsets. @@ -49,13 +49,33 @@ * pci_read_config_word(HWIF(drive)->pci_dev, 0x44, ®44); * pci_read_config_word(HWIF(drive)->pci_dev, 0x48, ®48); * pci_read_config_word(HWIF(drive)->pci_dev, 0x4a, ®4a); + * pci_read_config_word(HWIF(drive)->pci_dev, 0x54, ®54); + * + * 00:1f.1 IDE interface: Intel Corporation: + * Unknown device 2411 (rev 01) (prog-if 80 [Master]) + * Control: I/O+ Mem- BusMaster+ SpecCycle- MemWINV- VGASnoop- + * ParErr- Stepping- SERR- FastB2B- + * Status: Cap- 66Mhz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- + * SERR- @@ -86,16 +106,88 @@ static struct pci_dev *bmide_dev; static int piix_get_info (char *buffer, char **addr, off_t offset, int count) { - /* int rc; */ - int piix_who = ((bmide_dev->device == PCI_DEVICE_ID_INTEL_82801AA_1) || - (bmide_dev->device == PCI_DEVICE_ID_INTEL_82801AB_1) || - (bmide_dev->device == PCI_DEVICE_ID_INTEL_82371AB)) ? 4 : 3; char *p = buffer; - p += sprintf(p, "\n Intel PIIX%d Chipset.\n", piix_who); - p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n\n"); + u32 bibma = bmide_dev->resource[4].start; + u16 reg40 = 0, psitre = 0, reg42 = 0, ssitre = 0; + u8 c0 = 0, c1 = 0; + u8 reg44 = 0, reg48 = 0, reg4a = 0, reg4b = 0, reg54 = 0; + + pci_read_config_word(bmide_dev, 0x40, ®40); + pci_read_config_word(bmide_dev, 0x42, ®42); + pci_read_config_byte(bmide_dev, 0x44, ®44); + pci_read_config_byte(bmide_dev, 0x48, ®48); + pci_read_config_byte(bmide_dev, 0x4a, ®4a); + pci_read_config_byte(bmide_dev, 0x4b, ®4b); + pci_read_config_byte(bmide_dev, 0x54, ®54); + + psitre = (reg40 & 0x4000) ? 1 : 0; + ssitre = (reg42 & 0x4000) ? 1 : 0; + + /* + * at that point bibma+0x2 et bibma+0xa are byte registers + * to investigate: + */ + c0 = inb_p((unsigned short)bibma + 0x02); + c1 = inb_p((unsigned short)bibma + 0x0a); + + switch(bmide_dev->device) { + case PCI_DEVICE_ID_INTEL_82372FB_1: + case PCI_DEVICE_ID_INTEL_82801AA_1: + p += sprintf(p, "\n Intel PIIX4 Ultra 66 Chipset.\n"); + break; + case PCI_DEVICE_ID_INTEL_82801AB_1: + case PCI_DEVICE_ID_INTEL_82371AB: + p += sprintf(p, "\n Intel PIIX4 Ultra 33 Chipset.\n"); + break; + case PCI_DEVICE_ID_INTEL_82371SB_1: + p += sprintf(p, "\n Intel PIIX3 Chipset.\n"); + break; + case PCI_DEVICE_ID_INTEL_82371FB_1: + case PCI_DEVICE_ID_INTEL_82371FB_0: + default: + p += sprintf(p, "\n Intel PIIX Chipset.\n"); + break; + } + p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n"); + p += sprintf(p, " %sabled %sabled\n", + (c0&0x80) ? "dis" : " en", + (c1&0x80) ? "dis" : " en"); p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n"); - p += sprintf(p, "\n"); - p += sprintf(p, "\n"); + p += sprintf(p, "DMA enabled: %s %s %s %s\n", + (c0&0x20) ? "yes" : "no ", + (c0&0x40) ? "yes" : "no ", + (c1&0x20) ? "yes" : "no ", + (c1&0x40) ? "yes" : "no " ); + p += sprintf(p, "UDMA enabled: %s %s %s %s\n", + (reg48&0x01) ? "yes" : "no ", + (reg48&0x02) ? "yes" : "no ", + (reg48&0x04) ? "yes" : "no ", + (reg48&0x08) ? "yes" : "no " ); + p += sprintf(p, "UDMA enabled: %s %s %s %s\n", + ((reg54&0x11) && (reg4a&0x02)) ? "4" : + ((reg54&0x11) && (reg4a&0x01)) ? "3" : + (reg4a&0x02) ? "2" : + (reg4a&0x01) ? "1" : + (reg4a&0x00) ? "0" : "X", + ((reg54&0x22) && (reg4a&0x20)) ? "4" : + ((reg54&0x22) && (reg4a&0x10)) ? "3" : + (reg4a&0x20) ? "2" : + (reg4a&0x10) ? "1" : + (reg4a&0x00) ? "0" : "X", + ((reg54&0x44) && (reg4b&0x02)) ? "4" : + ((reg54&0x44) && (reg4b&0x01)) ? "3" : + (reg4b&0x02) ? "2" : + (reg4b&0x01) ? "1" : + (reg4b&0x00) ? "0" : "X", + ((reg54&0x88) && (reg4b&0x20)) ? "4" : + ((reg54&0x88) && (reg4b&0x10)) ? "3" : + (reg4b&0x20) ? "2" : + (reg4b&0x10) ? "1" : + (reg4b&0x00) ? "0" : "X"); + + p += sprintf(p, "UDMA\n"); + p += sprintf(p, "DMA\n"); + p += sprintf(p, "PIO\n"); /* * FIXME.... Add configuration junk data....blah blah...... @@ -113,7 +205,6 @@ byte piix_proc = 0; extern char *ide_xfer_verbose (byte xfer_rate); -#ifdef CONFIG_BLK_DEV_PIIX_TUNING /* * */ @@ -143,7 +234,6 @@ static byte piix_dma_2_pio (byte xfer_rate) { return 0; } } -#endif /* CONFIG_BLK_DEV_PIIX_TUNING */ /* * Based on settings done by AMI BIOS @@ -191,8 +281,6 @@ static void piix_tune_drive (ide_drive_t *drive, byte pio) restore_flags(flags); } -#ifdef CONFIG_BLK_DEV_PIIX_TUNING - static int piix_config_drive_for_dma (ide_drive_t *drive) { struct hd_driveid *id = drive->id; @@ -205,12 +293,15 @@ static int piix_config_drive_for_dma (ide_drive_t *drive) byte maslave = hwif->channel ? 0x42 : 0x40; byte udma_66 = ((id->hw_config & 0x2000) && (hwif->udma_four)) ? 1 : 0; - int ultra = ((dev->device == PCI_DEVICE_ID_INTEL_82371AB) || + int ultra66 = ((dev->device == PCI_DEVICE_ID_INTEL_82801AA_1) || + (dev->device == PCI_DEVICE_ID_INTEL_82372FB_1)) ? 1 : 0; + int ultra = ((ultra66) || + (dev->device == PCI_DEVICE_ID_INTEL_82371AB) || (dev->device == PCI_DEVICE_ID_INTEL_82801AB_1)) ? 1 : 0; - int ultra66 = (dev->device == PCI_DEVICE_ID_INTEL_82801AA_1) ? 1 : 0; int drive_number = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); int a_speed = 2 << (drive_number * 4); int u_flag = 1 << drive_number; + int v_flag = 0x10 << drive_number; int u_speed = 0; pci_read_config_word(dev, maslave, ®4042); @@ -245,10 +336,6 @@ static int piix_config_drive_for_dma (ide_drive_t *drive) speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL); } - /* - * This is !@#$% ugly and stupid............. - * But ugly harware generates ugly code......... - */ if (speed >= XFER_UDMA_0) { if (!(reg48 & u_flag)) pci_write_config_word(dev, 0x48, reg48|u_flag); @@ -256,10 +343,12 @@ static int piix_config_drive_for_dma (ide_drive_t *drive) pci_write_config_word(dev, 0x4a, reg4a & ~a_speed); pci_write_config_word(dev, 0x4a, reg4a|u_speed); } - if ((speed > XFER_UDMA_2) && (!(reg54 & u_flag))) { - pci_write_config_word(dev, 0x54, reg54|u_flag); + if (speed > XFER_UDMA_2) { + if (!(reg54 & v_flag)) { + pci_write_config_word(dev, 0x54, reg54|v_flag); + } } else { - pci_write_config_word(dev, 0x54, reg54 & ~u_flag); + pci_write_config_word(dev, 0x54, reg54 & ~v_flag); } } @@ -268,8 +357,8 @@ static int piix_config_drive_for_dma (ide_drive_t *drive) pci_write_config_word(dev, 0x48, reg48 & ~u_flag); if (reg4a & a_speed) pci_write_config_word(dev, 0x4a, reg4a & ~a_speed); - if (reg54 & u_flag) - pci_write_config_word(dev, 0x54, reg54 & ~u_flag); + if (reg54 & v_flag) + pci_write_config_word(dev, 0x54, reg54 & ~v_flag); } piix_tune_drive(drive, piix_dma_2_pio(speed)); @@ -277,8 +366,7 @@ static int piix_config_drive_for_dma (ide_drive_t *drive) (void) ide_config_drive_speed(drive, speed); #if PIIX_DEBUG_DRIVE_INFO - printk("%s: %s drive%d ", drive->name, ide_xfer_verbose(speed), drive_number); - printk("\n"); + printk("%s: %s drive%d\n", drive->name, ide_xfer_verbose(speed), drive_number); #endif /* PIIX_DEBUG_DRIVE_INFO */ return ((int) ((id->dma_ultra >> 11) & 3) ? ide_dma_on : @@ -299,16 +387,13 @@ static int piix_dmaproc(ide_dma_action_t func, ide_drive_t *drive) /* Other cases are done by generic IDE-DMA code. */ return ide_dmaproc(func, drive); } -#endif /* CONFIG_BLK_DEV_PIIX_TUNING */ unsigned int __init pci_init_piix (struct pci_dev *dev, const char *name) { #if defined(DISPLAY_PIIX_TIMINGS) && defined(CONFIG_PROC_FS) - if (!piix_proc) { - piix_proc = 1; - bmide_dev = dev; - piix_display_info = &piix_get_info; - } + piix_proc = 1; + bmide_dev = dev; + piix_display_info = &piix_get_info; #endif /* DISPLAY_PIIX_TIMINGS && CONFIG_PROC_FS */ return 0; } @@ -325,7 +410,7 @@ unsigned int __init ata66_piix (ide_hwif_t *hwif) pci_read_config_byte(hwif->pci_dev, 0x54, ®54h); pci_read_config_byte(hwif->pci_dev, 0x55, ®55h); - ata66 = (reg54h & mask) ? 0 : 1; + ata66 = (reg54h & mask) ? 1 : 0; return ata66; } @@ -335,9 +420,9 @@ void __init ide_init_piix (ide_hwif_t *hwif) hwif->tuneproc = &piix_tune_drive; if (hwif->dma_base) { -#ifdef CONFIG_BLK_DEV_PIIX_TUNING +#ifdef CONFIG_PIIX_TUNING hwif->dmaproc = &piix_dmaproc; -#endif /* CONFIG_BLK_DEV_PIIX_TUNING */ +#endif /* CONFIG_PIIX_TUNING */ hwif->drives[0].autotune = 0; hwif->drives[1].autotune = 0; } else { diff --git a/drivers/block/qd6580.c b/drivers/block/qd6580.c index d7b2784d1..31781a9f0 100644 --- a/drivers/block/qd6580.c +++ b/drivers/block/qd6580.c @@ -1,5 +1,5 @@ /* - * linux/drivers/block/qd6580.c Version 0.02 Feb 09, 1996 + * linux/drivers/block/qd6580.c Version 0.02 Feb 09, 1996 * * Copyright (C) 1996 Linus Torvalds & author (see below) */ @@ -60,7 +60,7 @@ static void tune_qd6580 (ide_drive_t *drive, byte pio) restore_flags(flags); /* all CPUs */ } -void init_qd6580 (void) +void __init init_qd6580 (void) { ide_hwifs[0].chipset = ide_qd6580; ide_hwifs[1].chipset = ide_qd6580; diff --git a/drivers/block/raid0.c b/drivers/block/raid0.c index 661855a18..0e075277a 100644 --- a/drivers/block/raid0.c +++ b/drivers/block/raid0.c @@ -223,23 +223,23 @@ static int raid0_stop (mddev_t *mddev) * Of course, those facts may not be valid anymore (and surely won't...) * Hey guys, there's some work out there ;-) */ -static int raid0_make_request (mddev_t *mddev, int rw, struct buffer_head * bh) +static int raid0_make_request (request_queue_t *q, mddev_t *mddev, + int rw, struct buffer_head * bh) { - unsigned long size = bh->b_size >> 10; + int blk_in_chunk, chunksize_bits, chunk, chunk_size; raid0_conf_t *conf = mddev_to_conf(mddev); struct raid0_hash *hash; struct strip_zone *zone; mdk_rdev_t *tmp_dev; - int blk_in_chunk, chunksize_bits, chunk, chunk_size; long block, rblock; chunk_size = mddev->param.chunk_size >> 10; chunksize_bits = ffz(~chunk_size); - block = bh->b_blocknr * size; + block = bh->b_rsector >> 1; hash = conf->hash_table + block / conf->smallest->size; /* Sanity check */ - if (chunk_size < (block % chunk_size) + size) + if (chunk_size < (block % chunk_size) + (bh->b_size >> 10)) goto bad_map; if (!hash) @@ -261,20 +261,19 @@ static int raid0_make_request (mddev_t *mddev, int rw, struct buffer_head * bh) rblock = (chunk << chunksize_bits) + blk_in_chunk + zone->dev_offset; /* - * Important, at this point we are not guaranteed to be the only - * CPU modifying b_rdev and b_rsector! Only __make_request() later - * on serializes the IO. So in 2.4 we must never write temporary - * values to bh->b_rdev, like 2.2 and 2.0 did. + * The new BH_Lock semantics in ll_rw_blk.c guarantee that this + * is the only IO operation happening on this bh. */ bh->b_rdev = tmp_dev->dev; bh->b_rsector = rblock << 1; - generic_make_request(rw, bh); - - return 0; + /* + * Let the main block layer submit the IO and resolve recursion: + */ + return 1; bad_map: - printk ("raid0_make_request bug: can't convert block across chunks or bigger than %dk %ld %ld\n", chunk_size, bh->b_rsector, size); + printk ("raid0_make_request bug: can't convert block across chunks or bigger than %dk %ld %d\n", chunk_size, bh->b_rsector, bh->b_size >> 10); return -1; bad_hash: printk("raid0_make_request bug: hash==NULL for block %ld\n", block); diff --git a/drivers/block/rapide.c b/drivers/block/rapide.c index 468f2e3b1..5905aca41 100644 --- a/drivers/block/rapide.c +++ b/drivers/block/rapide.c @@ -1,5 +1,5 @@ /* - * linux/arch/arm/drivers/block/ide-rapide.c + * linux/drivers/block/rapide.c * * Copyright (c) 1996-1998 Russell King. * @@ -16,7 +16,7 @@ #include -static const card_ids rapide_cids[] = { +static const card_ids __init rapide_cids[] = { { MANU_YELLOWSTONE, PROD_YELLOWSTONE_RAPIDE32 }, { 0xffff, 0xffff } }; @@ -43,7 +43,7 @@ static inline int rapide_register(struct expansion_card *ec) return ide_register_hw(&hw, NULL); } -int rapide_init(void) +int __init rapide_init(void) { int i; diff --git a/drivers/block/rz1000.c b/drivers/block/rz1000.c index 811e1665f..455641c1d 100644 --- a/drivers/block/rz1000.c +++ b/drivers/block/rz1000.c @@ -1,5 +1,5 @@ /* - * linux/drivers/block/rz1000.c Version 0.05 December 8, 1997 + * linux/drivers/block/rz1000.c Version 0.05 December 8, 1997 * * Copyright (C) 1995-1998 Linus Torvalds & author (see below) */ diff --git a/drivers/block/sis5513.c b/drivers/block/sis5513.c index d255bbdf8..942187900 100644 --- a/drivers/block/sis5513.c +++ b/drivers/block/sis5513.c @@ -1,7 +1,7 @@ /* - * linux/drivers/block/sis5513.c Version 0.08 Dec. 13, 1999 + * linux/drivers/block/sis5513.c Version 0.09 Feb. 10, 2000 * - * Copyright (C) 1999 Andre Hedrick (andre@suse.com) + * Copyright (C) 1999-2000 Andre Hedrick (andre@suse.com) * May be copied or modified under the terms of the GNU General Public License * * Thanks to SIS Taiwan for direct support and hardware. @@ -50,6 +50,7 @@ static const struct { { "SiS540", PCI_DEVICE_ID_SI_540, SIS5513_FLAG_ATA_66, }, { "SiS620", PCI_DEVICE_ID_SI_620, SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, }, { "SiS630", PCI_DEVICE_ID_SI_630, SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, }, + { "SiS5591", PCI_DEVICE_ID_SI_5591, SIS5513_FLAG_ATA_33, }, { "SiS5597", PCI_DEVICE_ID_SI_5597, SIS5513_FLAG_ATA_33, }, { "SiS5600", PCI_DEVICE_ID_SI_5600, SIS5513_FLAG_ATA_33, }, { "SiS5511", PCI_DEVICE_ID_SI_5511, SIS5513_FLAG_ATA_16, }, @@ -233,8 +234,10 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra) byte drive_pci, test1, test2, mask; int err; + unsigned long dma_base = hwif->dma_base; + byte unit = (drive->select.b.unit & 0x01); byte speed = 0x00, unmask = 0xE0, four_two = 0x00; - int drive_number = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); + int drive_number = ((hwif->channel ? 2 : 0) + unit); byte udma_66 = ((id->hw_config & 0x2000) && (hwif->udma_four)) ? 1 : 0; if (host_dev) { @@ -314,6 +317,7 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra) return ((int) ide_dma_off_quietly); } + outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2); err = ide_config_drive_speed(drive, speed); #if SIS5513_DEBUG_DRIVE_INFO @@ -532,6 +536,7 @@ void __init ide_init_sis5513 (ide_hwif_t *hwif) case PCI_DEVICE_ID_SI_630: case PCI_DEVICE_ID_SI_5600: case PCI_DEVICE_ID_SI_5597: + case PCI_DEVICE_ID_SI_5591: hwif->autodma = 1; hwif->dmaproc = &sis5513_dmaproc; break; diff --git a/drivers/block/sl82c105.c b/drivers/block/sl82c105.c index 9ab90f0df..29f006682 100644 --- a/drivers/block/sl82c105.c +++ b/drivers/block/sl82c105.c @@ -1,5 +1,5 @@ /* - * drivers/block/sl82c105.c + * linux/drivers/block/sl82c105.c * * SL82C105/Winbond 553 IDE driver * diff --git a/drivers/block/trm290.c b/drivers/block/trm290.c index 4ec1d09c6..fb5e8d1af 100644 --- a/drivers/block/trm290.c +++ b/drivers/block/trm290.c @@ -1,5 +1,5 @@ /* - * linux/drivers/block/trm290.c Version 1.01 December 5, 1997 + * linux/drivers/block/trm290.c Version 1.01 December 5, 1997 * * Copyright (c) 1997-1998 Mark Lord * May be copied or modified under the terms of the GNU General Public License diff --git a/drivers/block/umc8672.c b/drivers/block/umc8672.c index 13f5f39a7..02b581a28 100644 --- a/drivers/block/umc8672.c +++ b/drivers/block/umc8672.c @@ -1,5 +1,5 @@ /* - * linux/drivers/block/umc8672.c Version 0.05 Jul 31, 1996 + * linux/drivers/block/umc8672.c Version 0.05 Jul 31, 1996 * * Copyright (C) 1995-1996 Linus Torvalds & author (see below) */ @@ -76,7 +76,7 @@ static void out_umc (char port,char wert) outb_p (wert,0x109); } -static byte in_umc (char port) +static inline byte in_umc (char port) { outb_p (port,0x108); return inb_p (0x109); @@ -125,7 +125,7 @@ static void tune_umc (ide_drive_t *drive, byte pio) restore_flags(flags); /* all CPUs */ } -void init_umc8672 (void) /* called from ide.c */ +void __init init_umc8672 (void) /* called from ide.c */ { unsigned long flags; diff --git a/drivers/block/via82cxxx.c b/drivers/block/via82cxxx.c index 09c4a86a7..54681f38c 100644 --- a/drivers/block/via82cxxx.c +++ b/drivers/block/via82cxxx.c @@ -1,9 +1,10 @@ /* - * linux/drivers/block/via82cxxx.c Version 0.06 Dec. 13, 1999 + * linux/drivers/block/via82cxxx.c Version 0.07 Feb. 10, 2000 * - * Copyright (C) 1998-99 Michel Aubry, Maintainer - * Copyright (C) 1999 Jeff Garzik, MVP4 Support (jgarzik@mandrakesoft.com) - * Copyright (C) 1998-99 Andre Hedrick (andre@suse.com) + * Copyright (C) 1998-99 Michel Aubry, Maintainer + * Copyright (C) 1999 Jeff Garzik, MVP4 Support + * (jgarzik@mandrakesoft.com) + * Copyright (C) 1998-2000 Andre Hedrick (andre@suse.com) * May be copied or modified under the terms of the GNU General Public License * * The VIA MVP-4 is reported OK with UDMA. @@ -473,12 +474,6 @@ static int via_set_fifoconfig(ide_hwif_t *hwif) !(newfifo & 0x03) ? "1" : (!(newfifo & 0x02) ? "3/4" : (newfifo & 0x01) ? "1/4" : "1/2")); - -#if defined(DISPLAY_VIA_TIMINGS) && defined(CONFIG_PROC_FS) - via_proc = 1; - bmide_dev = hwif->pci_dev; - via_display_info = &via_get_info; -#endif /* DISPLAY_VIA_TIMINGS && CONFIG_PROC_FS*/ return 0; } @@ -530,6 +525,12 @@ unsigned int __init pci_init_via82cxxx (struct pci_dev *dev, const char *name) printk("\n"); } +#if defined(DISPLAY_VIA_TIMINGS) && defined(CONFIG_PROC_FS) + via_proc = 1; + bmide_dev = dev; + via_display_info = &via_get_info; +#endif /* DISPLAY_VIA_TIMINGS && CONFIG_PROC_FS*/ + return 0; } @@ -555,7 +556,7 @@ void __init ide_init_via82cxxx (ide_hwif_t *hwif) } /* - * ide_dmacapable_via82c568(ide_hwif_t *, unsigned long) + * ide_dmacapable_via82cxxx(ide_hwif_t *, unsigned long) * checks if channel "channel" of if hwif is dma * capable or not, according to kernel command line, * and the new fifo settings. diff --git a/drivers/char/Config.in b/drivers/char/Config.in index c34978479..97e1f1f58 100644 --- a/drivers/char/Config.in +++ b/drivers/char/Config.in @@ -122,7 +122,8 @@ endmenu tristate '/dev/nvram support' CONFIG_NVRAM tristate 'Enhanced Real Time Clock Support' CONFIG_RTC -if [ "$CONFIG_ALPHA_BOOK1" = "y" ]; then +bool 'EFI Real Time Clock Services' CONFIG_EFI_RTC +if [ "$CONFIG_OBSOLETE" = "y" -a "$CONFIG_ALPHA_BOOK1" = "y" ]; then bool 'Tadpole ANA H8 Support' CONFIG_H8 fi diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 4667e1fa3..7f3c6133b 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -158,13 +158,17 @@ obj-$(CONFIG_ADBMOUSE) += adbmouse.o busmouse.o obj-$(CONFIG_PC110_PAD) += pc110pad.o obj-$(CONFIG_WDT) += wdt.o obj-$(CONFIG_RTC) += rtc.o +obj-$(CONFIG_EFI_RTC) += efirtc.o ifeq ($(CONFIG_PPC),) obj-$(CONFIG_NVRAM) += nvram.o endif -obj-$(CONFIG_I810_RNG) += i810_rng.o obj-$(CONFIG_VIDEO_DEV) += videodev.o +obj-$(CONFIG_21825_WATCHDOG) += wdt285.o +obj-$(CONFIG_977_WATCHDOG) += wdt977.o +obj-$(CONFIG_DS1620) += ds1620.o + # # for external dependencies in arm/config.in and video/config.in # @@ -205,7 +209,7 @@ ifeq ($(CONFIG_I2C_PARPORT),y) L_I2C = y else ifeq ($(CONFIG_I2C_PARPORT),m) - M_I2C = y + L_I2C = m endif endif @@ -277,6 +281,13 @@ ifeq ($(CONFIG_DZ),y) L_OBJS += dz.o endif +obj-$(CONFIG_NWBUTTON) += nwbutton.o +obj-$(CONFIG_NWFLASH) += nwflash.o + +ifeq ($(CONFIG_DZ),y) + L_OBJS += dz.o +endif + ifeq ($(CONFIG_DRM),y) SUB_DIRS += drm ALL_SUB_DIRS += drm diff --git a/drivers/char/agp/agpgart_be.c b/drivers/char/agp/agpgart_be.c index a21556a2b..c478395f8 100644 --- a/drivers/char/agp/agpgart_be.c +++ b/drivers/char/agp/agpgart_be.c @@ -1397,8 +1397,6 @@ static int __init sis_generic_setup (struct pci_dev *pdev) agp_bridge.free_by_type = agp_generic_free_by_type; return 0; - - (void) pdev; /* unused */ } #endif /* CONFIG_AGP_SIS */ diff --git a/drivers/char/ds1620.c b/drivers/char/ds1620.c new file mode 100644 index 000000000..e3a37611d --- /dev/null +++ b/drivers/char/ds1620.c @@ -0,0 +1,436 @@ +/* + * linux/drivers/char/ds1620.c: Dallas Semiconductors DS1620 + * thermometer driver (as used in the Rebel.com NetWinder) + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#ifdef CONFIG_PROC_FS +/* define for /proc interface */ +#define THERM_USE_PROC +#endif + +/* Definitions for DS1620 chip */ +#define THERM_START_CONVERT 0xee +#define THERM_RESET 0xaf +#define THERM_READ_CONFIG 0xac +#define THERM_READ_TEMP 0xaa +#define THERM_READ_TL 0xa2 +#define THERM_READ_TH 0xa1 +#define THERM_WRITE_CONFIG 0x0c +#define THERM_WRITE_TL 0x02 +#define THERM_WRITE_TH 0x01 + +#define CFG_CPU 2 +#define CFG_1SHOT 1 + +static const char *fan_state[] = { "off", "on", "on (hardwired)" }; + +/* + * Start of NetWinder specifics + * Note! We have to hold the gpio lock with IRQs disabled over the + * whole of our transaction to the Dallas chip, since there is a + * chance that the WaveArtist driver could touch these bits to + * enable or disable the speaker. + */ +extern spinlock_t gpio_lock; +extern unsigned int system_rev; + +static inline void netwinder_ds1620_set_clk(int clk) +{ + gpio_modify_op(GPIO_DSCLK, clk ? GPIO_DSCLK : 0); +} + +static inline void netwinder_ds1620_set_data(int dat) +{ + gpio_modify_op(GPIO_DATA, dat ? GPIO_DATA : 0); +} + +static inline int netwinder_ds1620_get_data(void) +{ + return gpio_read() & GPIO_DATA; +} + +static inline void netwinder_ds1620_set_data_dir(int dir) +{ + gpio_modify_io(GPIO_DATA, dir ? GPIO_DATA : 0); +} + +static inline void netwinder_ds1620_reset(void) +{ + cpld_modify(CPLD_DS_ENABLE, 0); + cpld_modify(CPLD_DS_ENABLE, CPLD_DS_ENABLE); +} + +static inline void netwinder_lock(unsigned long *flags) +{ + spin_lock_irqsave(&gpio_lock, *flags); +} + +static inline void netwinder_unlock(unsigned long *flags) +{ + spin_unlock_irqrestore(&gpio_lock, *flags); +} + +static inline void netwinder_set_fan(int i) +{ + unsigned long flags; + + spin_lock_irqsave(&gpio_lock, flags); + gpio_modify_op(GPIO_FAN, i ? GPIO_FAN : 0); + spin_unlock_irqrestore(&gpio_lock, flags); +} + +static inline int netwinder_get_fan(void) +{ + if ((system_rev & 0xf000) == 0x4000) + return FAN_ALWAYS_ON; + + return (gpio_read() & GPIO_FAN) ? FAN_ON : FAN_OFF; +} + +/* + * End of NetWinder specifics + */ + +static void ds1620_send_bits(int nr, int value) +{ + int i; + + for (i = 0; i < nr; i++) { + netwinder_ds1620_set_data(value & 1); + netwinder_ds1620_set_clk(0); + udelay(1); + netwinder_ds1620_set_clk(1); + udelay(1); + + value >>= 1; + } +} + +static unsigned int ds1620_recv_bits(int nr) +{ + unsigned int value = 0, mask = 1; + int i; + + netwinder_ds1620_set_data(0); + + for (i = 0; i < nr; i++) { + netwinder_ds1620_set_clk(0); + udelay(1); + + if (netwinder_ds1620_get_data()) + value |= mask; + + mask <<= 1; + + netwinder_ds1620_set_clk(1); + udelay(1); + } + + return value; +} + +static void ds1620_out(int cmd, int bits, int value) +{ + unsigned long flags; + + netwinder_lock(&flags); + netwinder_ds1620_set_clk(1); + netwinder_ds1620_set_data_dir(0); + netwinder_ds1620_reset(); + + udelay(1); + + ds1620_send_bits(8, cmd); + if (bits) + ds1620_send_bits(bits, value); + + udelay(1); + + netwinder_ds1620_reset(); + netwinder_unlock(&flags); + + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(2); +} + +static unsigned int ds1620_in(int cmd, int bits) +{ + unsigned long flags; + unsigned int value; + + netwinder_lock(&flags); + netwinder_ds1620_set_clk(1); + netwinder_ds1620_set_data_dir(0); + netwinder_ds1620_reset(); + + udelay(1); + + ds1620_send_bits(8, cmd); + + netwinder_ds1620_set_data_dir(1); + value = ds1620_recv_bits(bits); + + netwinder_ds1620_reset(); + netwinder_unlock(&flags); + + return value; +} + +static int cvt_9_to_int(unsigned int val) +{ + if (val & 0x100) + val |= 0xfffffe00; + + return val; +} + +static void ds1620_write_state(struct therm *therm) +{ + ds1620_out(THERM_WRITE_CONFIG, 8, CFG_CPU); + ds1620_out(THERM_WRITE_TL, 9, therm->lo); + ds1620_out(THERM_WRITE_TH, 9, therm->hi); + ds1620_out(THERM_START_CONVERT, 0, 0); +} + +static void ds1620_read_state(struct therm *therm) +{ + therm->lo = cvt_9_to_int(ds1620_in(THERM_READ_TL, 9)); + therm->hi = cvt_9_to_int(ds1620_in(THERM_READ_TH, 9)); +} + +static ssize_t +ds1620_read(struct file *file, char *buf, size_t count, loff_t *ptr) +{ + signed int cur_temp; + signed char cur_temp_degF; + + /* Can't seek (pread) on this device */ + if (ptr != &file->f_pos) + return -ESPIPE; + + cur_temp = cvt_9_to_int(ds1620_in(THERM_READ_TEMP, 9)) >> 1; + + /* convert to Fahrenheit, as per wdt.c */ + cur_temp_degF = (cur_temp * 9) / 5 + 32; + + if (copy_to_user(buf, &cur_temp_degF, 1)) + return -EFAULT; + + return 1; +} + +static int +ds1620_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + struct therm therm; + int i; + + switch(cmd) { + case CMD_SET_THERMOSTATE: + case CMD_SET_THERMOSTATE2: + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (cmd == CMD_SET_THERMOSTATE) { + if (get_user(therm.hi, (int *)arg)) + return -EFAULT; + therm.lo = therm.hi - 3; + } else { + if (copy_from_user(&therm, (void *)arg, sizeof(therm))) + return -EFAULT; + } + + therm.lo <<= 1; + therm.hi <<= 1; + + ds1620_write_state(&therm); + break; + + case CMD_GET_THERMOSTATE: + case CMD_GET_THERMOSTATE2: + ds1620_read_state(&therm); + + therm.lo >>= 1; + therm.hi >>= 1; + + if (cmd == CMD_GET_THERMOSTATE) { + if (put_user(therm.hi, (int *)arg)) + return -EFAULT; + } else { + if (copy_to_user((void *)arg, &therm, sizeof(therm))) + return -EFAULT; + } + break; + + case CMD_GET_TEMPERATURE: + case CMD_GET_TEMPERATURE2: + i = cvt_9_to_int(ds1620_in(THERM_READ_TEMP, 9)); + + if (cmd == CMD_GET_TEMPERATURE) + i >>= 1; + + return put_user(i, (int *)arg) ? -EFAULT : 0; + + case CMD_GET_STATUS: + i = ds1620_in(THERM_READ_CONFIG, 8) & 0xe3; + + return put_user(i, (int *)arg) ? -EFAULT : 0; + + case CMD_GET_FAN: + i = netwinder_get_fan(); + + return put_user(i, (int *)arg) ? -EFAULT : 0; + + case CMD_SET_FAN: + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (get_user(i, (int *)arg)) + return -EFAULT; + + netwinder_set_fan(i); + break; + + default: + return -ENOIOCTLCMD; + } + + return 0; +} + +static int +ds1620_open(struct inode *inode, struct file *file) +{ + MOD_INC_USE_COUNT; + + return 0; +} + +static int +ds1620_release(struct inode *inode, struct file *file) +{ + MOD_DEC_USE_COUNT; + + return 0; +} + +#ifdef THERM_USE_PROC +static int +proc_therm_ds1620_read(char *buf, char **start, off_t offset, + int len, int *eof, void *unused) +{ + struct therm th; + int temp; + + ds1620_read_state(&th); + temp = cvt_9_to_int(ds1620_in(THERM_READ_TEMP, 9)); + + len = sprintf(buf, "Thermostat: HI %i.%i, LOW %i.%i; " + "temperature: %i.%i C, fan %s\n", + th.hi >> 1, th.hi & 1 ? 5 : 0, + th.lo >> 1, th.lo & 1 ? 5 : 0, + temp >> 1, temp & 1 ? 5 : 0, + fan_state[netwinder_get_fan()]); + + return len; +} + +static struct proc_dir_entry *proc_therm_ds1620; +#endif + +static struct file_operations ds1620_fops = { + NULL, /* lseek */ + ds1620_read, /* read */ + NULL, /* write */ + NULL, /* readdir */ + NULL, /* select */ + ds1620_ioctl, /* ioctl */ + NULL, /* mmap */ + ds1620_open, /* open */ + NULL, /* flush */ + ds1620_release, /* release */ + NULL, /* fsync */ + NULL, /* fasync */ +}; + +static struct miscdevice ds1620_miscdev = { + TEMP_MINOR, + "temp", + &ds1620_fops +}; + +int __init ds1620_init(void) +{ + int ret; + struct therm th, th_start; + + if (!machine_is_netwinder()) + return -ENODEV; + + ds1620_out(THERM_RESET, 0, 0); + ds1620_out(THERM_WRITE_CONFIG, 8, CFG_CPU); + ds1620_out(THERM_START_CONVERT, 0, 0); + + /* + * Trigger the fan to start by setting + * temperature high point low. This kicks + * the fan into action. + */ + ds1620_read_state(&th); + th_start.lo = 0; + th_start.hi = 1; + ds1620_write_state(&th_start); + + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(2*HZ); + + ds1620_write_state(&th); + + ret = misc_register(&ds1620_miscdev); + if (ret < 0) + return ret; + +#ifdef THERM_USE_PROC + proc_therm_ds1620 = create_proc_entry("therm", 0, 0); + if (proc_therm_ds1620) + proc_therm_ds1620->read_proc = proc_therm_ds1620_read; + else + printk(KERN_ERR "therm: unable to register /proc/therm\n"); +#endif + + ds1620_read_state(&th); + ret = cvt_9_to_int(ds1620_in(THERM_READ_TEMP, 9)); + + printk(KERN_INFO "Thermostat: high %i.%i, low %i.%i, " + "current %i.%i C, fan %s.\n", + th.hi >> 1, th.hi & 1 ? 5 : 0, + th.lo >> 1, th.lo & 1 ? 5 : 0, + ret >> 1, ret & 1 ? 5 : 0, + fan_state[netwinder_get_fan()]); + + return 0; +} + +void __exit ds1620_exit(void) +{ +#ifdef THERM_USE_PROC + remove_proc_entry("therm", NULL); +#endif + misc_deregister(&ds1620_miscdev); +} + +module_init(ds1620_init); +module_exit(ds1620_exit); diff --git a/drivers/char/efirtc.c b/drivers/char/efirtc.c index 391cfcfc0..0f26dedd9 100644 --- a/drivers/char/efirtc.c +++ b/drivers/char/efirtc.c @@ -334,6 +334,7 @@ efi_rtc_read_proc(char *page, char **start, off_t off, if (len<0) len = 0; return len; } + static int __init efi_rtc_init(void) { @@ -345,6 +346,7 @@ efi_rtc_init(void) return 0; } + static int __exit efi_rtc_exit(void) { diff --git a/drivers/char/h8.c b/drivers/char/h8.c index 0583923d9..acc898cb8 100644 --- a/drivers/char/h8.c +++ b/drivers/char/h8.c @@ -6,6 +6,8 @@ * * Fixes: * June 1999, AV added releasing /proc/driver/h8 + * Feb 2000, Borislav Deianov + * changed queues to use list.h instead of lists.h */ #include @@ -23,7 +25,7 @@ #include #include #include -#include +#include #include #include #include @@ -52,18 +54,13 @@ /* * Forward declarations. */ -int h8_init(void); +static int h8_init(void); int h8_display_blank(void); int h8_display_unblank(void); static void h8_intr(int irq, void *dev_id, struct pt_regs *regs); -#ifdef CONFIG_PROC_FS static int h8_get_info(char *, char **, off_t, int); -#else -static int h8_get_info(char *, char **, off_t, int) {} -#error "Somebody needs to learn C. Badly." -#endif /* * Support Routines. @@ -141,7 +138,9 @@ unsigned int h8_state = H8_IDLE; unsigned int h8_index = -1; unsigned int h8_enabled = 0; -queue_head_t h8_actq, h8_cmdq, h8_freeq; +LIST_HEAD(h8_actq); +LIST_HEAD(h8_cmdq); +LIST_HEAD(h8_freeq); /* * Globals used in thermal control of Alphabook1. @@ -170,7 +169,7 @@ int speed_tab[6] = {230, 153, 115, 57, 28, 14}; static void h8_intr(int irq, void *dev_id, struct pt_regs *regs) { u_char stat_reg, data_reg; - h8_cmd_q_t *qp = (h8_cmd_q_t *)QUEUE_FIRST(&h8_actq, link); + h8_cmd_q_t *qp = list_entry(h8_actq.next, h8_cmd_q_t, link); stat_reg = H8_GET_STATUS; data_reg = H8_READ_DATA; @@ -260,7 +259,7 @@ static void h8_intr(int irq, void *dev_id, struct pt_regs *regs) return; } else if (data_reg == H8_SYNC_BYTE) { h8_state = H8_IDLE; - if (!QUEUE_IS_EMPTY(&h8_actq, link)) + if (!list_empty(&h8_actq)) h8_send_next_cmd_byte(); } else { Dprintk ("h8_intr: resync unknown data 0x%x \n", data_reg); @@ -276,10 +275,10 @@ static void h8_intr(int irq, void *dev_id, struct pt_regs *regs) /* If command reception finished. */ if (qp->cnt == qp->nrsp) { h8_state = H8_IDLE; - QUEUE_REMOVE(&h8_actq, qp, link); + list_del(&qp->link); h8_cmd_done (qp); /* More commands to send over? */ - if (!QUEUE_IS_EMPTY(&h8_cmdq, link)) + if (!list_empty(&h8_cmdq)) h8_start_new_cmd(); } return; @@ -317,9 +316,6 @@ static int __init h8_init(void) misc_register(&h8_device); request_region(h8_base, 8, "h8"); - QUEUE_INIT(&h8_actq, link, h8_cmd_q_t *); - QUEUE_INIT(&h8_cmdq, link, h8_cmd_q_t *); - QUEUE_INIT(&h8_freeq, link, h8_cmd_q_t *); h8_alloc_queues(); h8_hw_init(); @@ -364,9 +360,9 @@ static void __init h8_hw_init(void) return; } -#ifdef CONFIG_PROC_FS static int h8_get_info(char *buf, char **start, off_t fpos, int length) { +#ifdef CONFIG_PROC_FS char *p; if (!h8_enabled) @@ -387,8 +383,10 @@ static int h8_get_info(char *buf, char **start, off_t fpos, int length) ); return p - buf; -} +#else + return 0; #endif +} /* Called from console driver -- must make sure h8_enabled. */ int h8_display_blank(void) @@ -440,7 +438,7 @@ h8_alloc_queues(void) save_flags(flags); cli(); for (i = 0; i < H8_Q_ALLOC_AMOUNT; i++) { /* place each at front of freeq */ - QUEUE_ENTER(&h8_freeq, &qp[i], link, h8_cmd_q_t *); + list_add(&qp[i].link, &h8_freeq); } restore_flags(flags); return (1); @@ -458,15 +456,15 @@ h8_q_cmd(u_char *cmd, int cmd_size, int resp_size) /* get cmd buf */ save_flags(flags); cli(); - while (QUEUE_IS_EMPTY(&h8_freeq, link)) { + while (list_empty(&h8_freeq)) { Dprintk("H8: need to allocate more cmd buffers\n"); restore_flags(flags); h8_alloc_queues(); save_flags(flags); cli(); } /* get first element from queue */ - qp = (h8_cmd_q_t *)QUEUE_FIRST(&h8_freeq, link); - QUEUE_REMOVE(&h8_freeq, qp, link); + qp = list_entry(h8_freeq.next, h8_cmd_q_t, link); + list_del(&qp->link); restore_flags(flags); @@ -479,7 +477,8 @@ h8_q_cmd(u_char *cmd, int cmd_size, int resp_size) /* queue it at the end of the cmd queue */ save_flags(flags); cli(); - QUEUE_ENTER(&h8_cmdq, qp, link, h8_cmd_q_t *); + /* XXX this actually puts it at the start of cmd queue, bug? */ + list_add(&qp->link, &h8_cmdq); restore_flags(flags); @@ -500,13 +499,13 @@ h8_start_new_cmd(void) return; } - if (!QUEUE_IS_EMPTY(&h8_actq, link)) { + if (!list_empty(&h8_actq)) { Dprintk("h8_start_new_cmd: inconsistency: IDLE with non-empty active queue!\n"); restore_flags(flags); return; } - if (QUEUE_IS_EMPTY(&h8_cmdq, link)) { + if (list_empty(&h8_cmdq)) { Dprintk("h8_start_new_cmd: no command to dequeue\n"); restore_flags(flags); return; @@ -515,9 +514,10 @@ h8_start_new_cmd(void) * Take first command off of the command queue and put * it on the active queue. */ - qp = (h8_cmd_q_t *) QUEUE_FIRST(&h8_cmdq, link); - QUEUE_REMOVE(&h8_cmdq, qp, link); - QUEUE_ENTER(&h8_actq, qp, link, h8_cmd_q_t *); + qp = list_entry(h8_cmdq.next, h8_cmd_q_t, link); + list_del(&qp->link); + /* XXX should this go to the end of the active queue? */ + list_add(&qp->link, &h8_actq); h8_state = H8_XMIT; if (h8_debug & 0x1) Dprintk("h8_start_new_cmd: Starting a command\n"); @@ -532,7 +532,7 @@ h8_start_new_cmd(void) void h8_send_next_cmd_byte(void) { - h8_cmd_q_t *qp = (h8_cmd_q_t *)QUEUE_FIRST(&h8_actq, link); + h8_cmd_q_t *qp = list_entry(h8_actq.next, h8_cmd_q_t, link); int cnt; cnt = qp->cnt; @@ -689,7 +689,7 @@ h8_cmd_done(h8_cmd_q_t *qp) if (h8_debug & 0x40000) printk("H8: Sync command done - byte returned was 0x%x\n", qp->rcvbuf[0]); - QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *); + list_add(&qp->link, &h8_freeq); break; case H8_RD_SN: @@ -697,7 +697,7 @@ h8_cmd_done(h8_cmd_q_t *qp) printk("H8: read Ethernet address: command done - address: %x - %x - %x - %x - %x - %x \n", qp->rcvbuf[0], qp->rcvbuf[1], qp->rcvbuf[2], qp->rcvbuf[3], qp->rcvbuf[4], qp->rcvbuf[5]); - QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *); + list_add(&qp->link, &h8_freeq); break; case H8_RD_HW_VER: @@ -705,13 +705,13 @@ h8_cmd_done(h8_cmd_q_t *qp) case H8_RD_MAX_TEMP: printk("H8: Max recorded CPU temp %d, Sys temp %d\n", qp->rcvbuf[0], qp->rcvbuf[1]); - QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *); + list_add(&qp->link, &h8_freeq); break; case H8_RD_MIN_TEMP: printk("H8: Min recorded CPU temp %d, Sys temp %d\n", qp->rcvbuf[0], qp->rcvbuf[1]); - QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *); + list_add(&qp->link, &h8_freeq); break; case H8_RD_CURR_TEMP: @@ -719,7 +719,7 @@ h8_cmd_done(h8_cmd_q_t *qp) xx.byte[0] = qp->rcvbuf[0]; xx.byte[1] = qp->rcvbuf[1]; wake_up(&h8_sync_wait); - QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *); + list_add(&qp->link, &h8_freeq); break; case H8_RD_SYS_VARIENT: @@ -740,7 +740,7 @@ h8_cmd_done(h8_cmd_q_t *qp) xx.byte[0] = qp->rcvbuf[1]; h8_sync_channel |= H8_GET_EXT_STATUS; wake_up(&h8_sync_wait); - QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *); + list_add(&qp->link, &h8_freeq); break; case H8_RD_USER_CFG: @@ -755,7 +755,7 @@ h8_cmd_done(h8_cmd_q_t *qp) case H8_RD_INT_BATT_STATUS: printk("H8: Read int batt status cmd done - returned was %x %x %x\n", qp->rcvbuf[0], qp->rcvbuf[1], qp->rcvbuf[2]); - QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *); + list_add(&qp->link, &h8_freeq); break; case H8_RD_EXT_BATT_STATUS: @@ -767,7 +767,7 @@ h8_cmd_done(h8_cmd_q_t *qp) printk("H8: Device control cmd done - byte returned was 0x%x\n", qp->rcvbuf[0]); } - QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *); + list_add(&qp->link, &h8_freeq); break; case H8_CTL_TFT_BRT_DC: @@ -788,7 +788,7 @@ h8_cmd_done(h8_cmd_q_t *qp) XDprintk("H8: ctl upper thermal thresh cmd done - returned was %d\n", qp->rcvbuf[0]); } - QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *); + list_add(&qp->link, &h8_freeq); break; case H8_CTL_LOWER_TEMP: diff --git a/drivers/char/h8.h b/drivers/char/h8.h index b59aadea8..986eef591 100644 --- a/drivers/char/h8.h +++ b/drivers/char/h8.h @@ -229,7 +229,7 @@ struct h8_data { * H8 command buffers */ typedef struct h8_cmd_q { - DLNODE(struct h8_cmd_q) link; /* double linked list */ + struct list_head link; /* double linked list */ int ncmd; /* number of bytes in command */ int nrsp; /* number of bytes in response */ int cnt; /* number of bytes sent/received */ @@ -238,10 +238,6 @@ typedef struct h8_cmd_q { u_char rcvbuf[H8_MAX_CMD_SIZE]; /* buffer to store response */ } h8_cmd_q_t; -typedef struct __queue_head { - DLNODE(struct h8_cmd_q) link; -} queue_head_t; - union intr_buf { u_char byte[2]; u_int word; diff --git a/drivers/char/lp.c b/drivers/char/lp.c index bb00a32fa..fcf0644ff 100644 --- a/drivers/char/lp.c +++ b/drivers/char/lp.c @@ -783,13 +783,13 @@ int __init lp_init (void) return -EIO; } + devfs_handle = devfs_mk_dir (NULL, "printers", 0, NULL); + if (parport_register_driver (&lp_driver)) { printk ("lp: unable to register with parport\n"); return -EIO; } - devfs_handle = devfs_mk_dir (NULL, "printers", 0, NULL); - if (!lp_count) { printk (KERN_INFO "lp: driver loaded but no devices found\n"); #ifndef CONFIG_PARPORT_1284 diff --git a/drivers/char/mem.c b/drivers/char/mem.c index e70860ea9..824ef94e4 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -5,6 +5,7 @@ * * Added devfs support. * Jan-11-1998, C. Scott Ananian + * Shared /dev/zero mmaping support, Feb 2000, Kanoj Sarcar */ #include @@ -285,8 +286,7 @@ static ssize_t write_kmem(struct file * file, const char * buf, return do_write_mem(file, (void*)p, p, buf, count, ppos); } -#if (!defined(CONFIG_PPC) && !defined(__mc68000__) && !defined(__mips__)) || \ - defined(CONFIG_HAVE_IO_PORTS) +#if (!defined(__mc68000__) && !defined(__mips__)) || defined(CONFIG_HAVE_IO_PORTS) static ssize_t read_port(struct file * file, char * buf, size_t count, loff_t *ppos) { @@ -435,7 +435,7 @@ out: static int mmap_zero(struct file * file, struct vm_area_struct * vma) { if (vma->vm_flags & VM_SHARED) - return -EINVAL; + return map_zero_setup(vma); if (zeromap_page_range(vma->vm_start, vma->vm_end - vma->vm_start, vma->vm_page_prot)) return -EAGAIN; return 0; @@ -515,8 +515,7 @@ static struct file_operations null_fops = { write: write_null, }; -#if (!defined(CONFIG_PPC) && !defined(__mc68000__) && !defined(__mips__)) || \ - defined(CONFIG_HAVE_IO_PORTS) +#if (!defined(__mc68000__) && !defined(__mips__)) || defined(CONFIG_HAVE_IO_PORTS) static struct file_operations port_fops = { llseek: memory_lseek, read: read_port, @@ -550,8 +549,7 @@ static int memory_open(struct inode * inode, struct file * filp) case 3: filp->f_op = &null_fops; break; -#if (!defined(CONFIG_PPC) && !defined(__mc68000__) && !defined(__mips__)) || \ - defined(CONFIG_HAVE_IO_PORTS) +#if (!defined(__mc68000__) && !defined(__mips__)) || defined(CONFIG_HAVE_IO_PORTS) case 4: filp->f_op = &port_fops; break; diff --git a/drivers/char/nwbutton.c b/drivers/char/nwbutton.c new file mode 100644 index 000000000..7c9bafc3b --- /dev/null +++ b/drivers/char/nwbutton.c @@ -0,0 +1,276 @@ +/* + * NetWinder Button Driver- + * Copyright (C) Alex Holden 1998, 1999. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#define __NWBUTTON_C /* Tell the header file who we are */ +#include "nwbutton.h" + +static int button_press_count = 0; /* The count of button presses */ +static struct timer_list button_timer; /* Times for the end of a sequence */ +static DECLARE_WAIT_QUEUE_HEAD(button_wait_queue); /* Used for blocking read */ +static char button_output_buffer[32]; /* Stores data to write out of device */ +static int bcount = 0; /* The number of bytes in the buffer */ +static int bdelay = BUTTON_DELAY; /* The delay, in jiffies */ +static struct button_callback button_callback_list[32]; /* The callback list */ +static int callback_count = 0; /* The number of callbacks registered */ +static int reboot_count = NUM_PRESSES_REBOOT; /* Number of presses to reboot */ + +/* + * This function is called by other drivers to register a callback function + * to be called when a particular number of button presses occurs. + * The callback list is a static array of 32 entries (I somehow doubt many + * people are ever going to want to register more than 32 different actions + * to be performed by the kernel on different numbers of button presses ;). + * However, if an attempt to register a 33rd entry (perhaps a stuck loop + * somewhere registering the same entry over and over?) it will fail to + * do so and return -ENOMEM. If an attempt is made to register a null pointer, + * it will fail to do so and return -EINVAL. + * Because callbacks can be unregistered at random the list can become + * fragmented, so we need to search through the list until we find the first + * free entry. + */ + +int button_add_callback (void (*callback) (void), int count) +{ + int lp = 0; + if (callback_count == 32) { + return -ENOMEM; + } + if (!callback) { + return -EINVAL; + } + callback_count++; + for (; (button_callback_list [lp].callback); lp++); + button_callback_list [lp].callback = callback; + button_callback_list [lp].count = count; + return 0; +} + +/* + * This function is called by other drivers to deregister a callback function. + * If you attempt to unregister a callback which does not exist, it will fail + * with -EINVAL. If there is more than one entry with the same address, + * because it searches the list from end to beginning, it will unregister the + * last one to be registered first (FILO- First In Last Out). + * Note that this is not neccessarily true if the entries are not submitted + * at the same time, because another driver could have unregistered a callback + * between the submissions creating a gap earlier in the list, which would + * be filled first at submission time. + */ + +int button_del_callback (void (*callback) (void)) +{ + int lp = 31; + if (!callback) { + return -EINVAL; + } + while (lp >= 0) { + if ((button_callback_list [lp].callback) == callback) { + button_callback_list [lp].callback = NULL; + button_callback_list [lp].count = 0; + callback_count--; + return 0; + }; + lp--; + }; + return -EINVAL; +} + +/* + * This function is called by button_sequence_finished to search through the + * list of callback functions, and call any of them whose count argument + * matches the current count of button presses. It starts at the beginning + * of the list and works up to the end. It will refuse to follow a null + * pointer (which should never happen anyway). + */ + +static void button_consume_callbacks (int bpcount) +{ + int lp = 0; + for (; lp <= 31; lp++) { + if ((button_callback_list [lp].count) == bpcount) { + if (button_callback_list [lp].callback) { + button_callback_list[lp].callback(); + } + } + } +} + +/* + * This function is called when the button_timer times out. + * ie. When you don't press the button for bdelay jiffies, this is taken to + * mean you have ended the sequence of key presses, and this function is + * called to wind things up (write the press_count out to /dev/button, call + * any matching registered function callbacks, initiate reboot, etc.). + */ + +static void button_sequence_finished (unsigned long parameters) +{ +#ifdef CONFIG_NWBUTTON_REBOOT /* Reboot using button is enabled */ + if (button_press_count == reboot_count) { + kill_proc (1, SIGINT, 1); /* Ask init to reboot us */ + } +#endif /* CONFIG_NWBUTTON_REBOOT */ + button_consume_callbacks (button_press_count); + bcount = sprintf (button_output_buffer, "%d\n", button_press_count); + button_press_count = 0; /* Reset the button press counter */ + wake_up_interruptible (&button_wait_queue); +} + +/* + * This handler is called when the orange button is pressed (GPIO 10 of the + * SuperIO chip, which maps to logical IRQ 26). If the press_count is 0, + * this is the first press, so it starts a timer and increments the counter. + * If it is higher than 0, it deletes the old timer, starts a new one, and + * increments the counter. + */ + +static void button_handler (int irq, void *dev_id, struct pt_regs *regs) +{ + if (button_press_count) { + del_timer (&button_timer); + } + button_press_count++; + init_timer (&button_timer); + button_timer.function = button_sequence_finished; + button_timer.expires = (jiffies + bdelay); + add_timer (&button_timer); +} + +/* + * This function is called when a user space program attempts to read + * /dev/nwbutton. It puts the device to sleep on the wait queue until + * button_sequence_finished writes some data to the buffer and flushes + * the queue, at which point it writes the data out to the device and + * returns the number of characters it has written. This function is + * reentrant, so that many processes can be attempting to read from the + * device at any one time. + */ + +static int button_read (struct file *filp, char *buffer, + size_t count, loff_t *ppos) +{ + interruptible_sleep_on (&button_wait_queue); + return (copy_to_user (buffer, &button_output_buffer, bcount)) + ? -EFAULT : bcount; +} + +/* + * This function is called when a user space process attempts to open the + * device. If the driver is compiled into the kernel it does nothing but + * succeed, but if it is compiled in as a module it also increments the + * module usage count to prevent the module from being removed whilst a + * process has the device open. + */ + +static int button_open (struct inode *inode, struct file *filp) +{ + MOD_INC_USE_COUNT; + return 0; +} + +/* + * This function is called when a user space process attempts to close the + * device. If the driver is compiled into the kernel it does nothing at all, + * but if it is compiled in as a module it also decrements the module usage + * count so that it will be possible to unload the module again once all the + * user processes have closed the device. + */ + +static int button_release (struct inode *inode, struct file *filp) +{ + MOD_DEC_USE_COUNT; + return 0; +} + +/* + * This structure is the file operations structure, which specifies what + * callbacks functions the kernel should call when a user mode process + * attempts to perform these operations on the device. + */ + +static struct file_operations button_fops = { + NULL, /* lseek */ + button_read, + NULL, /* write */ + NULL, /* readdir */ + NULL, /* select */ + NULL, /* ioctl */ + NULL, /* mmap */ + button_open, + NULL, /* flush */ + button_release, +}; + +/* + * This structure is the misc device structure, which specifies the minor + * device number (158 in this case), the name of the device (for /proc/misc), + * and the address of the above file operations structure. + */ + +static struct miscdevice button_misc_device = { + BUTTON_MINOR, + "nwbutton", + &button_fops, +}; + +/* + * This function is called to initialise the driver, either from misc.c at + * bootup if the driver is compiled into the kernel, or from init_module + * below at module insert time. It attempts to register the device node + * and the IRQ and fails with a warning message if either fails, though + * neither ever should because the device number and IRQ are unique to + * this driver. + */ + +static int __init nwbutton_init(void) +{ + if (!machine_is_netwinder()) + return -ENODEV; + + printk (KERN_INFO "NetWinder Button Driver Version %s (C) Alex Holden " + " 1998.\n", VERSION); + + if (misc_register (&button_misc_device)) { + printk (KERN_WARNING "nwbutton: Couldn't register device 10, " + "%d.\n", BUTTON_MINOR); + return -EBUSY; + } + + if (request_irq (IRQ_NETWINDER_BUTTON, button_handler, SA_INTERRUPT, + "nwbutton", NULL)) { + printk (KERN_WARNING "nwbutton: IRQ %d is not free.\n", + IRQ_NETWINDER_BUTTON); + misc_deregister (&button_misc_device); + return -EIO; + } + return 0; +} + +static void __exit nwbutton_exit (void) +{ + free_irq (IRQ_NETWINDER_BUTTON, NULL); + misc_deregister (&button_misc_device); +} + +EXPORT_NO_SYMBOLS; + +module_init(nwbutton_init); +module_exit(nwbutton_exit); diff --git a/drivers/char/nwbutton.h b/drivers/char/nwbutton.h new file mode 100644 index 000000000..ba5067443 --- /dev/null +++ b/drivers/char/nwbutton.h @@ -0,0 +1,48 @@ +#ifndef __NWBUTTON_H +#define __NWBUTTON_H + +/* + * NetWinder Button Driver- + * Copyright (C) Alex Holden 1998, 1999. + */ + +#ifdef __NWBUTTON_C /* Actually compiling the driver itself */ + +/* Various defines: */ + +#define NUM_PRESSES_REBOOT 2 /* How many presses to activate shutdown */ +#define BUTTON_DELAY 30 /* How many jiffies for sequence to end */ +#define VERSION "0.3" /* Driver version number */ +#define BUTTON_MINOR 158 /* Major 10, Minor 158, /dev/nwbutton */ + +/* Structure definitions: */ + +struct button_callback { + void (*callback) (void); + int count; +}; + +/* Function prototypes: */ + +static void button_sequence_finished (unsigned long parameters); +static void button_handler (int irq, void *dev_id, struct pt_regs *regs); +static int button_read (struct file *filp, char *buffer, + size_t count, loff_t *ppos); +static int button_open (struct inode *inode, struct file *filp); +static int button_release (struct inode *inode, struct file *filp); +int button_init (void); +int button_add_callback (void (*callback) (void), int count); +int button_del_callback (void (*callback) (void)); +static void button_consume_callbacks (int bpcount); +#ifdef MODULE +int init_module (void); +void cleanup_module (void); +#endif /* MODULE */ + +#else /* Not compiling the driver itself */ + +extern int button_add_callback (void (*callback) (void), int count); +extern int button_del_callback (void (*callback) (void)); + +#endif /* __NWBUTTON_C */ +#endif /* __NWBUTTON_H */ diff --git a/drivers/char/nwflash.c b/drivers/char/nwflash.c new file mode 100644 index 000000000..a905be058 --- /dev/null +++ b/drivers/char/nwflash.c @@ -0,0 +1,708 @@ +/* + * Flash memory interface rev.5 driver for the Intel + * Flash chips used on the NetWinder. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/*****************************************************************************/ +#include + +//#define MINIKERNEL 1 //export flash write, erase routines for MiniKernel + +#ifndef MINIKERNEL +#define MSTATIC static +#else +#define MSTATIC +#endif + +#define NWFLASH_VERSION "6.2" + +MSTATIC void kick_open(void); +MSTATIC int get_flash_id(void); +MSTATIC int erase_block(int nBlock); +MSTATIC int write_block(unsigned long p, const char *buf, int count); +static int open_flash(struct inode *inodep, struct file *filep); +static int release_flash(struct inode *inodep, struct file *filep); +static int flash_ioctl(struct inode *inodep, struct file *filep, unsigned int cmd, unsigned long arg); +static ssize_t flash_read(struct file *file, char *buf, size_t count, loff_t * ppos); +static ssize_t flash_write(struct file *file, const char *buf, size_t count, loff_t * ppos); +static long long flash_llseek(struct file *file, long long offset, int orig); + +#define KFLASH_SIZE 1024*1024 //1 Meg +#define KFLASH_SIZE4 4*1024*1024 //4 Meg +#define KFLASH_ID 0x89A6 //Intel flash +#define KFLASH_ID4 0xB0D4 //Intel flash 4Meg + +static int flashdebug = 0; //if set - we will display progress msgs + +static int gbWriteEnable = 0; +static int gbWriteBase64Enable = 0; +MSTATIC int gbFlashSize = KFLASH_SIZE; + +extern spinlock_t gpio_lock; + +static struct file_operations flash_fops = +{ + flash_llseek, /* llseek */ + flash_read, /* read */ + flash_write, /* write */ + NULL, /* no special readdir */ + NULL, /* no special select */ + flash_ioctl, + NULL, /* no special mmap */ + open_flash, + NULL, /* no special flush */ + release_flash, + NULL, /* no special fsync */ + NULL, /* no special fasync */ + NULL, /* no special check_media_change */ + NULL /* no special revaldate */ +}; + +static struct miscdevice flash_miscdev = +{ + FLASH_MINOR, + "nwflash", + &flash_fops +}; + +/* + * the delay routine - it is often required to let the flash "breeze"... + */ +void flash_wait(int timeout) +{ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(timeout); +} + +MSTATIC int get_flash_id(void) +{ + volatile unsigned int c1, c2; + + /* + * try to get flash chip ID + */ + kick_open(); + c2 = inb(0x80); + *(unsigned char *) (FLASH_BASE + 0x8000) = 0x90; + udelay(15); + c1 = *(unsigned char *) FLASH_BASE; + c2 = inb(0x80); + + /* + * on 4 Meg flash the second byte is actually at offset 2... + */ + if (c1 == 0xB0) + c2 = *(unsigned char *) (FLASH_BASE + 2); + else + c2 = *(unsigned char *) (FLASH_BASE + 1); + + c2 += (c1 << 8); + + /* + * set it back to read mode + */ + *(unsigned char *) (FLASH_BASE + 0x8000) = 0xFF; + + if (c2 == KFLASH_ID4) + gbFlashSize = KFLASH_SIZE4; + + return c2; +} + +static int open_flash(struct inode *inodep, struct file *filep) +{ + int id; + + id = get_flash_id(); + if ((id != KFLASH_ID) && (id != KFLASH_ID4)) { + printk("Flash: incorrect ID 0x%04X.\n", id); + return -ENXIO; + } + MOD_INC_USE_COUNT; + + return 0; +} + + +static int release_flash(struct inode *inodep, struct file *filep) +{ + MOD_DEC_USE_COUNT; + return 0; +} + + +static int flash_ioctl(struct inode *inodep, struct file *filep, unsigned int cmd, unsigned long arg) +{ +// printk("Flash_ioctl: cmd = 0x%X.\n",cmd); + + switch (cmd) { + case CMD_WRITE_DISABLE: + gbWriteBase64Enable = 0; + gbWriteEnable = 0; + break; + + case CMD_WRITE_ENABLE: + gbWriteEnable = 1; + break; + + case CMD_WRITE_BASE64K_ENABLE: + gbWriteBase64Enable = 1; + break; + + default: + gbWriteBase64Enable = 0; + gbWriteEnable = 0; + return -EINVAL; + } + + return 0; +} + + + +static ssize_t flash_read(struct file *file, char *buf, size_t count, loff_t * ppos) +{ + unsigned long p = file->f_pos; + int read; + + if (flashdebug) + printk("Flash_dev: flash_read: offset=0x%X, buffer=0x%X, count=0x%X.\n", + (unsigned int) p, (unsigned int) buf, count); + + + if (count < 0) + return -EINVAL; + + if (count > gbFlashSize - p) + count = gbFlashSize - p; + + /* + * flash virtual address + */ + p += FLASH_BASE; + + read = 0; + + if (copy_to_user(buf, (void *) p, count)) + return -EFAULT; + read += count; + file->f_pos += read; + return read; +} + +static ssize_t flash_write(struct file *file, const char *buf, size_t count, loff_t * ppos) +{ + unsigned long p = file->f_pos; + int written; + int nBlock, temp, rc; + int i, j; + + + if (flashdebug) + printk("Flash_dev: flash_write: offset=0x%X, buffer=0x%X, count=0x%X.\n", + (unsigned int) p, (unsigned int) buf, count); + + if (!gbWriteEnable) + return -EINVAL; + + if (p < 64 * 1024 && (!gbWriteBase64Enable)) + return -EINVAL; + + if (count < 0) + return -EINVAL; + + /* + * if write size to big - error! + */ + if (count > gbFlashSize - p) + return -EINVAL; + + + if (verify_area(VERIFY_READ, buf, count)) + return -EFAULT; + + + written = 0; + + leds_event(led_claim); + leds_event(led_green_on); + + nBlock = (int) p >> 16; //block # of 64K bytes + + /* + * # of 64K blocks to erase and write + */ + temp = ((int) (p + count) >> 16) - nBlock + 1; + + /* + * write ends at exactly 64k boundry? + */ + if (((int) (p + count) & 0xFFFF) == 0) + temp -= 1; + + if (flashdebug) + printk("FlashWrite: writing %d block(s) starting at %d.\n", temp, nBlock); + + for (; temp; temp--, nBlock++) { + if (flashdebug) + printk("FlashWrite: erasing block %d.\n", nBlock); + + /* + * first we have to erase the block(s), where we will write... + */ + i = 0; + j = 0; + RetryBlock: + do { + rc = erase_block(nBlock); + i++; + } while (rc && i < 10); + + if (rc) { + if (flashdebug) + printk("FlashWrite: erase error %X. Aborting...\n", rc); + + break; + } + if (flashdebug) + printk("FlashWrite: writing offset %X, from buf %X, bytes left %X.\n", + (unsigned int) p, (unsigned int) buf, count - written); + + /* + * write_block will limit write to space left in this block + */ + rc = write_block(p, buf, count - written); + j++; + + /* + * if somehow write verify failed? Can't happen?? + */ + if (!rc) { + /* + * retry up to 10 times + */ + if (j < 10) + goto RetryBlock; + else + /* + * else quit with error... + */ + rc = -1; + + } + if (rc < 0) { + if (flashdebug) + printk("FlashWrite: write error %X. Aborting...\n", rc); + break; + } + p += rc; + buf += rc; + written += rc; + file->f_pos += rc; + + if (flashdebug) + printk("FlashWrite: written 0x%X bytes OK.\n", written); + } + + /* + * restore reg on exit + */ + leds_event(led_release); + + return written; +} + + +/* + * The memory devices use the full 32/64 bits of the offset, and so we cannot + * check against negative addresses: they are ok. The return value is weird, + * though, in that case (0). + * + * also note that seeking relative to the "end of file" isn't supported: + * it has no meaning, so it returns -EINVAL. + */ +static long long flash_llseek(struct file *file, long long offset, int orig) +{ + if (flashdebug) + printk("Flash_dev: flash_lseek, offset=0x%X, orig=0x%X.\n", + (unsigned int) offset, (unsigned int) orig); + + switch (orig) { + case 0: + if (offset < 0) + return -EINVAL; + + if ((unsigned int) offset > gbFlashSize) + return -EINVAL; + + file->f_pos = (unsigned int) offset; + return file->f_pos; + case 1: + if ((file->f_pos + offset) > gbFlashSize) + return -EINVAL; + if ((file->f_pos + offset) < 0) + return -EINVAL; + file->f_pos += offset; + return file->f_pos; + default: + return -EINVAL; + } +} + + +/* + * assume that main Write routine did the parameter checking... + * so just go ahead and erase, what requested! + */ + +MSTATIC int erase_block(int nBlock) +{ + volatile unsigned int c1; + volatile unsigned char *pWritePtr; + int temp, temp1; + + /* + * orange LED == erase + */ + leds_event(led_amber_on); + + /* + * reset footbridge to the correct offset 0 (...0..3) + */ + *CSR_ROMWRITEREG = 0; + + /* + * dummy ROM read + */ + c1 = *(volatile unsigned char *) (FLASH_BASE + 0x8000); + + kick_open(); + /* + * reset status if old errors + */ + *(volatile unsigned char *) (FLASH_BASE + 0x8000) = 0x50; + + /* + * erase a block... + * aim at the middle of a current block... + */ + pWritePtr = (unsigned char *) ((unsigned int) (FLASH_BASE + 0x8000 + (nBlock << 16))); + /* + * dummy read + */ + c1 = *pWritePtr; + + kick_open(); + /* + * erase + */ + *(volatile unsigned char *) pWritePtr = 0x20; + + /* + * confirm + */ + *(volatile unsigned char *) pWritePtr = 0xD0; + + /* + * wait 10 ms + */ + flash_wait(HZ / 100); + + /* + * wait while erasing in process (up to 10 sec) + */ + temp = jiffies + 10 * HZ; + c1 = 0; + while (!(c1 & 0x80) && time_before(jiffies, temp)) { + flash_wait(HZ / 100); + /* + * read any address + */ + c1 = *(volatile unsigned char *) (pWritePtr); + // printk("Flash_erase: status=%X.\n",c1); + } + + /* + * set flash for normal read access + */ + kick_open(); +// *(volatile unsigned char*)(FLASH_BASE+0x8000) = 0xFF; + *(volatile unsigned char *) pWritePtr = 0xFF; //back to normal operation + + /* + * check if erase errors were reported + */ + if (c1 & 0x20) { + if (flashdebug) + printk("Flash_erase: err at %X.\n", (unsigned int) pWritePtr); + /* + * reset error + */ + *(volatile unsigned char *) (FLASH_BASE + 0x8000) = 0x50; + + return -2; + } + + /* + * just to make sure - verify if erased OK... + */ + flash_wait(HZ / 100); + + pWritePtr = (unsigned char *) ((unsigned int) (FLASH_BASE + (nBlock << 16))); + + for (temp = 0; temp < 16 * 1024; temp++, pWritePtr += 4) { + if ((temp1 = *(volatile unsigned int *) pWritePtr) != 0xFFFFFFFF) { + if (flashdebug) + printk("Flash_erase: verify err at %X = %X.\n", + (unsigned int) pWritePtr, temp1); + return -1; + } + } + + return 0; + +} + +/* + * write_block will limit number of bytes written to the space in this block + */ +MSTATIC int write_block(unsigned long p, const char *buf, int count) +{ + volatile unsigned int c1; + volatile unsigned int c2; + unsigned char *pWritePtr; + unsigned int uAddress; + unsigned int offset; + unsigned int timeout; + unsigned int timeout1; + + /* + * red LED == write + */ + leds_event(led_amber_off); + leds_event(led_red_on); + + pWritePtr = (unsigned char *) ((unsigned int) (FLASH_BASE + p)); + + /* + * check if write will end in this block.... + */ + offset = p & 0xFFFF; + + if (offset + count > 0x10000) + count = 0x10000 - offset; + + /* + * wait up to 30 sec for this block + */ + timeout = jiffies + 30 * HZ; + + for (offset = 0; offset < count; offset++, pWritePtr++) { + uAddress = (unsigned int) pWritePtr; + uAddress &= 0xFFFFFFFC; + if (__get_user(c2, buf + offset)) + return -EFAULT; + + WriteRetry: + /* + * dummy read + */ + c1 = *(volatile unsigned char *) (FLASH_BASE + 0x8000); + + /* + * kick open the write gate + */ + kick_open(); + + /* + * program footbridge to the correct offset...0..3 + */ + *CSR_ROMWRITEREG = (unsigned int) pWritePtr & 3; + + /* + * write cmd + */ + *(volatile unsigned char *) (uAddress) = 0x40; + + /* + * data to write + */ + *(volatile unsigned char *) (uAddress) = c2; + + /* + * get status + */ + *(volatile unsigned char *) (FLASH_BASE + 0x10000) = 0x70; + + c1 = 0; + + /* + * wait up to 1 sec for this byte + */ + timeout1 = jiffies + 1 * HZ; + + /* + * while not ready... + */ + while (!(c1 & 0x80) && time_before(jiffies, timeout1)) + c1 = *(volatile unsigned char *) (FLASH_BASE + 0x8000); + + /* + * if timeout getting status + */ + if (time_after_eq(jiffies, timeout1)) { + kick_open(); + /* + * reset err + */ + *(volatile unsigned char *) (FLASH_BASE + 0x8000) = 0x50; + + goto WriteRetry; + } + /* + * switch on read access, as a default flash operation mode + */ + kick_open(); + /* + * read access + */ + *(volatile unsigned char *) (FLASH_BASE + 0x8000) = 0xFF; + + /* + * if hardware reports an error writing, and not timeout - + * reset the chip and retry + */ + if (c1 & 0x10) { + kick_open(); + /* + * reset err + */ + *(volatile unsigned char *) (FLASH_BASE + 0x8000) = 0x50; + + /* + * before timeout? + */ + if (time_before(jiffies, timeout)) { + if (flashdebug) + printk("FlashWrite: Retrying write (addr=0x%X)...\n", + (unsigned int) pWritePtr - FLASH_BASE); + + /* + * no LED == waiting + */ + leds_event(led_amber_off); + /* + * wait couple ms + */ + flash_wait(HZ / 100); + /* + * red LED == write + */ + leds_event(led_red_on); + + goto WriteRetry; + } else { + printk("Timeout in flash write! (addr=0x%X) Aborting...\n", + (unsigned int) pWritePtr - FLASH_BASE); + /* + * return error -2 + */ + return -2; + + } + } + } + + /* + * green LED == read/verify + */ + leds_event(led_amber_off); + leds_event(led_green_on); + + flash_wait(HZ / 100); + + pWritePtr = (unsigned char *) ((unsigned int) (FLASH_BASE + p)); + + for (offset = 0; offset < count; offset++) { + char c, c1; + if (__get_user(c, buf)) + return -EFAULT; + buf++; + if ((c1 = *pWritePtr++) != c) { + if (flashdebug) + printk("flash write verify error at 0x%X! (%02X!=%02X) Retrying...\n", + (unsigned int) pWritePtr, c1, c); + return 0; + } + } + + return count; +} + + +MSTATIC void kick_open(void) +{ + unsigned long flags; + + /* + * we want to write a bit pattern XXX1 to Xilinx to enable + * the write gate, which will be open for about the next 2ms. + */ + spin_lock_irqsave(&gpio_lock, flags); + cpld_modify(1, 1); + spin_unlock_irqrestore(&gpio_lock, flags); + + /* + * let the ISA bus to catch on... + */ + udelay(25); +} + +MSTATIC int __init nwflash_init(void) +{ + int ret = -ENODEV; + + if (machine_is_netwinder()) { + int id; + + id = get_flash_id(); + printk("Flash ROM driver v.%s, flash device ID 0x%04X, size %d Mb.\n", + NWFLASH_VERSION, id, gbFlashSize / (1024 * 1024)); + + misc_register(&flash_miscdev); + + ret = 0; + } + + return ret; +} + +MSTATIC void __exit nwflash_exit(void) +{ + misc_deregister(&flash_miscdev); +} + +EXPORT_NO_SYMBOLS; + +MODULE_PARM(flashdebug, "i"); + +module_init(nwflash_init); +module_exit(nwflash_exit); diff --git a/drivers/char/raw.c b/drivers/char/raw.c index 6ffbb517c..61dfd6e42 100644 --- a/drivers/char/raw.c +++ b/drivers/char/raw.c @@ -197,7 +197,12 @@ int raw_ctl_ioctl(struct inode *inode, raw_device_bindings[minor] = bdget(kdev_t_to_nr(MKDEV(rq.block_major, rq.block_minor))); } else { - kdev_t dev=to_kdev_t(raw_device_bindings[minor]->bd_dev); + kdev_t dev; + if (!raw_device_bindings[minor]) { + err = -ENODEV; + break; + } + dev = to_kdev_t(raw_device_bindings[minor]->bd_dev); rq.block_major = MAJOR(dev); rq.block_minor = MINOR(dev); err = copy_to_user((void *) arg, &rq, sizeof(rq)); diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index 6296e789b..f68c65afe 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c @@ -36,9 +36,11 @@ * 1.09b Jeff Garzik: Modularize, init cleanup * 1.09c Jeff Garzik: SMP cleanup * 1.10 Paul Barton-Davis: add support for async I/O + * 1.10a Andrea Arcangeli: Alpha updates + * 1.10b Andrew Morton: SMP lock fix */ -#define RTC_VERSION "1.10" +#define RTC_VERSION "1.10b" #define RTC_IRQ 8 /* Can't see this changing soon. */ #define RTC_IO_EXTENT 0x10 /* Only really two ports, but... */ @@ -378,7 +380,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { if (yrs > 169) { - restore_flags(flags); + spin_unlock_irqrestore(&rtc_lock, flags); return -EINVAL; } if (yrs >= 100) @@ -706,7 +708,9 @@ static void __exit rtc_exit (void) free_irq (rtc_irq, &rtc_port); #else release_region (RTC_PORT (0), RTC_IO_EXTENT); +#ifndef __alpha__ free_irq (RTC_IRQ, NULL); +#endif #endif /* __sparc__ */ } diff --git a/drivers/char/wdt285.c b/drivers/char/wdt285.c new file mode 100644 index 000000000..b5dc94e2f --- /dev/null +++ b/drivers/char/wdt285.c @@ -0,0 +1,204 @@ +/* + * Intel 21285 watchdog driver + * Copyright (c) Phil Blundell , 1998 + * + * based on + * + * SoftDog 0.05: A Software Watchdog Device + * + * (c) Copyright 1996 Alan Cox , All Rights Reserved. + * http://www.cymru.net + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* + * Define this to stop the watchdog actually rebooting the machine. + */ +#undef ONLY_TESTING + +#define TIMER_MARGIN 60 /* (secs) Default is 1 minute */ + +#define FCLK (50*1000*1000) /* 50MHz */ + +static int soft_margin = TIMER_MARGIN; /* in seconds */ +static int timer_alive = 0; + +#ifdef ONLY_TESTING +/* + * If the timer expires.. + */ + +static void watchdog_fire(int irq, void *dev_id, struct pt_regs *regs) +{ + printk(KERN_CRIT "Watchdog: Would Reboot.\n"); + *CSR_TIMER4_CNTL = 0; + *CSR_TIMER4_CLR = 0; +} +#endif + +static void watchdog_ping(void) +{ + /* + * Refresh the timer. + */ + *CSR_TIMER4_LOAD = soft_margin * (FCLK / 256); +} + +/* + * Allow only one person to hold it open + */ + +static int watchdog_open(struct inode *inode, struct file *file) +{ + if(timer_alive) + return -EBUSY; + MOD_INC_USE_COUNT; + /* + * Ahead watchdog factor ten, Mr Sulu + */ + *CSR_TIMER4_CLR = 0; + watchdog_ping(); + *CSR_TIMER4_CNTL = TIMER_CNTL_ENABLE | TIMER_CNTL_AUTORELOAD + | TIMER_CNTL_DIV256; +#ifdef ONLY_TESTING + request_irq(IRQ_TIMER4, watchdog_fire, 0, "watchdog", NULL); +#else + *CSR_SA110_CNTL |= 1 << 13; +#endif + timer_alive = 1; + return 0; +} + +static int watchdog_release(struct inode *inode, struct file *file) +{ +#ifdef ONLY_TESTING + free_irq(IRQ_TIMER4, NULL); + timer_alive = 0; + MOD_DEC_USE_COUNT; +#else + /* + * It's irreversible! + */ +#endif + return 0; +} + +static ssize_t watchdog_write(struct file *file, const char *data, size_t len, loff_t *ppos) +{ + /* Can't seek (pwrite) on this device */ + if (ppos != &file->f_pos) + return -ESPIPE; + + /* + * Refresh the timer. + */ + if(len) + { + watchdog_ping(); + return 1; + } + return 0; +} + +static int watchdog_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int i; + static struct watchdog_info ident= + { + 0, + 0, + "Footbridge Watchdog" + }; + switch(cmd) + { + default: + return -ENOIOCTLCMD; + case WDIOC_GETSUPPORT: + i = verify_area(VERIFY_WRITE, (void*) arg, sizeof(struct watchdog_info)); + if (i) + return i; + else + return copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident)); + case WDIOC_GETSTATUS: + case WDIOC_GETBOOTSTATUS: + return put_user(0,(int *)arg); + case WDIOC_KEEPALIVE: + watchdog_ping(); + return 0; + } +} + +static struct file_operations watchdog_fops= +{ + NULL, /* Seek */ + NULL, /* Read */ + watchdog_write, /* Write */ + NULL, /* Readdir */ + NULL, /* Select */ + watchdog_ioctl, /* Ioctl */ + NULL, /* MMap */ + watchdog_open, + NULL, /* flush */ + watchdog_release, + NULL, + NULL /* Fasync */ +}; + +static struct miscdevice watchdog_miscdev= +{ + WATCHDOG_MINOR, + "watchdog", + &watchdog_fops +}; + +static int __init footbridge_watchdog_init(void) +{ + if (machine_is_netwinder()) + return -ENODEV; + + misc_register(&watchdog_miscdev); + printk("Footbridge Watchdog Timer: 0.01, timer margin: %d sec\n", + soft_margin); + if (machine_is_cats()) + printk("Warning: Watchdog reset may not work on this machine.\n"); + return 0; +} + +static void __exit footbridge_watchdog_exit(void) +{ + misc_deregister(&watchdog_miscdev); +} + +EXPORT_NO_SYMBOLS; + +MODULE_AUTHOR("Phil Blundell "); +MODULE_DESCRIPTION("21285 watchdog driver"); + +MODULE_PARM(soft_margin,"i"); +MODULE_PARM_DESC(soft_margin,"Watchdog timeout in seconds"); + +module_init(footbridge_watchdog_init); +module_exit(footbridge_watchdog_exit); diff --git a/drivers/char/wdt977.c b/drivers/char/wdt977.c new file mode 100644 index 000000000..c45e63d60 --- /dev/null +++ b/drivers/char/wdt977.c @@ -0,0 +1,204 @@ +/* + * Wdt977 0.01: A Watchdog Device for Netwinder W83977AF chip + * + * (c) Copyright 1998 Rebel.com (Woody Suwalski ) + * + * ----------------------- + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * ----------------------- + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define WATCHDOG_MINOR 130 + +static int timeout = 3; +static int timer_alive = 0; +static int testmode = 0; + +/* + * Allow only one person to hold it open + */ + +static int wdt977_open(struct inode *inode, struct file *file) +{ + if(timer_alive) + return -EBUSY; + MOD_INC_USE_COUNT; + timer_alive++; + + //max timeout value = 255 minutes (0xFF). Write 0 to disable WatchDog. + if (timeout>255) + timeout = 255; + + printk(KERN_INFO "Watchdog: active, current timeout %d min.\n",timeout); + + // unlock the SuperIO chip + outb(0x87,0x370); + outb(0x87,0x370); + + //select device Aux2 (device=8) and set watchdog regs F2, F3 and F4 + //F2 has the timeout in minutes + //F3 could be set to the POWER LED blink (with GP17 set to PowerLed) + // at timeout, and to reset timer on kbd/mouse activity (not now) + //F4 is used to just clear the TIMEOUT'ed state (bit 0) + + outb(0x07,0x370); + outb(0x08,0x371); + outb(0xF2,0x370); + outb(timeout,0x371); + outb(0xF3,0x370); + outb(0x00,0x371); //another setting is 0E for kbd/mouse/LED + outb(0xF4,0x370); + outb(0x00,0x371); + + //at last select device Aux1 (dev=7) and set GP16 as a watchdog output + if (!testmode) + { + outb(0x07,0x370); + outb(0x07,0x371); + outb(0xE6,0x370); + outb(0x08,0x371); + } + + // lock the SuperIO chip + outb(0xAA,0x370); + + return 0; +} + +static int wdt977_release(struct inode *inode, struct file *file) +{ + /* + * Shut off the timer. + * Lock it in if it's a module and we defined ...NOWAYOUT + */ +#ifndef CONFIG_WATCHDOG_NOWAYOUT + + // unlock the SuperIO chip + outb(0x87,0x370); + outb(0x87,0x370); + + //select device Aux2 (device=8) and set watchdog regs F2,F3 and F4 + //F3 is reset to its default state + //F4 can clear the TIMEOUT'ed state (bit 0) - back to default + //We can not use GP17 as a PowerLed, as we use its usage as a RedLed + + outb(0x07,0x370); + outb(0x08,0x371); + outb(0xF2,0x370); + outb(0xFF,0x371); + outb(0xF3,0x370); + outb(0x00,0x371); + outb(0xF4,0x370); + outb(0x00,0x371); + outb(0xF2,0x370); + outb(0x00,0x371); + + //at last select device Aux1 (dev=7) and set GP16 as a watchdog output + outb(0x07,0x370); + outb(0x07,0x371); + outb(0xE6,0x370); + outb(0x08,0x371); + + // lock the SuperIO chip + outb(0xAA,0x370); + + MOD_DEC_USE_COUNT; + timer_alive=0; + + printk(KERN_INFO "Watchdog: shutdown.\n"); +#endif + return 0; +} + +static ssize_t wdt977_write(struct file *file, const char *data, size_t len, loff_t *ppos) +{ + + //max timeout value = 255 minutes (0xFF). Write 0 to disable WatchDog. + if (timeout>255) + timeout = 255; + + /* + * Refresh the timer. + */ + + //we have a hw bug somewhere, so each 977 minute is actually only 30sec + //as such limit the max timeout to half of max of 255 minutes... +// if (timeout>126) +// timeout = 126; + + // unlock the SuperIO chip + outb(0x87,0x370); + outb(0x87,0x370); + + //select device Aux2 (device=8) and kicks watchdog reg F2 + //F2 has the timeout in minutes + + outb(0x07,0x370); + outb(0x08,0x371); + outb(0xF2,0x370); + outb(timeout,0x371); + + // lock the SuperIO chip + outb(0xAA,0x370); + + return 1; +} + +static struct file_operations wdt977_fops= +{ + NULL, /* Seek */ + NULL, /* Read */ + wdt977_write, /* Write */ + NULL, /* Readdir */ + NULL, /* Select */ + NULL, /* Ioctl */ + NULL, /* MMap */ + wdt977_open, + NULL, /* flush */ + wdt977_release, + NULL, + NULL /* Fasync */ +}; + +static struct miscdevice wdt977_miscdev= +{ + WATCHDOG_MINOR, + "watchdog", + &wdt977_fops +}; + +static int __init nwwatchdog_init(void) +{ + if (!machine_is_netwinder()) + return -ENODEV; + + misc_register(&wdt977_miscdev); + printk(KERN_INFO "NetWinder Watchdog sleeping.\n"); + return 0; +} + +static void __exit nwwatchdog_exit(void) +{ + misc_deregister(&wdt977_miscdev); +} + +EXPORT_NO_SYMBOLS; + +module_init(nwwatchdog_init); +module_exit(nwwatchdog_exit); diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index c98cb7c6f..493befb7d 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -101,10 +101,6 @@ static struct file_operations i2cproc_operations = { read: i2cproc_bus_read, }; -static struct inode_operations i2cproc_inode_operations = { - &i2cproc_operations -}; - static int i2cproc_initialized = 0; #else /* undef CONFIG_PROC_FS */ @@ -163,7 +159,7 @@ int i2c_add_adapter(struct i2c_adapter *adap) name); return -ENOENT; } - proc_entry->ops = &i2cproc_inode_operations; + proc_entry->proc_fops = &i2cproc_operations; #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,27)) proc_entry->owner = THIS_MODULE; #else diff --git a/drivers/isdn/avmb1/b1dma.c b/drivers/isdn/avmb1/b1dma.c index 8bf595282..d61b88375 100644 --- a/drivers/isdn/avmb1/b1dma.c +++ b/drivers/isdn/avmb1/b1dma.c @@ -1,11 +1,14 @@ /* - * $Id: b1dma.c,v 1.2 2000/01/25 14:44:47 calle Exp $ + * $Id: b1dma.c,v 1.3 2000/02/26 01:00:53 keil Exp $ * * Common module for AVM B1 cards that support dma with AMCC * * (c) Copyright 2000 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: b1dma.c,v $ + * Revision 1.3 2000/02/26 01:00:53 keil + * changes from 2.3.47 + * * Revision 1.2 2000/01/25 14:44:47 calle * typo in b1pciv4_detect(). * @@ -31,7 +34,7 @@ #include "capicmd.h" #include "capiutil.h" -static char *revision = "$Revision: 1.2 $"; +static char *revision = "$Revision: 1.3 $"; /* ------------------------------------------------------------- */ diff --git a/drivers/isdn/avmb1/capi.c b/drivers/isdn/avmb1/capi.c index 62f246407..fb8a32460 100644 --- a/drivers/isdn/avmb1/capi.c +++ b/drivers/isdn/avmb1/capi.c @@ -1,11 +1,14 @@ /* - * $Id: capi.c,v 1.22 1999/11/13 21:27:16 keil Exp $ + * $Id: capi.c,v 1.23 2000/02/26 01:00:53 keil Exp $ * * CAPI 2.0 Interface for Linux * * Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: capi.c,v $ + * Revision 1.23 2000/02/26 01:00:53 keil + * changes from 2.3.47 + * * Revision 1.22 1999/11/13 21:27:16 keil * remove KERNELVERSION * diff --git a/drivers/isdn/divert/divert_procfs.c b/drivers/isdn/divert/divert_procfs.c index 110b5a172..de56823c0 100644 --- a/drivers/isdn/divert/divert_procfs.c +++ b/drivers/isdn/divert/divert_procfs.c @@ -315,8 +315,6 @@ static struct file_operations isdn_fops = NULL /* fsync */ }; -struct inode_operations divert_file_inode_operations; - /****************************/ /* isdn subdir in /proc/net */ /****************************/ @@ -342,9 +340,7 @@ divert_dev_init(void) remove_proc_entry("isdn", proc_net); return (-1); } - memset(&divert_file_inode_operations, 0, sizeof(struct inode_operations)); - divert_file_inode_operations.default_file_ops = &isdn_fops; - isdn_divert_entry->ops = &divert_file_inode_operations; + isdn_divert_entry->proc_fops = &isdn_fops; #endif /* CONFIG_PROC_FS */ return (0); diff --git a/drivers/isdn/eicon/eicon_idi.c b/drivers/isdn/eicon/eicon_idi.c index e53469070..eb3590069 100644 --- a/drivers/isdn/eicon/eicon_idi.c +++ b/drivers/isdn/eicon/eicon_idi.c @@ -1,4 +1,4 @@ -/* $Id: eicon_idi.c,v 1.29 2000/01/23 21:21:23 armin Exp $ +/* $Id: eicon_idi.c,v 1.31 2000/02/22 16:26:40 armin Exp $ * * ISDN lowlevel-module for Eicon active cards. * IDI interface @@ -26,6 +26,13 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: eicon_idi.c,v $ + * Revision 1.31 2000/02/22 16:26:40 armin + * Fixed membase error message. + * Fixed missing log buffer struct. + * + * Revision 1.30 2000/02/16 16:08:46 armin + * Fixed virtual channel handling of IDI. + * * Revision 1.29 2000/01/23 21:21:23 armin * Added new trace capability and some updates. * DIVA Server BRI now supports data for ISDNLOG. @@ -149,7 +156,7 @@ #undef EICON_FULL_SERVICE_OKTETT -char *eicon_idi_revision = "$Revision: 1.29 $"; +char *eicon_idi_revision = "$Revision: 1.31 $"; eicon_manifbuf *manbuf; @@ -255,10 +262,10 @@ idi_assign_req(eicon_REQ *reqbuf, int signet, eicon_chan *chan) } int -idi_put_req(eicon_REQ *reqbuf, int rq, int signet) +idi_put_req(eicon_REQ *reqbuf, int rq, int signet, int Ch) { reqbuf->Req = rq; - reqbuf->ReqCh = 0; + reqbuf->ReqCh = Ch; reqbuf->ReqId = 1; reqbuf->XBuffer.length = 1; reqbuf->XBuffer.P[0] = 0; @@ -368,34 +375,34 @@ idi_do_req(eicon_card *card, eicon_chan *chan, int cmd, int layer) break; case REMOVE: case REMOVE|0x700: - idi_put_req(reqbuf, REMOVE, layer); + idi_put_req(reqbuf, REMOVE, layer, 0); break; case INDICATE_REQ: - idi_put_req(reqbuf, INDICATE_REQ, 0); + idi_put_req(reqbuf, INDICATE_REQ, 0, 0); break; case HANGUP: - idi_put_req(reqbuf, HANGUP, 0); + idi_put_req(reqbuf, HANGUP, 0, 0); break; case REJECT: - idi_put_req(reqbuf, REJECT, 0); + idi_put_req(reqbuf, REJECT, 0 ,0); break; case CALL_ALERT: - idi_put_req(reqbuf, CALL_ALERT, 0); + idi_put_req(reqbuf, CALL_ALERT, 0, 0); break; case CALL_RES: idi_call_res_req(reqbuf, chan); break; case IDI_N_CONNECT|0x700: - idi_put_req(reqbuf, IDI_N_CONNECT, 1); + idi_put_req(reqbuf, IDI_N_CONNECT, 1, 0); break; case IDI_N_CONNECT_ACK|0x700: - idi_put_req(reqbuf, IDI_N_CONNECT_ACK, 1); + idi_put_req(reqbuf, IDI_N_CONNECT_ACK, 1, 0); break; case IDI_N_DISC|0x700: - idi_put_req(reqbuf, IDI_N_DISC, 1); + idi_put_req(reqbuf, IDI_N_DISC, 1, chan->e.IndCh); break; case IDI_N_DISC_ACK|0x700: - idi_put_req(reqbuf, IDI_N_DISC_ACK, 1); + idi_put_req(reqbuf, IDI_N_DISC_ACK, 1, chan->e.IndCh); break; default: eicon_log(card, 1, "idi_req: Ch%d: Unknown request\n", chan->No); @@ -813,6 +820,11 @@ idi_IndParse(eicon_card *ccard, eicon_chan *chan, idi_ind_message *message, unsi message->osa[i] = buffer[pos++]; eicon_log(ccard, 2, "idi_inf: Ch%d: OSA=%s\n", chan->No, message->osa); break; + case CAD: + pos += wlen; + eicon_log(ccard, 2, "idi_inf: Ch%d: Connected Address in ind, len:%x\n", + chan->No, wlen); + break; case BC: if (wlen > sizeof(message->bc)) { pos += wlen; @@ -1206,7 +1218,7 @@ idi_send_edata(eicon_card *card, eicon_chan *chan) reqbuf = (eicon_REQ *)skb_put(skb, sizeof(eicon_t30_s) + sizeof(eicon_REQ)); reqbuf->Req = IDI_N_EDATA; - reqbuf->ReqCh = 0; + reqbuf->ReqCh = chan->e.IndCh; reqbuf->ReqId = 1; reqbuf->XBuffer.length = idi_fill_in_T30(chan, reqbuf->XBuffer.P); @@ -2205,7 +2217,7 @@ idi_send_udata(eicon_card *card, eicon_chan *chan, int UReq, u_char *buffer, int reqbuf = (eicon_REQ *)skb_put(skb, 1 + len + sizeof(eicon_REQ)); reqbuf->Req = IDI_N_UDATA; - reqbuf->ReqCh = 0; + reqbuf->ReqCh = chan->e.IndCh; reqbuf->ReqId = 1; reqbuf->XBuffer.length = len + 1; @@ -2322,7 +2334,7 @@ eicon_parse_trace(eicon_card *ccard, unsigned char *buffer, int len) unsigned char data[1]; } *q; - if (!(p = kmalloc(buflen, GFP_KERNEL))) { + if (!(p = kmalloc(buflen, GFP_ATOMIC))) { eicon_log(ccard, 1, "idi_err: Ch??: could not allocate trace buffer\n"); return; } @@ -2380,7 +2392,7 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) return; } - if (ind->Ind != 8) + if ((ind->Ind != 8) && (ind->Ind != 0xc)) dlev = 144; else dlev = 128; @@ -2634,6 +2646,7 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) break; case IDI_N_CONNECT: eicon_log(ccard, 16,"idi_ind: Ch%d: N_Connect\n", chan->No); + chan->e.IndCh = ind->IndCh; if (chan->e.B2Id) idi_do_req(ccard, chan, IDI_N_CONNECT_ACK, 1); if (chan->l2prot == ISDN_PROTO_L2_FAX) { break; @@ -2664,6 +2677,7 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) idi_fax_hangup(ccard, chan); } #endif + chan->e.IndCh = 0; save_flags(flags); cli(); chan->queued = 0; @@ -2693,7 +2707,7 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) #endif break; case IDI_N_DATA_ACK: - eicon_log(ccard, 16, "idi_ind: Ch%d: N_DATA_ACK\n", chan->No); + eicon_log(ccard, 128, "idi_ind: Ch%d: N_DATA_ACK\n", chan->No); break; case IDI_N_DATA: skb_pull(skb, sizeof(eicon_IND) - 1); @@ -2774,6 +2788,11 @@ idi_handle_ack_ok(eicon_card *ccard, eicon_chan *chan, eicon_RC *ack) } else { /* Network layer */ switch(chan->e.Req & 0x0f) { + case IDI_N_CONNECT: + chan->e.IndCh = ack->RcCh; + eicon_log(ccard, 16, "idi_ack: Ch%d: RC OK Id=%x Ch=%d (ref:%d)\n", chan->No, + ack->RcId, ack->RcCh, ack->Reference); + break; case IDI_N_MDATA: case IDI_N_DATA: if ((chan->e.Req & 0x0f) == IDI_N_DATA) { @@ -2999,7 +3018,7 @@ idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb, reqbuf->Req = IDI_N_DATA; if (ack) reqbuf->Req |= N_D_BIT; } - reqbuf->ReqCh = 0; + reqbuf->ReqCh = chan->e.IndCh; reqbuf->ReqId = 1; memcpy(&reqbuf->XBuffer.P, skb->data + offset, plen); reqbuf->XBuffer.length = plen; diff --git a/drivers/isdn/eicon/eicon_isa.c b/drivers/isdn/eicon/eicon_isa.c index 86e6c0ef7..265e07e08 100644 --- a/drivers/isdn/eicon/eicon_isa.c +++ b/drivers/isdn/eicon/eicon_isa.c @@ -1,4 +1,4 @@ -/* $Id: eicon_isa.c,v 1.13 2000/01/23 21:21:23 armin Exp $ +/* $Id: eicon_isa.c,v 1.14 2000/02/22 16:26:40 armin Exp $ * * ISDN low-level module for Eicon active ISDN-Cards. * Hardware-specific code for old ISA cards. @@ -22,6 +22,10 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: eicon_isa.c,v $ + * Revision 1.14 2000/02/22 16:26:40 armin + * Fixed membase error message. + * Fixed missing log buffer struct. + * * Revision 1.13 2000/01/23 21:21:23 armin * Added new trace capability and some updates. * DIVA Server BRI now supports data for ISDNLOG. @@ -83,7 +87,7 @@ #define release_shmem release_region #define request_shmem request_region -char *eicon_isa_revision = "$Revision: 1.13 $"; +char *eicon_isa_revision = "$Revision: 1.14 $"; #undef EICON_MCA_DEBUG @@ -146,6 +150,9 @@ eicon_isa_find_card(int Mem, int Irq, char * Id) if (!strlen(Id)) return -1; + if (Mem == -1) + return -1; + /* Check for valid membase address */ if ((Mem < 0x0c0000) || (Mem > 0x0fc000) || diff --git a/drivers/isdn/eicon/eicon_mod.c b/drivers/isdn/eicon/eicon_mod.c index 688d74de3..9bc91d6f4 100644 --- a/drivers/isdn/eicon/eicon_mod.c +++ b/drivers/isdn/eicon/eicon_mod.c @@ -1,4 +1,4 @@ -/* $Id: eicon_mod.c,v 1.24 2000/01/23 21:21:23 armin Exp $ +/* $Id: eicon_mod.c,v 1.25 2000/02/22 16:26:40 armin Exp $ * * ISDN lowlevel-module for Eicon active cards. * @@ -31,6 +31,10 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: eicon_mod.c,v $ + * Revision 1.25 2000/02/22 16:26:40 armin + * Fixed membase error message. + * Fixed missing log buffer struct. + * * Revision 1.24 2000/01/23 21:21:23 armin * Added new trace capability and some updates. * DIVA Server BRI now supports data for ISDNLOG. @@ -140,7 +144,7 @@ static eicon_card *cards = (eicon_card *) NULL; /* glob. var , contains start of card-list */ -static char *eicon_revision = "$Revision: 1.24 $"; +static char *eicon_revision = "$Revision: 1.25 $"; extern char *eicon_pci_revision; extern char *eicon_isa_revision; @@ -886,8 +890,10 @@ eicon_putstatus(eicon_card * card, char * buf) u_char *p; struct sk_buff *skb; - if (!card) - return; + if (!card) { + if (!(card = cards)) + return; + } save_flags(flags); cli(); diff --git a/drivers/isdn/hisax/avm_pci.c b/drivers/isdn/hisax/avm_pci.c index 319e0b264..d87c43f37 100644 --- a/drivers/isdn/hisax/avm_pci.c +++ b/drivers/isdn/hisax/avm_pci.c @@ -1,4 +1,4 @@ -/* $Id: avm_pci.c,v 1.14 1999/12/19 13:09:41 keil Exp $ +/* $Id: avm_pci.c,v 1.15 2000/02/26 00:35:12 keil Exp $ * avm_pci.c low level stuff for AVM Fritz!PCI and ISA PnP isdn cards * Thanks to AVM, Berlin for informations @@ -7,6 +7,9 @@ * * * $Log: avm_pci.c,v $ + * Revision 1.15 2000/02/26 00:35:12 keil + * Fix skb freeing in interrupt context + * * Revision 1.14 1999/12/19 13:09:41 keil * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for * signal proof delays @@ -63,7 +66,7 @@ #include extern const char *CardType[]; -static const char *avm_pci_rev = "$Revision: 1.14 $"; +static const char *avm_pci_rev = "$Revision: 1.15 $"; #define AVM_FRITZ_PCI 1 #define AVM_FRITZ_PNP 2 @@ -499,7 +502,7 @@ HDLC_irq(struct BCState *bcs, u_int stat) { if (bcs->st->lli.l1writewakeup && (PACKET_NOACK != bcs->tx_skb->pkt_type)) bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.hdlc.count); - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_irq(bcs->tx_skb); bcs->hw.hdlc.count = 0; bcs->tx_skb = NULL; } @@ -626,7 +629,7 @@ close_hdlcstate(struct BCState *bcs) discard_queue(&bcs->rqueue); discard_queue(&bcs->squeue); if (bcs->tx_skb) { - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); } diff --git a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c index 8d389c623..377819551 100644 --- a/drivers/isdn/hisax/config.c +++ b/drivers/isdn/hisax/config.c @@ -1,10 +1,13 @@ -/* $Id: config.c,v 2.43 2000/01/20 19:49:36 keil Exp $ +/* $Id: config.c,v 2.44 2000/02/26 00:35:12 keil Exp $ * Author Karsten Keil (keil@isdn4linux.de) * based on the teles driver from Jan den Ouden * * * $Log: config.c,v $ + * Revision 2.44 2000/02/26 00:35:12 keil + * Fix skb freeing in interrupt context + * * Revision 2.43 2000/01/20 19:49:36 keil * Support teles 13.3c vendor version 2.1 * @@ -549,9 +552,9 @@ HiSaxVersion(void)) printk(KERN_INFO "HiSax: Linux Driver for passive ISDN cards\n"); #ifdef MODULE - printk(KERN_INFO "HiSax: Version 3.3d (module)\n"); + printk(KERN_INFO "HiSax: Version 3.3e (module)\n"); #else - printk(KERN_INFO "HiSax: Version 3.3d (kernel)\n"); + printk(KERN_INFO "HiSax: Version 3.3e (kernel)\n"); #endif strcpy(tmp, l1_revision); printk(KERN_INFO "HiSax: Layer1 Revision %s\n", HiSax_getrev(tmp)); diff --git a/drivers/isdn/hisax/diva.c b/drivers/isdn/hisax/diva.c index 5dc868942..30c6331a5 100644 --- a/drivers/isdn/hisax/diva.c +++ b/drivers/isdn/hisax/diva.c @@ -1,4 +1,4 @@ -/* $Id: diva.c,v 1.18 1999/12/19 13:09:41 keil Exp $ +/* $Id: diva.c,v 1.19 2000/02/26 00:35:12 keil Exp $ * diva.c low level stuff for Eicon.Diehl Diva Family ISDN cards * @@ -12,6 +12,9 @@ * * * $Log: diva.c,v $ + * Revision 1.19 2000/02/26 00:35:12 keil + * Fix skb freeing in interrupt context + * * Revision 1.18 1999/12/19 13:09:41 keil * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for * signal proof delays @@ -84,7 +87,7 @@ extern const char *CardType[]; -const char *Diva_revision = "$Revision: 1.18 $"; +const char *Diva_revision = "$Revision: 1.19 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -585,7 +588,7 @@ Memhscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx) if (bcs->st->lli.l1writewakeup && (PACKET_NOACK != bcs->tx_skb->pkt_type)) bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.hscx.count); - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_irq(bcs->tx_skb); bcs->hw.hscx.count = 0; bcs->tx_skb = NULL; } diff --git a/drivers/isdn/hisax/elsa_ser.c b/drivers/isdn/hisax/elsa_ser.c index 529a74815..8bff1db1c 100644 --- a/drivers/isdn/hisax/elsa_ser.c +++ b/drivers/isdn/hisax/elsa_ser.c @@ -298,7 +298,7 @@ modem_fill(struct BCState *bcs) { (PACKET_NOACK != bcs->tx_skb->pkt_type)) bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.hscx.count); - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; } } @@ -442,13 +442,13 @@ close_elsastate(struct BCState *bcs) bcs->hw.hscx.rcvbuf = NULL; } while ((skb = skb_dequeue(&bcs->rqueue))) { - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); } while ((skb = skb_dequeue(&bcs->squeue))) { - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); } if (bcs->tx_skb) { - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); } diff --git a/drivers/isdn/hisax/hfc_2bds0.c b/drivers/isdn/hisax/hfc_2bds0.c index 2b22cdfea..bc4665863 100644 --- a/drivers/isdn/hisax/hfc_2bds0.c +++ b/drivers/isdn/hisax/hfc_2bds0.c @@ -1,4 +1,4 @@ -/* $Id: hfc_2bds0.c,v 1.11 1999/12/23 15:09:32 keil Exp $ +/* $Id: hfc_2bds0.c,v 1.12 2000/02/26 00:35:12 keil Exp $ * * specific routines for CCD's HFC 2BDS0 * @@ -6,6 +6,9 @@ * * * $Log: hfc_2bds0.c,v $ + * Revision 1.12 2000/02/26 00:35:12 keil + * Fix skb freeing in interrupt context + * * Revision 1.11 1999/12/23 15:09:32 keil * change email * @@ -293,7 +296,7 @@ static struct sk_buff sti(); debugl1(cs, "RFIFO BUSY error"); printk(KERN_WARNING "HFC FIFO channel %d BUSY Error\n", bcs->channel); - dev_kfree_skb(skb); + dev_kfree_skb_irq(skb); skb = NULL; } else { cli(); @@ -309,7 +312,7 @@ static struct sk_buff bcs->channel, chksum, stat); if (stat) { debugl1(cs, "FIFO CRC error"); - dev_kfree_skb(skb); + dev_kfree_skb_irq(skb); skb = NULL; #ifdef ERROR_STATISTIC bcs->err_crc++; @@ -401,7 +404,7 @@ hfc_fill_fifo(struct BCState *bcs) if (bcs->st->lli.l1writewakeup && (PACKET_NOACK != bcs->tx_skb->pkt_type)) bcs->st->lli.l1writewakeup(bcs->st, bcs->tx_skb->len); - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; } WaitForBusy(cs); @@ -603,7 +606,7 @@ close_2bs0(struct BCState *bcs) discard_queue(&bcs->rqueue); discard_queue(&bcs->squeue); if (bcs->tx_skb) { - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); } @@ -751,7 +754,7 @@ int receive_dmsg(struct IsdnCardState *cs) sti(); debugl1(cs, "RFIFO D BUSY error"); printk(KERN_WARNING "HFC DFIFO channel BUSY Error\n"); - dev_kfree_skb(skb); + dev_kfree_skb_irq(skb); skb = NULL; #ifdef ERROR_STATISTIC cs->err_rx++; @@ -770,7 +773,7 @@ int receive_dmsg(struct IsdnCardState *cs) chksum, stat); if (stat) { debugl1(cs, "FIFO CRC error"); - dev_kfree_skb(skb); + dev_kfree_skb_irq(skb); skb = NULL; #ifdef ERROR_STATISTIC cs->err_crc++; @@ -870,7 +873,7 @@ hfc_fill_dfifo(struct IsdnCardState *cs) cli(); WaitNoBusy(cs); ReadReg(cs, HFCD_DATA, HFCD_FIFO | HFCD_F1_INC | HFCD_SEND); - dev_kfree_skb(cs->tx_skb); + dev_kfree_skb_any(cs->tx_skb); cs->tx_skb = NULL; sti(); WaitForBusy(cs); @@ -1004,7 +1007,7 @@ hfc2bds0_interrupt(struct IsdnCardState *cs, u_char val) } goto afterXPR; } else { - dev_kfree_skb(cs->tx_skb); + dev_kfree_skb_irq(cs->tx_skb); cs->tx_cnt = 0; cs->tx_skb = NULL; } diff --git a/drivers/isdn/hisax/hfc_2bs0.c b/drivers/isdn/hisax/hfc_2bs0.c index f3edefa3e..8a1d29762 100644 --- a/drivers/isdn/hisax/hfc_2bs0.c +++ b/drivers/isdn/hisax/hfc_2bs0.c @@ -1,4 +1,4 @@ -/* $Id: hfc_2bs0.c,v 1.12 1999/12/19 14:17:12 keil Exp $ +/* $Id: hfc_2bs0.c,v 1.13 2000/02/26 00:35:12 keil Exp $ * specific routines for CCD's HFC 2BS0 * @@ -6,6 +6,9 @@ * * * $Log: hfc_2bs0.c,v $ + * Revision 1.13 2000/02/26 00:35:12 keil + * Fix skb freeing in interrupt context + * * Revision 1.12 1999/12/19 14:17:12 keil * fix compiler warning * @@ -249,7 +252,7 @@ hfc_empty_fifo(struct BCState *bcs, int count) if (idx != count) { debugl1(cs, "RFIFO BUSY error"); printk(KERN_WARNING "HFC FIFO channel %d BUSY Error\n", bcs->channel); - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); if (bcs->mode != L1_MODE_TRANS) { WaitNoBusy(cs); stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC | @@ -270,7 +273,7 @@ hfc_empty_fifo(struct BCState *bcs, int count) bcs->channel, chksum, stat); if (stat) { debugl1(cs, "FIFO CRC error"); - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); skb = NULL; #ifdef ERROR_STATISTIC bcs->err_crc++; @@ -359,7 +362,7 @@ hfc_fill_fifo(struct BCState *bcs) bcs->tx_cnt -= count; if (PACKET_NOACK == bcs->tx_skb->pkt_type) count = -1; - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; if (bcs->mode != L1_MODE_TRANS) { WaitForBusy(cs); @@ -573,7 +576,7 @@ close_hfcstate(struct BCState *bcs) discard_queue(&bcs->rqueue); discard_queue(&bcs->squeue); if (bcs->tx_skb) { - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); } diff --git a/drivers/isdn/hisax/hfc_pci.c b/drivers/isdn/hisax/hfc_pci.c index 76f353861..f2e7abf10 100644 --- a/drivers/isdn/hisax/hfc_pci.c +++ b/drivers/isdn/hisax/hfc_pci.c @@ -1,4 +1,4 @@ -/* $Id: hfc_pci.c,v 1.26 2000/02/09 20:22:55 werner Exp $ +/* $Id: hfc_pci.c,v 1.27 2000/02/26 00:35:12 keil Exp $ * hfc_pci.c low level driver for CCD´s hfc-pci based cards * @@ -23,6 +23,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: hfc_pci.c,v $ + * Revision 1.27 2000/02/26 00:35:12 keil + * Fix skb freeing in interrupt context + * * Revision 1.26 2000/02/09 20:22:55 werner * * Updated PCI-ID table @@ -126,7 +129,7 @@ extern const char *CardType[]; -static const char *hfcpci_revision = "$Revision: 1.26 $"; +static const char *hfcpci_revision = "$Revision: 1.27 $"; /* table entry in the PCI devices list */ typedef struct { @@ -636,7 +639,7 @@ hfcpci_fill_dfifo(struct IsdnCardState *cs) df->f1 = new_f1; /* next frame */ restore_flags(flags); - dev_kfree_skb(cs->tx_skb); + dev_kfree_skb_any(cs->tx_skb); cs->tx_skb = NULL; return; } @@ -710,7 +713,7 @@ hfcpci_fill_fifo(struct BCState *bcs) debugl1(cs, "hfcpci_fill_fifo_trans %d frame length %d discarded", bcs->channel, bcs->tx_skb->len); - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_any(bcs->tx_skb); cli(); bcs->tx_skb = skb_dequeue(&bcs->squeue); /* fetch next data */ sti(); @@ -778,7 +781,7 @@ hfcpci_fill_fifo(struct BCState *bcs) bz->f1 = new_f1; /* next frame */ restore_flags(flags); - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); return; @@ -1130,7 +1133,7 @@ hfcpci_interrupt(int intno, void *dev_id, struct pt_regs *regs) } goto afterXPR; } else { - dev_kfree_skb(cs->tx_skb); + dev_kfree_skb_irq(cs->tx_skb); cs->tx_cnt = 0; cs->tx_skb = NULL; } @@ -1522,7 +1525,7 @@ close_hfcpci(struct BCState *bcs) discard_queue(&bcs->rqueue); discard_queue(&bcs->squeue); if (bcs->tx_skb) { - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); } diff --git a/drivers/isdn/hisax/hfc_sx.c b/drivers/isdn/hisax/hfc_sx.c index 462de9d91..85040aabf 100644 --- a/drivers/isdn/hisax/hfc_sx.c +++ b/drivers/isdn/hisax/hfc_sx.c @@ -1,4 +1,4 @@ -/* $Id: hfc_sx.c,v 1.3 2000/01/20 19:49:36 keil Exp $ +/* $Id: hfc_sx.c,v 1.4 2000/02/26 00:35:12 keil Exp $ * hfc_sx.c low level driver for CCD´s hfc-s+/sp based cards * @@ -22,6 +22,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: hfc_sx.c,v $ + * Revision 1.4 2000/02/26 00:35:12 keil + * Fix skb freeing in interrupt context + * * Revision 1.3 2000/01/20 19:49:36 keil * Support teles 13.3c vendor version 2.1 * @@ -38,6 +41,7 @@ * */ +#include #define __NO_VERSION__ #include "hisax.h" #include "hfc_sx.h" @@ -46,7 +50,7 @@ extern const char *CardType[]; -static const char *hfcsx_revision = "$Revision: 1.3 $"; +static const char *hfcsx_revision = "$Revision: 1.4 $"; /***************************************/ /* IRQ-table for CCDs demo board */ @@ -327,7 +331,7 @@ read_fifo(struct IsdnCardState *cs, u_char fifo, int trans_max) Read_hfc(cs, HFCSX_FIF_DRD); /* CRC 1 */ Read_hfc(cs, HFCSX_FIF_DRD); /* CRC 2 */ if (Read_hfc(cs, HFCSX_FIF_DRD)) { - dev_kfree_skb(skb); + dev_kfree_skb_irq(skb); if (cs->debug & L1_DEB_ISAC_FIFO) debugl1(cs, "hfcsx_read_fifo %d crc error", fifo); skb = NULL; @@ -600,7 +604,7 @@ hfcsx_fill_dfifo(struct IsdnCardState *cs) return; if (write_fifo(cs, cs->tx_skb, HFCSX_SEL_D_TX, 0)) { - dev_kfree_skb(cs->tx_skb); + dev_kfree_skb_any(cs->tx_skb); cs->tx_skb = NULL; } return; @@ -633,7 +637,7 @@ hfcsx_fill_fifo(struct BCState *bcs) if (bcs->st->lli.l1writewakeup && (PACKET_NOACK != bcs->tx_skb->pkt_type)) bcs->st->lli.l1writewakeup(bcs->st, bcs->tx_skb->len); - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); } @@ -777,7 +781,7 @@ receive_emsg(struct IsdnCardState *cs) } else HiSax_putstatus(cs, "LogEcho: ", "warning Frame too big (%d)", skb->len); } - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); } } while (--count && skb); @@ -931,7 +935,7 @@ hfcsx_interrupt(int intno, void *dev_id, struct pt_regs *regs) } goto afterXPR; } else { - dev_kfree_skb(cs->tx_skb); + dev_kfree_skb_irq(cs->tx_skb); cs->tx_cnt = 0; cs->tx_skb = NULL; } @@ -1305,7 +1309,7 @@ close_hfcsx(struct BCState *bcs) discard_queue(&bcs->rqueue); discard_queue(&bcs->squeue); if (bcs->tx_skb) { - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); } diff --git a/drivers/isdn/hisax/hisax.h b/drivers/isdn/hisax/hisax.h index 6f5b5615c..da55eb2df 100644 --- a/drivers/isdn/hisax/hisax.h +++ b/drivers/isdn/hisax/hisax.h @@ -1,8 +1,11 @@ -/* $Id: hisax.h,v 2.40 2000/01/20 19:51:46 keil Exp $ +/* $Id: hisax.h,v 2.41 2000/02/26 00:35:13 keil Exp $ * Basic declarations, defines and prototypes * * $Log: hisax.h,v $ + * Revision 2.41 2000/02/26 00:35:13 keil + * Fix skb freeing in interrupt context + * * Revision 2.40 2000/01/20 19:51:46 keil * Fix AddTimer message * Change CONFIG defines @@ -157,8 +160,9 @@ #include #include #include +#include -#undef ERROR_STATISTIC +#define ERROR_STATISTIC #define REQUEST 0 #define CONFIRM 1 diff --git a/drivers/isdn/hisax/hscx.c b/drivers/isdn/hisax/hscx.c index 1c57cd3f1..092b23243 100644 --- a/drivers/isdn/hisax/hscx.c +++ b/drivers/isdn/hisax/hscx.c @@ -1,4 +1,4 @@ -/* $Id: hscx.c,v 1.17 1999/07/01 08:11:41 keil Exp $ +/* $Id: hscx.c,v 1.18 2000/02/26 00:35:13 keil Exp $ * hscx.c HSCX specific routines * @@ -6,6 +6,9 @@ * * * $Log: hscx.c,v $ + * Revision 1.18 2000/02/26 00:35:13 keil + * Fix skb freeing in interrupt context + * * Revision 1.17 1999/07/01 08:11:41 keil * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel * @@ -219,7 +222,7 @@ close_hscxstate(struct BCState *bcs) discard_queue(&bcs->rqueue); discard_queue(&bcs->squeue); if (bcs->tx_skb) { - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); } diff --git a/drivers/isdn/hisax/hscx_irq.c b/drivers/isdn/hisax/hscx_irq.c index 655508f70..821f5bc8b 100644 --- a/drivers/isdn/hisax/hscx_irq.c +++ b/drivers/isdn/hisax/hscx_irq.c @@ -1,4 +1,4 @@ -/* $Id: hscx_irq.c,v 1.13 1999/10/14 20:25:28 keil Exp $ +/* $Id: hscx_irq.c,v 1.14 2000/02/26 00:35:13 keil Exp $ * hscx_irq.c low level b-channel stuff for Siemens HSCX * @@ -7,6 +7,9 @@ * This is an include file for fast inline IRQ stuff * * $Log: hscx_irq.c,v $ + * Revision 1.14 2000/02/26 00:35:13 keil + * Fix skb freeing in interrupt context + * * Revision 1.13 1999/10/14 20:25:28 keil * add a statistic for error monitoring * @@ -250,7 +253,7 @@ hscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx) if (bcs->st->lli.l1writewakeup && (PACKET_NOACK != bcs->tx_skb->pkt_type)) bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.hscx.count); - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_irq(bcs->tx_skb); bcs->hw.hscx.count = 0; bcs->tx_skb = NULL; } diff --git a/drivers/isdn/hisax/isac.c b/drivers/isdn/hisax/isac.c index a992f76c4..07c76cf2f 100644 --- a/drivers/isdn/hisax/isac.c +++ b/drivers/isdn/hisax/isac.c @@ -1,4 +1,4 @@ -/* $Id: isac.c,v 1.24 1999/10/14 20:25:28 keil Exp $ +/* $Id: isac.c,v 1.25 2000/02/26 00:35:13 keil Exp $ * isac.c ISAC specific routines * @@ -9,6 +9,9 @@ * ../../../Documentation/isdn/HiSax.cert * * $Log: isac.c,v $ + * Revision 1.25 2000/02/26 00:35:13 keil + * Fix skb freeing in interrupt context + * * Revision 1.24 1999/10/14 20:25:28 keil * add a statistic for error monitoring * @@ -338,7 +341,7 @@ isac_interrupt(struct IsdnCardState *cs, u_char val) isac_fill_fifo(cs); goto afterXPR; } else { - dev_kfree_skb(cs->tx_skb); + dev_kfree_skb_irq(cs->tx_skb); cs->tx_cnt = 0; cs->tx_skb = NULL; } @@ -627,7 +630,7 @@ ISAC_l1hw(struct PStack *st, int pr, void *arg) discard_queue(&cs->rq); discard_queue(&cs->sq); if (cs->tx_skb) { - dev_kfree_skb(cs->tx_skb); + dev_kfree_skb_any(cs->tx_skb); cs->tx_skb = NULL; } if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) @@ -683,7 +686,7 @@ dbusy_timer_handler(struct IsdnCardState *cs) /* discard frame; reset transceiver */ test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags); if (cs->tx_skb) { - dev_kfree_skb(cs->tx_skb); + dev_kfree_skb_any(cs->tx_skb); cs->tx_cnt = 0; cs->tx_skb = NULL; } else { diff --git a/drivers/isdn/hisax/isar.c b/drivers/isdn/hisax/isar.c index bfff86707..d53dc729a 100644 --- a/drivers/isdn/hisax/isar.c +++ b/drivers/isdn/hisax/isar.c @@ -1,4 +1,4 @@ -/* $Id: isar.c,v 1.9 2000/01/20 19:47:45 keil Exp $ +/* $Id: isar.c,v 1.10 2000/02/26 00:35:13 keil Exp $ * isar.c ISAR (Siemens PSB 7110) specific routines * @@ -6,6 +6,9 @@ * * * $Log: isar.c,v $ + * Revision 1.10 2000/02/26 00:35:13 keil + * Fix skb freeing in interrupt context + * * Revision 1.9 2000/01/20 19:47:45 keil * Add Fax Class 1 support * @@ -774,7 +777,7 @@ send_frames(struct BCState *bcs) } } } - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_any(bcs->tx_skb); bcs->hw.isar.txcnt = 0; bcs->tx_skb = NULL; } @@ -1631,7 +1634,7 @@ close_isarstate(struct BCState *bcs) discard_queue(&bcs->rqueue); discard_queue(&bcs->squeue); if (bcs->tx_skb) { - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); if (bcs->cs->debug & L1_DEB_HSCX) diff --git a/drivers/isdn/hisax/jade.c b/drivers/isdn/hisax/jade.c index 4f07eed87..c1bf72ca8 100644 --- a/drivers/isdn/hisax/jade.c +++ b/drivers/isdn/hisax/jade.c @@ -1,10 +1,13 @@ -/* $Id: jade.c,v 1.2 1999/07/01 08:07:57 keil Exp $ +/* $Id: jade.c,v 1.3 2000/02/26 00:35:13 keil Exp $ * * jade.c JADE stuff (derived from original hscx.c) * * Author Roland Klabunde (R.Klabunde@Berkom.de) * * $Log: jade.c,v $ + * Revision 1.3 2000/02/26 00:35:13 keil + * Fix skb freeing in interrupt context + * * Revision 1.2 1999/07/01 08:07:57 keil * Initial version * @@ -214,7 +217,7 @@ close_jadestate(struct BCState *bcs) discard_queue(&bcs->rqueue); discard_queue(&bcs->squeue); if (bcs->tx_skb) { - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); } diff --git a/drivers/isdn/hisax/jade_irq.c b/drivers/isdn/hisax/jade_irq.c index e54c80c1a..02fef2627 100644 --- a/drivers/isdn/hisax/jade_irq.c +++ b/drivers/isdn/hisax/jade_irq.c @@ -1,10 +1,13 @@ -/* $Id: jade_irq.c,v 1.2 1999/07/01 08:07:59 keil Exp $ +/* $Id: jade_irq.c,v 1.3 2000/02/26 00:35:13 keil Exp $ * * jade_irq.c Low level JADE IRQ stuff (derived from original hscx_irq.c) * * Author Roland Klabunde (R.Klabunde@Berkom.de) * * $Log: jade_irq.c,v $ + * Revision 1.3 2000/02/26 00:35:13 keil + * Fix skb freeing in interrupt context + * * Revision 1.2 1999/07/01 08:07:59 keil * Initial version * @@ -192,7 +195,7 @@ jade_interrupt(struct IsdnCardState *cs, u_char val, u_char jade) if (bcs->st->lli.l1writewakeup && (PACKET_NOACK != bcs->tx_skb->pkt_type)) bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.hscx.count); - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_irq(bcs->tx_skb); bcs->hw.hscx.count = 0; bcs->tx_skb = NULL; } diff --git a/drivers/isdn/hisax/l3dss1.c b/drivers/isdn/hisax/l3dss1.c index 9fa10e326..2b0451a0a 100644 --- a/drivers/isdn/hisax/l3dss1.c +++ b/drivers/isdn/hisax/l3dss1.c @@ -1,4 +1,4 @@ -/* $Id: l3dss1.c,v 2.22 2000/01/20 19:44:20 keil Exp $ +/* $Id: l3dss1.c,v 2.23 2000/02/26 01:38:14 keil Exp $ * EURO/DSS1 D-channel protocol * @@ -13,6 +13,9 @@ * Fritz Elfert * * $Log: l3dss1.c,v $ + * Revision 2.23 2000/02/26 01:38:14 keil + * Fixes for V.110 encoding LLC from Jens Jakobsen + * * Revision 2.22 2000/01/20 19:44:20 keil * Fixed uninitialiesed location * Fixed redirecting number IE in Setup @@ -104,7 +107,7 @@ #include extern char *HiSax_getrev(const char *revision); -const char *dss1_revision = "$Revision: 2.22 $"; +const char *dss1_revision = "$Revision: 2.23 $"; #define EXT_BEARER_CAPS 1 @@ -1045,7 +1048,8 @@ u_char * EncodeASyncParams(u_char * p, u_char si2) { // 7c 06 88 90 21 42 00 bb - p[0] = p[1] = 0; + p[0] = 0; + p[1] = 0x40; // Intermediate rate: 16 kbit/s jj 2000.02.19 p[2] = 0x80; if (si2 & 32) // 7 data bits @@ -1059,7 +1063,7 @@ EncodeASyncParams(u_char * p, u_char si2) p[2] += 96; else // 1 stop bit - p[2] = 32; + p[2] += 32; if (si2 & 8) // even parity diff --git a/drivers/isdn/hisax/md5sums.asc b/drivers/isdn/hisax/md5sums.asc index 985bd4cb4..afb83e1c8 100644 --- a/drivers/isdn/hisax/md5sums.asc +++ b/drivers/isdn/hisax/md5sums.asc @@ -6,26 +6,26 @@ # Eicon Technology Diva 2.01 PCI cards in the moment. # Read ../../../Documentation/isdn/HiSax.cert for more informations. # -3c2b1c96274cba97a8261d1cecc662b8 isac.c -a9a15d069dbacb383cc24c238cb5ebbe isdnl1.c +3fb9c99465857a4c136ae2881f4e30ba isac.c +dd3955847bbf680b41233478fe521d88 isdnl1.c bb51bd223040b511c18f091da5ab6456 isdnl2.c b7aa7f97b2374967a4aca7c52991142c isdnl3.c a23fbf8879c1432b04640b8b04bdf419 tei.c -d7072dbbeeb7c4c45f3810ed13cf5545 callc.c +ce248e56c2e1326012d0b25f92bbf99b callc.c bf9605b36429898f7be6630034e83230 cert.c -0e500813968adacaea2ef22c9cdd89eb l3dss1.c -2d748ced0eea375b21fe7ea91ca7917c l3_1tr6.c -d45fde1c90dda636ab134f2a51db435e elsa.c -0b5fb429f5bfe188fd42a5be01abbb14 diva.c +6ce0a184127be1a44747e2017ed24ad9 l3dss1.c +a3a570781f828b6d59e6b231653133de l3_1tr6.c +4aeba32c4c3480d2a6b9af34600b974f elsa.c +a296edc459b508bf0346c3132815a4db diva.c # end of md5sums -----BEGIN PGP SIGNATURE----- Version: 2.6.3i Charset: noconv -iQCVAwUBOCYF6jpxHvX/mS9tAQFnxQP/dpHyNjbo5BhFEZ8qIgpPJzoCgV+b2pB+ -h9Z/Q1jg8l23L/lP9dW00ogrKnKziVUUJqg+wWVEAA7BnNVr3aeyQKFTVuOnK5MC -Oy0Z98p530vgOBiZ47elNfpefjhfD3duSSYNA4R9fEHVZB/atKFYvB5GDGmrwjIZ -2f3g3kBP5Os= -=zNnO +iQCVAwUBOLcvXDpxHvX/mS9tAQGPWAP9Fg14RXcAwjCy4VeFoDBMOFpxllvG7xZR +HQKENCYIzXKPb6I/IBUv3+BhL8Lnhjw8a2DXz6c6u+0nmUIFnzyt1BfzT70P9rKd +BBN7f1KdIiQEmv0fZwd79Rz5PYvRDbY520bNTJZhorwqGI/qc3gGgHVtSR8OHhuS +ZMQ1pb9W6jE= +=CA5N -----END PGP SIGNATURE----- diff --git a/drivers/isdn/hisax/netjet.c b/drivers/isdn/hisax/netjet.c index 3855625bd..b1b0fd8d4 100644 --- a/drivers/isdn/hisax/netjet.c +++ b/drivers/isdn/hisax/netjet.c @@ -1,4 +1,4 @@ -/* $Id: netjet.c,v 1.17 1999/12/19 13:09:42 keil Exp $ +/* $Id: netjet.c,v 1.18 2000/02/26 00:35:13 keil Exp $ * netjet.c low level stuff for Traverse Technologie NETJet ISDN cards * @@ -7,6 +7,9 @@ * Thanks to Traverse Technologie Australia for documents and informations * * $Log: netjet.c,v $ + * Revision 1.18 2000/02/26 00:35:13 keil + * Fix skb freeing in interrupt context + * * Revision 1.17 1999/12/19 13:09:42 keil * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for * signal proof delays @@ -85,7 +88,7 @@ extern const char *CardType[]; -const char *NETjet_revision = "$Revision: 1.17 $"; +const char *NETjet_revision = "$Revision: 1.18 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -730,7 +733,7 @@ static void write_raw(struct BCState *bcs, u_int *buf, int cnt) { if (bcs->st->lli.l1writewakeup && (PACKET_NOACK != bcs->tx_skb->pkt_type)) bcs->st->lli.l1writewakeup(bcs->st, bcs->tx_skb->len); - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; } test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); @@ -873,7 +876,7 @@ close_tigerstate(struct BCState *bcs) discard_queue(&bcs->rqueue); discard_queue(&bcs->squeue); if (bcs->tx_skb) { - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); } diff --git a/drivers/isdn/hisax/w6692.c b/drivers/isdn/hisax/w6692.c index 724ce52c9..c6fe2acdd 100644 --- a/drivers/isdn/hisax/w6692.c +++ b/drivers/isdn/hisax/w6692.c @@ -1,4 +1,4 @@ -/* $Id: w6692.c,v 1.1 1999/09/04 06:28:58 keil Exp $ +/* $Id: w6692.c,v 1.2 2000/02/26 00:35:13 keil Exp $ * w6692.c Winbond W6692 specific routines * @@ -8,6 +8,9 @@ * This file is (c) under GNU PUBLIC LICENSE * * $Log: w6692.c,v $ + * Revision 1.2 2000/02/26 00:35:13 keil + * Fix skb freeing in interrupt context + * * Revision 1.1 1999/09/04 06:28:58 keil * first revision * @@ -47,7 +50,7 @@ static const PCI_ENTRY id_list[] = extern const char *CardType[]; -const char *w6692_revision = "$Revision: 1.1 $"; +const char *w6692_revision = "$Revision: 1.2 $"; #define DBUSY_TIMER_VALUE 80 @@ -378,7 +381,7 @@ W6692B_interrupt(struct IsdnCardState *cs, u_char bchan) if (bcs->st->lli.l1writewakeup && (PACKET_NOACK != bcs->tx_skb->pkt_type)) bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.w6692.count); - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_irq(bcs->tx_skb); bcs->hw.w6692.count = 0; bcs->tx_skb = NULL; } @@ -478,7 +481,7 @@ W6692_interrupt(int intno, void *dev_id, struct pt_regs *regs) W6692_fill_fifo(cs); goto afterXFR; } else { - dev_kfree_skb(cs->tx_skb); + dev_kfree_skb_irq(cs->tx_skb); cs->tx_cnt = 0; cs->tx_skb = NULL; } @@ -655,7 +658,7 @@ W6692_l1hw(struct PStack *st, int pr, void *arg) discard_queue(&cs->rq); discard_queue(&cs->sq); if (cs->tx_skb) { - dev_kfree_skb(cs->tx_skb); + dev_kfree_skb_any(cs->tx_skb); cs->tx_skb = NULL; } if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) @@ -704,7 +707,7 @@ dbusy_timer_handler(struct IsdnCardState *cs) /* discard frame; reset transceiver */ test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags); if (cs->tx_skb) { - dev_kfree_skb(cs->tx_skb); + dev_kfree_skb_any(cs->tx_skb); cs->tx_cnt = 0; cs->tx_skb = NULL; } else { @@ -819,7 +822,7 @@ close_w6692state(struct BCState *bcs) discard_queue(&bcs->rqueue); discard_queue(&bcs->squeue); if (bcs->tx_skb) { - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); } diff --git a/drivers/isdn/hysdn/hysdn_procconf.c b/drivers/isdn/hysdn/hysdn_procconf.c index 81e1b84f0..4cb480588 100644 --- a/drivers/isdn/hysdn/hysdn_procconf.c +++ b/drivers/isdn/hysdn/hysdn_procconf.c @@ -416,8 +416,6 @@ static struct file_operations conf_fops = NULL /* fsync */ }; -static struct inode_operations conf_inode_operations; - /*****************************/ /* hysdn subdir in /proc/net */ /*****************************/ @@ -446,10 +444,8 @@ hysdn_procconf_init(void) if ((card->procconf = (void *) create_proc_entry(conf_name, S_IFREG | S_IRUGO | S_IWUSR, hysdn_proc_entry)) != NULL) { - memset(&conf_inode_operations, 0, sizeof(struct inode_operations)); - conf_inode_operations.default_file_ops = &conf_fops; - ((struct proc_dir_entry *) card->procconf)->ops = &conf_inode_operations; + ((struct proc_dir_entry *) card->procconf)->proc_fops = &conf_fops; hysdn_proclog_init(card); /* init the log file entry */ } card = card->next; /* next entry */ diff --git a/drivers/isdn/hysdn/hysdn_procfs.c b/drivers/isdn/hysdn/hysdn_procfs.c index d70d350e9..b43e2ade7 100644 --- a/drivers/isdn/hysdn/hysdn_procfs.c +++ b/drivers/isdn/hysdn/hysdn_procfs.c @@ -351,27 +351,6 @@ static struct file_operations log_fops = NULL /* fsync */ }; -struct inode_operations log_inode_operations = -{ - &log_fops, /* log proc file-ops */ - NULL, /* create */ - NULL, /* lookup */ - NULL, /* link */ - NULL, /* unlink */ - NULL, /* symlink */ - NULL, /* mkdir */ - NULL, /* rmdir */ - NULL, /* mknod */ - NULL, /* rename */ - NULL, /* readlink */ - NULL, /* follow_link */ - NULL, /* readpage */ - NULL, /* writepage */ - NULL, /* bmap */ - NULL, /* truncate */ - NULL /* permission */ -}; - /*****************************************/ /* Output info data to the cardinfo file */ /*****************************************/ @@ -464,7 +443,7 @@ hysdn_procfs_init(void) sprintf(pd->log_name, "%s%d", PROC_LOG_BASENAME, card->myid); if ((pd->log = create_proc_entry(pd->log_name, S_IFREG | S_IRUGO | S_IWUSR, hysdn_proc_entry)) != NULL) - pd->log->ops = &log_inode_operations; /* set new operations table */ + pd->log->proc_fops = &log_fops; /* set new operations table */ init_waitqueue_head(&(pd->rd_queue)); diff --git a/drivers/isdn/hysdn/hysdn_proclog.c b/drivers/isdn/hysdn/hysdn_proclog.c index aea6a96ad..67a91cf0f 100644 --- a/drivers/isdn/hysdn/hysdn_proclog.c +++ b/drivers/isdn/hysdn/hysdn_proclog.c @@ -433,8 +433,6 @@ static struct file_operations log_fops = NULL /* fsync */ }; -struct inode_operations log_inode_operations; - /***********************************************************************************/ /* hysdn_proclog_init is called when the module is loaded after creating the cards */ /* conf files. */ @@ -448,12 +446,10 @@ hysdn_proclog_init(hysdn_card * card) if ((pd = (struct procdata *) kmalloc(sizeof(struct procdata), GFP_KERNEL)) != NULL) { memset(pd, 0, sizeof(struct procdata)); - memset(&log_inode_operations, 0, sizeof(struct inode_operations)); - log_inode_operations.default_file_ops = &log_fops; sprintf(pd->log_name, "%s%d", PROC_LOG_BASENAME, card->myid); if ((pd->log = create_proc_entry(pd->log_name, S_IFREG | S_IRUGO | S_IWUSR, hysdn_proc_entry)) != NULL) - pd->log->ops = &log_inode_operations; /* set new operations table */ + pd->log->proc_fops = &log_fops; /* set new operations table */ init_waitqueue_head(&(pd->rd_queue)); diff --git a/drivers/isdn/isdn_common.c b/drivers/isdn/isdn_common.c index f1df11f55..b259cdc4b 100644 --- a/drivers/isdn/isdn_common.c +++ b/drivers/isdn/isdn_common.c @@ -1,4 +1,4 @@ -/* $Id: isdn_common.c,v 1.97 2000/01/23 18:45:37 keil Exp $ +/* $Id: isdn_common.c,v 1.99 2000/02/26 01:00:52 keil Exp $ * Linux ISDN subsystem, common used functions (linklevel). * @@ -21,6 +21,12 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_common.c,v $ + * Revision 1.99 2000/02/26 01:00:52 keil + * changes from 2.3.47 + * + * Revision 1.98 2000/02/16 14:56:27 paul + * translated ISDN_MODEM_ANZREG to ISDN_MODEM_NUMREG for english speakers + * * Revision 1.97 2000/01/23 18:45:37 keil * Change EAZ mapping to forbit the use of cards (insert a "-" for the MSN) * @@ -443,7 +449,7 @@ isdn_dev *dev = (isdn_dev *) 0; -static char *isdn_revision = "$Revision: 1.97 $"; +static char *isdn_revision = "$Revision: 1.99 $"; extern char *isdn_net_revision; extern char *isdn_tty_revision; @@ -1795,15 +1801,15 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) int i; if ((ret = verify_area(VERIFY_WRITE, (void *) arg, - (ISDN_MODEM_ANZREG + ISDN_MSNLEN + ISDN_LMSNLEN) + (ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN) * ISDN_MAX_CHANNELS))) return ret; for (i = 0; i < ISDN_MAX_CHANNELS; i++) { if (copy_to_user(p, dev->mdm.info[i].emu.profile, - ISDN_MODEM_ANZREG)) + ISDN_MODEM_NUMREG)) return -EFAULT; - p += ISDN_MODEM_ANZREG; + p += ISDN_MODEM_NUMREG; if (copy_to_user(p, dev->mdm.info[i].emu.pmsn, ISDN_MSNLEN)) return -EFAULT; p += ISDN_MSNLEN; @@ -1811,7 +1817,7 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) return -EFAULT; p += ISDN_LMSNLEN; } - return (ISDN_MODEM_ANZREG + ISDN_MSNLEN + ISDN_LMSNLEN) * ISDN_MAX_CHANNELS; + return (ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN) * ISDN_MAX_CHANNELS; } else return -EINVAL; break; @@ -1822,15 +1828,15 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) int i; if ((ret = verify_area(VERIFY_READ, (void *) arg, - (ISDN_MODEM_ANZREG + ISDN_MSNLEN) + (ISDN_MODEM_NUMREG + ISDN_MSNLEN) * ISDN_MAX_CHANNELS))) return ret; for (i = 0; i < ISDN_MAX_CHANNELS; i++) { if (copy_from_user(dev->mdm.info[i].emu.profile, p, - ISDN_MODEM_ANZREG)) + ISDN_MODEM_NUMREG)) return -EFAULT; - p += ISDN_MODEM_ANZREG; + p += ISDN_MODEM_NUMREG; if (copy_from_user(dev->mdm.info[i].emu.pmsn, p, ISDN_MSNLEN)) return -EFAULT; p += ISDN_MSNLEN; @@ -2632,7 +2638,7 @@ static void isdn_cleanup_devfs(void) devfs_unregister (devfs_handle); } -#else /* CONFIG_DEVFS_FS */ +#else /* CONFIG_DEVFS_FS */ static void isdn_register_devfs(int dummy) { return; @@ -2653,7 +2659,7 @@ static void isdn_cleanup_devfs(void) return; } -#endif /* CONFIG_DEVFS_FS */ +#endif /* CONFIG_DEVFS_FS */ /* * Allocate and initialize all data, register modem-devices diff --git a/drivers/isdn/isdn_net.c b/drivers/isdn/isdn_net.c index 592d20ed9..ee3af91fa 100644 --- a/drivers/isdn/isdn_net.c +++ b/drivers/isdn/isdn_net.c @@ -1,4 +1,4 @@ -/* $Id: isdn_net.c,v 1.107 2000/02/13 09:52:05 kai Exp $ +/* $Id: isdn_net.c,v 1.110 2000/02/26 01:00:53 keil Exp $ * Linux ISDN subsystem, network interfaces and related functions (linklevel). * @@ -21,6 +21,16 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_net.c,v $ + * Revision 1.110 2000/02/26 01:00:53 keil + * changes from 2.3.47 + * + * Revision 1.109 2000/02/25 11:29:17 paul + * changed chargetime to ulong from int (after about 20 days the "chargetime of + * ipppX is now 1234" message displays a negative number on alpha). + * + * Revision 1.108 2000/02/15 12:54:01 kai + * set TX timeout back to 2 secs for 2.2.x, just to be safe + * * Revision 1.107 2000/02/13 09:52:05 kai * increased TX_TIMEOUT to 20sec * @@ -521,6 +531,14 @@ static void __inline__ isdn_net_lp_xon(isdn_net_local * lp) netif_wake_queue(&lp->netdev->dev); } +/* For 2.2.x we leave the transmitter busy timeout at 2 secs, just + * to be safe. + * For 2.3.x we push it up to 20 secs, because call establishment + * (in particular callback) may take such a long time, and we + * don't want confusing messages in the log. However, there is a slight + * possibility that this large timeout will break other things like MPPP, + * which might rely on the tx timeout. If so, we'll find out this way... + */ #define ISDN_NET_TX_TIMEOUT (20*HZ) @@ -530,7 +548,7 @@ int isdn_net_force_dial_lp(isdn_net_local *); static int isdn_net_start_xmit(struct sk_buff *, struct net_device *); static int isdn_net_xmit(struct net_device *, isdn_net_local *, struct sk_buff *); -char *isdn_net_revision = "$Revision: 1.107 $"; +char *isdn_net_revision = "$Revision: 1.110 $"; /* * Code for raw-networking over ISDN @@ -727,7 +745,7 @@ isdn_net_autohup() isdn_net_hangup(&p->dev); } else if (jiffies - l->chargetime > l->chargeint) { printk(KERN_DEBUG - "isdn_net: %s: chtime = %d, chint = %d\n", + "isdn_net: %s: chtime = %lu, chint = %d\n", l->name, l->chargetime, l->chargeint); isdn_net_hangup(&p->dev); } @@ -868,7 +886,7 @@ isdn_net_stat_callback(int idx, isdn_ctrl *c) * we correct the timestamp here. */ lp->chargetime = jiffies; - printk(KERN_DEBUG "isdn_net: chargetime of %s now %d\n", + printk(KERN_DEBUG "isdn_net: chargetime of %s now %lu\n", lp->name, lp->chargetime); /* reset dial-timeout */ @@ -915,7 +933,7 @@ isdn_net_stat_callback(int idx, isdn_ctrl *c) if (lp->hupflags & ISDN_WAITCHARGE) lp->hupflags |= ISDN_HAVECHARGE; lp->chargetime = jiffies; - printk(KERN_DEBUG "isdn_net: Got CINF chargetime of %s now %d\n", + printk(KERN_DEBUG "isdn_net: Got CINF chargetime of %s now %lu\n", lp->name, lp->chargetime); return 1; } diff --git a/drivers/isdn/isdn_tty.c b/drivers/isdn/isdn_tty.c index 0503c67a2..1e314128c 100644 --- a/drivers/isdn/isdn_tty.c +++ b/drivers/isdn/isdn_tty.c @@ -1,4 +1,4 @@ -/* $Id: isdn_tty.c,v 1.82 2000/01/23 18:45:37 keil Exp $ +/* $Id: isdn_tty.c,v 1.84 2000/02/16 15:10:14 paul Exp $ * Linux ISDN subsystem, tty functions and AT-command emulator (linklevel). * @@ -20,6 +20,15 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_tty.c,v $ + * Revision 1.84 2000/02/16 15:10:14 paul + * If a ttyI has no open FDs, don't connect incoming calls to it. + * (Hangup on close of last FD is still to be done.) + * + * Revision 1.83 2000/02/16 14:59:33 paul + * translated ISDN_MODEM_ANZREG to ISDN_MODEM_NUMREG for english speakers; + * used defines for result codes; + * fixed RING ... RUNG problem (no empty lines in between). + * * Revision 1.82 2000/01/23 18:45:37 keil * Change EAZ mapping to forbit the use of cards (insert a "-" for the MSN) * @@ -379,7 +388,7 @@ static int bit2si[8] = static int si2bit[8] = {4, 1, 4, 4, 4, 4, 4, 4}; -char *isdn_tty_revision = "$Revision: 1.82 $"; +char *isdn_tty_revision = "$Revision: 1.84 $"; /* isdn_tty_try_read() is called from within isdn_tty_rcv_skb() @@ -901,7 +910,7 @@ static void isdn_tty_modem_do_ncarrier(unsigned long data) { modem_info *info = (modem_info *) data; - isdn_tty_modem_result(3, info); + isdn_tty_modem_result(RESULT_NO_CARRIER, info); } /* Next routine is called, whenever the DTR-signal is raised. @@ -986,7 +995,7 @@ isdn_tty_dial(char *n, modem_info * info, atemu * m) i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn); if (i < 0) { restore_flags(flags); - isdn_tty_modem_result(6, info); + isdn_tty_modem_result(RESULT_NO_DIALTONE, info); } else { info->isdn_driver = dev->drvmap[i]; info->isdn_channel = dev->chanmap[i]; @@ -1056,8 +1065,7 @@ isdn_tty_modem_hup(modem_info * info, int local) if (info->online) { info->last_lhup = local; info->online = 0; - /* NO CARRIER message */ - isdn_tty_modem_result(3, info); + isdn_tty_modem_result(RESULT_NO_CARRIER, info); } #ifdef CONFIG_ISDN_AUDIO info->vonline = 0; @@ -1086,7 +1094,7 @@ isdn_tty_modem_hup(modem_info * info, int local) #endif if ((info->msr & UART_MSR_RI) && (info->emu.mdmreg[REG_RUNG] & BIT_RUNG)) - isdn_tty_modem_result(12, info); + isdn_tty_modem_result(RESULT_RUNG, info); info->msr &= ~(UART_MSR_DCD | UART_MSR_RI); info->lsr |= UART_LSR_TEMT; if (info->isdn_driver >= 0) { @@ -1197,7 +1205,7 @@ isdn_tty_resume(char *id, modem_info * info, atemu * m) i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn); if (i < 0) { restore_flags(flags); - isdn_tty_modem_result(6, info); + isdn_tty_modem_result(RESULT_NO_DIALTONE, info); } else { info->isdn_driver = dev->drvmap[i]; info->isdn_channel = dev->chanmap[i]; @@ -1265,7 +1273,7 @@ isdn_tty_send_msg(modem_info * info, atemu * m, char *msg) l = strlen(msg); if (!l) { - isdn_tty_modem_result(4, info); + isdn_tty_modem_result(RESULT_ERROR, info); return; } for (j = 7; j >= 0; j--) @@ -1291,7 +1299,7 @@ isdn_tty_send_msg(modem_info * info, atemu * m, char *msg) i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn); if (i < 0) { restore_flags(flags); - isdn_tty_modem_result(6, info); + isdn_tty_modem_result(RESULT_NO_DIALTONE, info); } else { info->isdn_driver = dev->drvmap[i]; info->isdn_channel = dev->chanmap[i]; @@ -1589,7 +1597,7 @@ isdn_tty_write(struct tty_struct *tty, int from_user, const u_char * buf, int co #ifdef ISDN_DEBUG_MODEM_HUP printk(KERN_DEBUG "Mhup in isdn_tty_write\n"); #endif - isdn_tty_modem_result(3, info); + isdn_tty_modem_result(RESULT_NO_CARRIER, info); isdn_tty_modem_hup(info, 1); } else c = isdn_tty_edit_at(buf, c, info, from_user); @@ -2321,7 +2329,7 @@ isdn_tty_modem_reset_regs(modem_info * info, int force) { atemu *m = &info->emu; if ((m->mdmreg[REG_DTRR] & BIT_DTRR) || force) { - memcpy(m->mdmreg, m->profile, ISDN_MODEM_ANZREG); + memcpy(m->mdmreg, m->profile, ISDN_MODEM_NUMREG); memcpy(m->msn, m->pmsn, ISDN_MSNLEN); memcpy(m->lmsn, m->plmsn, ISDN_LMSNLEN); info->xmit_size = m->mdmreg[REG_PSIZE] * 16; @@ -2338,7 +2346,7 @@ isdn_tty_modem_reset_regs(modem_info * info, int force) static void modem_write_profile(atemu * m) { - memcpy(m->profile, m->mdmreg, ISDN_MODEM_ANZREG); + memcpy(m->profile, m->mdmreg, ISDN_MODEM_NUMREG); memcpy(m->pmsn, m->msn, ISDN_MSNLEN); memcpy(m->plmsn, m->lmsn, ISDN_LMSNLEN); if (dev->profd) @@ -2447,6 +2455,13 @@ isdn_tty_modem_init(void) return 0; } + +/* + * isdn_tty_match_icall(char *MSN, atemu *tty_emulator, int dev_idx) + * match the MSN against the MSNs (glob patterns) defined for tty_emulator, + * and return 0 for match, 1 for no match, 2 if MSN could match if longer. + */ + static int isdn_tty_match_icall(char *cid, atemu *emu, int di) { @@ -2512,15 +2527,14 @@ isdn_tty_find_icall(int di, int ch, setup_parm setup) int idx; int si1; int si2; - char nr[32]; + char *nr; ulong flags; if (!setup.phone[0]) { - nr[0] = '0'; - nr[1] = '\0'; + nr = "0"; printk(KERN_INFO "isdn_tty: Incoming call without OAD, assuming '0'\n"); } else - strcpy(nr, setup.phone); + nr = setup.phone; si1 = (int) setup.si1; si2 = (int) setup.si2; if (!setup.eazmsn[0]) { @@ -2537,6 +2551,8 @@ isdn_tty_find_icall(int di, int ch, setup_parm setup) for (i = 0; i < ISDN_MAX_CHANNELS; i++) { modem_info *info = &dev->mdm.info[i]; + if (info->count == 0) + continue; if ((info->emu.mdmreg[REG_SI1] & si2bit[si1]) && /* SI1 is matching */ (info->emu.mdmreg[REG_SI2] == si2)) { /* SI2 is matching */ idx = isdn_dc2minor(di, ch); @@ -2574,7 +2590,7 @@ isdn_tty_find_icall(int di, int ch, setup_parm setup) printk(KERN_INFO "isdn_tty: call from %s, -> RING on ttyI%d\n", nr, info->line); info->msr |= UART_MSR_RI; - isdn_tty_modem_result(2, info); + isdn_tty_modem_result(RESULT_RING, info); isdn_timer_ctrl(ISDN_TIMER_MODEMRING, 1); return 1; } @@ -2660,9 +2676,9 @@ isdn_tty_stat_callback(int i, isdn_ctrl *c) #endif if (TTY_IS_ACTIVE(info)) { if (info->dialing == 1) - isdn_tty_modem_result(7, info); + isdn_tty_modem_result(RESULT_BUSY, info); if (info->dialing > 1) - isdn_tty_modem_result(3, info); + isdn_tty_modem_result(RESULT_NO_CARRIER, info); info->dialing = 0; #ifdef ISDN_DEBUG_MODEM_HUP printk(KERN_DEBUG "Mhup in ISDN_STAT_DHUP\n"); @@ -2691,12 +2707,12 @@ isdn_tty_stat_callback(int i, isdn_ctrl *c) if (USG_MODEM(dev->usage[i])) { if (info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM) { strcpy(info->emu.connmsg, c->parm.num); - isdn_tty_modem_result(1, info); + isdn_tty_modem_result(RESULT_CONNECT, info); } else - isdn_tty_modem_result(5, info); + isdn_tty_modem_result(RESULT_CONNECT64000, info); } if (USG_VOICE(dev->usage[i])) - isdn_tty_modem_result(11, info); + isdn_tty_modem_result(RESULT_VCON, info); return 1; } break; @@ -2722,7 +2738,7 @@ isdn_tty_stat_callback(int i, isdn_ctrl *c) info->last_l2 = -1; info->last_si = 0; sprintf(info->last_cause, "0000"); - isdn_tty_modem_result(6, info); + isdn_tty_modem_result(RESULT_NO_DIALTONE, info); } isdn_tty_modem_hup(info, 0); return 1; @@ -2937,6 +2953,7 @@ isdn_tty_check_esc(const u_char * p, u_char plus, int count, int *pluscount, * For CONNECT-messages also switch to online-mode. * For RING-message handle auto-ATA if register 0 != 0 */ + static void isdn_tty_modem_result(int code, modem_info * info) { @@ -2949,14 +2966,13 @@ isdn_tty_modem_result(int code, modem_info * info) char s[ISDN_MSNLEN+10]; switch (code) { - case 2: - m->mdmreg[REG_RINGCNT]++; /* RING */ + case RESULT_RING: + m->mdmreg[REG_RINGCNT]++; if (m->mdmreg[REG_RINGCNT] == m->mdmreg[REG_RINGATA]) /* Automatically accept incoming call */ isdn_tty_cmd_ATA(info); break; - case 3: - /* NO CARRIER */ + case RESULT_NO_CARRIER: #ifdef ISDN_DEBUG_MODEM_HUP printk(KERN_DEBUG "modem_result: NO CARRIER %d %d\n", (info->flags & ISDN_ASYNC_CLOSING), @@ -2991,13 +3007,13 @@ isdn_tty_modem_result(int code, modem_info * info) } #endif break; - case 1: - case 5: + case RESULT_CONNECT: + case RESULT_CONNECT64000: sprintf(info->last_cause, "0000"); if (!info->online) info->online = 2; break; - case 11: + case RESULT_VCON: #ifdef ISDN_DEBUG_MODEM_VOICE printk(KERN_DEBUG "res3: send VCON on ttyI%d\n", info->line); @@ -3006,27 +3022,30 @@ isdn_tty_modem_result(int code, modem_info * info) if (!info->online) info->online = 1; break; - } + } /* switch(code) */ + if (m->mdmreg[REG_RESP] & BIT_RESP) { /* Show results */ - isdn_tty_at_cout("\r\n", info); if (m->mdmreg[REG_RESPNUM] & BIT_RESPNUM) { - /* Show numeric results */ - sprintf(s, "%d", code); + /* Show numeric results only */ + sprintf(s, "\r\n%d\r\n", code); isdn_tty_at_cout(s, info); } else { - if ((code == 2) && - (m->mdmreg[REG_RUNG] & BIT_RUNG) && - (m->mdmreg[REG_RINGCNT] > 1)) - return; - if ((code == 2) && (!(m->mdmreg[REG_CIDONCE] & BIT_CIDONCE))) { - isdn_tty_at_cout("CALLER NUMBER: ", info); - isdn_tty_at_cout(dev->num[info->drv_index], info); - isdn_tty_at_cout("\r\n", info); + if (code == RESULT_RING) { + /* return if "show RUNG" and ringcounter>1 */ + if ((m->mdmreg[REG_RUNG] & BIT_RUNG) && + (m->mdmreg[REG_RINGCNT] > 1)) + return; + /* print CID, _before_ _every_ ring */ + if (!(m->mdmreg[REG_CIDONCE] & BIT_CIDONCE)) { + isdn_tty_at_cout("\r\nCALLER NUMBER: ", info); + isdn_tty_at_cout(dev->num[info->drv_index], info); + } } + isdn_tty_at_cout("\r\n", info); isdn_tty_at_cout(msg[code], info); switch (code) { - case 1: + case RESULT_CONNECT: switch (m->mdmreg[REG_L2PROT]) { case ISDN_PROTO_L2_MODEM: isdn_tty_at_cout(" ", info); @@ -3034,13 +3053,13 @@ isdn_tty_modem_result(int code, modem_info * info) break; } break; - case 2: + case RESULT_RING: /* Append CPN, if enabled */ if ((m->mdmreg[REG_CPN] & BIT_CPN)) { sprintf(s, "/%s", m->cpn); isdn_tty_at_cout(s, info); } - /* Print CID only once, _after_ 1.st RING */ + /* Print CID only once, _after_ 1st RING */ if ((m->mdmreg[REG_CIDONCE] & BIT_CIDONCE) && (m->mdmreg[REG_RINGCNT] == 1)) { isdn_tty_at_cout("\r\n", info); @@ -3048,10 +3067,10 @@ isdn_tty_modem_result(int code, modem_info * info) isdn_tty_at_cout(dev->num[info->drv_index], info); } break; - case 3: - case 6: - case 7: - case 8: + case RESULT_NO_CARRIER: + case RESULT_NO_DIALTONE: + case RESULT_BUSY: + case RESULT_NO_ANSWER: m->mdmreg[REG_RINGCNT] = 0; /* Append Cause-Message if enabled */ if (m->mdmreg[REG_RESPXT] & BIT_RESPXT) { @@ -3059,7 +3078,7 @@ isdn_tty_modem_result(int code, modem_info * info) isdn_tty_at_cout(s, info); } break; - case 5: + case RESULT_CONNECT64000: /* Append Protocol to CONNECT message */ switch (m->mdmreg[REG_L2PROT]) { case ISDN_PROTO_L2_X75I: @@ -3087,10 +3106,10 @@ isdn_tty_modem_result(int code, modem_info * info) } break; } + isdn_tty_at_cout("\r\n", info); } - isdn_tty_at_cout("\r\n", info); } - if (code == 3) { + if (code == RESULT_NO_CARRIER) { save_flags(flags); cli(); if ((info->flags & ISDN_ASYNC_CLOSING) || (!info->tty)) { @@ -3108,6 +3127,7 @@ isdn_tty_modem_result(int code, modem_info * info) } } + /* * Display a modem-register-value. */ @@ -3160,8 +3180,8 @@ isdn_tty_getdial(char *p, char *q,int cnt) *q = 0; } -#define PARSE_ERROR { isdn_tty_modem_result(4, info); return; } -#define PARSE_ERROR1 { isdn_tty_modem_result(4, info); return 1; } +#define PARSE_ERROR { isdn_tty_modem_result(RESULT_ERROR, info); return; } +#define PARSE_ERROR1 { isdn_tty_modem_result(RESULT_ERROR, info); return 1; } static void isdn_tty_report(modem_info * info) @@ -3329,8 +3349,8 @@ isdn_tty_cmd_ATand(char **p, modem_info * info) /* &L -Set Numbers to listen on */ p[0]++; i = 0; - while ((strchr("0123456789,-*[]?;", *p[0])) && - (i < ISDN_LMSNLEN) && *p[0]) + while (*p[0] && (strchr("0123456789,-*[]?;", *p[0])) && + (i < ISDN_LMSNLEN)) m->lmsn[i++] = *p[0]++; m->lmsn[i] = '\0'; break; @@ -3381,7 +3401,7 @@ isdn_tty_cmd_ATand(char **p, modem_info * info) /* &V - Show registers */ p[0]++; isdn_tty_at_cout("\r\n", info); - for (i = 0; i < ISDN_MODEM_ANZREG; i++) { + for (i = 0; i < ISDN_MODEM_NUMREG; i++) { sprintf(rb, "S%02d=%03d%s", i, m->mdmreg[i], ((i + 1) % 10) ? " " : "\r\n"); isdn_tty_at_cout(rb, info); @@ -3486,7 +3506,7 @@ isdn_tty_cmd_ATS(char **p, modem_info * info) int bval; mreg = isdn_getnum(p); - if (mreg < 0 || mreg >= ISDN_MODEM_ANZREG) + if (mreg < 0 || mreg >= ISDN_MODEM_NUMREG) PARSE_ERROR1; switch (*p[0]) { case '=': @@ -3589,7 +3609,7 @@ isdn_tty_cmd_ATA(modem_info * info) isdn_command(&cmd); isdn_timer_ctrl(ISDN_TIMER_CARRIER, 1); } else - isdn_tty_modem_result(8, info); + isdn_tty_modem_result(RESULT_NO_ANSWER, info); } #ifdef CONFIG_ISDN_AUDIO @@ -3779,7 +3799,7 @@ isdn_tty_cmd_PLUSV(char **p, modem_info * info) if (!m->vpar[0]) PARSE_ERROR1; if (info->online != 1) { - isdn_tty_modem_result(8, info); + isdn_tty_modem_result(RESULT_NO_ANSWER, info); return 1; } info->dtmf_state = isdn_audio_dtmf_init(info->dtmf_state); @@ -3803,7 +3823,7 @@ isdn_tty_cmd_PLUSV(char **p, modem_info * info) printk(KERN_DEBUG "AT: +VRX\n"); #endif info->vonline |= 1; - isdn_tty_modem_result(1, info); + isdn_tty_modem_result(RESULT_CONNECT, info); return 0; break; case 4: @@ -3893,7 +3913,7 @@ isdn_tty_cmd_PLUSV(char **p, modem_info * info) if (!m->vpar[0]) PARSE_ERROR1; if (info->online != 1) { - isdn_tty_modem_result(8, info); + isdn_tty_modem_result(RESULT_NO_ANSWER, info); return 1; } info->dtmf_state = isdn_audio_dtmf_init(info->dtmf_state); @@ -3913,7 +3933,7 @@ isdn_tty_cmd_PLUSV(char **p, modem_info * info) #endif m->lastDLE = 0; info->vonline |= 2; - isdn_tty_modem_result(1, info); + isdn_tty_modem_result(RESULT_CONNECT, info); return 0; break; case 7: @@ -3998,13 +4018,13 @@ isdn_tty_parse_at(modem_info * info) if (info->msr & UART_MSR_DCD) PARSE_ERROR; if (info->msr & UART_MSR_RI) { - isdn_tty_modem_result(3, info); + isdn_tty_modem_result(RESULT_NO_CARRIER, info); return; } isdn_tty_getdial(++p, ds, sizeof ds); p += strlen(p); if (!strlen(m->msn)) - isdn_tty_modem_result(10, info); + isdn_tty_modem_result(RESULT_NO_MSN_EAZ, info); else if (strlen(ds)) isdn_tty_dial(ds, info, m); else @@ -4076,9 +4096,9 @@ isdn_tty_parse_at(modem_info * info) p++; if (info->msr & UART_MSR_DCD) /* if B-Channel is up */ - isdn_tty_modem_result((m->mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM) ? 1:5, info); + isdn_tty_modem_result((m->mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM) ? RESULT_CONNECT:RESULT_CONNECT64000, info); else - isdn_tty_modem_result(3, info); + isdn_tty_modem_result(RESULT_NO_CARRIER, info); return; case 'Q': /* Q - Turn Emulator messages on/off */ @@ -4171,7 +4191,7 @@ isdn_tty_parse_at(modem_info * info) #ifdef CONFIG_ISDN_AUDIO if (!info->vonline) #endif - isdn_tty_modem_result(0, info); + isdn_tty_modem_result(RESULT_OK, info); } /* Need own toupper() because standard-toupper is not available @@ -4282,7 +4302,7 @@ isdn_tty_modem_escape(void) ((jiffies - info->emu.lastplus) > PLUSWAIT2)) { info->emu.pluscount = 0; info->online = 0; - isdn_tty_modem_result(0, info); + isdn_tty_modem_result(RESULT_OK, info); } } } @@ -4304,7 +4324,7 @@ isdn_tty_modem_ring(void) modem_info *info = &dev->mdm.info[i]; if (info->msr & UART_MSR_RI) { ton = 1; - isdn_tty_modem_result(2, info); + isdn_tty_modem_result(RESULT_RING, info); } } isdn_timer_ctrl(ISDN_TIMER_MODEMRING, ton); @@ -4346,7 +4366,7 @@ isdn_tty_carrier_timeout(void) if (info->dialing) { if (info->emu.carrierwait++ > info->emu.mdmreg[REG_WAITC]) { info->dialing = 0; - isdn_tty_modem_result(3, info); + isdn_tty_modem_result(RESULT_NO_CARRIER, info); isdn_tty_modem_hup(info, 1); } else diff --git a/drivers/isdn/isdn_tty.h b/drivers/isdn/isdn_tty.h index ff7e479f0..ed9190cfe 100644 --- a/drivers/isdn/isdn_tty.h +++ b/drivers/isdn/isdn_tty.h @@ -1,4 +1,4 @@ -/* $Id: isdn_tty.h,v 1.18 2000/01/20 19:55:33 keil Exp $ +/* $Id: isdn_tty.h,v 1.19 2000/02/16 14:59:33 paul Exp $ * header for Linux ISDN subsystem, tty related functions (linklevel). * @@ -20,6 +20,11 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_tty.h,v $ + * Revision 1.19 2000/02/16 14:59:33 paul + * translated ISDN_MODEM_ANZREG to ISDN_MODEM_NUMREG for english speakers; + * used defines for result codes; + * fixed RING ... RUNG problem (no empty lines in between). + * * Revision 1.18 2000/01/20 19:55:33 keil * Add FAX Class 1 support * @@ -110,7 +115,7 @@ * Definition of some special Registers of AT-Emulator */ #define REG_RINGATA 0 -#define REG_RINGCNT 1 +#define REG_RINGCNT 1 /* ring counter register */ #define REG_ESC 2 #define REG_CR 3 #define REG_LF 4 @@ -118,10 +123,10 @@ #define REG_WAITC 7 -#define REG_RESP 12 -#define BIT_RESP 1 -#define REG_RESPNUM 12 -#define BIT_RESPNUM 2 +#define REG_RESP 12 /* show response messages register */ +#define BIT_RESP 1 /* show response messages bit */ +#define REG_RESPNUM 12 /* show numeric responses register */ +#define BIT_RESPNUM 2 /* show numeric responses bit */ #define REG_ECHO 12 #define BIT_ECHO 4 #define REG_DCD 12 @@ -144,8 +149,8 @@ #define BIT_RESPXT 8 #define REG_CIDONCE 13 #define BIT_CIDONCE 16 -#define REG_RUNG 13 -#define BIT_RUNG 64 +#define REG_RUNG 13 /* show RUNG message register */ +#define BIT_RUNG 64 /* show RUNG message bit */ #define REG_DISPLAY 13 #define BIT_DISPLAY 128 @@ -163,6 +168,21 @@ #define BIT_CPN 1 #define BIT_CPNFCON 2 +/* defines for result codes */ +#define RESULT_OK 0 +#define RESULT_CONNECT 1 +#define RESULT_RING 2 +#define RESULT_NO_CARRIER 3 +#define RESULT_ERROR 4 +#define RESULT_CONNECT64000 5 +#define RESULT_NO_DIALTONE 6 +#define RESULT_BUSY 7 +#define RESULT_NO_ANSWER 8 +#define RESULT_RINGING 9 +#define RESULT_NO_MSN_EAZ 10 +#define RESULT_VCON 11 +#define RESULT_RUNG 12 + #define TTY_IS_FCLASS1(info) \ ((info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_FAX) && \ (info->emu.mdmreg[REG_L3PROT] == ISDN_PROTO_L3_FCLASS1)) diff --git a/drivers/isdn/sc/debug.h b/drivers/isdn/sc/debug.h index f813b5c99..ba100543d 100644 --- a/drivers/isdn/sc/debug.h +++ b/drivers/isdn/sc/debug.h @@ -1,5 +1,5 @@ /* - * $Id: debug.h,v 1.1 1996/11/07 13:07:42 fritz Exp $ + * $Id: debug.h,v 1.2 2000/02/26 01:00:53 keil Exp $ * Copyright (C) 1996 SpellCaster Telecommunications Inc. * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c index d66393649..5a5d5fcf0 100644 --- a/drivers/net/3c505.c +++ b/drivers/net/3c505.c @@ -361,8 +361,7 @@ static inline unsigned int send_pcb_fast(unsigned int base_addr, unsigned char b static inline void prime_rx(struct net_device *dev) { elp_device *adapter = dev->priv; - while (adapter->rx_active < ELP_RX_PCBS && - netif_running(dev->state)) { + while (adapter->rx_active < ELP_RX_PCBS && netif_running(dev)) { if (!start_receive(dev, &adapter->itx_pcb)) break; } diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index c2eceb8db..6169eb742 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -87,7 +87,7 @@ an MMIO register read. #include -#define RTL8139_VERSION "0.9.3" +#define RTL8139_VERSION "0.9.4" #define RTL8139_MODULE_NAME "8139too" #define RTL8139_DRIVER_NAME RTL8139_MODULE_NAME " Fast Ethernet driver " RTL8139_VERSION #define PFX RTL8139_MODULE_NAME ": " @@ -101,8 +101,8 @@ an MMIO register read. #define DPRINTK(fmt, args...) #endif -#define RTL8139_NDEBUG 0 /* define to 1 to disable lightweight runtime checks */ -#if RTL8139_NDEBUG +#undef RTL8139_NDEBUG /* define to 1 to disable lightweight runtime checks */ +#ifdef RTL8139_NDEBUG #define assert(expr) #else #define assert(expr) \ @@ -144,6 +144,7 @@ static int multicast_filter_limit = 32; #define RX_DMA_BURST 4 /* Maximum PCI burst, '4' is 256 bytes */ #define TX_DMA_BURST 4 /* Calculate as 16< 0x80 ? */ + spinlock_t lock; }; MODULE_AUTHOR ("Jeff Garzik "); @@ -374,6 +392,8 @@ static int mii_ioctl (struct net_device *dev, struct ifreq *rq, int cmd); static struct net_device_stats *rtl8139_get_stats (struct net_device *dev); static inline u32 ether_crc (int length, unsigned char *data); static void rtl8139_set_rx_mode (struct net_device *dev); +static void rtl8139_hw_start (struct net_device *dev); + /* write MMIO register, with flush */ /* Flush avoids rtl8139 bug w/ posted MMIO writes */ @@ -409,30 +429,17 @@ static const u16 rtl8139_intr_mask = TxErr | TxOK | RxErr | RxOK; static const unsigned int rtl8139_rx_config = - (RX_FIFO_THRESH << 13) | - (RX_BUF_LEN_IDX << 11) | + (RX_FIFO_THRESH << 13) | (RxCfgRcv32K) | (RX_DMA_BURST << 8); -static const char * __devinit rtl8139_name_from_chip (chip_t chip) -{ - int i; - - for (i = 0; i < arraysize (chip_info); i++) - if (chip == chip_info[i].chip) - return chip_info[i].name; - - return "unknown"; -} - - static int __devinit rtl8139_init_pci (struct pci_dev *pdev, void **ioaddr_out) { void *ioaddr = NULL; u8 tmp8; int rc; - u32 pio_start, pio_end, pio_flags; - u32 mmio_start, mmio_end, mmio_flags; + u32 pio_start, pio_end, pio_flags, pio_len; + u32 mmio_start, mmio_end, mmio_flags, mmio_len; DPRINTK ("ENTER\n"); @@ -444,48 +451,67 @@ static int __devinit rtl8139_init_pci (struct pci_dev *pdev, void **ioaddr_out) pio_start = pci_resource_start (pdev, 0); pio_end = pci_resource_end (pdev, 0); pio_flags = pci_resource_flags (pdev, 0); + pio_len = pci_resource_len (pdev, 0); mmio_start = pci_resource_start (pdev, 1); mmio_end = pci_resource_end (pdev, 1); mmio_flags = pci_resource_flags (pdev, 1); + mmio_len = pci_resource_len (pdev, 1); /* make sure PCI base addr 0 is PIO */ - if (pio_start == 0 || pio_end <= pio_start || - (!(pio_flags & IORESOURCE_IO))) { - printk (KERN_ERR PFX "no PIO resource, aborting\n"); - return -ENODEV; + if (!(pio_flags & IORESOURCE_IO)) { + printk (KERN_ERR PFX "region #0 not a PIO resource, aborting\n"); + rc = -ENODEV; + goto err_out; } /* make sure PCI base addr 1 is MMIO */ - if (mmio_start == 0 || mmio_end <= mmio_start || - (!(mmio_flags & IORESOURCE_MEM))) { - printk (KERN_ERR PFX "no MMIO resource, aborting\n"); - return -ENODEV; + if (!(mmio_flags & IORESOURCE_MEM)) { + printk (KERN_ERR PFX "region #1 not an MMIO resource, aborting\n"); + rc = -ENODEV; + goto err_out; + } + + /* check for weird/broken PCI region reporting */ + if ((pio_len != mmio_len) || + (pio_len < RTL_MIN_IO_SIZE) || + (mmio_len < RTL_MIN_IO_SIZE)) { + printk (KERN_ERR PFX "Invalid PCI region size(s), aborting\n"); + rc = -ENODEV; + goto err_out; } /* make sure our PIO region in PCI space is available */ - if (!request_region (pio_start, RTL_IO_SIZE, RTL8139_MODULE_NAME)) { + if (!request_region (pio_start, pio_len, RTL8139_MODULE_NAME)) { printk (KERN_ERR PFX "no I/O resource available, aborting\n"); - return -EBUSY; + rc = -EBUSY; + goto err_out; } /* make sure our MMIO region in PCI space is available */ - if (!request_mem_region (mmio_start, RTL_IO_SIZE, RTL8139_MODULE_NAME)) { - release_region (pio_start, RTL_IO_SIZE); + if (!request_mem_region (mmio_start, mmio_len, RTL8139_MODULE_NAME)) { printk (KERN_ERR PFX "no mem resource available, aborting\n"); - return -EBUSY; + rc = -EBUSY; + goto err_out_free_pio; } /* enable device (incl. PCI PM wakeup), and bus-mastering */ - pci_enable_device (pdev); + rc = pci_enable_device (pdev); + if (rc) { + printk (KERN_ERR PFX "cannot enable PCI device (bus %d, " + "devfn %d), aborting\n", + pdev->bus->number, pdev->devfn); + goto err_out_free_mmio; + } + pci_set_master (pdev); /* ioremap MMIO region */ - ioaddr = ioremap (mmio_start, RTL_IO_SIZE); + ioaddr = ioremap (mmio_start, mmio_len); if (ioaddr == NULL) { printk (KERN_ERR PFX "cannot remap MMIO, aborting\n"); rc = -EIO; - goto err_out; + goto err_out_free_mmio; } /* Bring the chip out of low-power mode. */ @@ -496,12 +522,12 @@ static int __devinit rtl8139_init_pci (struct pci_dev *pdev, void **ioaddr_out) if ((tmp8 & Cfg1_PIO) == 0) { printk (KERN_ERR PFX "PIO not enabled, Cfg1=%02X, aborting\n", tmp8); rc = -EIO; - goto err_out; + goto err_out_iounmap; } if ((tmp8 & Cfg1_MMIO) == 0) { printk (KERN_ERR PFX "MMIO not enabled, Cfg1=%02X, aborting\n", tmp8); rc = -EIO; - goto err_out; + goto err_out_iounmap; } /* sanity checks -- ensure PIO and MMIO registers agree */ @@ -514,28 +540,43 @@ static int __devinit rtl8139_init_pci (struct pci_dev *pdev, void **ioaddr_out) *ioaddr_out = ioaddr; return 0; +err_out_iounmap: + assert (ioaddr > 0); + iounmap (ioaddr); +err_out_free_mmio: + release_mem_region (mmio_start, mmio_len); +err_out_free_pio: + release_region (pio_start, pio_len); err_out: - if (ioaddr) - iounmap (ioaddr); - release_region (pio_start, RTL_IO_SIZE); - release_mem_region (mmio_start, RTL_IO_SIZE); DPRINTK ("EXIT, returning %d\n", rc); return rc; } -static int __devinit rtl8139_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) +static int __devinit rtl8139_init_one (struct pci_dev *pdev, + const struct pci_device_id *ent) { struct net_device *dev; struct rtl8139_private *tp; int i, addr_len, option = -1; void *ioaddr = NULL; +#ifndef RTL8139_NDEBUG + static int printed_version = 0; +#endif /* RTL8139_NDEBUG */ + DPRINTK ("ENTER\n"); assert (pdev != NULL); assert (ent != NULL); - + +#ifndef RTL8139_NDEBUG + if (!printed_version) { + printk (KERN_INFO RTL8139_DRIVER_NAME " loaded\n"); + printed_version = 1; + } +#endif /* RTL8139_NDEBUG */ + i = rtl8139_init_pci (pdev, &ioaddr); if (i < 0) { DPRINTK ("EXIT, returning %d\n", i); @@ -571,31 +612,34 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev, const struct pci_de dev->irq = pdev->irq; dev->base_addr = pci_resource_start (pdev, 1); + /* dev->priv/tp zeroed in init_etherdev */ dev->priv = tp = (void *) (((long)dev->priv + PRIV_ALIGN) & ~PRIV_ALIGN); - printk (KERN_INFO "%s: %s at 0x%lx, IRQ %d, " - "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", - dev->name, rtl8139_name_from_chip(ent->driver_data), - dev->base_addr, dev->irq, - dev->dev_addr[0], dev->dev_addr[1], - dev->dev_addr[2], dev->dev_addr[3], - dev->dev_addr[4], dev->dev_addr[5]); - - /* tp zeroed in init_etherdev */ tp->drv_flags = PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | RTL8139_CAPS; tp->pci_dev = pdev; tp->chip = ent->driver_data; tp->mmio_addr = ioaddr; + tp->extended_regs = + (pci_resource_len (pdev, 0) == RTL8139B_IO_SIZE) ? 1 : 0; tp->lock = SPIN_LOCK_UNLOCKED; PCI_SET_DRIVER_DATA (pdev, dev); tp->phys[0] = 32; + printk (KERN_INFO "%s: %s at 0x%lx, IRQ %d,%s " + "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", + dev->name, chip_info[ent->driver_data].name, + dev->base_addr, dev->irq, + tp->extended_regs ? " 8139B regs," : "", + dev->dev_addr[0], dev->dev_addr[1], + dev->dev_addr[2], dev->dev_addr[3], + dev->dev_addr[4], dev->dev_addr[5]); + /* Put the chip into low-power mode. */ - RTL_W8 (Cfg9346, 0xC0); + RTL_W8 (Cfg9346, Cfg9346_Unlock); RTL_W8 (Config1, 0x03); /* Enable PM & PCI VPD */ RTL_W8 (HltClk, 'H'); /* 'R' would leave the clock running. */ @@ -635,8 +679,10 @@ static void __devexit rtl8139_remove_one (struct pci_dev *pdev) unregister_netdev (dev); iounmap (np->mmio_addr); - release_region (pci_resource_start (pdev, 0), RTL_IO_SIZE); - release_mem_region (pci_resource_start (pdev, 1), RTL_IO_SIZE); + release_region (pci_resource_start (pdev, 0), + pci_resource_len (pdev, 0)); + release_mem_region (pci_resource_start (pdev, 1), + pci_resource_len (pdev, 1)); #ifndef RTL8139_NDEBUG /* poison memory before freeing */ @@ -644,7 +690,7 @@ static void __devexit rtl8139_remove_one (struct pci_dev *pdev) sizeof (struct net_device) + sizeof (struct rtl8139_private) + PRIV_ALIGN); -#endif +#endif /* RTL8139_NDEBUG */ kfree (dev); @@ -851,16 +897,14 @@ static void mdio_write (struct net_device *dev, int phy_id, int location, static int rtl8139_open (struct net_device *dev) { struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; +#ifdef RTL8139_DEBUG void *ioaddr = tp->mmio_addr; - int i; +#endif DPRINTK ("ENTER\n"); MOD_INC_USE_COUNT; - /* Soft reset the chip. */ - RTL_W8 (ChipCmd, CmdReset); - if (request_irq (dev->irq, &rtl8139_interrupt, SA_SHIRQ, dev->name, dev)) { DPRINTK ("EXIT, returning -EBUSY\n"); MOD_DEC_USE_COUNT; @@ -891,44 +935,7 @@ static int rtl8139_open (struct net_device *dev) tp->full_duplex = tp->duplex_lock; tp->tx_flag = (TX_FIFO_THRESH << 11) & 0x003f0000; - /* Check that the chip has finished the reset. */ - for (i = 1000; i > 0; i--) - if ((RTL_R8 (ChipCmd) & CmdReset) == 0) - break; - - RTL_W32_F (MAC0 + 0, cpu_to_le32 (*(u32 *) (dev->dev_addr + 0))); - RTL_W32_F (MAC0 + 4, cpu_to_le32 (*(u32 *) (dev->dev_addr + 4))); - - /* Must enable Tx/Rx before setting transfer thresholds! */ - RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb); - RTL_W32 (RxConfig, rtl8139_rx_config); - RTL_W32 (TxConfig, (TX_DMA_BURST << 8) | 0x00000000); - - /* Reset N-Way to chipset defaults */ - RTL_W16 (BasicModeCtrl, (1<<15)|(1<<12)|(1<<9)); - for (i = 1000; i > 0; i--) - if ((RTL_R8 (BasicModeCtrl) & (1<<15)) == 0) - break; - - /* Set N-Way to sane defaults */ - RTL_W16 (FIFOTMS, 0x0000); - RTL_W16 (NWayAdvert, (1<<13)|(1<<8)|(1<<7)|(1<<6)|(1<<5)|0x1); - RTL_W16 (BasicModeCtrl, (1<<13)|(1<<12)|(1<<9)|(1<<8)); - - RTL_W8 (Cfg9346, 0xC0); - RTL_W8 (Config1, tp->full_duplex ? 0x60 : 0x20); - RTL_W8 (Cfg9346, 0x00); - - RTL_W32 (RxBuf, tp->rx_ring_dma); - - /* Start the chip's Tx and Rx process. */ - RTL_W32 (RxMissed, 0); - rtl8139_set_rx_mode (dev); - - RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb); - - /* Enable all known interrupts by setting the interrupt mask. */ - RTL_W16 (IntrMask, rtl8139_intr_mask); + rtl8139_hw_start (dev); DPRINTK ("%s: rtl8139_open() ioaddr %#lx IRQ %d" " GP Pins %2.2x %s-duplex.\n", @@ -944,23 +951,26 @@ static int rtl8139_open (struct net_device *dev) tp->timer.function = &rtl8139_timer; add_timer (&tp->timer); - netif_start_queue (dev); - DPRINTK ("EXIT, returning 0\n"); return 0; } + /* Start the hardware at open or resume. */ static void rtl8139_hw_start (struct net_device *dev) { struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; void *ioaddr = tp->mmio_addr; int i; + unsigned long flags; DPRINTK ("ENTER\n"); + + spin_lock_irqsave (&tp->lock, flags); /* Soft reset the chip. */ RTL_W8 (ChipCmd, CmdReset); + /* Check that the chip has finished the reset. */ for (i = 1000; i > 0; i--) if ((RTL_R8 (ChipCmd) & CmdReset) == 0) @@ -970,8 +980,9 @@ static void rtl8139_hw_start (struct net_device *dev) RTL_W32_F (MAC0 + 0, cpu_to_le32 (*(u32 *) (dev->dev_addr + 0))); RTL_W32_F (MAC0 + 4, cpu_to_le32 (*(u32 *) (dev->dev_addr + 4))); - /* Hmmm, do these belong here? */ - RTL_W8 (Cfg9346, 0x00); + /* unlock Config[01234] and BMCR register writes */ + RTL_W8 (Cfg9346, Cfg9346_Unlock); + tp->cur_rx = 0; /* Must enable Tx/Rx before setting transfer thresholds! */ @@ -993,19 +1004,30 @@ static void rtl8139_hw_start (struct net_device *dev) RTL_W16 (BasicModeCtrl, (1<<13)|(1<<12)|(1<<9)|(1<<8)); /* check_duplex() here. */ - RTL_W8 (Cfg9346, 0xC0); RTL_W8 (Config1, tp->full_duplex ? 0x60 : 0x20); - RTL_W8 (Cfg9346, 0x00); + + /* lock Config[01234] and BMCR register writes */ + RTL_W8 (Cfg9346, Cfg9346_Lock); RTL_W32 (RxBuf, tp->rx_ring_dma); + /* Start the chip's Tx and Rx process. */ RTL_W32 (RxMissed, 0); + + /* release lock cuz set_rx_mode wants it */ + spin_unlock_irqrestore (&tp->lock, flags); rtl8139_set_rx_mode (dev); + spin_lock_irqsave (&tp->lock, flags); + RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb); + /* Enable all known interrupts by setting the interrupt mask. */ RTL_W16 (IntrMask, rtl8139_intr_mask); - netif_start_queue (dev); + if (netif_queue_stopped (dev)) + netif_start_queue (dev); + + spin_unlock_irqrestore (&tp->lock, flags); DPRINTK ("EXIT\n"); } @@ -1111,9 +1133,14 @@ static void rtl8139_timer (unsigned long data) struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; void *ioaddr = tp->mmio_addr; int next_tick = 60 * HZ; - int mii_reg5 = mdio_read (dev, tp->phys[0], 5); + int mii_reg5; + unsigned long flags; DPRINTK ("ENTER\n"); + + spin_lock_irqsave (&tp->lock, flags); + + mii_reg5 = mdio_read (dev, tp->phys[0], 5); if (!tp->duplex_lock && mii_reg5 != 0xffff) { int duplex = (mii_reg5 & 0x0100) @@ -1125,9 +1152,9 @@ static void rtl8139_timer (unsigned long data) " partner ability of %4.4x.\n", dev->name, tp->full_duplex ? "full" : "half", tp->phys[0], mii_reg5); - RTL_W8 (Cfg9346, 0xC0); + RTL_W8 (Cfg9346, Cfg9346_Unlock); RTL_W8 (Config1, tp->full_duplex ? 0x60 : 0x20); - RTL_W8 (Cfg9346, 0x00); + RTL_W8 (Cfg9346, Cfg9346_Lock); } } @@ -1144,6 +1171,8 @@ static void rtl8139_timer (unsigned long data) dev->name, RTL_R8 (Config0), RTL_R8 (Config1)); + spin_unlock_irqrestore (&tp->lock, flags); + tp->timer.expires = jiffies + next_tick; add_timer (&tp->timer); @@ -1156,10 +1185,11 @@ static void rtl8139_tx_timeout (struct net_device *dev) struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; void *ioaddr = tp->mmio_addr; int mii_reg, i; + unsigned long flags; DPRINTK ("ENTER\n"); - netif_stop_queue (dev); + spin_lock_irqsave (&tp->lock, flags); DPRINTK ("%s: Transmit timeout, status %2.2x %4.4x " "media %2.2x.\n", dev->name, @@ -1201,6 +1231,8 @@ static void rtl8139_tx_timeout (struct net_device *dev) } } + spin_unlock_irqrestore (&tp->lock, flags); + rtl8139_hw_start (dev); DPRINTK ("EXIT\n"); @@ -1227,6 +1259,7 @@ static void rtl8139_init_ring (struct net_device *dev) DPRINTK ("EXIT\n"); } + static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev) { struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; @@ -1236,13 +1269,11 @@ static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev) DPRINTK ("ENTER\n"); - netif_stop_queue (dev); + spin_lock_irqsave (&tp->lock, flags); /* Calculate the next Tx descriptor entry. */ entry = tp->cur_tx % NUM_TX_DESC; - spin_lock_irqsave (&tp->lock, flags); - tp->tx_info[entry].skb = skb; if ((long) skb->data & 3) { /* Must use alignment buffer. */ tp->tx_info[entry].mapping = 0; @@ -1263,12 +1294,12 @@ static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev) tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN)); dev->trans_start = jiffies; - if (++tp->cur_tx - tp->dirty_tx < NUM_TX_DESC) /* Typical path */ - netif_start_queue (dev); + if (++tp->cur_tx - tp->dirty_tx >= NUM_TX_DESC) + netif_stop_queue (dev); spin_unlock_irqrestore (&tp->lock, flags); - - DPRINTK ("%s: Queued Tx packet at %p size %lu to slot %d.\n", + + DPRINTK ("%s: Queued Tx packet at %p size %u to slot %d.\n", dev->name, skb->data, skb->len, entry); DPRINTK ("EXIT\n"); @@ -1277,16 +1308,16 @@ static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev) static inline void rtl8139_tx_interrupt (struct net_device *dev, - struct rtl8139_private *tp) + struct rtl8139_private *tp, + void *ioaddr) { - void *ioaddr; unsigned int dirty_tx; assert (dev != NULL); assert (tp != NULL); - + assert (ioaddr != NULL); + dirty_tx = tp->dirty_tx; - ioaddr = tp->mmio_addr; while (tp->cur_tx - dirty_tx > 0) { int entry = dirty_tx % NUM_TX_DESC; @@ -1338,8 +1369,6 @@ static inline void rtl8139_tx_interrupt (struct net_device *dev, dirty_tx++; if (tp->cur_tx - dirty_tx < NUM_TX_DESC) netif_wake_queue (dev); - else - netif_stop_queue (dev); } #ifndef RTL8139_NDEBUG @@ -1349,7 +1378,7 @@ static inline void rtl8139_tx_interrupt (struct net_device *dev, dev->name, dirty_tx, tp->cur_tx); dirty_tx += NUM_TX_DESC; } -#endif +#endif /* RTL8139_NDEBUG */ tp->dirty_tx = dirty_tx; } @@ -1358,11 +1387,18 @@ static inline void rtl8139_tx_interrupt (struct net_device *dev, /* The data sheet doesn't describe the Rx ring at all, so I'm guessing at the field alignments and semantics. */ static inline void rtl8139_rx_interrupt (struct net_device *dev, - struct rtl8139_private *tp) + struct rtl8139_private *tp, + void *ioaddr) { - void *ioaddr = tp->mmio_addr; - unsigned char *rx_ring = tp->rx_ring; - u16 cur_rx = tp->cur_rx; + unsigned char *rx_ring; + u16 cur_rx; + + assert (dev != NULL); + assert (tp != NULL); + assert (ioaddr != NULL); + + rx_ring = tp->rx_ring; + cur_rx = tp->cur_rx; DPRINTK ("%s: In rtl8139_rx(), current %4.4x BufAddr %4.4x," " free to %4.4x, Cmd %2.2x.\n", dev->name, cur_rx, @@ -1376,15 +1412,17 @@ static inline void rtl8139_rx_interrupt (struct net_device *dev, le32_to_cpu (*(u32 *) (rx_ring + ring_offset)); int rx_size = rx_status >> 16; -#ifdef RTL8139_DEBUG - int i; DPRINTK ("%s: rtl8139_rx() status %4.4x, size %4.4x," " cur %4.4x.\n", dev->name, rx_status, rx_size, cur_rx); +#if RTL8139_DEBUG > 2 + { + int i; DPRINTK ("%s: Frame contents ", dev->name); for (i = 0; i < 70; i++) printk (" %2.2x", rx_ring[ring_offset + i]); printk (".\n"); + } #endif /* E. Gill */ @@ -1490,23 +1528,16 @@ static inline void rtl8139_rx_interrupt (struct net_device *dev, static inline int rtl8139_weird_interrupt (struct net_device *dev, struct rtl8139_private *tp, + void *ioaddr, int status, int link_changed) { - void *ioaddr; - DPRINTK ("%s: Abnormal interrupt, status %8.8x.\n", dev->name, status); assert (dev != NULL); assert (tp != NULL); - - ioaddr = tp->mmio_addr; - - if (status == 0xffffffff) { - printk (KERN_WARNING PFX "abnormal interrupt, card ejected? (ok to ignore)\n"); - return -1; - } - + assert (ioaddr != NULL); + /* Update the error count. */ tp->stats.rx_missed_errors += RTL_R32 (RxMissed); RTL_W32 (RxMissed, 0); @@ -1519,9 +1550,9 @@ static inline int rtl8139_weird_interrupt (struct net_device *dev, || tp->duplex_lock; if (tp->full_duplex != duplex) { tp->full_duplex = duplex; - RTL_W8 (Cfg9346, 0xC0); + RTL_W8 (Cfg9346, Cfg9346_Unlock); RTL_W8 (Config1, tp->full_duplex ? 0x60 : 0x20); - RTL_W8 (Cfg9346, 0x00); + RTL_W8 (Cfg9346, Cfg9346_Lock); } status &= ~RxUnderrun; } @@ -1559,15 +1590,20 @@ static void rtl8139_interrupt (int irq, void *dev_instance, struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; int boguscnt = max_interrupt_work; void *ioaddr = tp->mmio_addr; - int link_changed = 0; /* Grrr, avoid bogus "uninitialized" warning */ - - spin_lock_irq (&tp->lock); + int status = 0, link_changed = 0; /* avoid bogus "uninit" warning */ + spin_lock (&tp->lock); + /* disable interrupt generation while handling this interrupt */ RTL_W16 (IntrMask, 0x0000); do { - int status = RTL_R16 (IntrStatus); + status = RTL_R16 (IntrStatus); + + /* h/w no longer present (hotplug?) or major error, bail */ + if (status == 0xFFFFFFFF) + break; + /* Acknowledge all of the current interrupt sources ASAP, but an first get an additional status bit from CSCR. */ if (status & RxUnderrun) @@ -1606,42 +1642,45 @@ static void rtl8139_interrupt (int irq, void *dev_instance, /* Check uncommon events with one test. */ if (status & (PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver | TxErr | RxErr)) - if (rtl8139_weird_interrupt (dev, tp, status, - link_changed) == -1) - break; + rtl8139_weird_interrupt (dev, tp, ioaddr, + status, link_changed); if (status & (RxOK | RxUnderrun | RxOverflow | RxFIFOOver)) /* Rx interrupt */ - rtl8139_rx_interrupt (dev, tp); + rtl8139_rx_interrupt (dev, tp, ioaddr); if (status & (TxOK | TxErr)) - rtl8139_tx_interrupt (dev, tp); - - if (--boguscnt < 0) { - printk (KERN_WARNING - "%s: Too much work at interrupt, " - "IntrStatus=0x%4.4x.\n", dev->name, - status); - /* Clear all interrupt sources. */ - RTL_W16 (IntrStatus, 0xffff); - break; - } - } while (1); + rtl8139_tx_interrupt (dev, tp, ioaddr); + + boguscnt--; + } while (boguscnt > 0); + + if (boguscnt <= 0) { + printk (KERN_WARNING + "%s: Too much work at interrupt, " + "IntrStatus=0x%4.4x.\n", dev->name, + status); + + /* Clear all interrupt sources. */ + RTL_W16 (IntrStatus, 0xffff); + } /* Enable all known interrupts by setting the interrupt mask. */ RTL_W16 (IntrMask, rtl8139_intr_mask); - spin_unlock_irq (&tp->lock); - + spin_unlock (&tp->lock); + DPRINTK ("%s: exiting interrupt, intr_status=%#4.4x.\n", - dev->name, RTL_R16 (IntrStatus)); + dev->name, RTL_R16 (IntrStatus)); } + static int rtl8139_close (struct net_device *dev) { struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; void *ioaddr = tp->mmio_addr; int i; + unsigned long flags; DPRINTK ("ENTER\n"); @@ -1650,6 +1689,8 @@ static int rtl8139_close (struct net_device *dev) DPRINTK ("%s: Shutting down ethercard, status was 0x%4.4x.\n", dev->name, RTL_R16 (IntrStatus)); + spin_lock_irqsave (&tp->lock, flags); + /* Disable interrupts by clearing the interrupt mask. */ RTL_W16 (IntrMask, 0x0000); @@ -1660,7 +1701,13 @@ static int rtl8139_close (struct net_device *dev) tp->stats.rx_missed_errors += RTL_R32 (RxMissed); RTL_W32 (RxMissed, 0); + spin_unlock_irqrestore (&tp->lock, flags); + del_timer (&tp->timer); + + /* snooze for a small bit */ + if (current->need_resched) + schedule (); free_irq (dev->irq, dev); @@ -1685,7 +1732,7 @@ static int rtl8139_close (struct net_device *dev) tp->tx_bufs = NULL; /* Green! Put the chip in low-power mode. */ - RTL_W8 (Cfg9346, 0xC0); + RTL_W8 (Cfg9346, Cfg9346_Unlock); RTL_W8 (Config1, 0x03); RTL_W8 (HltClk, 'H'); /* 'R' would leave the clock running. */ @@ -1695,10 +1742,13 @@ static int rtl8139_close (struct net_device *dev) return 0; } + static int mii_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) { struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; u16 *data = (u16 *) & rq->ifr_data; + unsigned long flags; + int rc = 0; DPRINTK ("ENTER\n"); @@ -1706,24 +1756,34 @@ static int mii_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ data[0] = tp->phys[0] & 0x3f; /* Fall Through */ + case SIOCDEVPRIVATE + 1: /* Read the specified MII register. */ + spin_lock_irqsave (&tp->lock, flags); data[3] = mdio_read (dev, data[0], data[1] & 0x1f); - DPRINTK ("EXIT\n"); - return 0; + spin_unlock_irqrestore (&tp->lock, flags); + break; + case SIOCDEVPRIVATE + 2: /* Write the specified MII register */ - if (!capable (CAP_NET_ADMIN)) - return -EPERM; + if (!capable (CAP_NET_ADMIN)) { + rc = -EPERM; + break; + } + + spin_lock_irqsave (&tp->lock, flags); mdio_write (dev, data[0], data[1] & 0x1f, data[2]); - DPRINTK ("EXIT\n"); - return 0; + spin_unlock_irqrestore (&tp->lock, flags); + break; + default: - DPRINTK ("EXIT\n"); - return -EOPNOTSUPP; + rc = -EOPNOTSUPP; + break; } - DPRINTK ("EXIT\n"); + DPRINTK ("EXIT, returning %d\n", rc); + return rc; } + static struct net_device_stats *rtl8139_get_stats (struct net_device *dev) { struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; @@ -1734,8 +1794,14 @@ static struct net_device_stats *rtl8139_get_stats (struct net_device *dev) assert (tp != NULL); if (netif_running(dev)) { + unsigned long flags; + + spin_lock_irqsave (&tp->lock, flags); + tp->stats.rx_missed_errors += RTL_R32 (RxMissed); RTL_W32 (RxMissed, 0); + + spin_unlock_irqrestore (&tp->lock, flags); } DPRINTK ("EXIT\n"); @@ -1765,12 +1831,14 @@ static inline u32 ether_crc (int length, unsigned char *data) return crc; } + static void rtl8139_set_rx_mode (struct net_device *dev) { struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; void *ioaddr = tp->mmio_addr; u32 mc_filter[2]; /* Multicast hash filter */ int i, rx_mode; + unsigned long flags; DPRINTK ("ENTER\n"); @@ -1803,11 +1871,19 @@ static void rtl8139_set_rx_mode (struct net_device *dev) dmi_addr) >> 26, mc_filter); } + + /* if called from irq handler, lock already acquired */ + if (!in_irq ()) + spin_lock_irqsave (&tp->lock, flags); + /* We can safely update without stopping the chip. */ RTL_W32 (RxConfig, rtl8139_rx_config | rx_mode); RTL_W32_F (MAR0 + 0, mc_filter[0]); RTL_W32_F (MAR0 + 4, mc_filter[1]); + if (!in_irq ()) + spin_unlock_irqrestore (&tp->lock, flags); + DPRINTK ("EXIT\n"); } @@ -1817,9 +1893,12 @@ static void rtl8139_suspend (struct pci_dev *pdev) struct net_device *dev = PCI_GET_DRIVER_DATA (pdev); struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; void *ioaddr = tp->mmio_addr; + unsigned long flags; - netif_stop_queue (dev); + netif_device_detach (dev); + spin_lock_irqsave (&tp->lock, flags); + /* Disable interrupts, stop Tx and Rx. */ RTL_W16 (IntrMask, 0x0000); RTL_W8 (ChipCmd, 0x00); @@ -1827,6 +1906,8 @@ static void rtl8139_suspend (struct pci_dev *pdev) /* Update the error counts. */ tp->stats.rx_missed_errors += RTL_R32 (RxMissed); RTL_W32 (RxMissed, 0); + + spin_unlock_irqrestore (&tp->lock, flags); } @@ -1834,7 +1915,8 @@ static void rtl8139_resume (struct pci_dev *pdev) { struct net_device *dev = PCI_GET_DRIVER_DATA (pdev); - rtl8139_hw_start(dev); + netif_device_attach (dev); + rtl8139_hw_start (dev); } @@ -1850,22 +1932,7 @@ static struct pci_driver rtl8139_pci_driver = { static int __init rtl8139_init_module (void) { - int rc; - - DPRINTK ("ENTER\n"); - - rc = pci_register_driver (&rtl8139_pci_driver); - - if (rc > 0) { - printk (KERN_INFO RTL8139_DRIVER_NAME - " loaded (%d device%s registered)\n", - rc, rc > 1 ? "s" : ""); - } else { - pci_unregister_driver (&rtl8139_pci_driver); - } - - DPRINTK ("EXIT\n"); - return rc > 0 ? 0 : -ENODEV; + return pci_module_init (&rtl8139_pci_driver); } diff --git a/drivers/net/Config.in b/drivers/net/Config.in index f3cc0af3a..abf7958ef 100644 --- a/drivers/net/Config.in +++ b/drivers/net/Config.in @@ -254,9 +254,7 @@ comment 'Wireless LAN (non-hamradio)' bool 'Wireless LAN (non-hamradio)' CONFIG_NET_RADIO if [ "$CONFIG_NET_RADIO" = "y" ]; then dep_tristate ' STRIP (Metricom starmode radio IP)' CONFIG_STRIP $CONFIG_INET - if [ "$CONFIG_OBSOLETE" = "y" ]; then - tristate ' AT&T WaveLAN & DEC RoamAbout DS support' CONFIG_WAVELAN - fi + tristate ' AT&T WaveLAN & DEC RoamAbout DS support' CONFIG_WAVELAN tristate ' Aironet Arlan 655 & IC2200 DS support' CONFIG_ARLAN tristate ' Aironet 4500/4800 series adapters' CONFIG_AIRONET4500 dep_tristate ' Aironet 4500/4800 ISA/PCI/PNP/365 support ' CONFIG_AIRONET4500_NONCS $CONFIG_AIRONET4500 diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 3c2ede8f5..550a97ae2 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -18,7 +18,7 @@ SUB_DIRS := MOD_SUB_DIRS := MOD_IN_SUB_DIRS := ALL_SUB_DIRS := $(SUB_DIRS) fc hamradio irda pcmcia tokenring wan sk98lin \ - arcnet skfp + arcnet skfp tulip O_TARGET := net.o MOD_LIST_NAME := NET_MODULES @@ -38,6 +38,15 @@ else endif endif +ifeq ($(CONFIG_TULIP),y) + SUB_DIRS += tulip + obj-y += tulip/tulip.o +else + ifeq ($(CONFIG_TULIP),m) + MOD_SUB_DIRS += tulip + endif +endif + ifeq ($(CONFIG_IRDA),y) SUB_DIRS += irda MOD_IN_SUB_DIRS += irda @@ -122,7 +131,6 @@ obj-$(CONFIG_NE2K_PCI) += ne2k-pci.o 8390.o obj-$(CONFIG_PCNET32) += pcnet32.o obj-$(CONFIG_EEPRO100) += eepro100.o obj-$(CONFIG_TLAN) += tlan.o -obj-$(CONFIG_TULIP) += tulip.o obj-$(CONFIG_EPIC100) += epic100.o obj-$(CONFIG_SIS900) += sis900.o obj-$(CONFIG_DM9102) += dmfe.o diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c index 8410c0cf8..404d4a996 100644 --- a/drivers/net/eepro100.c +++ b/drivers/net/eepro100.c @@ -536,6 +536,9 @@ static int __devinit eepro100_init_one (struct pci_dev *pdev, static int did_version = 0; /* Already printed version info. */ + if (speedo_debug > 0 && did_version++ == 0) + printk(version); + #ifdef USE_IO ioaddr = pci_resource_start (pdev, 0); #else @@ -569,9 +572,6 @@ static int __devinit eepro100_init_one (struct pci_dev *pdev, } #endif - if (speedo_debug > 0 && did_version++ == 0) - printk(version); - tx_ring = pci_alloc_consistent(pdev, TX_RING_SIZE * sizeof(struct TxFD) + sizeof(struct speedo_stats), &tx_ring_dma); if (!tx_ring) { @@ -604,7 +604,11 @@ static int __devinit eepro100_init_one (struct pci_dev *pdev, acpi_idle_state = pwr_command & PCI_PM_CTRL_STATE_MASK; } - pci_enable_device (pdev); + if (pci_enable_device (pdev)) { + printk(KERN_ERR PFX "Could not enable PCI device\n"); + goto err_out_free_netdev; + } + pci_set_master (pdev); /* Read the station address EEPROM before doing the reset. @@ -732,11 +736,12 @@ static int __devinit eepro100_init_one (struct pci_dev *pdev, /* Return the chip to its original power state. */ pci_set_power_state (pdev, acpi_idle_state); + pdev->driver_data = dev; + dev->base_addr = ioaddr; dev->irq = irq; sp = dev->priv; - memset(sp, 0, sizeof(*sp)); sp->pdev = pdev; sp->acpi_pwr = acpi_idle_state; @@ -872,6 +877,8 @@ speedo_open(struct net_device *dev) if (speedo_debug > 1) printk(KERN_DEBUG "%s: speedo_open() irq %d.\n", dev->name, dev->irq); + MOD_INC_USE_COUNT; + pci_set_power_state(sp->pdev, 0); /* Set up the Tx queue early.. */ @@ -882,12 +889,13 @@ speedo_open(struct net_device *dev) spin_lock_init(&sp->lock); /* .. we can safely take handler calls during init. */ - if (request_irq(dev->irq, &speedo_interrupt, SA_SHIRQ, dev->name, dev)) + if (request_irq(dev->irq, &speedo_interrupt, SA_SHIRQ, dev->name, dev)) { + MOD_DEC_USE_COUNT; return -EBUSY; - - MOD_INC_USE_COUNT; + } dev->if_port = sp->default_port; + #if 0 /* With some transceivers we must retrigger negotiation to reset power-up errors. */ @@ -1174,8 +1182,6 @@ speedo_start_xmit(struct sk_buff *skb, struct net_device *dev) long ioaddr = dev->base_addr; int entry; - netif_stop_queue (dev); - /* Caution: the write order is important here, set the base address with the "ownership" bits last. */ @@ -1216,16 +1222,15 @@ speedo_start_xmit(struct sk_buff *skb, struct net_device *dev) } if (sp->cur_tx - sp->dirty_tx >= TX_QUEUE_LIMIT) { sp->tx_full = 1; + netif_stop_queue (dev); } spin_unlock_irqrestore(&sp->lock, flags); } + wait_for_cmd_done(ioaddr + SCBCmd); outw(CUResume, ioaddr + SCBCmd); dev->trans_start = jiffies; - if (! sp->tx_full) - netif_start_queue (dev); - return 0; } @@ -1328,22 +1333,18 @@ static void speedo_interrupt(int irq, void *dev_instance, struct pt_regs *regs) && sp->cur_tx - dirty_tx < TX_QUEUE_LIMIT - 1) { /* The ring is no longer full, clear tbusy. */ sp->tx_full = 0; - } - - if (sp->tx_full) - netif_stop_queue (dev); - else netif_wake_queue (dev); + } } - if (--boguscnt < 0) { - printk(KERN_ERR "%s: Too much work at interrupt, status=0x%4.4x.\n", - dev->name, status); - /* Clear all interrupt sources. */ - outl(0xfc00, ioaddr + SCBStatus); - break; - } - } while (1); + } while (--boguscnt > 0); + + if (boguscnt <= 0) { + printk(KERN_ERR "%s: Too much work at interrupt, status=0x%4.4x.\n", + dev->name, status); + /* Clear all interrupt sources. */ + outl(0xfc00, ioaddr + SCBStatus); + } if (speedo_debug > 3) printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n", @@ -1502,8 +1503,8 @@ speedo_close(struct net_device *dev) /* Clear the Tx descriptors. */ if (skb) { pci_unmap_single(sp->pdev, - le32_to_cpu(sp->tx_ring[i].tx_buf_addr0), - skb->len, PCI_DMA_TODEVICE); + le32_to_cpu(sp->tx_ring[i].tx_buf_addr0), + skb->len, PCI_DMA_TODEVICE); dev_kfree_skb(skb); } } @@ -1811,8 +1812,6 @@ static void __devexit eepro100_remove_one (struct pci_dev *pdev) iounmap ((char *) dev->base_addr); #endif - pci_set_power_state (pdev, sp->acpi_pwr); - pci_free_consistent(pdev, TX_RING_SIZE * sizeof(struct TxFD) + sizeof(struct speedo_stats), sp->tx_ring, sp->tx_ring_dma); @@ -1841,23 +1840,10 @@ static struct pci_driver eepro100_driver = { static int __init eepro100_init_module(void) { - int cards_found; - if (debug >= 0) speedo_debug = debug; - /* Always emit the version message. */ - if (speedo_debug) - printk(KERN_INFO "%s", version); - - cards_found = pci_register_driver (&eepro100_driver); - if (cards_found <= 0) { - printk(KERN_INFO PFX "No cards found, driver not installed.\n"); - pci_unregister_driver (&eepro100_driver); - return -ENODEV; - } - - return 0; + return pci_module_init (&eepro100_driver); } diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c index b1871485a..8aa3ef765 100644 --- a/drivers/net/hamradio/6pack.c +++ b/drivers/net/hamradio/6pack.c @@ -752,8 +752,8 @@ static void __exit sixpack_cleanup_driver(void) * VSV = if dev->start==0, then device * unregistered while close proc. */ - if (netif_running(sixpack_ctrls[i]->dev)) - unregister_netdev(&(sixpack_ctrls[i]->dev)); + if (netif_running(&sixpack_ctrls[i]->dev)) + unregister_netdev(&sixpack_ctrls[i]->dev); kfree(sixpack_ctrls[i]); sixpack_ctrls[i] = NULL; diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c index 1886ec73a..7a6cc5091 100644 --- a/drivers/net/irda/nsc-ircc.c +++ b/drivers/net/irda/nsc-ircc.c @@ -6,7 +6,7 @@ * Status: Stable. * Author: Dag Brattli * Created at: Sat Nov 7 21:43:15 1998 - * Modified at: Fri Jan 28 12:10:10 2000 + * Modified at: Fri Feb 18 01:48:51 2000 * Modified by: Dag Brattli * * Copyright (c) 1998-2000 Dag Brattli @@ -42,6 +42,7 @@ ********************************************************************/ #include + #include #include #include @@ -1431,8 +1432,10 @@ static int nsc_ircc_dma_receive_complete(struct nsc_ircc_cb *self, int iobase) /* We must empty the status FIFO no matter what */ len = inb(iobase+RFLFL) | ((inb(iobase+RFLFH) & 0x1f) << 8); - if (st_fifo->tail >= MAX_RX_WINDOW) + if (st_fifo->tail >= MAX_RX_WINDOW) { + IRDA_DEBUG(0, __FUNCTION__ "(), window is full!\n"); continue; + } st_fifo->entries[st_fifo->tail].status = status; st_fifo->entries[st_fifo->tail].len = len; @@ -1492,7 +1495,18 @@ static int nsc_ircc_dma_receive_complete(struct nsc_ircc_cb *self, int iobase) st_fifo->pending_bytes += len; st_fifo->entries[st_fifo->head].status = status; st_fifo->entries[st_fifo->head].len = len; - + /* + * DMA not finished yet, so try again + * later, set timer value, resolution + * 125 us + */ + switch_bank(iobase, BANK4); + outb(0x02, iobase+TMRL); /* x 125 us */ + outb(0x00, iobase+TMRH); + + /* Start timer */ + outb(IRCR1_TMR_EN, iobase+IRCR1); + /* Restore bank register */ outb(bank, iobase+BSR); @@ -1597,7 +1611,7 @@ static void nsc_ircc_sir_interrupt(struct nsc_ircc_cb *self, int eir) else { self->stats.tx_packets++; - netif_wakeup_queue(self->netdev); + netif_wake_queue(self->netdev); self->ier = IER_TXEMP_IE; } @@ -1648,21 +1662,12 @@ static void nsc_ircc_fir_interrupt(struct nsc_ircc_cb *self, int iobase, /* Status FIFO event*/ if (eir & EIR_SFIF_EV) { + /* Check if DMA has finished */ if (nsc_ircc_dma_receive_complete(self, iobase)) { /* Wait for next status FIFO interrupt */ self->ier = IER_SFIF_IE; } else { - /* - * DMA not finished yet, so try again later, set - * timer value, resolution 125 us - */ - switch_bank(iobase, BANK4); - outb(0x02, iobase+TMRL); /* 2 * 125 us */ - outb(0x00, iobase+TMRH); - - /* Start timer */ - outb(IRCR1_TMR_EN, iobase+IRCR1); - self->ier = IER_TMR_IE | IER_SFIF_IE; + self->ier = IER_SFIF_IE | IER_TMR_IE; } } else if (eir & EIR_TMR_EV) { /* Timer finished */ /* Disable timer */ @@ -1677,15 +1682,17 @@ static void nsc_ircc_fir_interrupt(struct nsc_ircc_cb *self, int iobase, if (self->io.direction == IO_XMIT) { nsc_ircc_dma_xmit(self, iobase); - /* Interrupt on DMA */ + /* Interrupt on DMA */ self->ier = IER_DMA_IE; } else { - /* Check if DMA has now finished */ - nsc_ircc_dma_receive_complete(self, iobase); - - self->ier = IER_SFIF_IE; + /* Check (again) if DMA has finished */ + if (nsc_ircc_dma_receive_complete(self, iobase)) { + self->ier = IER_SFIF_IE; + } else { + self->ier = IER_SFIF_IE | IER_TMR_IE; + } } - } else if (eir & EIR_DMA_EV) { + } else if (eir & EIR_DMA_EV) { /* Finished with all transmissions? */ if (nsc_ircc_dma_xmit_complete(self)) { /* Check if there are more frames to be transmitted */ diff --git a/drivers/net/irda/smc-ircc.c b/drivers/net/irda/smc-ircc.c index a93720cc9..06ebc072c 100644 --- a/drivers/net/irda/smc-ircc.c +++ b/drivers/net/irda/smc-ircc.c @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Thomas Davis (tadavis@jps.net) * Created at: - * Modified at: Fri Jan 21 09:41:08 2000 + * Modified at: Tue Feb 22 10:05:06 2000 * Modified by: Dag Brattli * * Copyright (c) 1999-2000 Dag Brattli @@ -567,7 +567,6 @@ static void ircc_change_speed(void *priv, __u32 speed) "(), using irport to change speed to %d\n", speed); irport_change_speed(self->irport, speed); } - dev->tbusy = 0; register_bank(iobase, 1); outb(((inb(iobase+IRCC_SCE_CFGA) & 0x87) | ir_mode), @@ -617,9 +616,7 @@ static int ircc_hard_xmit(struct sk_buff *skb, struct net_device *dev) if ((speed = irda_get_speed(skb)) != self->io.speed) self->new_speed = speed; - /* Lock transmit buffer */ - if (irda_lock((void *) &dev->tbusy) == FALSE) - return -EBUSY; + netif_stop_queue(dev); memcpy(self->tx_buff.head, skb->data, skb->len); @@ -741,11 +738,7 @@ static void ircc_dma_xmit_complete(struct ircc_cb *self, int iobase) self->new_speed = 0; } - /* Unlock tx_buff and request another frame */ - self->netdev->tbusy = 0; /* Unlock */ - - /* Tell the network layer, that we can accept more frames */ - mark_bh(NET_BH); + netif_wake_queue(self->netdev); } /* @@ -875,7 +868,6 @@ static void ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs) iobase = self->io.fir_base; spin_lock(&self->lock); - dev->interrupt = 1; register_bank(iobase, 0); iir = inb(iobase+IRCC_IIR); @@ -898,7 +890,6 @@ static void ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs) register_bank(iobase, 0); outb(IRCC_IER_ACTIVE_FRAME|IRCC_IER_EOM, iobase+IRCC_IER); - dev->interrupt = 0; spin_unlock(&self->lock); } diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c index 33b1dbc60..010c7cfd0 100644 --- a/drivers/net/pcmcia/3c589_cs.c +++ b/drivers/net/pcmcia/3c589_cs.c @@ -788,8 +788,7 @@ static void el3_interrupt(int irq, void *dev_id, struct pt_regs *regs) while ((status = inw(ioaddr + EL3_STATUS)) & (IntLatch | RxComplete | StatsFull)) { - if (!netif_device_present(dev)) || - ((status & 0xe000) != 0x2000)) { + if (!netif_device_present(dev) || ((status & 0xe000) != 0x2000)) { DEBUG(1, "%s: interrupt from dead card\n", dev->name); break; } diff --git a/drivers/net/sk_g16.c b/drivers/net/sk_g16.c index d3722cf2d..fad404a4d 100644 --- a/drivers/net/sk_g16.c +++ b/drivers/net/sk_g16.c @@ -1172,7 +1172,7 @@ static int SK_lance_init(struct net_device *dev, unsigned short mode) * YY/MM/DD uid Description -*/ -static int SK_timeout(struct net_device *dev) +static void SK_timeout(struct net_device *dev) { printk(KERN_WARNING "%s: xmitter timed out, try to restart!\n", dev->name); SK_lance_init(dev, MODE_NORMAL); /* Reinit LANCE */ diff --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c index 5f80fc5eb..d4b2e0380 100644 --- a/drivers/net/tokenring/olympic.c +++ b/drivers/net/tokenring/olympic.c @@ -26,10 +26,9 @@ * resource. Driver also reports the card name returned by * the pci resource. * 1/11/00 - Added spinlocks for smp - * - * To Do: + * 2/23/00 - Updated to dev_kfree_irq * - * IPv6 Multicast + * To Do: * * If Problems do Occur * Most problems can be rectified by either closing and opening the interface @@ -88,7 +87,7 @@ */ static char *version = -"Olympic.c v0.3.1 1/11/00 - Peter De Schrijver & Mike Phillips" ; +"Olympic.c v0.3.2 2/23/00 - Peter De Schrijver & Mike Phillips" ; static char *open_maj_error[] = {"No error", "Lobe Media Test", "Physical Insertion", "Address Verification", "Neighbor Notification (Ring Poll)", @@ -777,7 +776,7 @@ static void olympic_interrupt(int irq, void *dev_id, struct pt_regs *regs) olympic_priv->free_tx_ring_entries++; olympic_priv->olympic_stats.tx_bytes += olympic_priv->tx_ring_skb[olympic_priv->tx_ring_last_status]->len; olympic_priv->olympic_stats.tx_packets++ ; - dev_kfree_skb(olympic_priv->tx_ring_skb[olympic_priv->tx_ring_last_status]); + dev_kfree_skb_irq(olympic_priv->tx_ring_skb[olympic_priv->tx_ring_last_status]); olympic_priv->olympic_tx_ring[olympic_priv->tx_ring_last_status].buffer=0xdeadbeef; olympic_priv->olympic_tx_status_ring[olympic_priv->tx_ring_last_status].status=0; netif_wake_queue(dev); diff --git a/drivers/net/tulip.c b/drivers/net/tulip.c deleted file mode 100644 index 5619b961d..000000000 --- a/drivers/net/tulip.c +++ /dev/null @@ -1,3159 +0,0 @@ -/* tulip.c: A DEC 21040-family ethernet driver for Linux. */ -/* - Copyright 2000 The Linux Kernel Team - Written/copyright 1994-1999 by Donald Becker. - - This software may be used and distributed according to the terms - of the GNU Public License, incorporated herein by reference. - - This driver is for the Digital "Tulip" Ethernet adapter interface. - It should work with most DEC 21*4*-based chips/ethercards, as well as - with work-alike chips from Lite-On (PNIC) and Macronix (MXIC) and ASIX. - - The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O - Center of Excellence in Space Data and Information Sciences - Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 - - Additional information available at - http://cesdis.gsfc.nasa.gov/linux/drivers/tulip.html - - For this specific driver variant please use linux-kernel for - bug reports. - - - Theory of Operation - -I. Board Compatibility - -This device driver is designed for the DECchip "Tulip", Digital's -single-chip ethernet controllers for PCI. Supported members of the family -are the 21040, 21041, 21140, 21140A, 21142, and 21143. Similar work-alike -chips from Lite-On, Macronics, ASIX, Compex and other listed below are also -supported. - -These chips are used on at least 140 unique PCI board designs. The great -number of chips and board designs supported is the reason for the -driver size and complexity. Almost of the increasing complexity is in the -board configuration and media selection code. There is very little -increasing in the operational critical path length. - -II. Board-specific settings - -PCI bus devices are configured by the system at boot time, so no jumpers -need to be set on the board. The system BIOS preferably should assign the -PCI INTA signal to an otherwise unused system IRQ line. - -Some boards have EEPROMs tables with default media entry. The factory default -is usually "autoselect". This should only be overridden when using -transceiver connections without link beat e.g. 10base2 or AUI, or (rarely!) -for forcing full-duplex when used with old link partners that do not do -autonegotiation. - -III. Driver operation - -IIIa. Ring buffers - -The Tulip can use either ring buffers or lists of Tx and Rx descriptors. -This driver uses statically allocated rings of Rx and Tx descriptors, set at -compile time by RX/TX_RING_SIZE. This version of the driver allocates skbuffs -for the Rx ring buffers at open() time and passes the skb->data field to the -Tulip as receive data buffers. When an incoming frame is less than -RX_COPYBREAK bytes long, a fresh skbuff is allocated and the frame is -copied to the new skbuff. When the incoming frame is larger, the skbuff is -passed directly up the protocol stack and replaced by a newly allocated -skbuff. - -The RX_COPYBREAK value is chosen to trade-off the memory wasted by -using a full-sized skbuff for small frames vs. the copying costs of larger -frames. For small frames the copying cost is negligible (esp. considering -that we are pre-loading the cache with immediately useful header -information). For large frames the copying cost is non-trivial, and the -larger copy might flush the cache of useful data. A subtle aspect of this -choice is that the Tulip only receives into longword aligned buffers, thus -the IP header at offset 14 isn't longword aligned for further processing. -Copied frames are put into the new skbuff at an offset of "+2", thus copying -has the beneficial effect of aligning the IP header and preloading the -cache. - -IIIC. Synchronization -The driver runs as two independent, single-threaded flows of control. One -is the send-packet routine, which enforces single-threaded use by the -dev->tbusy flag. The other thread is the interrupt handler, which is single -threaded by the hardware and other software. - -The send packet thread has partial control over the Tx ring and 'dev->tbusy' -flag. It sets the tbusy flag whenever it's queuing a Tx packet. If the next -queue slot is empty, it clears the tbusy flag when finished otherwise it sets -the 'tp->tx_full' flag. - -The interrupt handler has exclusive control over the Rx ring and records stats -from the Tx ring. (The Tx-done interrupt can't be selectively turned off, so -we can't avoid the interrupt overhead by having the Tx routine reap the Tx -stats.) After reaping the stats, it marks the queue entry as empty by setting -the 'base' to zero. Iff the 'tp->tx_full' flag is set, it clears both the -tx_full and tbusy flags. - -IV. Notes - -Thanks to Duke Kamstra of SMC for long ago providing an EtherPower board. -Greg LaPolla at Linksys provided PNIC and other Linksys boards. -Znyx provided a four-port card for testing. - -IVb. References - -http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html -http://www.digital.com (search for current 21*4* datasheets and "21X4 SROM") -http://www.national.com/pf/DP/DP83840A.html -http://www.asix.com.tw/pmac.htm -http://www.admtek.com.tw/ - -IVc. Errata - -The old DEC databooks were light on details. -The 21040 databook claims that CSR13, CSR14, and CSR15 should each be the last -register of the set CSR12-15 written. Hmmm, now how is that possible? - -The DEC SROM format is very badly designed not precisely defined, leading to -part of the media selection junkheap below. Some boards do not have EEPROM -media tables and need to be patched up. Worse, other boards use the DEC -design kit media table when it isn't correct for their board. - -We cannot use MII interrupts because there is no defined GPIO pin to attach -them. The MII transceiver status is polled using an kernel timer. - -*/ - -static const char version[] = "Linux Tulip driver version 0.9.2 (Feb 15, 2000)\n"; - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* Processor type for cache alignment. */ -#include -#include -#include -#include - - -/* A few user-configurable values. */ - -/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ -static int max_interrupt_work = 25; - -#define MAX_UNITS 8 -/* Used to pass the full-duplex flag, etc. */ -static int full_duplex[MAX_UNITS] = {0, }; -static int options[MAX_UNITS] = {0, }; -static int mtu[MAX_UNITS] = {0, }; /* Jumbo MTU for interfaces. */ - -/* The possible media types that can be set in options[] are: */ -static const char * const medianame[] = { - "10baseT", "10base2", "AUI", "100baseTx", - "10baseT-FD", "100baseTx-FD", "100baseT4", "100baseFx", - "100baseFx-FD", "MII 10baseT", "MII 10baseT-FD", "MII", - "10baseT(forced)", "MII 100baseTx", "MII 100baseTx-FD", "MII 100baseT4", -}; - -/* Set if the PCI BIOS detects the chips on a multiport board backwards. */ -#ifdef REVERSE_PROBE_ORDER -static int reverse_probe = 1; -#else -static int reverse_probe = 0; -#endif - -/* Keep the ring sizes a power of two for efficiency. - Making the Tx ring too large decreases the effectiveness of channel - bonding and packet priority. - There are no ill effects from too-large receive rings. */ -#define TX_RING_SIZE 16 -#define RX_RING_SIZE 32 - -/* Set the copy breakpoint for the copy-only-tiny-buffer Rx structure. */ -#ifdef __alpha__ -static int rx_copybreak = 1518; -#else -static int rx_copybreak = 100; -#endif - -/* - Set the bus performance register. - Typical: Set 16 longword cache alignment, no burst limit. - Cache alignment bits 15:14 Burst length 13:8 - 0000 No alignment 0x00000000 unlimited 0800 8 longwords - 4000 8 longwords 0100 1 longword 1000 16 longwords - 8000 16 longwords 0200 2 longwords 2000 32 longwords - C000 32 longwords 0400 4 longwords - Warning: many older 486 systems are broken and require setting 0x00A04800 - 8 longword cache alignment, 8 longword burst. - ToDo: Non-Intel setting could be better. -*/ - -#if defined(__alpha__) -static int csr0 = 0x01A00000 | 0xE000; -#elif defined(__i386__) || defined(__powerpc__) || defined(__sparc__) -static int csr0 = 0x01A00000 | 0x8000; -#else -#warning Processor architecture undefined! -static int csr0 = 0x00A00000 | 0x4800; -#endif - -/* Operational parameters that usually are not changed. */ -/* Time in jiffies before concluding the transmitter is hung. */ -#define TX_TIMEOUT (4*HZ) -#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/ -/* This is a mysterious value that can be written to CSR11 in the 21040 (only) - to support a pre-NWay full-duplex signaling mechanism using short frames. - No one knows what it should be, but if left at its default value some - 10base2(!) packets trigger a full-duplex-request interrupt. */ -#define FULL_DUPLEX_MAGIC 0x6969 - - -/* Kernel compatibility defines, some common to David Hind's PCMCIA package. - This is only in the support-all-kernels source code. */ - -MODULE_AUTHOR("Donald Becker "); -MODULE_DESCRIPTION("Digital 21*4* Tulip ethernet driver"); -MODULE_PARM(debug, "i"); -MODULE_PARM(max_interrupt_work, "i"); -MODULE_PARM(reverse_probe, "i"); -MODULE_PARM(rx_copybreak, "i"); -MODULE_PARM(csr0, "i"); -MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); -MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); - -#define TULIP_MODULE_NAME "tulip" -#define PFX TULIP_MODULE_NAME ": " - -#define RUN_AT(x) (jiffies + (x)) - -/* Condensed operations for readability. */ -#define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr)) -#define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr)) - -#define tulip_debug debug -#ifdef TULIP_DEBUG -static int tulip_debug = TULIP_DEBUG; -#else -static int tulip_debug = 1; -#endif - - - -/* This table use during operation for capabilities and media timer. */ - -static void tulip_timer(unsigned long data); -static void t21142_timer(unsigned long data); -static void mxic_timer(unsigned long data); -static void pnic_timer(unsigned long data); -static void comet_timer(unsigned long data); - -enum tbl_flag { - HAS_MII=1, HAS_MEDIA_TABLE=2, CSR12_IN_SROM=4, ALWAYS_CHECK_MII=8, - HAS_ACPI=0x10, MC_HASH_ONLY=0x20, /* Hash-only multicast filter. */ - HAS_PNICNWAY=0x80, HAS_NWAY143=0x40, /* Uses internal NWay xcvr. */ - HAS_8023X=0x100, -}; -static struct tulip_chip_table { - char *chip_name; - int io_size; - int valid_intrs; /* CSR7 interrupt enable settings */ - int flags; - void (*media_timer)(unsigned long data); -} tulip_tbl[] = { - { "Digital DC21040 Tulip", 128, 0x0001ebef, 0, tulip_timer }, - { "Digital DC21041 Tulip", 128, 0x0001ebff, HAS_MEDIA_TABLE, tulip_timer }, - { "Digital DS21140 Tulip", 128, 0x0001ebef, - HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, tulip_timer }, - { "Digital DS21143 Tulip", 128, 0x0801fbff, - HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI | HAS_NWAY143, - t21142_timer }, - { "Lite-On 82c168 PNIC", 256, 0x0001ebef, - HAS_MII | HAS_PNICNWAY, pnic_timer }, - { "Macronix 98713 PMAC", 128, 0x0001ebef, - HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer }, - { "Macronix 98715 PMAC", 256, 0x0001ebef, - HAS_MEDIA_TABLE, mxic_timer }, - { "Macronix 98725 PMAC", 256, 0x0001ebef, - HAS_MEDIA_TABLE, mxic_timer }, - { "ASIX AX88140", 128, 0x0001fbff, - HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | MC_HASH_ONLY, tulip_timer }, - { "Lite-On PNIC-II", 256, 0x0801fbff, - HAS_MII | HAS_NWAY143 | HAS_8023X, t21142_timer }, - { "ADMtek Comet", 256, 0x0001abef, - MC_HASH_ONLY, comet_timer }, - { "Compex 9881 PMAC", 128, 0x0001ebef, - HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer }, - { "Intel DS21145 Tulip", 128, 0x0801fbff, - HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_NWAY143, - t21142_timer }, - { "Xircom tulip work-alike", 128, 0x0801fbff, - HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI | HAS_NWAY143, - t21142_timer }, - {0}, -}; -/* This matches the table above. Note 21142 == 21143. */ -enum chips { - DC21040=0, - DC21041=1, - DC21140=2, - DC21142=3, DC21143=3, - LC82C168, - MX98713, - MX98715, - MX98725, - AX88140, - PNIC2, - COMET, - COMPEX9881, - I21145, - X3201_3, -}; - - -static struct pci_device_id tulip_pci_tbl[] __devinitdata = { - { 0x1011, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21040 }, - { 0x1011, 0x0014, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21041 }, - { 0x1011, 0x0009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21140 }, - { 0x1011, 0x0019, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21143 }, - { 0x11AD, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, LC82C168 }, - { 0x10d9, 0x0512, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98713 }, - { 0x10d9, 0x0531, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98715 }, - { 0x10d9, 0x0531, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98725 }, - { 0x125B, 0x1400, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AX88140 }, - { 0x11AD, 0xc115, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PNIC2 }, - { 0x1317, 0x0981, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, - { 0x11F6, 0x9881, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMPEX9881 }, - { 0x8086, 0x0039, PCI_ANY_ID, PCI_ANY_ID, 0, 0, I21145 }, - { 0x115d, 0x0003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, X3201_3 }, - {0}, -}; -MODULE_DEVICE_TABLE(pci,tulip_pci_tbl); - - -/* A full-duplex map for media types. */ -enum MediaIs { - MediaIsFD = 1, MediaAlwaysFD=2, MediaIsMII=4, MediaIsFx=8, - MediaIs100=16}; -static const char media_cap[] = -{0,0,0,16, 3,19,16,24, 27,4,7,5, 0,20,23,20 }; -static u8 t21040_csr13[] = {2,0x0C,8,4, 4,0,0,0, 0,0,0,0, 4,0,0,0}; -/* 21041 transceiver register settings: 10-T, 10-2, AUI, 10-T, 10T-FD*/ -static u16 t21041_csr13[] = { 0xEF01, 0xEF09, 0xEF09, 0xEF01, 0xEF09, }; -static u16 t21041_csr14[] = { 0xFFFF, 0xF7FD, 0xF7FD, 0x7F3F, 0x7F3D, }; -static u16 t21041_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, }; - -static u16 t21142_csr13[] = { 0x0001, 0x0009, 0x0009, 0x0000, 0x0001, }; -static u16 t21142_csr14[] = { 0xFFFF, 0x0705, 0x0705, 0x0000, 0x7F3D, }; -static u16 t21142_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, }; - -/* Offsets to the Command and Status Registers, "CSRs". All accesses - must be longword instructions and quadword aligned. */ -enum tulip_offsets { - CSR0=0, CSR1=0x08, CSR2=0x10, CSR3=0x18, CSR4=0x20, CSR5=0x28, - CSR6=0x30, CSR7=0x38, CSR8=0x40, CSR9=0x48, CSR10=0x50, CSR11=0x58, - CSR12=0x60, CSR13=0x68, CSR14=0x70, CSR15=0x78 }; - -/* The bits in the CSR5 status registers, mostly interrupt sources. */ -enum status_bits { - TimerInt=0x800, SytemError=0x2000, TPLnkFail=0x1000, TPLnkPass=0x10, - NormalIntr=0x10000, AbnormalIntr=0x8000, - RxJabber=0x200, RxDied=0x100, RxNoBuf=0x80, RxIntr=0x40, - TxFIFOUnderflow=0x20, TxJabber=0x08, TxNoBuf=0x04, TxDied=0x02, TxIntr=0x01, -}; - -/* The Tulip Rx and Tx buffer descriptors. */ -struct tulip_rx_desc { - s32 status; - s32 length; - u32 buffer1, buffer2; -}; - -struct tulip_tx_desc { - s32 status; - s32 length; - u32 buffer1, buffer2; /* We use only buffer 1. */ -}; - -enum desc_status_bits { - DescOwned=0x80000000, RxDescFatalErr=0x8000, RxWholePkt=0x0300, -}; - -/* Ring-wrap flag in length field, use for last ring entry. - 0x01000000 means chain on buffer2 address, - 0x02000000 means use the ring start address in CSR2/3. - Note: Some work-alike chips do not function correctly in chained mode. - The ASIX chip works only in chained mode. - Thus we indicates ring mode, but always write the 'next' field for - chained mode as well. -*/ -#define DESC_RING_WRAP 0x02000000 - -#define EEPROM_SIZE 128 /* 2 << EEPROM_ADDRLEN */ - -struct medialeaf { - u8 type; - u8 media; - unsigned char *leafdata; -}; - -struct mediatable { - u16 defaultmedia; - u8 leafcount, csr12dir; /* General purpose pin directions. */ - unsigned has_mii:1, has_nonmii:1, has_reset:6; - u32 csr15dir, csr15val; /* 21143 NWay setting. */ - struct medialeaf mleaf[0]; -}; - -struct mediainfo { - struct mediainfo *next; - int info_type; - int index; - unsigned char *info; -}; - -struct tulip_private { - char devname[8]; /* Used only for kernel debugging. */ - const char *product_name; - struct net_device *next_module; - struct tulip_rx_desc rx_ring[RX_RING_SIZE]; - struct tulip_tx_desc tx_ring[TX_RING_SIZE]; - /* The saved address of a sent-in-place packet/buffer, for skfree(). */ - struct sk_buff* tx_skbuff[TX_RING_SIZE]; - /* The addresses of receive-in-place skbuffs. */ - struct sk_buff* rx_skbuff[RX_RING_SIZE]; - char *rx_buffs; /* Address of temporary Rx buffers. */ - u16 setup_frame[96]; /* Pseudo-Tx frame to init address table. */ - int chip_id; - int revision; - int flags; - struct net_device_stats stats; - struct timer_list timer; /* Media selection timer. */ - spinlock_t tx_lock; - unsigned int cur_rx, cur_tx; /* The next free ring entry */ - unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */ - unsigned int tx_full:1; /* The Tx queue is full. */ - unsigned int full_duplex:1; /* Full-duplex operation requested. */ - unsigned int full_duplex_lock:1; - unsigned int fake_addr:1; /* Multiport board faked address. */ - unsigned int default_port:4; /* Last dev->if_port value. */ - unsigned int media2:4; /* Secondary monitored media port. */ - unsigned int medialock:1; /* Don't sense media type. */ - unsigned int mediasense:1; /* Media sensing in progress. */ - unsigned int nway:1, nwayset:1; /* 21143 internal NWay. */ - unsigned int csr0; /* CSR0 setting. */ - unsigned int csr6; /* Current CSR6 control settings. */ - unsigned char eeprom[EEPROM_SIZE]; /* Serial EEPROM contents. */ - void (*link_change)(struct net_device *dev, int csr5); - u16 to_advertise; /* NWay capabilities advertised. */ - u16 lpar; /* 21143 Link partner ability. */ - u16 advertising[4]; - signed char phys[4], mii_cnt; /* MII device addresses. */ - struct mediatable *mtable; - int cur_index; /* Current media index. */ - int saved_if_port; - struct pci_dev *pdev; - int ttimer; - int susp_rx; - unsigned long nir; - unsigned long base_addr; - int pad0, pad1; /* Used for 8-byte alignment */ -}; - -static void parse_eeprom(struct net_device *dev); -static int read_eeprom(long ioaddr, int location, int addr_len); -static int mdio_read(struct net_device *dev, int phy_id, int location); -static void mdio_write(struct net_device *dev, int phy_id, int location, int value); -static void select_media(struct net_device *dev, int startup); -/* Chip-specific media selection (timer functions prototyped above). */ -static void t21142_lnk_change(struct net_device *dev, int csr5); -static void t21142_start_nway(struct net_device *dev); -static void pnic_lnk_change(struct net_device *dev, int csr5); -static void pnic_do_nway(struct net_device *dev); - -static void tulip_tx_timeout(struct net_device *dev); -static void tulip_init_ring(struct net_device *dev); -static int tulip_start_xmit(struct sk_buff *skb, struct net_device *dev); -static int tulip_refill_rx(struct net_device *dev); -static int tulip_rx(struct net_device *dev); -static void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs); -static int tulip_open(struct net_device *dev); -static int tulip_close(struct net_device *dev); -static void tulip_up(struct net_device *dev); -static void tulip_down(struct net_device *dev); -static struct net_device_stats *tulip_get_stats(struct net_device *dev); -static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -static void set_rx_mode(struct net_device *dev); - - -/* Serial EEPROM section. */ -/* The main routine to parse the very complicated SROM structure. - Search www.digital.com for "21X4 SROM" to get details. - This code is very complex, and will require changes to support - additional cards, so I'll be verbose about what is going on. - */ - -/* Known cards that have old-style EEPROMs. */ -static struct fixups { - char *name; - unsigned char addr0, addr1, addr2; - u16 newtable[32]; /* Max length below. */ -} eeprom_fixups[] = { - {"Asante", 0, 0, 0x94, {0x1e00, 0x0000, 0x0800, 0x0100, 0x018c, - 0x0000, 0x0000, 0xe078, 0x0001, 0x0050, 0x0018 }}, - {"SMC9332DST", 0, 0, 0xC0, { 0x1e00, 0x0000, 0x0800, 0x041f, - 0x0000, 0x009E, /* 10baseT */ - 0x0004, 0x009E, /* 10baseT-FD */ - 0x0903, 0x006D, /* 100baseTx */ - 0x0905, 0x006D, /* 100baseTx-FD */ }}, - {"Cogent EM100", 0, 0, 0x92, { 0x1e00, 0x0000, 0x0800, 0x063f, - 0x0107, 0x8021, /* 100baseFx */ - 0x0108, 0x8021, /* 100baseFx-FD */ - 0x0100, 0x009E, /* 10baseT */ - 0x0104, 0x009E, /* 10baseT-FD */ - 0x0103, 0x006D, /* 100baseTx */ - 0x0105, 0x006D, /* 100baseTx-FD */ }}, - {"Maxtech NX-110", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x0513, - 0x1001, 0x009E, /* 10base2, CSR12 0x10*/ - 0x0000, 0x009E, /* 10baseT */ - 0x0004, 0x009E, /* 10baseT-FD */ - 0x0303, 0x006D, /* 100baseTx, CSR12 0x03 */ - 0x0305, 0x006D, /* 100baseTx-FD CSR12 0x03 */}}, - {"Accton EN1207", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x051F, - 0x1B01, 0x0000, /* 10base2, CSR12 0x1B */ - 0x0B00, 0x009E, /* 10baseT, CSR12 0x0B */ - 0x0B04, 0x009E, /* 10baseT-FD,CSR12 0x0B */ - 0x1B03, 0x006D, /* 100baseTx, CSR12 0x1B */ - 0x1B05, 0x006D, /* 100baseTx-FD CSR12 0x1B */ - }}, - {0, 0, 0, 0, {}}}; - -static const char * block_name[] = {"21140 non-MII", "21140 MII PHY", - "21142 Serial PHY", "21142 MII PHY", "21143 SYM PHY", "21143 reset method"}; - -#if defined(__i386__) /* AKA get_unaligned() */ -#define get_u16(ptr) (*(u16 *)(ptr)) -#else -#define get_u16(ptr) (((u8*)(ptr))[0] + (((u8*)(ptr))[1]<<8)) -#endif - -static void parse_eeprom(struct net_device *dev) -{ - /* The last media info list parsed, for multiport boards. */ - static struct mediatable *last_mediatable = NULL; - static unsigned char *last_ee_data = NULL; - static int controller_index = 0; - struct tulip_private *tp = (struct tulip_private *)dev->priv; - unsigned char *ee_data = tp->eeprom; - int i; - - tp->mtable = 0; - /* Detect an old-style (SA only) EEPROM layout: - memcmp(eedata, eedata+16, 8). */ - for (i = 0; i < 8; i ++) - if (ee_data[i] != ee_data[16+i]) - break; - if (i >= 8) { - if (ee_data[0] == 0xff) { - if (last_mediatable) { - controller_index++; - printk(KERN_INFO "%s: Controller %d of multiport board.\n", - dev->name, controller_index); - tp->mtable = last_mediatable; - ee_data = last_ee_data; - goto subsequent_board; - } else - printk(KERN_INFO "%s: Missing EEPROM, this interface may " - "not work correctly!\n", - dev->name); - return; - } - /* Do a fix-up based on the vendor half of the station address prefix. */ - for (i = 0; eeprom_fixups[i].name; i++) { - if (dev->dev_addr[0] == eeprom_fixups[i].addr0 - && dev->dev_addr[1] == eeprom_fixups[i].addr1 - && dev->dev_addr[2] == eeprom_fixups[i].addr2) { - if (dev->dev_addr[2] == 0xE8 && ee_data[0x1a] == 0x55) - i++; /* An Accton EN1207, not an outlaw Maxtech. */ - memcpy(ee_data + 26, eeprom_fixups[i].newtable, - sizeof(eeprom_fixups[i].newtable)); - printk(KERN_INFO "%s: Old format EEPROM on '%s' board. Using" - " substitute media control info.\n", - dev->name, eeprom_fixups[i].name); - break; - } - } - if (eeprom_fixups[i].name == NULL) { /* No fixup found. */ - printk(KERN_INFO "%s: Old style EEPROM with no media selection " - "information.\n", - dev->name); - return; - } - } - - controller_index = 0; - if (ee_data[19] > 1) { /* Multiport board. */ - last_ee_data = ee_data; - } -subsequent_board: - - if (ee_data[27] == 0) { /* No valid media table. */ - } else if (tp->chip_id == DC21041) { - unsigned char *p = (void *)ee_data + ee_data[27 + controller_index*3]; - int media = get_u16(p); - int count = p[2]; - p += 3; - - printk(KERN_INFO "%s: 21041 Media table, default media %4.4x (%s).\n", - dev->name, media, - media & 0x0800 ? "Autosense" : medianame[media & 15]); - for (i = 0; i < count; i++) { - unsigned char media_code = *p++; - if (media_code & 0x40) - p += 6; - printk(KERN_INFO "%s: 21041 media #%d, %s.\n", - dev->name, media_code & 15, medianame[media_code & 15]); - } - } else { - unsigned char *p = (void *)ee_data + ee_data[27]; - unsigned char csr12dir = 0; - int count, new_advertise = 0; - struct mediatable *mtable; - u16 media = get_u16(p); - - p += 2; - if (tp->flags & CSR12_IN_SROM) - csr12dir = *p++; - count = *p++; - mtable = (struct mediatable *) - kmalloc(sizeof(struct mediatable) + count*sizeof(struct medialeaf), - GFP_KERNEL); - if (mtable == NULL) - return; /* Horrible, impossible failure. */ - last_mediatable = tp->mtable = mtable; - mtable->defaultmedia = media; - mtable->leafcount = count; - mtable->csr12dir = csr12dir; - mtable->has_nonmii = mtable->has_mii = mtable->has_reset = 0; - mtable->csr15dir = mtable->csr15val = 0; - - printk(KERN_INFO "%s: EEPROM default media type %s.\n", dev->name, - media & 0x0800 ? "Autosense" : medianame[media & 15]); - for (i = 0; i < count; i++) { - struct medialeaf *leaf = &mtable->mleaf[i]; - - if ((p[0] & 0x80) == 0) { /* 21140 Compact block. */ - leaf->type = 0; - leaf->media = p[0] & 0x3f; - leaf->leafdata = p; - if ((p[2] & 0x61) == 0x01) /* Bogus, but Znyx boards do it. */ - mtable->has_mii = 1; - p += 4; - } else { - leaf->type = p[1]; - if (p[1] == 0x05) { - mtable->has_reset = i; - leaf->media = p[2] & 0x0f; - } else if (p[1] & 1) { - mtable->has_mii = 1; - leaf->media = 11; - } else { - mtable->has_nonmii = 1; - leaf->media = p[2] & 0x0f; - switch (leaf->media) { - case 0: new_advertise |= 0x0020; break; - case 4: new_advertise |= 0x0040; break; - case 3: new_advertise |= 0x0080; break; - case 5: new_advertise |= 0x0100; break; - case 6: new_advertise |= 0x0200; break; - } - if (p[1] == 2 && leaf->media == 0) { - if (p[2] & 0x40) { - u32 base15 = get_unaligned((u16*)&p[7]); - mtable->csr15dir = - (get_unaligned((u16*)&p[9])<<16) + base15; - mtable->csr15val = - (get_unaligned((u16*)&p[11])<<16) + base15; - } else { - mtable->csr15dir = get_unaligned((u16*)&p[3])<<16; - mtable->csr15val = get_unaligned((u16*)&p[5])<<16; - } - } - } - leaf->leafdata = p + 2; - p += (p[0] & 0x3f) + 1; - } - if (tulip_debug > 1 && leaf->media == 11) { - unsigned char *bp = leaf->leafdata; - printk(KERN_INFO "%s: MII interface PHY %d, setup/reset " - "sequences %d/%d long, capabilities %2.2x %2.2x.\n", - dev->name, bp[0], bp[1], bp[2 + bp[1]*2], - bp[5 + bp[2 + bp[1]*2]*2], bp[4 + bp[2 + bp[1]*2]*2]); - } - printk(KERN_INFO "%s: Index #%d - Media %s (#%d) described " - "by a %s (%d) block.\n", - dev->name, i, medianame[leaf->media], leaf->media, - block_name[leaf->type], leaf->type); - } - if (new_advertise) - tp->to_advertise = new_advertise; - } -} -/* Reading a serial EEPROM is a "bit" grungy, but we work our way through:->.*/ - -/* EEPROM_Ctrl bits. */ -#define EE_SHIFT_CLK 0x02 /* EEPROM shift clock. */ -#define EE_CS 0x01 /* EEPROM chip select. */ -#define EE_DATA_WRITE 0x04 /* Data from the Tulip to EEPROM. */ -#define EE_WRITE_0 0x01 -#define EE_WRITE_1 0x05 -#define EE_DATA_READ 0x08 /* Data from the EEPROM chip. */ -#define EE_ENB (0x4800 | EE_CS) - -/* Delay between EEPROM clock transitions. - Even at 33Mhz current PCI implementations don't overrun the EEPROM clock. - We add a bus turn-around to insure that this remains true. */ -#define eeprom_delay() inl(ee_addr) - -/* The EEPROM commands include the alway-set leading bit. */ -#define EE_READ_CMD (6) - -/* Note: this routine returns extra data bits for size detection. */ -static int __devinit read_eeprom(long ioaddr, int location, int addr_len) -{ - int i; - unsigned retval = 0; - long ee_addr = ioaddr + CSR9; - int read_cmd = location | (EE_READ_CMD << addr_len); - - outl(EE_ENB & ~EE_CS, ee_addr); - outl(EE_ENB, ee_addr); - - /* Shift the read command bits out. */ - for (i = 4 + addr_len; i >= 0; i--) { - short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0; - outl(EE_ENB | dataval, ee_addr); - eeprom_delay(); - outl(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr); - eeprom_delay(); - retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0); - } - outl(EE_ENB, ee_addr); - - for (i = 16; i > 0; i--) { - outl(EE_ENB | EE_SHIFT_CLK, ee_addr); - eeprom_delay(); - retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0); - outl(EE_ENB, ee_addr); - eeprom_delay(); - } - - /* Terminate the EEPROM access. */ - outl(EE_ENB & ~EE_CS, ee_addr); - return retval; -} - -/* MII transceiver control section. - Read and write the MII registers using software-generated serial - MDIO protocol. See the MII specifications or DP83840A data sheet - for details. */ - -/* The maximum data clock rate is 2.5 Mhz. The minimum timing is usually - met by back-to-back PCI I/O cycles, but we insert a delay to avoid - "overclocking" issues or future 66Mhz PCI. */ -#define mdio_delay() inl(mdio_addr) - -/* Read and write the MII registers using software-generated serial - MDIO protocol. It is just different enough from the EEPROM protocol - to not share code. The maxium data clock rate is 2.5 Mhz. */ -#define MDIO_SHIFT_CLK 0x10000 -#define MDIO_DATA_WRITE0 0x00000 -#define MDIO_DATA_WRITE1 0x20000 -#define MDIO_ENB 0x00000 /* Ignore the 0x02000 databook setting. */ -#define MDIO_ENB_IN 0x40000 -#define MDIO_DATA_READ 0x80000 - -static int mdio_read(struct net_device *dev, int phy_id, int location) -{ - struct tulip_private *tp = (struct tulip_private *)dev->priv; - int i; - int read_cmd = (0xf6 << 10) | (phy_id << 5) | location; - int retval = 0; - long ioaddr = dev->base_addr; - long mdio_addr = ioaddr + CSR9; - - if (tp->chip_id == LC82C168) { - int i = 1000; - outl(0x60020000 + (phy_id<<23) + (location<<18), ioaddr + 0xA0); - inl(ioaddr + 0xA0); - inl(ioaddr + 0xA0); - while (--i > 0) - if ( ! ((retval = inl(ioaddr + 0xA0)) & 0x80000000)) - return retval & 0xffff; - return 0xffff; - } - - if (tp->chip_id == COMET) { - if (phy_id == 1) { - if (location < 7) - return inl(ioaddr + 0xB4 + (location<<2)); - else if (location == 17) - return inl(ioaddr + 0xD0); - else if (location >= 29 && location <= 31) - return inl(ioaddr + 0xD4 + ((location-29)<<2)); - } - return 0xffff; - } - - /* Establish sync by sending at least 32 logic ones. */ - for (i = 32; i >= 0; i--) { - outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr); - mdio_delay(); - outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr); - mdio_delay(); - } - /* Shift the read command bits out. */ - for (i = 15; i >= 0; i--) { - int dataval = (read_cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0; - - outl(MDIO_ENB | dataval, mdio_addr); - mdio_delay(); - outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr); - mdio_delay(); - } - /* Read the two transition, 16 data, and wire-idle bits. */ - for (i = 19; i > 0; i--) { - outl(MDIO_ENB_IN, mdio_addr); - mdio_delay(); - retval = (retval << 1) | ((inl(mdio_addr) & MDIO_DATA_READ) ? 1 : 0); - outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); - mdio_delay(); - } - return (retval>>1) & 0xffff; -} - -static void mdio_write(struct net_device *dev, int phy_id, int location, int value) -{ - struct tulip_private *tp = (struct tulip_private *)dev->priv; - int i; - int cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value; - long ioaddr = dev->base_addr; - long mdio_addr = ioaddr + CSR9; - - if (tp->chip_id == LC82C168) { - int i = 1000; - outl(cmd, ioaddr + 0xA0); - do - if ( ! (inl(ioaddr + 0xA0) & 0x80000000)) - break; - while (--i > 0); - return; - } - - if (tp->chip_id == COMET) { - if (phy_id != 1) - return; - if (location < 7) - outl(value, ioaddr + 0xB4 + (location<<2)); - else if (location == 17) - outl(value, ioaddr + 0xD0); - else if (location >= 29 && location <= 31) - outl(value, ioaddr + 0xD4 + ((location-29)<<2)); - return; - } - - /* Establish sync by sending 32 logic ones. */ - for (i = 32; i >= 0; i--) { - outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr); - mdio_delay(); - outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr); - mdio_delay(); - } - /* Shift the command bits out. */ - for (i = 31; i >= 0; i--) { - int dataval = (cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0; - outl(MDIO_ENB | dataval, mdio_addr); - mdio_delay(); - outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr); - mdio_delay(); - } - /* Clear out extra bits. */ - for (i = 2; i > 0; i--) { - outl(MDIO_ENB_IN, mdio_addr); - mdio_delay(); - outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); - mdio_delay(); - } - return; -} - - -/* The Xircom cards are picky about when certain bits in CSR6 can be - manipulated. Keith Owens . */ - -static void outl_CSR6 (struct tulip_private *tp, u32 newcsr6) -{ - long ioaddr = tp->base_addr; - const int strict_bits = 0x0060e202; - int csr5, csr5_22_20, csr5_19_17, currcsr6, attempts = 200; - long flags; - - /* really a hw lock */ - spin_lock_irqsave (&tp->tx_lock, flags); - - if (tp->chip_id != X3201_3) - goto out_write; - - newcsr6 &= 0x726cfeca; /* mask out the reserved CSR6 bits that always */ - /* read 0 on the Xircom cards */ - newcsr6 |= 0x320c0000; /* or in the reserved bits that always read 1 */ - currcsr6 = inl (ioaddr + CSR6); - if (((newcsr6 & strict_bits) == (currcsr6 & strict_bits)) || - ((currcsr6 & ~0x2002) == 0)) - goto out_write; - - /* make sure the transmitter and receiver are stopped first */ - currcsr6 &= ~0x2002; - while (1) { - csr5 = inl (ioaddr + CSR5); - if (csr5 == 0xffffffff) - break; /* cannot read csr5, card removed? */ - csr5_22_20 = csr5 & 0x700000; - csr5_19_17 = csr5 & 0x0e0000; - if ((csr5_22_20 == 0 || csr5_22_20 == 0x600000) && - (csr5_19_17 == 0 || csr5_19_17 == 0x80000 || csr5_19_17 == 0xc0000)) - break; /* both are stopped or suspended */ - if (!--attempts) { - printk (KERN_INFO "tulip.c: outl_CSR6 too many attempts," - "csr5=0x%08x\n", csr5); - goto out_write; - } - outl (currcsr6, ioaddr + CSR6); - udelay (1); - } - -out_write: - /* now it is safe to change csr6 */ - outl (newcsr6, ioaddr + CSR6); - - spin_unlock_irqrestore (&tp->lock, flags); -} - - -static void tulip_up(struct net_device *dev) -{ - struct tulip_private *tp = (struct tulip_private *)dev->priv; - long ioaddr = dev->base_addr; - int next_tick = 3*HZ; - int i; - - /* Wake the chip from sleep/snooze mode. */ - if (tp->flags & HAS_ACPI) - pci_write_config_dword(tp->pdev, 0x40, 0); - - /* On some chip revs we must set the MII/SYM port before the reset!? */ - if (tp->mii_cnt || (tp->mtable && tp->mtable->has_mii)) - outl_CSR6 (tp, 0x00040000); - - /* Reset the chip, holding bit 0 set at least 50 PCI cycles. */ - outl(0x00000001, ioaddr + CSR0); - - /* Deassert reset. - Wait the specified 50 PCI cycles after a reset by initializing - Tx and Rx queues and the address filter list. */ - outl(tp->csr0, ioaddr + CSR0); - - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: tulip_open() irq %d.\n", dev->name, dev->irq); - - if (tp->flags & MC_HASH_ONLY) { - u32 addr_low = cpu_to_le32(get_unaligned((u32 *)dev->dev_addr)); - u32 addr_high = cpu_to_le32(get_unaligned((u16 *)(dev->dev_addr+4))); - if (tp->chip_id == AX88140) { - outl(0, ioaddr + CSR13); - outl(addr_low, ioaddr + CSR14); - outl(1, ioaddr + CSR13); - outl(addr_high, ioaddr + CSR14); - } else if (tp->chip_id == COMET) { - outl(addr_low, ioaddr + 0xA4); - outl(addr_high, ioaddr + 0xA8); - outl(0, ioaddr + 0xAC); - outl(0, ioaddr + 0xB0); - } - } else { - /* This is set_rx_mode(), but without starting the transmitter. */ - u16 *eaddrs = (u16 *)dev->dev_addr; - u16 *setup_frm = &tp->setup_frame[15*6]; - - /* 21140 bug: you must add the broadcast address. */ - memset(tp->setup_frame, 0xff, sizeof(tp->setup_frame)); - /* Fill the final entry of the table with our physical address. */ - *setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0]; - *setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1]; - *setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2]; - /* Put the setup frame on the Tx list. */ - tp->tx_ring[0].length = cpu_to_le32(0x08000000 | 192); - tp->tx_ring[0].buffer1 = virt_to_le32desc(tp->setup_frame); - tp->tx_ring[0].status = cpu_to_le32(DescOwned); - - tp->cur_tx++; - } - - outl(virt_to_bus(tp->rx_ring), ioaddr + CSR3); - outl(virt_to_bus(tp->tx_ring), ioaddr + CSR4); - - tp->saved_if_port = dev->if_port; - if (dev->if_port == 0) - dev->if_port = tp->default_port; - - /* Allow selecting a default media. */ - i = 0; - if (tp->mtable == NULL) - goto media_picked; - if (dev->if_port) { - int looking_for = media_cap[dev->if_port] & MediaIsMII ? 11 : - (dev->if_port == 12 ? 0 : dev->if_port); - for (i = 0; i < tp->mtable->leafcount; i++) - if (tp->mtable->mleaf[i].media == looking_for) { - printk(KERN_INFO "%s: Using user-specified media %s.\n", - dev->name, medianame[dev->if_port]); - goto media_picked; - } - } - if ((tp->mtable->defaultmedia & 0x0800) == 0) { - int looking_for = tp->mtable->defaultmedia & 15; - for (i = 0; i < tp->mtable->leafcount; i++) - if (tp->mtable->mleaf[i].media == looking_for) { - printk(KERN_INFO "%s: Using EEPROM-set media %s.\n", - dev->name, medianame[looking_for]); - goto media_picked; - } - } - /* Start sensing first non-full-duplex media. */ - for (i = tp->mtable->leafcount - 1; - (media_cap[tp->mtable->mleaf[i].media] & MediaAlwaysFD) && i > 0; i--) - ; -media_picked: - - tp->csr6 = 0; - tp->cur_index = i; - tp->nwayset = 0; - if (dev->if_port == 0 && tp->chip_id == DC21041) { - tp->nway = 1; - } - if (dev->if_port == 0 && tp->chip_id == DC21142) { - if (tp->mii_cnt) { - select_media(dev, 1); - if (tulip_debug > 1) - printk(KERN_INFO "%s: Using MII transceiver %d, status " - "%4.4x.\n", - dev->name, tp->phys[0], mdio_read(dev, tp->phys[0], 1)); - outl_CSR6(tp, 0x82020000); - tp->csr6 = 0x820E0000; - dev->if_port = 11; - outl(0x0000, ioaddr + CSR13); - outl(0x0000, ioaddr + CSR14); - } else - t21142_start_nway(dev); - } else if (tp->chip_id == PNIC2) { - t21142_start_nway(dev); - } else if (tp->chip_id == LC82C168 && ! tp->medialock) { - if (tp->mii_cnt) { - dev->if_port = 11; - tp->csr6 = 0x814C0000 | (tp->full_duplex ? 0x0200 : 0); - outl(0x0001, ioaddr + CSR15); - } else if (inl(ioaddr + CSR5) & TPLnkPass) - pnic_do_nway(dev); - else { - /* Start with 10mbps to do autonegotiation. */ - outl(0x32, ioaddr + CSR12); - tp->csr6 = 0x00420000; - outl(0x0001B078, ioaddr + 0xB8); - outl(0x0201B078, ioaddr + 0xB8); - next_tick = 1*HZ; - } - } else if ((tp->chip_id == MX98713 || tp->chip_id == COMPEX9881) - && ! tp->medialock) { - dev->if_port = 0; - tp->csr6 = 0x01880000 | (tp->full_duplex ? 0x0200 : 0); - outl(0x0f370000 | inw(ioaddr + 0x80), ioaddr + 0x80); - } else if (tp->chip_id == MX98715 || tp->chip_id == MX98725) { - /* Provided by BOLO, Macronix - 12/10/1998. */ - dev->if_port = 0; - tp->csr6 = 0x01a80200; - outl(0x0f370000 | inw(ioaddr + 0x80), ioaddr + 0x80); - outl(0x11000 | inw(ioaddr + 0xa0), ioaddr + 0xa0); - } else if (tp->chip_id == DC21143 && - media_cap[dev->if_port] & MediaIsMII) { - /* We must reset the media CSRs when we force-select MII mode. */ - outl(0x0000, ioaddr + CSR13); - outl(0x0000, ioaddr + CSR14); - outl(0x0008, ioaddr + CSR15); - } else if (tp->chip_id == COMET) { - dev->if_port = 0; - tp->csr6 = 0x00040000; - } else if (tp->chip_id == AX88140) { - tp->csr6 = tp->mii_cnt ? 0x00040100 : 0x00000100; - } else - select_media(dev, 1); - - /* Start the chip's Tx to process setup frame. */ - outl_CSR6(tp, tp->csr6); - outl_CSR6(tp, tp->csr6 | 0x2000); - - /* Enable interrupts by setting the interrupt mask. */ - outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR5); - outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7); - outl_CSR6(tp, tp->csr6 | 0x2002); - outl(0, ioaddr + CSR2); /* Rx poll demand */ - - if (tulip_debug > 2) { - printk(KERN_DEBUG "%s: Done tulip_open(), CSR0 %8.8x, CSR5 %8.8x CSR6 %8.8x.\n", - dev->name, inl(ioaddr + CSR0), inl(ioaddr + CSR5), - inl(ioaddr + CSR6)); - } - /* Set the timer to switch to check for link beat and perhaps switch - to an alternate media type. */ - init_timer(&tp->timer); - tp->timer.expires = RUN_AT(next_tick); - tp->timer.data = (unsigned long)dev; - tp->timer.function = tulip_tbl[tp->chip_id].media_timer; - add_timer(&tp->timer); - - netif_device_attach(dev); -} - - -static int -tulip_open(struct net_device *dev) -{ - MOD_INC_USE_COUNT; - - if (request_irq(dev->irq, &tulip_interrupt, SA_SHIRQ, dev->name, dev)) { - MOD_DEC_USE_COUNT; - return -EBUSY; - } - - tulip_init_ring (dev); - - tulip_up (dev); - - return 0; -} - - -/* Set up the transceiver control registers for the selected media type. */ -static void select_media(struct net_device *dev, int startup) -{ - long ioaddr = dev->base_addr; - struct tulip_private *tp = (struct tulip_private *)dev->priv; - struct mediatable *mtable = tp->mtable; - u32 new_csr6; - int i; - - if (mtable) { - struct medialeaf *mleaf = &mtable->mleaf[tp->cur_index]; - unsigned char *p = mleaf->leafdata; - switch (mleaf->type) { - case 0: /* 21140 non-MII xcvr. */ - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Using a 21140 non-MII transceiver" - " with control setting %2.2x.\n", - dev->name, p[1]); - dev->if_port = p[0]; - if (startup) - outl(mtable->csr12dir | 0x100, ioaddr + CSR12); - outl(p[1], ioaddr + CSR12); - new_csr6 = 0x02000000 | ((p[2] & 0x71) << 18); - break; - case 2: case 4: { - u16 setup[5]; - u32 csr13val, csr14val, csr15dir, csr15val; - for (i = 0; i < 5; i++) - setup[i] = get_u16(&p[i*2 + 1]); - - dev->if_port = p[0] & 15; - if (media_cap[dev->if_port] & MediaAlwaysFD) - tp->full_duplex = 1; - - if (startup && mtable->has_reset) { - struct medialeaf *rleaf = &mtable->mleaf[mtable->has_reset]; - unsigned char *rst = rleaf->leafdata; - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Resetting the transceiver.\n", - dev->name); - for (i = 0; i < rst[0]; i++) - outl(get_u16(rst + 1 + (i<<1)) << 16, ioaddr + CSR15); - } - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: 21143 non-MII %s transceiver control " - "%4.4x/%4.4x.\n", - dev->name, medianame[dev->if_port], setup[0], setup[1]); - if (p[0] & 0x40) { /* SIA (CSR13-15) setup values are provided. */ - csr13val = setup[0]; - csr14val = setup[1]; - csr15dir = (setup[3]<<16) | setup[2]; - csr15val = (setup[4]<<16) | setup[2]; - outl(0, ioaddr + CSR13); - outl(csr14val, ioaddr + CSR14); - outl(csr15dir, ioaddr + CSR15); /* Direction */ - outl(csr15val, ioaddr + CSR15); /* Data */ - outl(csr13val, ioaddr + CSR13); - } else { - csr13val = 1; - csr14val = 0x0003FF7F; - csr15dir = (setup[0]<<16) | 0x0008; - csr15val = (setup[1]<<16) | 0x0008; - if (dev->if_port <= 4) - csr14val = t21142_csr14[dev->if_port]; - if (startup) { - outl(0, ioaddr + CSR13); - outl(csr14val, ioaddr + CSR14); - } - outl(csr15dir, ioaddr + CSR15); /* Direction */ - outl(csr15val, ioaddr + CSR15); /* Data */ - if (startup) outl(csr13val, ioaddr + CSR13); - } - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Setting CSR15 to %8.8x/%8.8x.\n", - dev->name, csr15dir, csr15val); - if (mleaf->type == 4) - new_csr6 = 0x82020000 | ((setup[2] & 0x71) << 18); - else - new_csr6 = 0x82420000; - break; - } - case 1: case 3: { - int phy_num = p[0]; - int init_length = p[1]; - u16 *misc_info; - u16 to_advertise; - - dev->if_port = 11; - new_csr6 = 0x020E0000; - if (mleaf->type == 3) { /* 21142 */ - u16 *init_sequence = (u16*)(p+2); - u16 *reset_sequence = &((u16*)(p+3))[init_length]; - int reset_length = p[2 + init_length*2]; - misc_info = reset_sequence + reset_length; - if (startup) - for (i = 0; i < reset_length; i++) - outl(get_u16(&reset_sequence[i]) << 16, ioaddr + CSR15); - for (i = 0; i < init_length; i++) - outl(get_u16(&init_sequence[i]) << 16, ioaddr + CSR15); - } else { - u8 *init_sequence = p + 2; - u8 *reset_sequence = p + 3 + init_length; - int reset_length = p[2 + init_length]; - misc_info = (u16*)(reset_sequence + reset_length); - if (startup) { - outl(mtable->csr12dir | 0x100, ioaddr + CSR12); - for (i = 0; i < reset_length; i++) - outl(reset_sequence[i], ioaddr + CSR12); - } - for (i = 0; i < init_length; i++) - outl(init_sequence[i], ioaddr + CSR12); - } - to_advertise = (get_u16(&misc_info[1]) & tp->to_advertise) | 1; - tp->advertising[phy_num] = to_advertise; - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Advertising %4.4x on PHY %d (%d).\n", - dev->name, to_advertise, phy_num, tp->phys[phy_num]); - /* Bogus: put in by a committee? */ - mdio_write(dev, tp->phys[phy_num], 4, to_advertise); - break; - } - default: - printk(KERN_DEBUG "%s: Invalid media table selection %d.\n", - dev->name, mleaf->type); - new_csr6 = 0x020E0000; - } - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Using media type %s, CSR12 is %2.2x.\n", - dev->name, medianame[dev->if_port], - inl(ioaddr + CSR12) & 0xff); - } else if (tp->chip_id == DC21041) { - int port = dev->if_port <= 4 ? dev->if_port : 0; - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: 21041 using media %s, CSR12 is %4.4x.\n", - dev->name, medianame[port == 3 ? 12: port], - inl(ioaddr + CSR12)); - outl(0x00000000, ioaddr + CSR13); /* Reset the serial interface */ - outl(t21041_csr14[port], ioaddr + CSR14); - outl(t21041_csr15[port], ioaddr + CSR15); - outl(t21041_csr13[port], ioaddr + CSR13); - new_csr6 = 0x80020000; - } else if (tp->chip_id == LC82C168) { - if (startup && ! tp->medialock) - dev->if_port = tp->mii_cnt ? 11 : 0; - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: PNIC PHY status is %3.3x, media %s.\n", - dev->name, inl(ioaddr + 0xB8), medianame[dev->if_port]); - if (tp->mii_cnt) { - new_csr6 = 0x810C0000; - outl(0x0001, ioaddr + CSR15); - outl(0x0201B07A, ioaddr + 0xB8); - } else if (startup) { - /* Start with 10mbps to do autonegotiation. */ - outl(0x32, ioaddr + CSR12); - new_csr6 = 0x00420000; - outl(0x0001B078, ioaddr + 0xB8); - outl(0x0201B078, ioaddr + 0xB8); - } else if (dev->if_port == 3 || dev->if_port == 5) { - outl(0x33, ioaddr + CSR12); - new_csr6 = 0x01860000; - /* Trigger autonegotiation. */ - outl(startup ? 0x0201F868 : 0x0001F868, ioaddr + 0xB8); - } else { - outl(0x32, ioaddr + CSR12); - new_csr6 = 0x00420000; - outl(0x1F078, ioaddr + 0xB8); - } - } else if (tp->chip_id == DC21040) { /* 21040 */ - /* Turn on the xcvr interface. */ - int csr12 = inl(ioaddr + CSR12); - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: 21040 media type is %s, CSR12 is %2.2x.\n", - dev->name, medianame[dev->if_port], csr12); - if (media_cap[dev->if_port] & MediaAlwaysFD) - tp->full_duplex = 1; - new_csr6 = 0x20000; - /* Set the full duplux match frame. */ - outl(FULL_DUPLEX_MAGIC, ioaddr + CSR11); - outl(0x00000000, ioaddr + CSR13); /* Reset the serial interface */ - if (t21040_csr13[dev->if_port] & 8) { - outl(0x0705, ioaddr + CSR14); - outl(0x0006, ioaddr + CSR15); - } else { - outl(0xffff, ioaddr + CSR14); - outl(0x0000, ioaddr + CSR15); - } - outl(0x8f01 | t21040_csr13[dev->if_port], ioaddr + CSR13); - } else { /* Unknown chip type with no media table. */ - if (tp->default_port == 0) - dev->if_port = tp->mii_cnt ? 11 : 3; - if (media_cap[dev->if_port] & MediaIsMII) { - new_csr6 = 0x020E0000; - } else if (media_cap[dev->if_port] & MediaIsFx) { - new_csr6 = 0x028600000; - } else - new_csr6 = 0x038600000; - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: No media description table, assuming " - "%s transceiver, CSR12 %2.2x.\n", - dev->name, medianame[dev->if_port], - inl(ioaddr + CSR12)); - } - - tp->csr6 = new_csr6 | (tp->csr6 & 0xfdff) | (tp->full_duplex ? 0x0200 : 0); - return; -} - -/* - Check the MII negotiated duplex, and change the CSR6 setting if - required. - Return 0 if everything is OK. - Return < 0 if the transceiver is missing or has no link beat. - */ -static int check_duplex(struct net_device *dev) -{ - struct tulip_private *tp = (struct tulip_private *)dev->priv; - int mii_reg1, mii_reg5, negotiated, duplex; - - if (tp->full_duplex_lock) - return 0; - mii_reg1 = mdio_read(dev, tp->phys[0], 1); - mii_reg5 = mdio_read(dev, tp->phys[0], 5); - if (tulip_debug > 1) - printk(KERN_INFO "%s: MII status %4.4x, Link partner report " - "%4.4x.\n", dev->name, mii_reg1, mii_reg5); - if (mii_reg1 == 0xffff) - return -2; - if ((mii_reg1 & 0x0004) == 0) { - int new_reg1 = mdio_read(dev, tp->phys[0], 1); - if ((new_reg1 & 0x0004) == 0) { - if (tulip_debug > 1) - printk(KERN_INFO "%s: No link beat on the MII interface," - " status %4.4x.\n", dev->name, new_reg1); - return -1; - } - } - negotiated = mii_reg5 & tp->advertising[0]; - duplex = ((negotiated & 0x0300) == 0x0100 - || (negotiated & 0x00C0) == 0x0040); - /* 100baseTx-FD or 10T-FD, but not 100-HD */ - if (tp->full_duplex != duplex) { - tp->full_duplex = duplex; - if (negotiated & 0x038) /* 100mbps. */ - tp->csr6 &= ~0x00400000; - if (tp->full_duplex) tp->csr6 |= 0x0200; - else tp->csr6 &= ~0x0200; - outl_CSR6(tp, tp->csr6 | 0x0002); - outl_CSR6(tp, tp->csr6 | 0x2002); - if (tulip_debug > 0) - printk(KERN_INFO "%s: Setting %s-duplex based on MII" - "#%d link partner capability of %4.4x.\n", - dev->name, tp->full_duplex ? "full" : "half", - tp->phys[0], mii_reg5); - return 1; - } - return 0; -} - -static void tulip_timer(unsigned long data) -{ - struct net_device *dev = (struct net_device *)data; - struct tulip_private *tp = (struct tulip_private *)dev->priv; - long ioaddr = dev->base_addr; - u32 csr12 = inl(ioaddr + CSR12); - int next_tick = 2*HZ; - - if (tulip_debug > 2) { - printk(KERN_DEBUG "%s: Media selection tick, %s, status %8.8x mode" - " %8.8x SIA %8.8x %8.8x %8.8x %8.8x.\n", - dev->name, medianame[dev->if_port], inl(ioaddr + CSR5), - inl(ioaddr + CSR6), csr12, inl(ioaddr + CSR13), - inl(ioaddr + CSR14), inl(ioaddr + CSR15)); - } - switch (tp->chip_id) { - case DC21040: - if (!tp->medialock && csr12 & 0x0002) { /* Network error */ - printk(KERN_INFO "%s: No link beat found.\n", - dev->name); - dev->if_port = (dev->if_port == 2 ? 0 : 2); - select_media(dev, 0); - dev->trans_start = jiffies; - } - break; - case DC21041: - if (tulip_debug > 2) - printk(KERN_DEBUG "%s: 21041 media tick CSR12 %8.8x.\n", - dev->name, csr12); - if (tp->medialock) break; - switch (dev->if_port) { - case 0: case 3: case 4: - if (csr12 & 0x0004) { /*LnkFail */ - /* 10baseT is dead. Check for activity on alternate port. */ - tp->mediasense = 1; - if (csr12 & 0x0200) - dev->if_port = 2; - else - dev->if_port = 1; - printk(KERN_INFO "%s: No 21041 10baseT link beat, Media switched to %s.\n", - dev->name, medianame[dev->if_port]); - outl(0, ioaddr + CSR13); /* Reset */ - outl(t21041_csr14[dev->if_port], ioaddr + CSR14); - outl(t21041_csr15[dev->if_port], ioaddr + CSR15); - outl(t21041_csr13[dev->if_port], ioaddr + CSR13); - next_tick = 10*HZ; /* 2.4 sec. */ - } else - next_tick = 30*HZ; - break; - case 1: /* 10base2 */ - case 2: /* AUI */ - if (csr12 & 0x0100) { - next_tick = (30*HZ); /* 30 sec. */ - tp->mediasense = 0; - } else if ((csr12 & 0x0004) == 0) { - printk(KERN_INFO "%s: 21041 media switched to 10baseT.\n", - dev->name); - dev->if_port = 0; - select_media(dev, 0); - next_tick = (24*HZ)/10; /* 2.4 sec. */ - } else if (tp->mediasense || (csr12 & 0x0002)) { - dev->if_port = 3 - dev->if_port; /* Swap ports. */ - select_media(dev, 0); - next_tick = 20*HZ; - } else { - next_tick = 20*HZ; - } - break; - } - break; - case DC21140: case DC21142: case MX98713: case COMPEX9881: default: { - struct medialeaf *mleaf; - unsigned char *p; - if (tp->mtable == NULL) { /* No EEPROM info, use generic code. */ - /* Not much that can be done. - Assume this a generic MII or SYM transceiver. */ - next_tick = 60*HZ; - if (tulip_debug > 2) - printk(KERN_DEBUG "%s: network media monitor CSR6 %8.8x " - "CSR12 0x%2.2x.\n", - dev->name, inl(ioaddr + CSR6), csr12 & 0xff); - break; - } - mleaf = &tp->mtable->mleaf[tp->cur_index]; - p = mleaf->leafdata; - switch (mleaf->type) { - case 0: case 4: { - /* Type 0 serial or 4 SYM transceiver. Check the link beat bit. */ - int offset = mleaf->type == 4 ? 5 : 2; - s8 bitnum = p[offset]; - if (p[offset+1] & 0x80) { - if (tulip_debug > 1) - printk(KERN_DEBUG"%s: Transceiver monitor tick " - "CSR12=%#2.2x, no media sense.\n", - dev->name, csr12); - if (mleaf->type == 4) { - if (mleaf->media == 3 && (csr12 & 0x02)) - goto select_next_media; - } - break; - } - if (tulip_debug > 2) - printk(KERN_DEBUG "%s: Transceiver monitor tick: CSR12=%#2.2x" - " bit %d is %d, expecting %d.\n", - dev->name, csr12, (bitnum >> 1) & 7, - (csr12 & (1 << ((bitnum >> 1) & 7))) != 0, - (bitnum >= 0)); - /* Check that the specified bit has the proper value. */ - if ((bitnum < 0) != - ((csr12 & (1 << ((bitnum >> 1) & 7))) != 0)) { - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Link beat detected for %s.\n", dev->name, - medianame[mleaf->media]); - if ((p[2] & 0x61) == 0x01) /* Bogus Znyx board. */ - goto actually_mii; - break; - } - if (tp->medialock) - break; - select_next_media: - if (--tp->cur_index < 0) { - /* We start again, but should instead look for default. */ - tp->cur_index = tp->mtable->leafcount - 1; - } - dev->if_port = tp->mtable->mleaf[tp->cur_index].media; - if (media_cap[dev->if_port] & MediaIsFD) - goto select_next_media; /* Skip FD entries. */ - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: No link beat on media %s," - " trying transceiver type %s.\n", - dev->name, medianame[mleaf->media & 15], - medianame[tp->mtable->mleaf[tp->cur_index].media]); - select_media(dev, 0); - /* Restart the transmit process. */ - outl_CSR6(tp, tp->csr6 | 0x0002); - outl_CSR6(tp, tp->csr6 | 0x2002); - next_tick = (24*HZ)/10; - break; - } - case 1: case 3: /* 21140, 21142 MII */ - actually_mii: - check_duplex(dev); - next_tick = 60*HZ; - break; - case 2: /* 21142 serial block has no link beat. */ - default: - break; - } - } - break; - } - tp->timer.expires = RUN_AT(next_tick); - add_timer(&tp->timer); -} - - -/* Handle the 21143 uniquely: do autoselect with NWay, not the EEPROM list - of available transceivers. */ -static void t21142_timer(unsigned long data) -{ - struct net_device *dev = (struct net_device *)data; - struct tulip_private *tp = (struct tulip_private *)dev->priv; - long ioaddr = dev->base_addr; - int csr12 = inl(ioaddr + CSR12); - int next_tick = 60*HZ; - int new_csr6 = 0; - - if (tulip_debug > 2) - printk(KERN_INFO"%s: 21143 negotiation status %8.8x, %s.\n", - dev->name, csr12, medianame[dev->if_port]); - if (media_cap[dev->if_port] & MediaIsMII) { - check_duplex(dev); - next_tick = 60*HZ; - } else if (tp->nwayset) { - /* Don't screw up a negotiated session! */ - if (tulip_debug > 1) - printk(KERN_INFO"%s: Using NWay-set %s media, csr12 %8.8x.\n", - dev->name, medianame[dev->if_port], csr12); - } else if (tp->medialock) { - ; - } else if (dev->if_port == 3) { - if (csr12 & 2) { /* No 100mbps link beat, revert to 10mbps. */ - if (tulip_debug > 1) - printk(KERN_INFO"%s: No 21143 100baseTx link beat, %8.8x, " - "trying NWay.\n", dev->name, csr12); - t21142_start_nway(dev); - next_tick = 3*HZ; - } - } else if ((csr12 & 0x7000) != 0x5000) { - /* Negotiation failed. Search media types. */ - if (tulip_debug > 1) - printk(KERN_INFO"%s: 21143 negotiation failed, status %8.8x.\n", - dev->name, csr12); - if (!(csr12 & 4)) { /* 10mbps link beat good. */ - new_csr6 = 0x82420000; - dev->if_port = 0; - outl(0, ioaddr + CSR13); - outl(0x0003FFFF, ioaddr + CSR14); - outw(t21142_csr15[dev->if_port], ioaddr + CSR15); - outl(t21142_csr13[dev->if_port], ioaddr + CSR13); - } else { - /* Select 100mbps port to check for link beat. */ - new_csr6 = 0x83860000; - dev->if_port = 3; - outl(0, ioaddr + CSR13); - outl(0x0003FF7F, ioaddr + CSR14); - outw(8, ioaddr + CSR15); - outl(1, ioaddr + CSR13); - } - if (tulip_debug > 1) - printk(KERN_INFO"%s: Testing new 21143 media %s.\n", - dev->name, medianame[dev->if_port]); - if (new_csr6 != (tp->csr6 & ~0x00D5)) { - tp->csr6 &= 0x00D5; - tp->csr6 |= new_csr6; - outl(0x0301, ioaddr + CSR12); - outl_CSR6(tp, tp->csr6 | 0x0002); - outl_CSR6(tp, tp->csr6 | 0x2002); - } - next_tick = 3*HZ; - } - - tp->timer.expires = RUN_AT(next_tick); - add_timer(&tp->timer); -} - - -static void t21142_start_nway(struct net_device *dev) -{ - struct tulip_private *tp = (struct tulip_private *)dev->priv; - long ioaddr = dev->base_addr; - int csr14 = ((tp->to_advertise & 0x0780) << 9) | - ((tp->to_advertise&0x0020)<<1) | 0xffbf; - - dev->if_port = 0; - tp->nway = tp->mediasense = 1; - tp->nwayset = tp->lpar = 0; - if (debug > 1) - printk(KERN_DEBUG "%s: Restarting 21143 autonegotiation, %8.8x.\n", - dev->name, csr14); - outl(0x0001, ioaddr + CSR13); - outl(csr14, ioaddr + CSR14); - tp->csr6 = 0x82420000 | (tp->to_advertise & 0x0040 ? 0x0200 : 0); - outl_CSR6(tp, tp->csr6); - if (tp->mtable && tp->mtable->csr15dir) { - outl(tp->mtable->csr15dir, ioaddr + CSR15); - outl(tp->mtable->csr15val, ioaddr + CSR15); - } else - outw(0x0008, ioaddr + CSR15); - outl(0x1301, ioaddr + CSR12); /* Trigger NWAY. */ -} - - -static void t21142_lnk_change(struct net_device *dev, int csr5) -{ - struct tulip_private *tp = (struct tulip_private *)dev->priv; - long ioaddr = dev->base_addr; - int csr12 = inl(ioaddr + CSR12); - - if (tulip_debug > 1) - printk(KERN_INFO"%s: 21143 link status interrupt %8.8x, CSR5 %x, " - "%8.8x.\n", dev->name, csr12, csr5, inl(ioaddr + CSR14)); - - /* If NWay finished and we have a negotiated partner capability. */ - if (tp->nway && !tp->nwayset && (csr12 & 0x7000) == 0x5000) { - int setup_done = 0; - int negotiated = tp->to_advertise & (csr12 >> 16); - tp->lpar = csr12 >> 16; - tp->nwayset = 1; - if (negotiated & 0x0100) dev->if_port = 5; - else if (negotiated & 0x0080) dev->if_port = 3; - else if (negotiated & 0x0040) dev->if_port = 4; - else if (negotiated & 0x0020) dev->if_port = 0; - else { - tp->nwayset = 0; - if ((csr12 & 2) == 0 && (tp->to_advertise & 0x0180)) - dev->if_port = 3; - } - tp->full_duplex = (media_cap[dev->if_port] & MediaAlwaysFD) ? 1:0; - - if (tulip_debug > 1) { - if (tp->nwayset) - printk(KERN_INFO "%s: Switching to %s based on link " - "negotiation %4.4x & %4.4x = %4.4x.\n", - dev->name, medianame[dev->if_port], tp->to_advertise, - tp->lpar, negotiated); - else - printk(KERN_INFO "%s: Autonegotiation failed, using %s," - " link beat status %4.4x.\n", - dev->name, medianame[dev->if_port], csr12); - } - - if (tp->mtable) { - int i; - for (i = 0; i < tp->mtable->leafcount; i++) - if (tp->mtable->mleaf[i].media == dev->if_port) { - tp->cur_index = i; - select_media(dev, 0); - setup_done = 1; - break; - } - } - if ( ! setup_done) { - tp->csr6 = dev->if_port & 1 ? 0x83860000 : 0x82420000; - if (tp->full_duplex) - tp->csr6 |= 0x0200; - outl(1, ioaddr + CSR13); - } -#if 0 /* Restart shouldn't be needed. */ - outl_CSR6(tp, tp->csr6 | 0x0000); - if (debug > 2) - printk(KERN_DEBUG "%s: Restarting Tx and Rx, CSR5 is %8.8x.\n", - dev->name, inl(ioaddr + CSR5)); -#endif - outl_CSR6(tp, tp->csr6 | 0x2002); - if (debug > 2) - printk(KERN_DEBUG "%s: Setting CSR6 %8.8x/%x CSR12 %8.8x.\n", - dev->name, tp->csr6, inl(ioaddr + CSR6), - inl(ioaddr + CSR12)); - } else if ((tp->nwayset && (csr5 & 0x08000000) - && (dev->if_port == 3 || dev->if_port == 5) - && (csr12 & 2) == 2) || - (tp->nway && (csr5 & (TPLnkFail)))) { - /* Link blew? Maybe restart NWay. */ - del_timer(&tp->timer); - t21142_start_nway(dev); - tp->timer.expires = RUN_AT(3*HZ); - add_timer(&tp->timer); - } else if (dev->if_port == 3 || dev->if_port == 5) { - if (tulip_debug > 1) - printk(KERN_INFO"%s: 21143 %s link beat %s.\n", - dev->name, medianame[dev->if_port], - (csr12 & 2) ? "failed" : "good"); - if ((csr12 & 2) && ! tp->medialock) { - del_timer(&tp->timer); - t21142_start_nway(dev); - tp->timer.expires = RUN_AT(3*HZ); - add_timer(&tp->timer); - } - } else if (dev->if_port == 0 || dev->if_port == 4) { - if ((csr12 & 4) == 0) - printk(KERN_INFO"%s: 21143 10baseT link beat good.\n", - dev->name); - } else if (!(csr12 & 4)) { /* 10mbps link beat good. */ - if (tulip_debug) - printk(KERN_INFO"%s: 21143 10mbps sensed media.\n", - dev->name); - dev->if_port = 0; - } else if (tp->nwayset) { - if (tulip_debug) - printk(KERN_INFO"%s: 21143 using NWay-set %s, csr6 %8.8x.\n", - dev->name, medianame[dev->if_port], tp->csr6); - } else { /* 100mbps link beat good. */ - if (tulip_debug) - printk(KERN_INFO"%s: 21143 100baseTx sensed media.\n", - dev->name); - dev->if_port = 3; - tp->csr6 = 0x83860000; - outl(0x0003FF7F, ioaddr + CSR14); - outl(0x0301, ioaddr + CSR12); - outl_CSR6(tp, tp->csr6 | 0x0002); - outl_CSR6(tp, tp->csr6 | 0x2002); - } -} - - -static void mxic_timer(unsigned long data) -{ - struct net_device *dev = (struct net_device *)data; - struct tulip_private *tp = (struct tulip_private *)dev->priv; - long ioaddr = dev->base_addr; - int next_tick = 60*HZ; - - if (tulip_debug > 3) { - printk(KERN_INFO"%s: MXIC negotiation status %8.8x.\n", dev->name, - inl(ioaddr + CSR12)); - } - if (next_tick) { - tp->timer.expires = RUN_AT(next_tick); - add_timer(&tp->timer); - } -} - - -static void pnic_do_nway(struct net_device *dev) -{ - struct tulip_private *tp = (struct tulip_private *)dev->priv; - long ioaddr = dev->base_addr; - u32 phy_reg = inl(ioaddr + 0xB8); - u32 new_csr6 = tp->csr6 & ~0x40C40200; - - if (phy_reg & 0x78000000) { /* Ignore baseT4 */ - if (phy_reg & 0x20000000) dev->if_port = 5; - else if (phy_reg & 0x40000000) dev->if_port = 3; - else if (phy_reg & 0x10000000) dev->if_port = 4; - else if (phy_reg & 0x08000000) dev->if_port = 0; - tp->nwayset = 1; - new_csr6 = (dev->if_port & 1) ? 0x01860000 : 0x00420000; - outl(0x32 | (dev->if_port & 1), ioaddr + CSR12); - if (dev->if_port & 1) - outl(0x1F868, ioaddr + 0xB8); - if (phy_reg & 0x30000000) { - tp->full_duplex = 1; - new_csr6 |= 0x00000200; - } - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: PNIC autonegotiated status %8.8x, %s.\n", - dev->name, phy_reg, medianame[dev->if_port]); - if (tp->csr6 != new_csr6) { - tp->csr6 = new_csr6; - /* Restart Tx */ - outl_CSR6(tp, tp->csr6 | 0x0002); - outl_CSR6(tp, tp->csr6 | 0x2002); - dev->trans_start = jiffies; - } - } -} - - -static void pnic_lnk_change(struct net_device *dev, int csr5) -{ - struct tulip_private *tp = (struct tulip_private *)dev->priv; - long ioaddr = dev->base_addr; - int phy_reg = inl(ioaddr + 0xB8); - - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: PNIC link changed state %8.8x, CSR5 %8.8x.\n", - dev->name, phy_reg, csr5); - if (inl(ioaddr + CSR5) & TPLnkFail) { - outl((inl(ioaddr + CSR7) & ~TPLnkFail) | TPLnkPass, ioaddr + CSR7); - if (! tp->nwayset || jiffies - dev->trans_start > 1*HZ) { - tp->csr6 = 0x00420000 | (tp->csr6 & 0x0000fdff); - outl_CSR6(tp, tp->csr6); - outl(0x30, ioaddr + CSR12); - outl(0x0201F078, ioaddr + 0xB8); /* Turn on autonegotiation. */ - dev->trans_start = jiffies; - } - } else if (inl(ioaddr + CSR5) & TPLnkPass) { - pnic_do_nway(dev); - outl((inl(ioaddr + CSR7) & ~TPLnkPass) | TPLnkFail, ioaddr + CSR7); - } -} - - -static void pnic_timer(unsigned long data) -{ - struct net_device *dev = (struct net_device *)data; - struct tulip_private *tp = (struct tulip_private *)dev->priv; - long ioaddr = dev->base_addr; - int next_tick = 60*HZ; - - if (media_cap[dev->if_port] & MediaIsMII) { - if (check_duplex(dev) > 0) - next_tick = 3*HZ; - } else { - int csr12 = inl(ioaddr + CSR12); - int new_csr6 = tp->csr6 & ~0x40C40200; - int phy_reg = inl(ioaddr + 0xB8); - int csr5 = inl(ioaddr + CSR5); - - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: PNIC timer PHY status %8.8x, %s " - "CSR5 %8.8x.\n", - dev->name, phy_reg, medianame[dev->if_port], csr5); - if (phy_reg & 0x04000000) { /* Remote link fault */ - outl(0x0201F078, ioaddr + 0xB8); - next_tick = 1*HZ; - tp->nwayset = 0; - } else if (phy_reg & 0x78000000) { /* Ignore baseT4 */ - pnic_do_nway(dev); - next_tick = 60*HZ; - } else if (csr5 & TPLnkFail) { /* 100baseTx link beat */ - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: %s link beat failed, CSR12 %4.4x, " - "CSR5 %8.8x, PHY %3.3x.\n", - dev->name, medianame[dev->if_port], csr12, - inl(ioaddr + CSR5), inl(ioaddr + 0xB8)); - next_tick = 3*HZ; - if (tp->medialock) { - } else if (tp->nwayset && (dev->if_port & 1)) { - next_tick = 1*HZ; - } else if (dev->if_port == 0) { - dev->if_port = 3; - outl(0x33, ioaddr + CSR12); - new_csr6 = 0x01860000; - outl(0x1F868, ioaddr + 0xB8); - } else { - dev->if_port = 0; - outl(0x32, ioaddr + CSR12); - new_csr6 = 0x00420000; - outl(0x1F078, ioaddr + 0xB8); - } - if (tp->csr6 != new_csr6) { - tp->csr6 = new_csr6; - /* Restart Tx */ - outl_CSR6(tp, tp->csr6 | 0x0002); - outl_CSR6(tp, tp->csr6 | 0x2002); - dev->trans_start = jiffies; - if (tulip_debug > 1) - printk(KERN_INFO "%s: Changing PNIC configuration to %s " - "%s-duplex, CSR6 %8.8x.\n", - dev->name, medianame[dev->if_port], - tp->full_duplex ? "full" : "half", new_csr6); - } - } - } - tp->timer.expires = RUN_AT(next_tick); - add_timer(&tp->timer); -} - -static void comet_timer(unsigned long data) -{ - struct net_device *dev = (struct net_device *)data; - struct tulip_private *tp = (struct tulip_private *)dev->priv; - long ioaddr = dev->base_addr; - int next_tick = 60*HZ; - - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Comet link status %4.4x partner capability " - "%4.4x.\n", - dev->name, inl(ioaddr + 0xB8), inl(ioaddr + 0xC8)); - tp->timer.expires = RUN_AT(next_tick); - add_timer(&tp->timer); -} - -static void tulip_tx_timeout(struct net_device *dev) -{ - struct tulip_private *tp = (struct tulip_private *)dev->priv; - long ioaddr = dev->base_addr; - - if (media_cap[dev->if_port] & MediaIsMII) { - /* Do nothing -- the media monitor should handle this. */ - if (tulip_debug > 1) - printk(KERN_WARNING "%s: Transmit timeout using MII device.\n", - dev->name); - } else if (tp->chip_id == DC21040) { - if ( !tp->medialock && inl(ioaddr + CSR12) & 0x0002) { - dev->if_port = (dev->if_port == 2 ? 0 : 2); - printk(KERN_INFO "%s: transmit timed out, switching to " - "%s.\n", - dev->name, medianame[dev->if_port]); - select_media(dev, 0); - } - dev->trans_start = jiffies; - return; - } else if (tp->chip_id == DC21041) { - int csr12 = inl(ioaddr + CSR12); - - printk(KERN_WARNING "%s: 21041 transmit timed out, status %8.8x, " - "CSR12 %8.8x, CSR13 %8.8x, CSR14 %8.8x, resetting...\n", - dev->name, inl(ioaddr + CSR5), csr12, - inl(ioaddr + CSR13), inl(ioaddr + CSR14)); - tp->mediasense = 1; - if ( ! tp->medialock) { - if (dev->if_port == 1 || dev->if_port == 2) - if (csr12 & 0x0004) { - dev->if_port = 2 - dev->if_port; - } else - dev->if_port = 0; - else - dev->if_port = 1; - select_media(dev, 0); - } - } else if (tp->chip_id == DC21140 || tp->chip_id == DC21142 - || tp->chip_id == MX98713 || tp->chip_id == COMPEX9881) { - printk(KERN_WARNING "%s: 21140 transmit timed out, status %8.8x, " - "SIA %8.8x %8.8x %8.8x %8.8x, resetting...\n", - dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR12), - inl(ioaddr + CSR13), inl(ioaddr + CSR14), inl(ioaddr + CSR15)); - if ( ! tp->medialock && tp->mtable) { - do - --tp->cur_index; - while (tp->cur_index >= 0 - && (media_cap[tp->mtable->mleaf[tp->cur_index].media] - & MediaIsFD)); - if (--tp->cur_index < 0) { - /* We start again, but should instead look for default. */ - tp->cur_index = tp->mtable->leafcount - 1; - } - select_media(dev, 0); - printk(KERN_WARNING "%s: transmit timed out, switching to %s " - "media.\n", dev->name, medianame[dev->if_port]); - } - } else { - printk(KERN_WARNING "%s: Transmit timed out, status %8.8x, CSR12 " - "%8.8x, resetting...\n", - dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR12)); - dev->if_port = 0; - } - -#if defined(way_too_many_messages) - if (tulip_debug > 3) { - int i; - for (i = 0; i < RX_RING_SIZE; i++) { - u8 *buf = (u8 *)(tp->rx_ring[i].buffer1); - int j; - printk(KERN_DEBUG "%2d: %8.8x %8.8x %8.8x %8.8x " - "%2.2x %2.2x %2.2x.\n", - i, (unsigned int)tp->rx_ring[i].status, - (unsigned int)tp->rx_ring[i].length, - (unsigned int)tp->rx_ring[i].buffer1, - (unsigned int)tp->rx_ring[i].buffer2, - buf[0], buf[1], buf[2]); - for (j = 0; buf[j] != 0xee && j < 1600; j++) - if (j < 100) printk(" %2.2x", buf[j]); - printk(" j=%d.\n", j); - } - printk(KERN_DEBUG " Rx ring %8.8x: ", (int)tp->rx_ring); - for (i = 0; i < RX_RING_SIZE; i++) - printk(" %8.8x", (unsigned int)tp->rx_ring[i].status); - printk("\n" KERN_DEBUG " Tx ring %8.8x: ", (int)tp->tx_ring); - for (i = 0; i < TX_RING_SIZE; i++) - printk(" %8.8x", (unsigned int)tp->tx_ring[i].status); - printk("\n"); - } -#endif - - /* Stop and restart the chip's Tx processes . */ - outl_CSR6(tp, tp->csr6 | 0x0002); - outl_CSR6(tp, tp->csr6 | 0x2002); - /* Trigger an immediate transmit demand. */ - outl(0, ioaddr + CSR1); - - dev->trans_start = jiffies; - tp->stats.tx_errors++; - return; -} - - -/* Initialize the Rx and Tx rings, along with various 'dev' bits. */ -static void tulip_init_ring(struct net_device *dev) -{ - struct tulip_private *tp = (struct tulip_private *)dev->priv; - int i; - - tp->tx_full = 0; - tp->cur_rx = tp->cur_tx = 0; - tp->dirty_rx = tp->dirty_tx = 0; - tp->susp_rx = 0; - tp->ttimer = 0; - tp->nir = 0; - - for (i = 0; i < RX_RING_SIZE; i++) { - tp->rx_ring[i].status = 0x00000000; - tp->rx_ring[i].length = cpu_to_le32(PKT_BUF_SZ); - tp->rx_ring[i].buffer2 = virt_to_le32desc(&tp->rx_ring[i+1]); - tp->rx_skbuff[i] = NULL; - } - /* Mark the last entry as wrapping the ring. */ - tp->rx_ring[i-1].length = cpu_to_le32(PKT_BUF_SZ | DESC_RING_WRAP); - tp->rx_ring[i-1].buffer2 = virt_to_le32desc(&tp->rx_ring[0]); - - for (i = 0; i < RX_RING_SIZE; i++) { - /* Note the receive buffer must be longword aligned. - dev_alloc_skb() provides 16 byte alignment. But do *not* - use skb_reserve() to align the IP header! */ - struct sk_buff *skb = dev_alloc_skb(PKT_BUF_SZ); - tp->rx_skbuff[i] = skb; - if (skb == NULL) - break; - skb->dev = dev; /* Mark as being used by this device. */ - tp->rx_ring[i].status = cpu_to_le32(DescOwned); /* Owned by Tulip chip */ - tp->rx_ring[i].buffer1 = virt_to_le32desc(skb->tail); - } - tp->dirty_rx = (unsigned int)(i - RX_RING_SIZE); - - /* The Tx buffer descriptor is filled in as needed, but we - do need to clear the ownership bit. */ - for (i = 0; i < TX_RING_SIZE; i++) { - tp->tx_skbuff[i] = 0; - tp->tx_ring[i].status = 0x00000000; - tp->tx_ring[i].buffer2 = virt_to_le32desc(&tp->tx_ring[i+1]); - } - tp->tx_ring[i-1].buffer2 = virt_to_le32desc(&tp->tx_ring[0]); -} - -static int -tulip_start_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct tulip_private *tp = (struct tulip_private *)dev->priv; - int entry; - u32 flag; - unsigned long cpuflags; - - /* Caution: the write order is important here, set the field - with the ownership bits last. */ - - spin_lock_irqsave(&tp->tx_lock, cpuflags); - - /* Calculate the next Tx descriptor entry. */ - entry = tp->cur_tx % TX_RING_SIZE; - - tp->tx_skbuff[entry] = skb; - tp->tx_ring[entry].buffer1 = virt_to_le32desc(skb->data); - - if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE/2) {/* Typical path */ - flag = 0x60000000; /* No interrupt */ - } else if (tp->cur_tx - tp->dirty_tx == TX_RING_SIZE/2) { - flag = 0xe0000000; /* Tx-done intr. */ - } else if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE - 2) { - flag = 0x60000000; /* No Tx-done intr. */ - } else { /* Leave room for set_rx_mode() to fill entries. */ - tp->tx_full = 1; - flag = 0xe0000000; /* Tx-done intr. */ - netif_stop_queue(dev); - } - if (entry == TX_RING_SIZE-1) - flag = 0xe0000000 | DESC_RING_WRAP; - - tp->tx_ring[entry].length = cpu_to_le32(skb->len | flag); - tp->tx_ring[entry].status = cpu_to_le32(DescOwned); - tp->cur_tx++; - spin_unlock_irqrestore(&tp->tx_lock, cpuflags); - - /* Trigger an immediate transmit demand. */ - outl(0, dev->base_addr + CSR1); - - dev->trans_start = jiffies; - - return 0; -} - -/* The interrupt handler does all of the Rx thread work and cleans up - after the Tx thread. */ -static void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs) -{ - struct net_device *dev = (struct net_device *)dev_instance; - struct tulip_private *tp = (struct tulip_private *)dev->priv; - long ioaddr = dev->base_addr; - int csr5; - int entry; - int missed; - int rx = 0; - int tx = 0; - int oi = 0; - int maxrx = RX_RING_SIZE; - int maxtx = TX_RING_SIZE; - int maxoi = TX_RING_SIZE; - - tp->nir++; - - do { - csr5 = inl(ioaddr + CSR5); - /* Acknowledge all of the current interrupt sources ASAP. */ - outl(csr5 & 0x0001ffff, ioaddr + CSR5); - - if (tulip_debug > 4) - printk(KERN_DEBUG "%s: interrupt csr5=%#8.8x new csr5=%#8.8x.\n", - dev->name, csr5, inl(dev->base_addr + CSR5)); - - if ((csr5 & (NormalIntr|AbnormalIntr)) == 0) - break; - - if (csr5 & (RxIntr | RxNoBuf)) { - rx += tulip_rx(dev); - tulip_refill_rx(dev); - } - - if (csr5 & (TxNoBuf | TxDied | TxIntr | TimerInt)) { - unsigned int dirty_tx; - - spin_lock(&tp->tx_lock); - - for (dirty_tx = tp->dirty_tx; tp->cur_tx - dirty_tx > 0; - dirty_tx++) { - int entry = dirty_tx % TX_RING_SIZE; - int status = le32_to_cpu(tp->tx_ring[entry].status); - - if (status < 0) - break; /* It still has not been Txed */ - /* Check for Rx filter setup frames. */ - if (tp->tx_skbuff[entry] == NULL) - continue; - - if (status & 0x8000) { - /* There was an major error, log it. */ -#ifndef final_version - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n", - dev->name, status); -#endif - tp->stats.tx_errors++; - if (status & 0x4104) tp->stats.tx_aborted_errors++; - if (status & 0x0C00) tp->stats.tx_carrier_errors++; - if (status & 0x0200) tp->stats.tx_window_errors++; - if (status & 0x0002) tp->stats.tx_fifo_errors++; - if ((status & 0x0080) && tp->full_duplex == 0) - tp->stats.tx_heartbeat_errors++; -#ifdef ETHER_STATS - if (status & 0x0100) tp->stats.collisions16++; -#endif - } else { -#ifdef ETHER_STATS - if (status & 0x0001) tp->stats.tx_deferred++; -#endif - tp->stats.tx_bytes += tp->tx_skbuff[entry]->len; - tp->stats.collisions += (status >> 3) & 15; - tp->stats.tx_packets++; - } - - /* Free the original skb. */ - dev_kfree_skb_irq(tp->tx_skbuff[entry]); - tp->tx_skbuff[entry] = 0; - tx++; - } - -#ifndef final_version - if (tp->cur_tx - dirty_tx > TX_RING_SIZE) { - printk(KERN_ERR "%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n", - dev->name, dirty_tx, tp->cur_tx, tp->tx_full); - dirty_tx += TX_RING_SIZE; - } -#endif - - if (tp->tx_full && tp->cur_tx - dirty_tx < TX_RING_SIZE - 2) { - /* The ring is no longer full, clear tbusy. */ - tp->tx_full = 0; - netif_wake_queue(dev); - } - - tp->dirty_tx = dirty_tx; - if (csr5 & TxDied) { - if (tulip_debug > 2) - printk(KERN_WARNING "%s: The transmitter stopped." - " CSR5 is %x, CSR6 %x, new CSR6 %x.\n", - dev->name, csr5, inl(ioaddr + CSR6), tp->csr6); - outl_CSR6(tp, tp->csr6 | 0x0002); - outl_CSR6(tp, tp->csr6 | 0x2002); - } - spin_unlock(&tp->tx_lock); - } - - /* Log errors. */ - if (csr5 & AbnormalIntr) { /* Abnormal error summary bit. */ - if (csr5 == 0xffffffff) - break; - if (csr5 & TxJabber) tp->stats.tx_errors++; - if (csr5 & TxFIFOUnderflow) { - if ((tp->csr6 & 0xC000) != 0xC000) - tp->csr6 += 0x4000; /* Bump up the Tx threshold */ - else - tp->csr6 |= 0x00200000; /* Store-n-forward. */ - /* Restart the transmit process. */ - outl_CSR6(tp, tp->csr6 | 0x0002); - outl_CSR6(tp, tp->csr6 | 0x2002); - outl(0, ioaddr + CSR1); - } - if (csr5 & RxDied) { /* Missed a Rx frame. */ - tp->stats.rx_errors++; - tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff; - outl_CSR6(tp, tp->csr6 | 0x2002); - } - if (csr5 & (TPLnkPass | TPLnkFail | 0x08000000)) { - if (tp->link_change) - (tp->link_change)(dev, csr5); - } - if (csr5 & SytemError) { - printk(KERN_ERR "%s: (%lu) System Error occured\n", dev->name, tp->nir); - } - /* Clear all error sources, included undocumented ones! */ - outl(0x0800f7ba, ioaddr + CSR5); - oi++; - } - if (csr5 & TimerInt) { -#if 0 - if (tulip_debug > 2) - printk(KERN_ERR "%s: Re-enabling interrupts, %8.8x.\n", - dev->name, csr5); - outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7); -#endif - tp->ttimer = 0; - oi++; - } - if (tx > maxtx || rx > maxrx || oi > maxoi) { - if (tulip_debug > 1) - printk(KERN_WARNING "%s: Too much work during an interrupt, " - "csr5=0x%8.8x. (%lu) (%d,%d,%d)\n", dev->name, csr5, tp->nir, tx, rx, oi); - /* Acknowledge all interrupt sources. */ -#if 0 - /* Clear all interrupting sources, set timer to re-enable. */ - outl(((~csr5) & 0x0001ebef) | NormalIntr | AbnormalIntr | TimerInt, - ioaddr + CSR7); - outl(12, ioaddr + CSR11); - tp->ttimer = 1; -#endif - break; - } - } while (1); - - tulip_refill_rx(dev); - - /* check if we card is in suspend mode */ - entry = tp->dirty_rx % RX_RING_SIZE; - if (tp->rx_skbuff[entry] == NULL) { - if (tulip_debug > 1) - printk(KERN_WARNING "%s: in rx suspend mode: (%lu) (tp->cur_rx = %u, ttimer = %d, rx = %d) go/stay in suspend mode\n", dev->name, tp->nir, tp->cur_rx, tp->ttimer, rx); - if (tp->ttimer == 0 || (inl(ioaddr + CSR11) & 0xffff) == 0) { - if (tulip_debug > 1) - printk(KERN_WARNING "%s: in rx suspend mode: (%lu) set timer\n", dev->name, tp->nir); - outl(tulip_tbl[tp->chip_id].valid_intrs | TimerInt, - ioaddr + CSR7); - outl(TimerInt, ioaddr + CSR5); - outl(12, ioaddr + CSR11); - tp->ttimer = 1; - } - } - - if ((missed = inl(ioaddr + CSR8) & 0x1ffff)) { - tp->stats.rx_dropped += missed & 0x10000 ? 0x10000 : missed; - } - - if (tulip_debug > 4) - printk(KERN_DEBUG "%s: exiting interrupt, csr5=%#4.4x.\n", - dev->name, inl(ioaddr + CSR5)); - -} - -static int tulip_refill_rx(struct net_device *dev) -{ - struct tulip_private *tp = (struct tulip_private *)dev->priv; - int entry; - int refilled = 0; - - /* Refill the Rx ring buffers. */ - for (; tp->cur_rx - tp->dirty_rx > 0; tp->dirty_rx++) { - entry = tp->dirty_rx % RX_RING_SIZE; - if (tp->rx_skbuff[entry] == NULL) { - struct sk_buff *skb; - skb = tp->rx_skbuff[entry] = dev_alloc_skb(PKT_BUF_SZ); - if (skb == NULL) - break; - skb->dev = dev; /* Mark as being used by this device. */ - tp->rx_ring[entry].buffer1 = virt_to_le32desc(skb->tail); - refilled++; - } - tp->rx_ring[entry].status = cpu_to_le32(DescOwned); - } - return refilled; -} - -static int tulip_rx(struct net_device *dev) -{ - struct tulip_private *tp = (struct tulip_private *)dev->priv; - int entry = tp->cur_rx % RX_RING_SIZE; - int rx_work_limit = tp->dirty_rx + RX_RING_SIZE - tp->cur_rx; - int received = 0; - - if (tulip_debug > 4) - printk(KERN_DEBUG " In tulip_rx(), entry %d %8.8x.\n", entry, - tp->rx_ring[entry].status); - /* If we own the next entry, it is a new packet. Send it up. */ - while ( ! (tp->rx_ring[entry].status & cpu_to_le32(DescOwned))) { - s32 status = le32_to_cpu(tp->rx_ring[entry].status); - - if (tulip_debug > 5) - printk(KERN_DEBUG "%s: In tulip_rx(), entry %d %8.8x.\n", - dev->name, entry, status); - if (--rx_work_limit < 0) - break; - if ((status & 0x38008300) != 0x0300) { - if ((status & 0x38000300) != 0x0300) { - /* Ingore earlier buffers. */ - if ((status & 0xffff) != 0x7fff) { - if (tulip_debug > 1) - printk(KERN_WARNING "%s: Oversized Ethernet frame " - "spanned multiple buffers, status %8.8x!\n", - dev->name, status); - tp->stats.rx_length_errors++; - } - } else if (status & RxDescFatalErr) { - /* There was a fatal error. */ - if (tulip_debug > 2) - printk(KERN_DEBUG "%s: Receive error, Rx status %8.8x.\n", - dev->name, status); - tp->stats.rx_errors++; /* end of a packet.*/ - if (status & 0x0890) tp->stats.rx_length_errors++; - if (status & 0x0004) tp->stats.rx_frame_errors++; - if (status & 0x0002) tp->stats.rx_crc_errors++; - if (status & 0x0001) tp->stats.rx_fifo_errors++; - } - } else { - /* Omit the four octet CRC from the length. */ - short pkt_len = ((status >> 16) & 0x7ff) - 4; - struct sk_buff *skb; - -#ifndef final_version - if (pkt_len > 1518) { - printk(KERN_WARNING "%s: Bogus packet size of %d (%#x).\n", - dev->name, pkt_len, pkt_len); - pkt_len = 1518; - tp->stats.rx_length_errors++; - } -#endif - /* Check if the packet is long enough to accept without copying - to a minimally-sized skbuff. */ - if (pkt_len < rx_copybreak - && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { - skb->dev = dev; - skb_reserve(skb, 2); /* 16 byte align the IP header */ -#if ! defined(__alpha__) - eth_copy_and_sum(skb, tp->rx_skbuff[entry]->tail, pkt_len, 0); - skb_put(skb, pkt_len); -#else - memcpy(skb_put(skb, pkt_len), tp->rx_skbuff[entry]->tail, - pkt_len); -#endif - } else { /* Pass up the skb already on the Rx ring. */ - char *temp = skb_put(skb = tp->rx_skbuff[entry], pkt_len); - tp->rx_skbuff[entry] = NULL; -#ifndef final_version - if (le32desc_to_virt(tp->rx_ring[entry].buffer1) != temp) - printk(KERN_ERR "%s: Internal fault: The skbuff addresses " - "do not match in tulip_rx: %p vs. %p / %p.\n", - dev->name, - le32desc_to_virt(tp->rx_ring[entry].buffer1), - skb->head, temp); -#endif - } - skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); - dev->last_rx = jiffies; - tp->stats.rx_packets++; - tp->stats.rx_bytes += pkt_len; - } - received++; - entry = (++tp->cur_rx) % RX_RING_SIZE; - } - - return received; -} - - -static void tulip_down (struct net_device *dev) -{ - long ioaddr = dev->base_addr; - struct tulip_private *tp = (struct tulip_private *) dev->priv; - - netif_device_detach (dev); - - del_timer (&tp->timer); - - /* Disable interrupts by clearing the interrupt mask. */ - outl (0x00000000, ioaddr + CSR7); - - /* Stop the Tx and Rx processes. */ - outl_CSR6 (tp, inl (ioaddr + CSR6) & ~0x2002); - - /* 21040 -- Leave the card in 10baseT state. */ - if (tp->chip_id == DC21040) - outl (0x00000004, ioaddr + CSR13); - - if (inl (ioaddr + CSR6) != 0xffffffff) - tp->stats.rx_missed_errors += inl (ioaddr + CSR8) & 0xffff; - - dev->if_port = tp->saved_if_port; - - /* Leave the driver in snooze, not sleep, mode. */ - if (tp->flags & HAS_ACPI) - pci_write_config_dword (tp->pdev, 0x40, 0x40000000); -} - - -static int tulip_close (struct net_device *dev) -{ - long ioaddr = dev->base_addr; - struct tulip_private *tp = (struct tulip_private *) dev->priv; - int i; - - tulip_down (dev); - - if (tulip_debug > 1) - printk (KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n", - dev->name, inl (ioaddr + CSR5)); - - free_irq (dev->irq, dev); - - /* Free all the skbuffs in the Rx queue. */ - for (i = 0; i < RX_RING_SIZE; i++) { - struct sk_buff *skb = tp->rx_skbuff[i]; - tp->rx_skbuff[i] = 0; - tp->rx_ring[i].status = 0; /* Not owned by Tulip chip. */ - tp->rx_ring[i].length = 0; - tp->rx_ring[i].buffer1 = 0xBADF00D0; /* An invalid address. */ - if (skb) { - dev_kfree_skb (skb); - } - } - for (i = 0; i < TX_RING_SIZE; i++) { - if (tp->tx_skbuff[i]) - dev_kfree_skb (tp->tx_skbuff[i]); - tp->tx_skbuff[i] = 0; - } - - MOD_DEC_USE_COUNT; - - return 0; -} - -static struct enet_statistics *tulip_get_stats(struct net_device *dev) -{ - struct tulip_private *tp = (struct tulip_private *)dev->priv; - long ioaddr = dev->base_addr; - - if (netif_running(dev)) - tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff; - - return &tp->stats; -} - - -/* Provide ioctl() calls to examine the MII xcvr state. */ -static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -{ - struct tulip_private *tp = (struct tulip_private *)dev->priv; - long ioaddr = dev->base_addr; - u16 *data = (u16 *)&rq->ifr_data; - int phy = tp->phys[0] & 0x1f; - long flags; - - switch(cmd) { - case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ - if (tp->mii_cnt) - data[0] = phy; - else if (tp->flags & HAS_NWAY143) - data[0] = 32; - else if (tp->chip_id == COMET) - data[0] = 1; - else - return -ENODEV; - case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ - if (data[0] == 32 && (tp->flags & HAS_NWAY143)) { - int csr12 = inl(ioaddr + CSR12); - int csr14 = inl(ioaddr + CSR14); - switch (data[1]) { - case 0: { - data[3] = (csr14<<5) & 0x1000; - break; } - case 1: - data[3] = 0x7848 + ((csr12&0x7000) == 0x5000 ? 0x20 : 0) - + (csr12&0x06 ? 0x04 : 0); - break; - case 4: { - data[3] = ((csr14>>9)&0x07C0) + - ((inl(ioaddr + CSR6)>>3)&0x0040) + ((csr14>>1)&0x20) + 1; - break; - } - case 5: data[3] = csr12 >> 16; break; - default: data[3] = 0; break; - } - } else { - save_flags(flags); - cli(); - data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f); - restore_flags(flags); - } - return 0; - case SIOCDEVPRIVATE+2: /* Write the specified MII register */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - if (data[0] == 32 && (tp->flags & HAS_NWAY143)) { - if (data[1] == 5) - tp->to_advertise = data[2]; - } else { - save_flags(flags); - cli(); - mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]); - restore_flags(flags); - } - return 0; - default: - return -EOPNOTSUPP; - } - - return -EOPNOTSUPP; -} - - -/* Set or clear the multicast filter for this adaptor. - Note that we only use exclusion around actually queueing the - new frame, not around filling tp->setup_frame. This is non-deterministic - when re-entered but still correct. */ - -/* The little-endian AUTODIN32 ethernet CRC calculation. - N.B. Do not use for bulk data, use a table-based routine instead. - This is common code and should be moved to net/core/crc.c */ -static unsigned const ethernet_polynomial_le = 0xedb88320U; -static inline u32 ether_crc_le(int length, unsigned char *data) -{ - u32 crc = 0xffffffff; /* Initial value. */ - while(--length >= 0) { - unsigned char current_octet = *data++; - int bit; - for (bit = 8; --bit >= 0; current_octet >>= 1) { - if ((crc ^ current_octet) & 1) { - crc >>= 1; - crc ^= ethernet_polynomial_le; - } else - crc >>= 1; - } - } - return crc; -} -static unsigned const ethernet_polynomial = 0x04c11db7U; -static inline u32 ether_crc(int length, unsigned char *data) -{ - int crc = -1; - - while(--length >= 0) { - unsigned char current_octet = *data++; - int bit; - for (bit = 0; bit < 8; bit++, current_octet >>= 1) - crc = (crc << 1) ^ - ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0); - } - return crc; -} - -static void set_rx_mode(struct net_device *dev) -{ - struct tulip_private *tp = (struct tulip_private *)dev->priv; - long ioaddr = dev->base_addr; - int csr6 = inl(ioaddr + CSR6) & ~0x00D5; - unsigned long cpuflags; - - tp->csr6 &= ~0x00D5; - if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ - tp->csr6 |= 0x00C0; - csr6 |= 0x00C0; - /* Unconditionally log net taps. */ - printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name); - } else if ((dev->mc_count > 1000) || (dev->flags & IFF_ALLMULTI)) { - /* Too many to filter well -- accept all multicasts. */ - tp->csr6 |= 0x0080; - csr6 |= 0x0080; - } else if (tp->flags & MC_HASH_ONLY) { - /* Some work-alikes have only a 64-entry hash filter table. */ - /* Should verify correctness on big-endian/__powerpc__ */ - struct dev_mc_list *mclist; - int i; - u32 mc_filter[2]; /* Multicast hash filter */ - if (dev->mc_count > 64) { /* Arbitrary non-effective limit. */ - tp->csr6 |= 0x0080; - csr6 |= 0x0080; - } else { - mc_filter[1] = mc_filter[0] = 0; - for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; - i++, mclist = mclist->next) - set_bit(ether_crc(ETH_ALEN, mclist->dmi_addr)>>26, mc_filter); - if (tp->chip_id == AX88140) { - outl(2, ioaddr + CSR13); - outl(mc_filter[0], ioaddr + CSR14); - outl(3, ioaddr + CSR13); - outl(mc_filter[1], ioaddr + CSR14); - } else if (tp->chip_id == COMET) { /* Has a simple hash filter. */ - outl(mc_filter[0], ioaddr + 0xAC); - outl(mc_filter[1], ioaddr + 0xB0); - } - } - } else { - u16 *eaddrs, *setup_frm = tp->setup_frame; - struct dev_mc_list *mclist; - u32 tx_flags = 0x08000000 | 192; - int i; - - /* Note that only the low-address shortword of setup_frame is valid! - The values are doubled for big-endian architectures. */ - if (dev->mc_count > 14) { /* Must use a multicast hash table. */ - u16 hash_table[32]; - tx_flags = 0x08400000 | 192; /* Use hash filter. */ - memset(hash_table, 0, sizeof(hash_table)); - set_bit(255, hash_table); /* Broadcast entry */ - /* This should work on big-endian machines as well. */ - for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; - i++, mclist = mclist->next) - set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x1ff, - hash_table); - for (i = 0; i < 32; i++) - *setup_frm++ = *setup_frm++ = hash_table[i]; - setup_frm = &tp->setup_frame[13*6]; - } else { - /* We have <= 14 addresses so we can use the wonderful - 16 address perfect filtering of the Tulip. */ - for (i = 0, mclist = dev->mc_list; i < dev->mc_count; - i++, mclist = mclist->next) { - eaddrs = (u16 *)mclist->dmi_addr; - *setup_frm++ = *setup_frm++ = *eaddrs++; - *setup_frm++ = *setup_frm++ = *eaddrs++; - *setup_frm++ = *setup_frm++ = *eaddrs++; - } - /* Fill the unused entries with the broadcast address. */ - memset(setup_frm, 0xff, (15-i)*12); - setup_frm = &tp->setup_frame[15*6]; - } - /* Fill the final entry with our physical address. */ - eaddrs = (u16 *)dev->dev_addr; - *setup_frm++ = *setup_frm++ = eaddrs[0]; - *setup_frm++ = *setup_frm++ = eaddrs[1]; - *setup_frm++ = *setup_frm++ = eaddrs[2]; - /* Now add this frame to the Tx list. */ - spin_lock_irqsave(&tp->tx_lock, cpuflags); - if (tp->cur_tx - tp->dirty_tx > TX_RING_SIZE - 2) { - /* Same setup recently queued, we need not add it. */ - } else { - unsigned long flags; - unsigned int entry; - - save_flags(flags); cli(); - entry = tp->cur_tx++ % TX_RING_SIZE; - - if (entry != 0) { - /* Avoid a chip errata by prefixing a dummy entry. */ - tp->tx_skbuff[entry] = 0; - tp->tx_ring[entry].length = - (entry == TX_RING_SIZE-1) ? cpu_to_le32(DESC_RING_WRAP) : 0; - tp->tx_ring[entry].buffer1 = 0; - tp->tx_ring[entry].status = cpu_to_le32(DescOwned); - entry = tp->cur_tx++ % TX_RING_SIZE; - } - - tp->tx_skbuff[entry] = 0; - /* Put the setup frame on the Tx list. */ - if (entry == TX_RING_SIZE-1) - tx_flags |= DESC_RING_WRAP; /* Wrap ring. */ - tp->tx_ring[entry].length = cpu_to_le32(tx_flags); - tp->tx_ring[entry].buffer1 = virt_to_le32desc(tp->setup_frame); - tp->tx_ring[entry].status = cpu_to_le32(DescOwned); - if (tp->cur_tx - tp->dirty_tx >= TX_RING_SIZE - 2) { - netif_stop_queue(dev); - tp->tx_full = 1; - } - spin_unlock_irqrestore(&tp->tx_lock, cpuflags); - /* Trigger an immediate transmit demand. */ - outl(0, ioaddr + CSR1); - } - } - outl_CSR6(tp, csr6 | 0x0000); -} - - -static int __devinit tulip_init_one (struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - static int did_version = 0; /* Already printed version info. */ - struct tulip_private *tp; - /* See note below on the multiport cards. */ - static unsigned char last_phys_addr[6] = {0x00, 'L', 'i', 'n', 'u', 'x'}; - static int last_irq = 0; - static int multiport_cnt = 0; /* For four-port boards w/one EEPROM */ - u8 chip_rev; - int i, irq; - unsigned short sum; - u8 ee_data[EEPROM_SIZE]; - struct net_device *dev; - long ioaddr; - static int board_idx = -1; - int chip_idx = ent->driver_data; - - board_idx++; - - if (tulip_debug > 0 && did_version++ == 0) - printk (KERN_INFO "%s", version); - - if( pdev->subsystem_vendor == 0x1376 ){ - printk (KERN_ERR PFX "skipping LMC card.\n"); - return -ENODEV; - } - - ioaddr = pci_resource_start (pdev, 0); - irq = pdev->irq; - - /* Make certain the data structures are quadword aligned. */ - dev = init_etherdev (NULL, sizeof (*tp)); - if (!dev) { - printk (KERN_ERR PFX "unable to allocate ether device, aborting\n"); - return -ENOMEM; - } - - /* We do a request_region() only to register /proc/ioports info. */ - /* Note that proper size is tulip_tbl[chip_idx].chip_name, but... */ - if (!request_region (ioaddr, tulip_tbl[chip_idx].io_size, dev->name)) { - printk (KERN_ERR PFX "unable to allocate ether device, aborting\n"); - goto err_out_free_netdev; - } - - if (pci_enable_device(pdev)) { - printk (KERN_ERR PFX "cannot enable PCI device (id %04x:%04x, bus %d, devfn %d), aborting\n", - pdev->vendor, pdev->device, - pdev->bus->number, pdev->devfn); - goto err_out_free_netdev; - } - - pci_set_master(pdev); - - tp = dev->priv; - memset(tp, 0, sizeof(*tp)); - - pci_read_config_byte (pdev, PCI_REVISION_ID, &chip_rev); - - printk(KERN_INFO "%s: %s rev %d at %#3lx,", - dev->name, tulip_tbl[chip_idx].chip_name, chip_rev, ioaddr); - - /* Stop the chip's Tx and Rx processes. */ - outl_CSR6(tp, inl(ioaddr + CSR6) & ~0x2002); - /* Clear the missed-packet counter. */ - (volatile int)inl(ioaddr + CSR8); - - if (chip_idx == DC21041 && inl(ioaddr + CSR9) & 0x8000) { - printk(" 21040 compatible mode,"); - chip_idx = DC21040; - } - - /* The station address ROM is read byte serially. The register must - be polled, waiting for the value to be read bit serially from the - EEPROM. - */ - sum = 0; - if (chip_idx == DC21040) { - outl(0, ioaddr + CSR9); /* Reset the pointer with a dummy write. */ - for (i = 0; i < 6; i++) { - int value, boguscnt = 100000; - do - value = inl(ioaddr + CSR9); - while (value < 0 && --boguscnt > 0); - dev->dev_addr[i] = value; - sum += value & 0xff; - } - } else if (chip_idx == LC82C168) { - for (i = 0; i < 3; i++) { - int value, boguscnt = 100000; - outl(0x600 | i, ioaddr + 0x98); - do - value = inl(ioaddr + CSR9); - while (value < 0 && --boguscnt > 0); - put_unaligned(le16_to_cpu(value), ((u16*)dev->dev_addr) + i); - sum += value & 0xffff; - } - } else if (chip_idx == COMET) { - /* No need to read the EEPROM. */ - put_unaligned(inl(ioaddr + 0xA4), (u32 *)dev->dev_addr); - put_unaligned(inl(ioaddr + 0xA8), (u16 *)(dev->dev_addr + 4)); - for (i = 0; i < 6; i ++) - sum += dev->dev_addr[i]; - } else { - /* A serial EEPROM interface, we read now and sort it out later. */ - int sa_offset = 0; - int ee_addr_size = read_eeprom(ioaddr, 0xff, 8) & 0x40000 ? 8 : 6; - - for (i = 0; i < sizeof(ee_data)/2; i++) - ((u16 *)ee_data)[i] = - le16_to_cpu(read_eeprom(ioaddr, i, ee_addr_size)); - - /* DEC now has a specification (see Notes) but early board makers - just put the address in the first EEPROM locations. */ - /* This does memcmp(eedata, eedata+16, 8) */ - for (i = 0; i < 8; i ++) - if (ee_data[i] != ee_data[16+i]) - sa_offset = 20; - if (ee_data[0] == 0xff && ee_data[1] == 0xff && ee_data[2] == 0) { - sa_offset = 2; /* Grrr, damn Matrox boards. */ - multiport_cnt = 4; - } - for (i = 0; i < 6; i ++) { - dev->dev_addr[i] = ee_data[i + sa_offset]; - sum += ee_data[i + sa_offset]; - } - } - /* Lite-On boards have the address byte-swapped. */ - if ((dev->dev_addr[0] == 0xA0 || dev->dev_addr[0] == 0xC0) - && dev->dev_addr[1] == 0x00) - for (i = 0; i < 6; i+=2) { - char tmp = dev->dev_addr[i]; - dev->dev_addr[i] = dev->dev_addr[i+1]; - dev->dev_addr[i+1] = tmp; - } - /* On the Zynx 315 Etherarray and other multiport boards only the - first Tulip has an EEPROM. - The addresses of the subsequent ports are derived from the first. - Many PCI BIOSes also incorrectly report the IRQ line, so we correct - that here as well. */ - if (sum == 0 || sum == 6*0xff) { - printk(" EEPROM not present,"); - for (i = 0; i < 5; i++) - dev->dev_addr[i] = last_phys_addr[i]; - dev->dev_addr[i] = last_phys_addr[i] + 1; -#if defined(__i386__) /* Patch up x86 BIOS bug. */ - if (last_irq) - irq = last_irq; -#endif - } - - for (i = 0; i < 6; i++) - printk("%c%2.2X", i ? ':' : ' ', last_phys_addr[i] = dev->dev_addr[i]); - printk(", IRQ %d.\n", irq); - last_irq = irq; - - pdev->driver_data = dev; - dev->base_addr = ioaddr; - dev->irq = irq; - - tp->chip_id = chip_idx; - tp->revision = chip_rev; - tp->flags = tulip_tbl[chip_idx].flags; - tp->csr0 = csr0; - tp->pdev = pdev; - tp->base_addr = dev->base_addr; - - /* BugFixes: The 21143-TD hangs with PCI Write-and-Invalidate cycles. - And the ASIX must have a burst limit or horrible things happen. */ - if (chip_idx == DC21143 && chip_rev == 65) - tp->csr0 &= ~0x01000000; - else if (chip_idx == AX88140) - tp->csr0 |= 0x2000; - -#ifdef TULIP_FULL_DUPLEX - tp->full_duplex = 1; - tp->full_duplex_lock = 1; -#endif -#ifdef TULIP_DEFAULT_MEDIA - tp->default_port = TULIP_DEFAULT_MEDIA; -#endif -#ifdef TULIP_NO_MEDIA_SWITCH - tp->medialock = 1; -#endif - tp->tx_lock = SPIN_LOCK_UNLOCKED; - - /* The lower four bits are the media type. */ - if (board_idx >= 0 && board_idx < MAX_UNITS) { - tp->default_port = options[board_idx] & 15; - if ((options[board_idx] & 0x90) || full_duplex[board_idx] > 0) - tp->full_duplex = 1; - if (mtu[board_idx] > 0) - dev->mtu = mtu[board_idx]; - } - if (dev->mem_start) - tp->default_port = dev->mem_start; - if (tp->default_port) { - tp->medialock = 1; - if (media_cap[tp->default_port] & MediaAlwaysFD) - tp->full_duplex = 1; - } - if (tp->full_duplex) - tp->full_duplex_lock = 1; - - if (media_cap[tp->default_port] & MediaIsMII) { - u16 media2advert[] = { 0x20, 0x40, 0x03e0, 0x60, 0x80, 0x100, 0x200 }; - tp->to_advertise = media2advert[tp->default_port - 9]; - } else if (tp->flags & HAS_8023X) - tp->to_advertise = 0x05e1; - else - tp->to_advertise = 0x01e1; - - /* This is logically part of probe1(), but too complex to write inline. */ - if (tp->flags & HAS_MEDIA_TABLE) { - memcpy(tp->eeprom, ee_data, sizeof(tp->eeprom)); - parse_eeprom(dev); - } - - if ((tp->flags & ALWAYS_CHECK_MII) || - (tp->mtable && tp->mtable->has_mii) || - ( ! tp->mtable && (tp->flags & HAS_MII))) { - int phy, phy_idx; - if (tp->mtable && tp->mtable->has_mii) { - for (i = 0; i < tp->mtable->leafcount; i++) - if (tp->mtable->mleaf[i].media == 11) { - tp->cur_index = i; - tp->saved_if_port = dev->if_port; - select_media(dev, 1); - dev->if_port = tp->saved_if_port; - break; - } - } - /* Find the connected MII xcvrs. - Doing this in open() would allow detecting external xcvrs later, - but takes much time. */ - for (phy = 0, phy_idx = 0; phy < 32 && phy_idx < sizeof(tp->phys); - phy++) { - int mii_status = mdio_read(dev, phy, 1); - if ((mii_status & 0x8301) == 0x8001 || - ((mii_status & 0x8000) == 0 && (mii_status & 0x7800) != 0)) { - int mii_reg0 = mdio_read(dev, phy, 0); - int mii_advert = mdio_read(dev, phy, 4); - int reg4 = ((mii_status>>6) & tp->to_advertise) | 1; - tp->phys[phy_idx] = phy; - tp->advertising[phy_idx++] = reg4; - printk(KERN_INFO "%s: MII transceiver #%d " - "config %4.4x status %4.4x advertising %4.4x.\n", - dev->name, phy, mii_reg0, mii_status, mii_advert); - /* Fixup for DLink with miswired PHY. */ - if (mii_advert != reg4) { - printk(KERN_DEBUG "%s: Advertising %4.4x on PHY %d," - " previously advertising %4.4x.\n", - dev->name, reg4, phy, mii_advert); - printk(KERN_DEBUG "%s: Advertising %4.4x (to advertise" - " is %4.4x).\n", - dev->name, reg4, tp->to_advertise); - mdio_write(dev, phy, 4, reg4); - } - /* Enable autonegotiation: some boards default to off. */ - mdio_write(dev, phy, 0, mii_reg0 | - (tp->full_duplex ? 0x1100 : 0x1000) | - (media_cap[tp->default_port]&MediaIs100 ? 0x2000:0)); - } - } - tp->mii_cnt = phy_idx; - if (tp->mtable && tp->mtable->has_mii && phy_idx == 0) { - printk(KERN_INFO "%s: ***WARNING***: No MII transceiver found!\n", - dev->name); - tp->phys[0] = 1; - } - } - - /* The Tulip-specific entries in the device structure. */ - dev->open = tulip_open; - dev->hard_start_xmit = tulip_start_xmit; - dev->tx_timeout = tulip_tx_timeout; - dev->watchdog_timeo = TX_TIMEOUT; - dev->stop = tulip_close; - dev->get_stats = tulip_get_stats; - dev->do_ioctl = private_ioctl; - dev->set_multicast_list = set_rx_mode; - - if ((tp->flags & HAS_NWAY143) || tp->chip_id == DC21041) - tp->link_change = t21142_lnk_change; - else if (tp->flags & HAS_PNICNWAY) - tp->link_change = pnic_lnk_change; - - /* Reset the xcvr interface and turn on heartbeat. */ - switch (chip_idx) { - case DC21041: - tp->to_advertise = 0x0061; - outl(0x00000000, ioaddr + CSR13); - outl(0xFFFFFFFF, ioaddr + CSR14); - outl(0x00000008, ioaddr + CSR15); /* Listen on AUI also. */ - outl_CSR6(tp, inl(ioaddr + CSR6) | 0x0200); - outl(0x0000EF05, ioaddr + CSR13); - break; - case DC21040: - outl(0x00000000, ioaddr + CSR13); - outl(0x00000004, ioaddr + CSR13); - break; - case DC21140: default: - if (tp->mtable) - outl(tp->mtable->csr12dir | 0x100, ioaddr + CSR12); - break; - case DC21142: - case PNIC2: - if (tp->mii_cnt || media_cap[dev->if_port] & MediaIsMII) { - outl_CSR6(tp, 0x82020000); - outl(0x0000, ioaddr + CSR13); - outl(0x0000, ioaddr + CSR14); - outl_CSR6(tp, 0x820E0000); - } else - t21142_start_nway(dev); - break; - case LC82C168: - if ( ! tp->mii_cnt) { - tp->nway = 1; - tp->nwayset = 0; - outl_CSR6(tp, 0x00420000); - outl(0x30, ioaddr + CSR12); - outl_CSR6(tp, 0x0001F078); - outl_CSR6(tp, 0x0201F078); /* Turn on autonegotiation. */ - } - break; - case MX98713: case COMPEX9881: - outl_CSR6(tp, 0x00000000); - outl(0x000711C0, ioaddr + CSR14); /* Turn on NWay. */ - outl(0x00000001, ioaddr + CSR13); - break; - case MX98715: case MX98725: - outl_CSR6(tp, 0x01a80000); - outl(0xFFFFFFFF, ioaddr + CSR14); - outl(0x00001000, ioaddr + CSR12); - break; - case COMET: - /* No initialization necessary. */ - break; - } - - /* put the chip in snooze mode until opened */ - if (tulip_tbl[chip_idx].flags & HAS_ACPI) - pci_write_config_dword(pdev, 0x40, 0x40000000); - - return 0; - -err_out_free_netdev: - unregister_netdev (dev); - kfree (dev); - return -ENODEV; -} - - -static void tulip_suspend (struct pci_dev *pdev) -{ - struct net_device *dev = pdev->driver_data; - - if (dev && netif_device_present (dev)) - tulip_down (dev); -} - - -static void tulip_resume (struct pci_dev *pdev) -{ - struct net_device *dev = pdev->driver_data; - - if (dev && !netif_device_present (dev)) - tulip_up (dev); -} - - -static void __devexit tulip_remove_one (struct pci_dev *pdev) -{ - struct net_device *dev = pdev->driver_data; - - if (dev) { - struct tulip_private *tp = (struct tulip_private *)dev->priv; - unregister_netdev(dev); - release_region(dev->base_addr, - tulip_tbl[tp->chip_id].io_size); - kfree(dev); - } -} - - -static struct pci_driver tulip_driver = { - name: TULIP_MODULE_NAME, - id_table: tulip_pci_tbl, - probe: tulip_init_one, - remove: tulip_remove_one, - suspend: tulip_suspend, - resume: tulip_resume, -}; - - -static int __init tulip_init (void) -{ - return pci_module_init (&tulip_driver); -} - - -static void __exit tulip_cleanup (void) -{ - pci_unregister_driver (&tulip_driver); -} - - -module_init(tulip_init); -module_exit(tulip_cleanup); diff --git a/drivers/net/tulip/21142.c b/drivers/net/tulip/21142.c new file mode 100644 index 000000000..57b3aa252 --- /dev/null +++ b/drivers/net/tulip/21142.c @@ -0,0 +1,235 @@ +/* + drivers/net/tulip/21142.c + + Maintained by Jeff Garzik + Copyright 2000 The Linux Kernel Team + Written/copyright 1994-1999 by Donald Becker. + + This software may be used and distributed according to the terms + of the GNU Public License, incorporated herein by reference. + + Please refer to Documentation/networking/tulip.txt for more + information on this driver. + +*/ + +#include "tulip.h" +#include + + +static u16 t21142_csr13[] = { 0x0001, 0x0009, 0x0009, 0x0000, 0x0001, }; +u16 t21142_csr14[] = { 0xFFFF, 0x0705, 0x0705, 0x0000, 0x7F3D, }; +static u16 t21142_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, }; + + + +/* Handle the 21143 uniquely: do autoselect with NWay, not the EEPROM list + of available transceivers. */ +void t21142_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + int csr12 = inl(ioaddr + CSR12); + int next_tick = 60*HZ; + int new_csr6 = 0; + + if (tulip_debug > 2) + printk(KERN_INFO"%s: 21143 negotiation status %8.8x, %s.\n", + dev->name, csr12, medianame[dev->if_port]); + if (tulip_media_cap[dev->if_port] & MediaIsMII) { + tulip_check_duplex(dev); + next_tick = 60*HZ; + } else if (tp->nwayset) { + /* Don't screw up a negotiated session! */ + if (tulip_debug > 1) + printk(KERN_INFO"%s: Using NWay-set %s media, csr12 %8.8x.\n", + dev->name, medianame[dev->if_port], csr12); + } else if (tp->medialock) { + ; + } else if (dev->if_port == 3) { + if (csr12 & 2) { /* No 100mbps link beat, revert to 10mbps. */ + if (tulip_debug > 1) + printk(KERN_INFO"%s: No 21143 100baseTx link beat, %8.8x, " + "trying NWay.\n", dev->name, csr12); + t21142_start_nway(dev); + next_tick = 3*HZ; + } + } else if ((csr12 & 0x7000) != 0x5000) { + /* Negotiation failed. Search media types. */ + if (tulip_debug > 1) + printk(KERN_INFO"%s: 21143 negotiation failed, status %8.8x.\n", + dev->name, csr12); + if (!(csr12 & 4)) { /* 10mbps link beat good. */ + new_csr6 = 0x82420000; + dev->if_port = 0; + outl(0, ioaddr + CSR13); + outl(0x0003FFFF, ioaddr + CSR14); + outw(t21142_csr15[dev->if_port], ioaddr + CSR15); + outl(t21142_csr13[dev->if_port], ioaddr + CSR13); + } else { + /* Select 100mbps port to check for link beat. */ + new_csr6 = 0x83860000; + dev->if_port = 3; + outl(0, ioaddr + CSR13); + outl(0x0003FF7F, ioaddr + CSR14); + outw(8, ioaddr + CSR15); + outl(1, ioaddr + CSR13); + } + if (tulip_debug > 1) + printk(KERN_INFO"%s: Testing new 21143 media %s.\n", + dev->name, medianame[dev->if_port]); + if (new_csr6 != (tp->csr6 & ~0x00D5)) { + tp->csr6 &= 0x00D5; + tp->csr6 |= new_csr6; + outl(0x0301, ioaddr + CSR12); + tulip_outl_CSR6(tp, tp->csr6 | 0x0002); + tulip_outl_CSR6(tp, tp->csr6 | 0x2002); + } + next_tick = 3*HZ; + } + + tp->timer.expires = RUN_AT(next_tick); + add_timer(&tp->timer); +} + + +void t21142_start_nway(struct net_device *dev) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + int csr14 = ((tp->to_advertise & 0x0780) << 9) | + ((tp->to_advertise&0x0020)<<1) | 0xffbf; + + dev->if_port = 0; + tp->nway = tp->mediasense = 1; + tp->nwayset = tp->lpar = 0; + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: Restarting 21143 autonegotiation, %8.8x.\n", + dev->name, csr14); + outl(0x0001, ioaddr + CSR13); + outl(csr14, ioaddr + CSR14); + tp->csr6 = 0x82420000 | (tp->to_advertise & 0x0040 ? 0x0200 : 0); + tulip_outl_CSR6(tp, tp->csr6); + if (tp->mtable && tp->mtable->csr15dir) { + outl(tp->mtable->csr15dir, ioaddr + CSR15); + outl(tp->mtable->csr15val, ioaddr + CSR15); + } else + outw(0x0008, ioaddr + CSR15); + outl(0x1301, ioaddr + CSR12); /* Trigger NWAY. */ +} + + +void t21142_lnk_change(struct net_device *dev, int csr5) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + int csr12 = inl(ioaddr + CSR12); + + if (tulip_debug > 1) + printk(KERN_INFO"%s: 21143 link status interrupt %8.8x, CSR5 %x, " + "%8.8x.\n", dev->name, csr12, csr5, inl(ioaddr + CSR14)); + + /* If NWay finished and we have a negotiated partner capability. */ + if (tp->nway && !tp->nwayset && (csr12 & 0x7000) == 0x5000) { + int setup_done = 0; + int negotiated = tp->to_advertise & (csr12 >> 16); + tp->lpar = csr12 >> 16; + tp->nwayset = 1; + if (negotiated & 0x0100) dev->if_port = 5; + else if (negotiated & 0x0080) dev->if_port = 3; + else if (negotiated & 0x0040) dev->if_port = 4; + else if (negotiated & 0x0020) dev->if_port = 0; + else { + tp->nwayset = 0; + if ((csr12 & 2) == 0 && (tp->to_advertise & 0x0180)) + dev->if_port = 3; + } + tp->full_duplex = (tulip_media_cap[dev->if_port] & MediaAlwaysFD) ? 1:0; + + if (tulip_debug > 1) { + if (tp->nwayset) + printk(KERN_INFO "%s: Switching to %s based on link " + "negotiation %4.4x & %4.4x = %4.4x.\n", + dev->name, medianame[dev->if_port], tp->to_advertise, + tp->lpar, negotiated); + else + printk(KERN_INFO "%s: Autonegotiation failed, using %s," + " link beat status %4.4x.\n", + dev->name, medianame[dev->if_port], csr12); + } + + if (tp->mtable) { + int i; + for (i = 0; i < tp->mtable->leafcount; i++) + if (tp->mtable->mleaf[i].media == dev->if_port) { + tp->cur_index = i; + tulip_select_media(dev, 0); + setup_done = 1; + break; + } + } + if ( ! setup_done) { + tp->csr6 = dev->if_port & 1 ? 0x83860000 : 0x82420000; + if (tp->full_duplex) + tp->csr6 |= 0x0200; + outl(1, ioaddr + CSR13); + } +#if 0 /* Restart shouldn't be needed. */ + tulip_outl_CSR6(tp, tp->csr6 | 0x0000); + if (tulip_debug > 2) + printk(KERN_DEBUG "%s: Restarting Tx and Rx, CSR5 is %8.8x.\n", + dev->name, inl(ioaddr + CSR5)); +#endif + tulip_outl_CSR6(tp, tp->csr6 | 0x2002); + if (tulip_debug > 2) + printk(KERN_DEBUG "%s: Setting CSR6 %8.8x/%x CSR12 %8.8x.\n", + dev->name, tp->csr6, inl(ioaddr + CSR6), + inl(ioaddr + CSR12)); + } else if ((tp->nwayset && (csr5 & 0x08000000) + && (dev->if_port == 3 || dev->if_port == 5) + && (csr12 & 2) == 2) || + (tp->nway && (csr5 & (TPLnkFail)))) { + /* Link blew? Maybe restart NWay. */ + del_timer(&tp->timer); + t21142_start_nway(dev); + tp->timer.expires = RUN_AT(3*HZ); + add_timer(&tp->timer); + } else if (dev->if_port == 3 || dev->if_port == 5) { + if (tulip_debug > 1) + printk(KERN_INFO"%s: 21143 %s link beat %s.\n", + dev->name, medianame[dev->if_port], + (csr12 & 2) ? "failed" : "good"); + if ((csr12 & 2) && ! tp->medialock) { + del_timer(&tp->timer); + t21142_start_nway(dev); + tp->timer.expires = RUN_AT(3*HZ); + add_timer(&tp->timer); + } + } else if (dev->if_port == 0 || dev->if_port == 4) { + if ((csr12 & 4) == 0) + printk(KERN_INFO"%s: 21143 10baseT link beat good.\n", + dev->name); + } else if (!(csr12 & 4)) { /* 10mbps link beat good. */ + if (tulip_debug) + printk(KERN_INFO"%s: 21143 10mbps sensed media.\n", + dev->name); + dev->if_port = 0; + } else if (tp->nwayset) { + if (tulip_debug) + printk(KERN_INFO"%s: 21143 using NWay-set %s, csr6 %8.8x.\n", + dev->name, medianame[dev->if_port], tp->csr6); + } else { /* 100mbps link beat good. */ + if (tulip_debug) + printk(KERN_INFO"%s: 21143 100baseTx sensed media.\n", + dev->name); + dev->if_port = 3; + tp->csr6 = 0x83860000; + outl(0x0003FF7F, ioaddr + CSR14); + outl(0x0301, ioaddr + CSR12); + tulip_outl_CSR6(tp, tp->csr6 | 0x0002); + tulip_outl_CSR6(tp, tp->csr6 | 0x2002); + } +} + + diff --git a/drivers/net/tulip/Makefile b/drivers/net/tulip/Makefile new file mode 100644 index 000000000..6e1368e32 --- /dev/null +++ b/drivers/net/tulip/Makefile @@ -0,0 +1,14 @@ +# +# Makefile for the Tulip ethernet driver +# +# 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... + +O_TARGET := tulip.o +O_OBJS := 21142.o eeprom.o interrupt.o media.o pnic.o timer.o tulip_core.o +M_OBJS := $(O_TARGET) + +include $(TOPDIR)/Rules.make diff --git a/drivers/net/tulip/eeprom.c b/drivers/net/tulip/eeprom.c new file mode 100644 index 000000000..7ac6aa08d --- /dev/null +++ b/drivers/net/tulip/eeprom.c @@ -0,0 +1,270 @@ +/* + drivers/net/tulip/eeprom.c + + Maintained by Jeff Garzik + Copyright 2000 The Linux Kernel Team + Written/copyright 1994-1999 by Donald Becker. + + This software may be used and distributed according to the terms + of the GNU Public License, incorporated herein by reference. + + Please refer to Documentation/networking/tulip.txt for more + information on this driver. + +*/ + +#include "tulip.h" +#include +#include +#include + + + +/* Serial EEPROM section. */ +/* The main routine to parse the very complicated SROM structure. + Search www.digital.com for "21X4 SROM" to get details. + This code is very complex, and will require changes to support + additional cards, so I'll be verbose about what is going on. + */ + +/* Known cards that have old-style EEPROMs. */ +static struct eeprom_fixup eeprom_fixups[] __devinitdata = { + {"Asante", 0, 0, 0x94, {0x1e00, 0x0000, 0x0800, 0x0100, 0x018c, + 0x0000, 0x0000, 0xe078, 0x0001, 0x0050, 0x0018 }}, + {"SMC9332DST", 0, 0, 0xC0, { 0x1e00, 0x0000, 0x0800, 0x041f, + 0x0000, 0x009E, /* 10baseT */ + 0x0004, 0x009E, /* 10baseT-FD */ + 0x0903, 0x006D, /* 100baseTx */ + 0x0905, 0x006D, /* 100baseTx-FD */ }}, + {"Cogent EM100", 0, 0, 0x92, { 0x1e00, 0x0000, 0x0800, 0x063f, + 0x0107, 0x8021, /* 100baseFx */ + 0x0108, 0x8021, /* 100baseFx-FD */ + 0x0100, 0x009E, /* 10baseT */ + 0x0104, 0x009E, /* 10baseT-FD */ + 0x0103, 0x006D, /* 100baseTx */ + 0x0105, 0x006D, /* 100baseTx-FD */ }}, + {"Maxtech NX-110", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x0513, + 0x1001, 0x009E, /* 10base2, CSR12 0x10*/ + 0x0000, 0x009E, /* 10baseT */ + 0x0004, 0x009E, /* 10baseT-FD */ + 0x0303, 0x006D, /* 100baseTx, CSR12 0x03 */ + 0x0305, 0x006D, /* 100baseTx-FD CSR12 0x03 */}}, + {"Accton EN1207", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x051F, + 0x1B01, 0x0000, /* 10base2, CSR12 0x1B */ + 0x0B00, 0x009E, /* 10baseT, CSR12 0x0B */ + 0x0B04, 0x009E, /* 10baseT-FD,CSR12 0x0B */ + 0x1B03, 0x006D, /* 100baseTx, CSR12 0x1B */ + 0x1B05, 0x006D, /* 100baseTx-FD CSR12 0x1B */ + }}, + {0, 0, 0, 0, {}}}; + + +static const char *block_name[] __devinitdata = { + "21140 non-MII", + "21140 MII PHY", + "21142 Serial PHY", + "21142 MII PHY", + "21143 SYM PHY", + "21143 reset method" +}; + + +void __devinit tulip_parse_eeprom(struct net_device *dev) +{ + /* The last media info list parsed, for multiport boards. */ + static struct mediatable *last_mediatable = NULL; + static unsigned char *last_ee_data = NULL; + static int controller_index = 0; + struct tulip_private *tp = (struct tulip_private *)dev->priv; + unsigned char *ee_data = tp->eeprom; + int i; + + tp->mtable = 0; + /* Detect an old-style (SA only) EEPROM layout: + memcmp(eedata, eedata+16, 8). */ + for (i = 0; i < 8; i ++) + if (ee_data[i] != ee_data[16+i]) + break; + if (i >= 8) { + if (ee_data[0] == 0xff) { + if (last_mediatable) { + controller_index++; + printk(KERN_INFO "%s: Controller %d of multiport board.\n", + dev->name, controller_index); + tp->mtable = last_mediatable; + ee_data = last_ee_data; + goto subsequent_board; + } else + printk(KERN_INFO "%s: Missing EEPROM, this interface may " + "not work correctly!\n", + dev->name); + return; + } + /* Do a fix-up based on the vendor half of the station address prefix. */ + for (i = 0; eeprom_fixups[i].name; i++) { + if (dev->dev_addr[0] == eeprom_fixups[i].addr0 + && dev->dev_addr[1] == eeprom_fixups[i].addr1 + && dev->dev_addr[2] == eeprom_fixups[i].addr2) { + if (dev->dev_addr[2] == 0xE8 && ee_data[0x1a] == 0x55) + i++; /* An Accton EN1207, not an outlaw Maxtech. */ + memcpy(ee_data + 26, eeprom_fixups[i].newtable, + sizeof(eeprom_fixups[i].newtable)); + printk(KERN_INFO "%s: Old format EEPROM on '%s' board. Using" + " substitute media control info.\n", + dev->name, eeprom_fixups[i].name); + break; + } + } + if (eeprom_fixups[i].name == NULL) { /* No fixup found. */ + printk(KERN_INFO "%s: Old style EEPROM with no media selection " + "information.\n", + dev->name); + return; + } + } + + controller_index = 0; + if (ee_data[19] > 1) { /* Multiport board. */ + last_ee_data = ee_data; + } +subsequent_board: + + if (ee_data[27] == 0) { /* No valid media table. */ + } else if (tp->chip_id == DC21041) { + unsigned char *p = (void *)ee_data + ee_data[27 + controller_index*3]; + int media = get_u16(p); + int count = p[2]; + p += 3; + + printk(KERN_INFO "%s: 21041 Media table, default media %4.4x (%s).\n", + dev->name, media, + media & 0x0800 ? "Autosense" : medianame[media & 15]); + for (i = 0; i < count; i++) { + unsigned char media_code = *p++; + if (media_code & 0x40) + p += 6; + printk(KERN_INFO "%s: 21041 media #%d, %s.\n", + dev->name, media_code & 15, medianame[media_code & 15]); + } + } else { + unsigned char *p = (void *)ee_data + ee_data[27]; + unsigned char csr12dir = 0; + int count, new_advertise = 0; + struct mediatable *mtable; + u16 media = get_u16(p); + + p += 2; + if (tp->flags & CSR12_IN_SROM) + csr12dir = *p++; + count = *p++; + mtable = (struct mediatable *) + kmalloc(sizeof(struct mediatable) + count*sizeof(struct medialeaf), + GFP_KERNEL); + if (mtable == NULL) + return; /* Horrible, impossible failure. */ + last_mediatable = tp->mtable = mtable; + mtable->defaultmedia = media; + mtable->leafcount = count; + mtable->csr12dir = csr12dir; + mtable->has_nonmii = mtable->has_mii = mtable->has_reset = 0; + mtable->csr15dir = mtable->csr15val = 0; + + printk(KERN_INFO "%s: EEPROM default media type %s.\n", dev->name, + media & 0x0800 ? "Autosense" : medianame[media & 15]); + for (i = 0; i < count; i++) { + struct medialeaf *leaf = &mtable->mleaf[i]; + + if ((p[0] & 0x80) == 0) { /* 21140 Compact block. */ + leaf->type = 0; + leaf->media = p[0] & 0x3f; + leaf->leafdata = p; + if ((p[2] & 0x61) == 0x01) /* Bogus, but Znyx boards do it. */ + mtable->has_mii = 1; + p += 4; + } else { + leaf->type = p[1]; + if (p[1] == 0x05) { + mtable->has_reset = i; + leaf->media = p[2] & 0x0f; + } else if (p[1] & 1) { + mtable->has_mii = 1; + leaf->media = 11; + } else { + mtable->has_nonmii = 1; + leaf->media = p[2] & 0x0f; + switch (leaf->media) { + case 0: new_advertise |= 0x0020; break; + case 4: new_advertise |= 0x0040; break; + case 3: new_advertise |= 0x0080; break; + case 5: new_advertise |= 0x0100; break; + case 6: new_advertise |= 0x0200; break; + } + if (p[1] == 2 && leaf->media == 0) { + if (p[2] & 0x40) { + u32 base15 = get_unaligned((u16*)&p[7]); + mtable->csr15dir = + (get_unaligned((u16*)&p[9])<<16) + base15; + mtable->csr15val = + (get_unaligned((u16*)&p[11])<<16) + base15; + } else { + mtable->csr15dir = get_unaligned((u16*)&p[3])<<16; + mtable->csr15val = get_unaligned((u16*)&p[5])<<16; + } + } + } + leaf->leafdata = p + 2; + p += (p[0] & 0x3f) + 1; + } + if (tulip_debug > 1 && leaf->media == 11) { + unsigned char *bp = leaf->leafdata; + printk(KERN_INFO "%s: MII interface PHY %d, setup/reset " + "sequences %d/%d long, capabilities %2.2x %2.2x.\n", + dev->name, bp[0], bp[1], bp[2 + bp[1]*2], + bp[5 + bp[2 + bp[1]*2]*2], bp[4 + bp[2 + bp[1]*2]*2]); + } + printk(KERN_INFO "%s: Index #%d - Media %s (#%d) described " + "by a %s (%d) block.\n", + dev->name, i, medianame[leaf->media], leaf->media, + block_name[leaf->type], leaf->type); + } + if (new_advertise) + tp->to_advertise = new_advertise; + } +} +/* Reading a serial EEPROM is a "bit" grungy, but we work our way through:->.*/ + +/* Note: this routine returns extra data bits for size detection. */ +int __devinit tulip_read_eeprom(long ioaddr, int location, int addr_len) +{ + int i; + unsigned retval = 0; + long ee_addr = ioaddr + CSR9; + int read_cmd = location | (EE_READ_CMD << addr_len); + + outl(EE_ENB & ~EE_CS, ee_addr); + outl(EE_ENB, ee_addr); + + /* Shift the read command bits out. */ + for (i = 4 + addr_len; i >= 0; i--) { + short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0; + outl(EE_ENB | dataval, ee_addr); + eeprom_delay(); + outl(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr); + eeprom_delay(); + retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0); + } + outl(EE_ENB, ee_addr); + + for (i = 16; i > 0; i--) { + outl(EE_ENB | EE_SHIFT_CLK, ee_addr); + eeprom_delay(); + retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0); + outl(EE_ENB, ee_addr); + eeprom_delay(); + } + + /* Terminate the EEPROM access. */ + outl(EE_ENB & ~EE_CS, ee_addr); + return retval; +} + diff --git a/drivers/net/tulip/interrupt.c b/drivers/net/tulip/interrupt.c new file mode 100644 index 000000000..6d70ffd70 --- /dev/null +++ b/drivers/net/tulip/interrupt.c @@ -0,0 +1,337 @@ +/* + drivers/net/tulip/interrupt.c + + Maintained by Jeff Garzik + Copyright 2000 The Linux Kernel Team + Written/copyright 1994-1999 by Donald Becker. + + This software may be used and distributed according to the terms + of the GNU Public License, incorporated herein by reference. + + Please refer to Documentation/networking/tulip.txt for more + information on this driver. + +*/ + +#include "tulip.h" +#include +#include + + +int tulip_rx_copybreak; +int tulip_max_interrupt_work; + + + +static int tulip_refill_rx(struct net_device *dev) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + int entry; + int refilled = 0; + + /* Refill the Rx ring buffers. */ + for (; tp->cur_rx - tp->dirty_rx > 0; tp->dirty_rx++) { + entry = tp->dirty_rx % RX_RING_SIZE; + if (tp->rx_skbuff[entry] == NULL) { + struct sk_buff *skb; + skb = tp->rx_skbuff[entry] = dev_alloc_skb(PKT_BUF_SZ); + if (skb == NULL) + break; + skb->dev = dev; /* Mark as being used by this device. */ + tp->rx_ring[entry].buffer1 = virt_to_le32desc(skb->tail); + refilled++; + } + tp->rx_ring[entry].status = cpu_to_le32(DescOwned); + } + return refilled; +} + + +static int tulip_rx(struct net_device *dev) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + int entry = tp->cur_rx % RX_RING_SIZE; + int rx_work_limit = tp->dirty_rx + RX_RING_SIZE - tp->cur_rx; + int received = 0; + + if (tulip_debug > 4) + printk(KERN_DEBUG " In tulip_rx(), entry %d %8.8x.\n", entry, + tp->rx_ring[entry].status); + /* If we own the next entry, it is a new packet. Send it up. */ + while ( ! (tp->rx_ring[entry].status & cpu_to_le32(DescOwned))) { + s32 status = le32_to_cpu(tp->rx_ring[entry].status); + + if (tulip_debug > 5) + printk(KERN_DEBUG "%s: In tulip_rx(), entry %d %8.8x.\n", + dev->name, entry, status); + if (--rx_work_limit < 0) + break; + if ((status & 0x38008300) != 0x0300) { + if ((status & 0x38000300) != 0x0300) { + /* Ingore earlier buffers. */ + if ((status & 0xffff) != 0x7fff) { + if (tulip_debug > 1) + printk(KERN_WARNING "%s: Oversized Ethernet frame " + "spanned multiple buffers, status %8.8x!\n", + dev->name, status); + tp->stats.rx_length_errors++; + } + } else if (status & RxDescFatalErr) { + /* There was a fatal error. */ + if (tulip_debug > 2) + printk(KERN_DEBUG "%s: Receive error, Rx status %8.8x.\n", + dev->name, status); + tp->stats.rx_errors++; /* end of a packet.*/ + if (status & 0x0890) tp->stats.rx_length_errors++; + if (status & 0x0004) tp->stats.rx_frame_errors++; + if (status & 0x0002) tp->stats.rx_crc_errors++; + if (status & 0x0001) tp->stats.rx_fifo_errors++; + } + } else { + /* Omit the four octet CRC from the length. */ + short pkt_len = ((status >> 16) & 0x7ff) - 4; + struct sk_buff *skb; + +#ifndef final_version + if (pkt_len > 1518) { + printk(KERN_WARNING "%s: Bogus packet size of %d (%#x).\n", + dev->name, pkt_len, pkt_len); + pkt_len = 1518; + tp->stats.rx_length_errors++; + } +#endif + /* Check if the packet is long enough to accept without copying + to a minimally-sized skbuff. */ + if (pkt_len < tulip_rx_copybreak + && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { + skb->dev = dev; + skb_reserve(skb, 2); /* 16 byte align the IP header */ +#if ! defined(__alpha__) + eth_copy_and_sum(skb, tp->rx_skbuff[entry]->tail, pkt_len, 0); + skb_put(skb, pkt_len); +#else + memcpy(skb_put(skb, pkt_len), tp->rx_skbuff[entry]->tail, + pkt_len); +#endif + } else { /* Pass up the skb already on the Rx ring. */ + char *temp = skb_put(skb = tp->rx_skbuff[entry], pkt_len); + tp->rx_skbuff[entry] = NULL; +#ifndef final_version + if (le32desc_to_virt(tp->rx_ring[entry].buffer1) != temp) + printk(KERN_ERR "%s: Internal fault: The skbuff addresses " + "do not match in tulip_rx: %p vs. %p / %p.\n", + dev->name, + le32desc_to_virt(tp->rx_ring[entry].buffer1), + skb->head, temp); +#endif + } + skb->protocol = eth_type_trans(skb, dev); + netif_rx(skb); + dev->last_rx = jiffies; + tp->stats.rx_packets++; + tp->stats.rx_bytes += pkt_len; + } + received++; + entry = (++tp->cur_rx) % RX_RING_SIZE; + } + + return received; +} + + +/* The interrupt handler does all of the Rx thread work and cleans up + after the Tx thread. */ +void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *)dev_instance; + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + int csr5; + int entry; + int missed; + int rx = 0; + int tx = 0; + int oi = 0; + int maxrx = RX_RING_SIZE; + int maxtx = TX_RING_SIZE; + int maxoi = TX_RING_SIZE; + int work_count = tulip_max_interrupt_work; + + tp->nir++; + + do { + csr5 = inl(ioaddr + CSR5); + /* Acknowledge all of the current interrupt sources ASAP. */ + outl(csr5 & 0x0001ffff, ioaddr + CSR5); + + if (tulip_debug > 4) + printk(KERN_DEBUG "%s: interrupt csr5=%#8.8x new csr5=%#8.8x.\n", + dev->name, csr5, inl(dev->base_addr + CSR5)); + + if ((csr5 & (NormalIntr|AbnormalIntr)) == 0) + break; + + if (csr5 & (RxIntr | RxNoBuf)) { + rx += tulip_rx(dev); + tulip_refill_rx(dev); + } + + if (csr5 & (TxNoBuf | TxDied | TxIntr | TimerInt)) { + unsigned int dirty_tx; + + spin_lock(&tp->lock); + + for (dirty_tx = tp->dirty_tx; tp->cur_tx - dirty_tx > 0; + dirty_tx++) { + int entry = dirty_tx % TX_RING_SIZE; + int status = le32_to_cpu(tp->tx_ring[entry].status); + + if (status < 0) + break; /* It still has not been Txed */ + /* Check for Rx filter setup frames. */ + if (tp->tx_skbuff[entry] == NULL) + continue; + + if (status & 0x8000) { + /* There was an major error, log it. */ +#ifndef final_version + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n", + dev->name, status); +#endif + tp->stats.tx_errors++; + if (status & 0x4104) tp->stats.tx_aborted_errors++; + if (status & 0x0C00) tp->stats.tx_carrier_errors++; + if (status & 0x0200) tp->stats.tx_window_errors++; + if (status & 0x0002) tp->stats.tx_fifo_errors++; + if ((status & 0x0080) && tp->full_duplex == 0) + tp->stats.tx_heartbeat_errors++; +#ifdef ETHER_STATS + if (status & 0x0100) tp->stats.collisions16++; +#endif + } else { +#ifdef ETHER_STATS + if (status & 0x0001) tp->stats.tx_deferred++; +#endif + tp->stats.tx_bytes += tp->tx_skbuff[entry]->len; + tp->stats.collisions += (status >> 3) & 15; + tp->stats.tx_packets++; + } + + /* Free the original skb. */ + dev_kfree_skb_irq(tp->tx_skbuff[entry]); + tp->tx_skbuff[entry] = 0; + tx++; + } + +#ifndef final_version + if (tp->cur_tx - dirty_tx > TX_RING_SIZE) { + printk(KERN_ERR "%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n", + dev->name, dirty_tx, tp->cur_tx, tp->tx_full); + dirty_tx += TX_RING_SIZE; + } +#endif + + if (tp->tx_full && tp->cur_tx - dirty_tx < TX_RING_SIZE - 2) { + /* The ring is no longer full, clear tbusy. */ + tp->tx_full = 0; + netif_wake_queue(dev); + } + + tp->dirty_tx = dirty_tx; + if (csr5 & TxDied) { + if (tulip_debug > 2) + printk(KERN_WARNING "%s: The transmitter stopped." + " CSR5 is %x, CSR6 %x, new CSR6 %x.\n", + dev->name, csr5, inl(ioaddr + CSR6), tp->csr6); + tulip_outl_CSR6(tp, tp->csr6 | 0x0002); + tulip_outl_CSR6(tp, tp->csr6 | 0x2002); + } + spin_unlock(&tp->lock); + } + + /* Log errors. */ + if (csr5 & AbnormalIntr) { /* Abnormal error summary bit. */ + if (csr5 == 0xffffffff) + break; + if (csr5 & TxJabber) tp->stats.tx_errors++; + if (csr5 & TxFIFOUnderflow) { + if ((tp->csr6 & 0xC000) != 0xC000) + tp->csr6 += 0x4000; /* Bump up the Tx threshold */ + else + tp->csr6 |= 0x00200000; /* Store-n-forward. */ + /* Restart the transmit process. */ + tulip_outl_CSR6(tp, tp->csr6 | 0x0002); + tulip_outl_CSR6(tp, tp->csr6 | 0x2002); + outl(0, ioaddr + CSR1); + } + if (csr5 & RxDied) { /* Missed a Rx frame. */ + tp->stats.rx_errors++; + tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff; + tulip_outl_CSR6(tp, tp->csr6 | 0x2002); + } + if (csr5 & (TPLnkPass | TPLnkFail | 0x08000000)) { + if (tp->link_change) + (tp->link_change)(dev, csr5); + } + if (csr5 & SytemError) { + printk(KERN_ERR "%s: (%lu) System Error occured\n", dev->name, tp->nir); + } + /* Clear all error sources, included undocumented ones! */ + outl(0x0800f7ba, ioaddr + CSR5); + oi++; + } + if (csr5 & TimerInt) { +#if 0 + if (tulip_debug > 2) + printk(KERN_ERR "%s: Re-enabling interrupts, %8.8x.\n", + dev->name, csr5); + outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7); +#endif + tp->ttimer = 0; + oi++; + } + if (tx > maxtx || rx > maxrx || oi > maxoi) { + if (tulip_debug > 1) + printk(KERN_WARNING "%s: Too much work during an interrupt, " + "csr5=0x%8.8x. (%lu) (%d,%d,%d)\n", dev->name, csr5, tp->nir, tx, rx, oi); + /* Acknowledge all interrupt sources. */ +#if 0 + /* Clear all interrupting sources, set timer to re-enable. */ + outl(((~csr5) & 0x0001ebef) | NormalIntr | AbnormalIntr | TimerInt, + ioaddr + CSR7); + outl(12, ioaddr + CSR11); + tp->ttimer = 1; +#endif + break; + } + } while (work_count-- > 0); + + tulip_refill_rx(dev); + + /* check if we card is in suspend mode */ + entry = tp->dirty_rx % RX_RING_SIZE; + if (tp->rx_skbuff[entry] == NULL) { + if (tulip_debug > 1) + printk(KERN_WARNING "%s: in rx suspend mode: (%lu) (tp->cur_rx = %u, ttimer = %d, rx = %d) go/stay in suspend mode\n", dev->name, tp->nir, tp->cur_rx, tp->ttimer, rx); + if (tp->ttimer == 0 || (inl(ioaddr + CSR11) & 0xffff) == 0) { + if (tulip_debug > 1) + printk(KERN_WARNING "%s: in rx suspend mode: (%lu) set timer\n", dev->name, tp->nir); + outl(tulip_tbl[tp->chip_id].valid_intrs | TimerInt, + ioaddr + CSR7); + outl(TimerInt, ioaddr + CSR5); + outl(12, ioaddr + CSR11); + tp->ttimer = 1; + } + } + + if ((missed = inl(ioaddr + CSR8) & 0x1ffff)) { + tp->stats.rx_dropped += missed & 0x10000 ? 0x10000 : missed; + } + + if (tulip_debug > 4) + printk(KERN_DEBUG "%s: exiting interrupt, csr5=%#4.4x.\n", + dev->name, inl(ioaddr + CSR5)); + +} + diff --git a/drivers/net/tulip/media.c b/drivers/net/tulip/media.c new file mode 100644 index 000000000..1d4c3b2e4 --- /dev/null +++ b/drivers/net/tulip/media.c @@ -0,0 +1,403 @@ +/* + drivers/net/tulip/media.c + + Maintained by Jeff Garzik + Copyright 2000 The Linux Kernel Team + Written/copyright 1994-1999 by Donald Becker. + + This software may be used and distributed according to the terms + of the GNU Public License, incorporated herein by reference. + + Please refer to Documentation/networking/tulip.txt for more + information on this driver. + +*/ + +#include "tulip.h" +#include + + +/* This is a mysterious value that can be written to CSR11 in the 21040 (only) + to support a pre-NWay full-duplex signaling mechanism using short frames. + No one knows what it should be, but if left at its default value some + 10base2(!) packets trigger a full-duplex-request interrupt. */ +#define FULL_DUPLEX_MAGIC 0x6969 + + +/* MII transceiver control section. + Read and write the MII registers using software-generated serial + MDIO protocol. See the MII specifications or DP83840A data sheet + for details. */ + +int tulip_mdio_read(struct net_device *dev, int phy_id, int location) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + int i; + int read_cmd = (0xf6 << 10) | (phy_id << 5) | location; + int retval = 0; + long ioaddr = dev->base_addr; + long mdio_addr = ioaddr + CSR9; + + if (tp->chip_id == LC82C168) { + int i = 1000; + outl(0x60020000 + (phy_id<<23) + (location<<18), ioaddr + 0xA0); + inl(ioaddr + 0xA0); + inl(ioaddr + 0xA0); + while (--i > 0) + if ( ! ((retval = inl(ioaddr + 0xA0)) & 0x80000000)) + return retval & 0xffff; + return 0xffff; + } + + if (tp->chip_id == COMET) { + if (phy_id == 1) { + if (location < 7) + return inl(ioaddr + 0xB4 + (location<<2)); + else if (location == 17) + return inl(ioaddr + 0xD0); + else if (location >= 29 && location <= 31) + return inl(ioaddr + 0xD4 + ((location-29)<<2)); + } + return 0xffff; + } + + /* Establish sync by sending at least 32 logic ones. */ + for (i = 32; i >= 0; i--) { + outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr); + mdio_delay(); + outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr); + mdio_delay(); + } + /* Shift the read command bits out. */ + for (i = 15; i >= 0; i--) { + int dataval = (read_cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0; + + outl(MDIO_ENB | dataval, mdio_addr); + mdio_delay(); + outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr); + mdio_delay(); + } + /* Read the two transition, 16 data, and wire-idle bits. */ + for (i = 19; i > 0; i--) { + outl(MDIO_ENB_IN, mdio_addr); + mdio_delay(); + retval = (retval << 1) | ((inl(mdio_addr) & MDIO_DATA_READ) ? 1 : 0); + outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); + mdio_delay(); + } + return (retval>>1) & 0xffff; +} + +void tulip_mdio_write(struct net_device *dev, int phy_id, int location, int value) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + int i; + int cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value; + long ioaddr = dev->base_addr; + long mdio_addr = ioaddr + CSR9; + + if (tp->chip_id == LC82C168) { + int i = 1000; + outl(cmd, ioaddr + 0xA0); + do + if ( ! (inl(ioaddr + 0xA0) & 0x80000000)) + break; + while (--i > 0); + return; + } + + if (tp->chip_id == COMET) { + if (phy_id != 1) + return; + if (location < 7) + outl(value, ioaddr + 0xB4 + (location<<2)); + else if (location == 17) + outl(value, ioaddr + 0xD0); + else if (location >= 29 && location <= 31) + outl(value, ioaddr + 0xD4 + ((location-29)<<2)); + return; + } + + /* Establish sync by sending 32 logic ones. */ + for (i = 32; i >= 0; i--) { + outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr); + mdio_delay(); + outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr); + mdio_delay(); + } + /* Shift the command bits out. */ + for (i = 31; i >= 0; i--) { + int dataval = (cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0; + outl(MDIO_ENB | dataval, mdio_addr); + mdio_delay(); + outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr); + mdio_delay(); + } + /* Clear out extra bits. */ + for (i = 2; i > 0; i--) { + outl(MDIO_ENB_IN, mdio_addr); + mdio_delay(); + outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); + mdio_delay(); + } +} + + +/* Set up the transceiver control registers for the selected media type. */ +void tulip_select_media(struct net_device *dev, int startup) +{ + long ioaddr = dev->base_addr; + struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct mediatable *mtable = tp->mtable; + u32 new_csr6; + int i; + + if (mtable) { + struct medialeaf *mleaf = &mtable->mleaf[tp->cur_index]; + unsigned char *p = mleaf->leafdata; + switch (mleaf->type) { + case 0: /* 21140 non-MII xcvr. */ + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: Using a 21140 non-MII transceiver" + " with control setting %2.2x.\n", + dev->name, p[1]); + dev->if_port = p[0]; + if (startup) + outl(mtable->csr12dir | 0x100, ioaddr + CSR12); + outl(p[1], ioaddr + CSR12); + new_csr6 = 0x02000000 | ((p[2] & 0x71) << 18); + break; + case 2: case 4: { + u16 setup[5]; + u32 csr13val, csr14val, csr15dir, csr15val; + for (i = 0; i < 5; i++) + setup[i] = get_u16(&p[i*2 + 1]); + + dev->if_port = p[0] & 15; + if (tulip_media_cap[dev->if_port] & MediaAlwaysFD) + tp->full_duplex = 1; + + if (startup && mtable->has_reset) { + struct medialeaf *rleaf = &mtable->mleaf[mtable->has_reset]; + unsigned char *rst = rleaf->leafdata; + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: Resetting the transceiver.\n", + dev->name); + for (i = 0; i < rst[0]; i++) + outl(get_u16(rst + 1 + (i<<1)) << 16, ioaddr + CSR15); + } + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: 21143 non-MII %s transceiver control " + "%4.4x/%4.4x.\n", + dev->name, medianame[dev->if_port], setup[0], setup[1]); + if (p[0] & 0x40) { /* SIA (CSR13-15) setup values are provided. */ + csr13val = setup[0]; + csr14val = setup[1]; + csr15dir = (setup[3]<<16) | setup[2]; + csr15val = (setup[4]<<16) | setup[2]; + outl(0, ioaddr + CSR13); + outl(csr14val, ioaddr + CSR14); + outl(csr15dir, ioaddr + CSR15); /* Direction */ + outl(csr15val, ioaddr + CSR15); /* Data */ + outl(csr13val, ioaddr + CSR13); + } else { + csr13val = 1; + csr14val = 0x0003FF7F; + csr15dir = (setup[0]<<16) | 0x0008; + csr15val = (setup[1]<<16) | 0x0008; + if (dev->if_port <= 4) + csr14val = t21142_csr14[dev->if_port]; + if (startup) { + outl(0, ioaddr + CSR13); + outl(csr14val, ioaddr + CSR14); + } + outl(csr15dir, ioaddr + CSR15); /* Direction */ + outl(csr15val, ioaddr + CSR15); /* Data */ + if (startup) outl(csr13val, ioaddr + CSR13); + } + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: Setting CSR15 to %8.8x/%8.8x.\n", + dev->name, csr15dir, csr15val); + if (mleaf->type == 4) + new_csr6 = 0x82020000 | ((setup[2] & 0x71) << 18); + else + new_csr6 = 0x82420000; + break; + } + case 1: case 3: { + int phy_num = p[0]; + int init_length = p[1]; + u16 *misc_info; + u16 to_advertise; + + dev->if_port = 11; + new_csr6 = 0x020E0000; + if (mleaf->type == 3) { /* 21142 */ + u16 *init_sequence = (u16*)(p+2); + u16 *reset_sequence = &((u16*)(p+3))[init_length]; + int reset_length = p[2 + init_length*2]; + misc_info = reset_sequence + reset_length; + if (startup) + for (i = 0; i < reset_length; i++) + outl(get_u16(&reset_sequence[i]) << 16, ioaddr + CSR15); + for (i = 0; i < init_length; i++) + outl(get_u16(&init_sequence[i]) << 16, ioaddr + CSR15); + } else { + u8 *init_sequence = p + 2; + u8 *reset_sequence = p + 3 + init_length; + int reset_length = p[2 + init_length]; + misc_info = (u16*)(reset_sequence + reset_length); + if (startup) { + outl(mtable->csr12dir | 0x100, ioaddr + CSR12); + for (i = 0; i < reset_length; i++) + outl(reset_sequence[i], ioaddr + CSR12); + } + for (i = 0; i < init_length; i++) + outl(init_sequence[i], ioaddr + CSR12); + } + to_advertise = (get_u16(&misc_info[1]) & tp->to_advertise) | 1; + tp->advertising[phy_num] = to_advertise; + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: Advertising %4.4x on PHY %d (%d).\n", + dev->name, to_advertise, phy_num, tp->phys[phy_num]); + /* Bogus: put in by a committee? */ + tulip_mdio_write(dev, tp->phys[phy_num], 4, to_advertise); + break; + } + default: + printk(KERN_DEBUG "%s: Invalid media table selection %d.\n", + dev->name, mleaf->type); + new_csr6 = 0x020E0000; + } + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: Using media type %s, CSR12 is %2.2x.\n", + dev->name, medianame[dev->if_port], + inl(ioaddr + CSR12) & 0xff); + } else if (tp->chip_id == DC21041) { + int port = dev->if_port <= 4 ? dev->if_port : 0; + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: 21041 using media %s, CSR12 is %4.4x.\n", + dev->name, medianame[port == 3 ? 12: port], + inl(ioaddr + CSR12)); + outl(0x00000000, ioaddr + CSR13); /* Reset the serial interface */ + outl(t21041_csr14[port], ioaddr + CSR14); + outl(t21041_csr15[port], ioaddr + CSR15); + outl(t21041_csr13[port], ioaddr + CSR13); + new_csr6 = 0x80020000; + } else if (tp->chip_id == LC82C168) { + if (startup && ! tp->medialock) + dev->if_port = tp->mii_cnt ? 11 : 0; + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: PNIC PHY status is %3.3x, media %s.\n", + dev->name, inl(ioaddr + 0xB8), medianame[dev->if_port]); + if (tp->mii_cnt) { + new_csr6 = 0x810C0000; + outl(0x0001, ioaddr + CSR15); + outl(0x0201B07A, ioaddr + 0xB8); + } else if (startup) { + /* Start with 10mbps to do autonegotiation. */ + outl(0x32, ioaddr + CSR12); + new_csr6 = 0x00420000; + outl(0x0001B078, ioaddr + 0xB8); + outl(0x0201B078, ioaddr + 0xB8); + } else if (dev->if_port == 3 || dev->if_port == 5) { + outl(0x33, ioaddr + CSR12); + new_csr6 = 0x01860000; + /* Trigger autonegotiation. */ + outl(startup ? 0x0201F868 : 0x0001F868, ioaddr + 0xB8); + } else { + outl(0x32, ioaddr + CSR12); + new_csr6 = 0x00420000; + outl(0x1F078, ioaddr + 0xB8); + } + } else if (tp->chip_id == DC21040) { /* 21040 */ + /* Turn on the xcvr interface. */ + int csr12 = inl(ioaddr + CSR12); + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: 21040 media type is %s, CSR12 is %2.2x.\n", + dev->name, medianame[dev->if_port], csr12); + if (tulip_media_cap[dev->if_port] & MediaAlwaysFD) + tp->full_duplex = 1; + new_csr6 = 0x20000; + /* Set the full duplux match frame. */ + outl(FULL_DUPLEX_MAGIC, ioaddr + CSR11); + outl(0x00000000, ioaddr + CSR13); /* Reset the serial interface */ + if (t21040_csr13[dev->if_port] & 8) { + outl(0x0705, ioaddr + CSR14); + outl(0x0006, ioaddr + CSR15); + } else { + outl(0xffff, ioaddr + CSR14); + outl(0x0000, ioaddr + CSR15); + } + outl(0x8f01 | t21040_csr13[dev->if_port], ioaddr + CSR13); + } else { /* Unknown chip type with no media table. */ + if (tp->default_port == 0) + dev->if_port = tp->mii_cnt ? 11 : 3; + if (tulip_media_cap[dev->if_port] & MediaIsMII) { + new_csr6 = 0x020E0000; + } else if (tulip_media_cap[dev->if_port] & MediaIsFx) { + new_csr6 = 0x028600000; + } else + new_csr6 = 0x038600000; + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: No media description table, assuming " + "%s transceiver, CSR12 %2.2x.\n", + dev->name, medianame[dev->if_port], + inl(ioaddr + CSR12)); + } + + tp->csr6 = new_csr6 | (tp->csr6 & 0xfdff) | (tp->full_duplex ? 0x0200 : 0); + return; +} + +/* + Check the MII negotiated duplex, and change the CSR6 setting if + required. + Return 0 if everything is OK. + Return < 0 if the transceiver is missing or has no link beat. + */ +int tulip_check_duplex(struct net_device *dev) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + int mii_reg1, mii_reg5, negotiated, duplex; + + if (tp->full_duplex_lock) + return 0; + mii_reg1 = tulip_mdio_read(dev, tp->phys[0], 1); + mii_reg5 = tulip_mdio_read(dev, tp->phys[0], 5); + if (tulip_debug > 1) + printk(KERN_INFO "%s: MII status %4.4x, Link partner report " + "%4.4x.\n", dev->name, mii_reg1, mii_reg5); + if (mii_reg1 == 0xffff) + return -2; + if ((mii_reg1 & 0x0004) == 0) { + int new_reg1 = tulip_mdio_read(dev, tp->phys[0], 1); + if ((new_reg1 & 0x0004) == 0) { + if (tulip_debug > 1) + printk(KERN_INFO "%s: No link beat on the MII interface," + " status %4.4x.\n", dev->name, new_reg1); + return -1; + } + } + negotiated = mii_reg5 & tp->advertising[0]; + duplex = ((negotiated & 0x0300) == 0x0100 + || (negotiated & 0x00C0) == 0x0040); + /* 100baseTx-FD or 10T-FD, but not 100-HD */ + if (tp->full_duplex != duplex) { + tp->full_duplex = duplex; + if (negotiated & 0x038) /* 100mbps. */ + tp->csr6 &= ~0x00400000; + if (tp->full_duplex) tp->csr6 |= 0x0200; + else tp->csr6 &= ~0x0200; + tulip_outl_CSR6(tp, tp->csr6 | 0x0002); + tulip_outl_CSR6(tp, tp->csr6 | 0x2002); + if (tulip_debug > 0) + printk(KERN_INFO "%s: Setting %s-duplex based on MII" + "#%d link partner capability of %4.4x.\n", + dev->name, tp->full_duplex ? "full" : "half", + tp->phys[0], mii_reg5); + return 1; + } + return 0; +} + diff --git a/drivers/net/tulip/pnic.c b/drivers/net/tulip/pnic.c new file mode 100644 index 000000000..445d4a440 --- /dev/null +++ b/drivers/net/tulip/pnic.c @@ -0,0 +1,146 @@ +/* + drivers/net/tulip/pnic.c + + Maintained by Jeff Garzik + Copyright 2000 The Linux Kernel Team + Written/copyright 1994-1999 by Donald Becker. + + This software may be used and distributed according to the terms + of the GNU Public License, incorporated herein by reference. + + Please refer to Documentation/networking/tulip.txt for more + information on this driver. + +*/ + +#include +#include "tulip.h" +#include + + +void pnic_do_nway(struct net_device *dev) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + u32 phy_reg = inl(ioaddr + 0xB8); + u32 new_csr6 = tp->csr6 & ~0x40C40200; + + if (phy_reg & 0x78000000) { /* Ignore baseT4 */ + if (phy_reg & 0x20000000) dev->if_port = 5; + else if (phy_reg & 0x40000000) dev->if_port = 3; + else if (phy_reg & 0x10000000) dev->if_port = 4; + else if (phy_reg & 0x08000000) dev->if_port = 0; + tp->nwayset = 1; + new_csr6 = (dev->if_port & 1) ? 0x01860000 : 0x00420000; + outl(0x32 | (dev->if_port & 1), ioaddr + CSR12); + if (dev->if_port & 1) + outl(0x1F868, ioaddr + 0xB8); + if (phy_reg & 0x30000000) { + tp->full_duplex = 1; + new_csr6 |= 0x00000200; + } + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: PNIC autonegotiated status %8.8x, %s.\n", + dev->name, phy_reg, medianame[dev->if_port]); + if (tp->csr6 != new_csr6) { + tp->csr6 = new_csr6; + /* Restart Tx */ + tulip_outl_CSR6(tp, tp->csr6 | 0x0002); + tulip_outl_CSR6(tp, tp->csr6 | 0x2002); + dev->trans_start = jiffies; + } + } +} + + +void pnic_lnk_change(struct net_device *dev, int csr5) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + int phy_reg = inl(ioaddr + 0xB8); + + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: PNIC link changed state %8.8x, CSR5 %8.8x.\n", + dev->name, phy_reg, csr5); + if (inl(ioaddr + CSR5) & TPLnkFail) { + outl((inl(ioaddr + CSR7) & ~TPLnkFail) | TPLnkPass, ioaddr + CSR7); + if (! tp->nwayset || jiffies - dev->trans_start > 1*HZ) { + tp->csr6 = 0x00420000 | (tp->csr6 & 0x0000fdff); + tulip_outl_CSR6(tp, tp->csr6); + outl(0x30, ioaddr + CSR12); + outl(0x0201F078, ioaddr + 0xB8); /* Turn on autonegotiation. */ + dev->trans_start = jiffies; + } + } else if (inl(ioaddr + CSR5) & TPLnkPass) { + pnic_do_nway(dev); + outl((inl(ioaddr + CSR7) & ~TPLnkPass) | TPLnkFail, ioaddr + CSR7); + } +} + + +void pnic_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + int next_tick = 60*HZ; + + if (tulip_media_cap[dev->if_port] & MediaIsMII) { + if (tulip_check_duplex(dev) > 0) + next_tick = 3*HZ; + } else { + int csr12 = inl(ioaddr + CSR12); + int new_csr6 = tp->csr6 & ~0x40C40200; + int phy_reg = inl(ioaddr + 0xB8); + int csr5 = inl(ioaddr + CSR5); + + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: PNIC timer PHY status %8.8x, %s " + "CSR5 %8.8x.\n", + dev->name, phy_reg, medianame[dev->if_port], csr5); + if (phy_reg & 0x04000000) { /* Remote link fault */ + outl(0x0201F078, ioaddr + 0xB8); + next_tick = 1*HZ; + tp->nwayset = 0; + } else if (phy_reg & 0x78000000) { /* Ignore baseT4 */ + pnic_do_nway(dev); + next_tick = 60*HZ; + } else if (csr5 & TPLnkFail) { /* 100baseTx link beat */ + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: %s link beat failed, CSR12 %4.4x, " + "CSR5 %8.8x, PHY %3.3x.\n", + dev->name, medianame[dev->if_port], csr12, + inl(ioaddr + CSR5), inl(ioaddr + 0xB8)); + next_tick = 3*HZ; + if (tp->medialock) { + } else if (tp->nwayset && (dev->if_port & 1)) { + next_tick = 1*HZ; + } else if (dev->if_port == 0) { + dev->if_port = 3; + outl(0x33, ioaddr + CSR12); + new_csr6 = 0x01860000; + outl(0x1F868, ioaddr + 0xB8); + } else { + dev->if_port = 0; + outl(0x32, ioaddr + CSR12); + new_csr6 = 0x00420000; + outl(0x1F078, ioaddr + 0xB8); + } + if (tp->csr6 != new_csr6) { + tp->csr6 = new_csr6; + /* Restart Tx */ + tulip_outl_CSR6(tp, tp->csr6 | 0x0002); + tulip_outl_CSR6(tp, tp->csr6 | 0x2002); + dev->trans_start = jiffies; + if (tulip_debug > 1) + printk(KERN_INFO "%s: Changing PNIC configuration to %s " + "%s-duplex, CSR6 %8.8x.\n", + dev->name, medianame[dev->if_port], + tp->full_duplex ? "full" : "half", new_csr6); + } + } + } + tp->timer.expires = RUN_AT(next_tick); + add_timer(&tp->timer); +} + diff --git a/drivers/net/tulip/timer.c b/drivers/net/tulip/timer.c new file mode 100644 index 000000000..796fdd136 --- /dev/null +++ b/drivers/net/tulip/timer.c @@ -0,0 +1,208 @@ +/* + drivers/net/tulip/timer.c + + Maintained by Jeff Garzik + Copyright 2000 The Linux Kernel Team + Written/copyright 1994-1999 by Donald Becker. + + This software may be used and distributed according to the terms + of the GNU Public License, incorporated herein by reference. + + Please refer to Documentation/networking/tulip.txt for more + information on this driver. + +*/ + +#include "tulip.h" +#include + + +void tulip_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + u32 csr12 = inl(ioaddr + CSR12); + int next_tick = 2*HZ; + + if (tulip_debug > 2) { + printk(KERN_DEBUG "%s: Media selection tick, %s, status %8.8x mode" + " %8.8x SIA %8.8x %8.8x %8.8x %8.8x.\n", + dev->name, medianame[dev->if_port], inl(ioaddr + CSR5), + inl(ioaddr + CSR6), csr12, inl(ioaddr + CSR13), + inl(ioaddr + CSR14), inl(ioaddr + CSR15)); + } + switch (tp->chip_id) { + case DC21040: + if (!tp->medialock && csr12 & 0x0002) { /* Network error */ + printk(KERN_INFO "%s: No link beat found.\n", + dev->name); + dev->if_port = (dev->if_port == 2 ? 0 : 2); + tulip_select_media(dev, 0); + dev->trans_start = jiffies; + } + break; + case DC21041: + if (tulip_debug > 2) + printk(KERN_DEBUG "%s: 21041 media tick CSR12 %8.8x.\n", + dev->name, csr12); + if (tp->medialock) break; + switch (dev->if_port) { + case 0: case 3: case 4: + if (csr12 & 0x0004) { /*LnkFail */ + /* 10baseT is dead. Check for activity on alternate port. */ + tp->mediasense = 1; + if (csr12 & 0x0200) + dev->if_port = 2; + else + dev->if_port = 1; + printk(KERN_INFO "%s: No 21041 10baseT link beat, Media switched to %s.\n", + dev->name, medianame[dev->if_port]); + outl(0, ioaddr + CSR13); /* Reset */ + outl(t21041_csr14[dev->if_port], ioaddr + CSR14); + outl(t21041_csr15[dev->if_port], ioaddr + CSR15); + outl(t21041_csr13[dev->if_port], ioaddr + CSR13); + next_tick = 10*HZ; /* 2.4 sec. */ + } else + next_tick = 30*HZ; + break; + case 1: /* 10base2 */ + case 2: /* AUI */ + if (csr12 & 0x0100) { + next_tick = (30*HZ); /* 30 sec. */ + tp->mediasense = 0; + } else if ((csr12 & 0x0004) == 0) { + printk(KERN_INFO "%s: 21041 media switched to 10baseT.\n", + dev->name); + dev->if_port = 0; + tulip_select_media(dev, 0); + next_tick = (24*HZ)/10; /* 2.4 sec. */ + } else if (tp->mediasense || (csr12 & 0x0002)) { + dev->if_port = 3 - dev->if_port; /* Swap ports. */ + tulip_select_media(dev, 0); + next_tick = 20*HZ; + } else { + next_tick = 20*HZ; + } + break; + } + break; + case DC21140: case DC21142: case MX98713: case COMPEX9881: default: { + struct medialeaf *mleaf; + unsigned char *p; + if (tp->mtable == NULL) { /* No EEPROM info, use generic code. */ + /* Not much that can be done. + Assume this a generic MII or SYM transceiver. */ + next_tick = 60*HZ; + if (tulip_debug > 2) + printk(KERN_DEBUG "%s: network media monitor CSR6 %8.8x " + "CSR12 0x%2.2x.\n", + dev->name, inl(ioaddr + CSR6), csr12 & 0xff); + break; + } + mleaf = &tp->mtable->mleaf[tp->cur_index]; + p = mleaf->leafdata; + switch (mleaf->type) { + case 0: case 4: { + /* Type 0 serial or 4 SYM transceiver. Check the link beat bit. */ + int offset = mleaf->type == 4 ? 5 : 2; + s8 bitnum = p[offset]; + if (p[offset+1] & 0x80) { + if (tulip_debug > 1) + printk(KERN_DEBUG"%s: Transceiver monitor tick " + "CSR12=%#2.2x, no media sense.\n", + dev->name, csr12); + if (mleaf->type == 4) { + if (mleaf->media == 3 && (csr12 & 0x02)) + goto select_next_media; + } + break; + } + if (tulip_debug > 2) + printk(KERN_DEBUG "%s: Transceiver monitor tick: CSR12=%#2.2x" + " bit %d is %d, expecting %d.\n", + dev->name, csr12, (bitnum >> 1) & 7, + (csr12 & (1 << ((bitnum >> 1) & 7))) != 0, + (bitnum >= 0)); + /* Check that the specified bit has the proper value. */ + if ((bitnum < 0) != + ((csr12 & (1 << ((bitnum >> 1) & 7))) != 0)) { + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: Link beat detected for %s.\n", dev->name, + medianame[mleaf->media]); + if ((p[2] & 0x61) == 0x01) /* Bogus Znyx board. */ + goto actually_mii; + break; + } + if (tp->medialock) + break; + select_next_media: + if (--tp->cur_index < 0) { + /* We start again, but should instead look for default. */ + tp->cur_index = tp->mtable->leafcount - 1; + } + dev->if_port = tp->mtable->mleaf[tp->cur_index].media; + if (tulip_media_cap[dev->if_port] & MediaIsFD) + goto select_next_media; /* Skip FD entries. */ + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: No link beat on media %s," + " trying transceiver type %s.\n", + dev->name, medianame[mleaf->media & 15], + medianame[tp->mtable->mleaf[tp->cur_index].media]); + tulip_select_media(dev, 0); + /* Restart the transmit process. */ + tulip_outl_CSR6(tp, tp->csr6 | 0x0002); + tulip_outl_CSR6(tp, tp->csr6 | 0x2002); + next_tick = (24*HZ)/10; + break; + } + case 1: case 3: /* 21140, 21142 MII */ + actually_mii: + tulip_check_duplex(dev); + next_tick = 60*HZ; + break; + case 2: /* 21142 serial block has no link beat. */ + default: + break; + } + } + break; + } + tp->timer.expires = RUN_AT(next_tick); + add_timer(&tp->timer); +} + + +void mxic_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + int next_tick = 60*HZ; + + if (tulip_debug > 3) { + printk(KERN_INFO"%s: MXIC negotiation status %8.8x.\n", dev->name, + inl(ioaddr + CSR12)); + } + if (next_tick) { + tp->timer.expires = RUN_AT(next_tick); + add_timer(&tp->timer); + } +} + + +void comet_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + int next_tick = 60*HZ; + + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: Comet link status %4.4x partner capability " + "%4.4x.\n", + dev->name, inl(ioaddr + 0xB8), inl(ioaddr + 0xC8)); + tp->timer.expires = RUN_AT(next_tick); + add_timer(&tp->timer); +} + diff --git a/drivers/net/tulip/tulip.h b/drivers/net/tulip/tulip.h new file mode 100644 index 000000000..3642a13b4 --- /dev/null +++ b/drivers/net/tulip/tulip.h @@ -0,0 +1,342 @@ +/* + drivers/net/tulip/tulip.h + + Copyright 2000 The Linux Kernel Team + Written/copyright 1994-1999 by Donald Becker. + + This software may be used and distributed according to the terms + of the GNU Public License, incorporated herein by reference. + +*/ + +#ifndef __NET_TULIP_H__ +#define __NET_TULIP_H__ + +#include +#include +#include +#include +#include + + +struct tulip_chip_table { + char *chip_name; + int io_size; + int valid_intrs; /* CSR7 interrupt enable settings */ + int flags; + void (*media_timer) (unsigned long data); +}; + + +enum tbl_flag { + HAS_MII = 1, + HAS_MEDIA_TABLE = 2, + CSR12_IN_SROM = 4, + ALWAYS_CHECK_MII = 8, + HAS_ACPI = 0x10, + MC_HASH_ONLY = 0x20, /* Hash-only multicast filter. */ + HAS_PNICNWAY = 0x80, + HAS_NWAY143 = 0x40, /* Uses internal NWay xcvr. */ + HAS_8023X = 0x100, +}; + + +/* chip types. careful! order is VERY IMPORTANT here, as these + * are used throughout the driver as indices into arrays */ +/* Note 21142 == 21143. */ +enum chips { + DC21040 = 0, + DC21041 = 1, + DC21140 = 2, + DC21142 = 3, DC21143 = 3, + LC82C168, + NGMC169, + MX98713, + MX98715, + MX98725, + AX88140, + PNIC2, + COMET, + COMPEX9881, + I21145, + X3201_3, +}; + + +enum MediaIs { + MediaIsFD = 1, + MediaAlwaysFD = 2, + MediaIsMII = 4, + MediaIsFx = 8, + MediaIs100 = 16 +}; + + +/* Offsets to the Command and Status Registers, "CSRs". All accesses + must be longword instructions and quadword aligned. */ +enum tulip_offsets { + CSR0 = 0, + CSR1 = 0x08, + CSR2 = 0x10, + CSR3 = 0x18, + CSR4 = 0x20, + CSR5 = 0x28, + CSR6 = 0x30, + CSR7 = 0x38, + CSR8 = 0x40, + CSR9 = 0x48, + CSR10 = 0x50, + CSR11 = 0x58, + CSR12 = 0x60, + CSR13 = 0x68, + CSR14 = 0x70, + CSR15 = 0x78 +}; + + +/* The bits in the CSR5 status registers, mostly interrupt sources. */ +enum status_bits { + TimerInt = 0x800, + SytemError = 0x2000, + TPLnkFail = 0x1000, + TPLnkPass = 0x10, + NormalIntr = 0x10000, + AbnormalIntr = 0x8000, + RxJabber = 0x200, + RxDied = 0x100, + RxNoBuf = 0x80, + RxIntr = 0x40, + TxFIFOUnderflow = 0x20, + TxJabber = 0x08, + TxNoBuf = 0x04, + TxDied = 0x02, + TxIntr = 0x01, +}; + + +/* The Tulip Rx and Tx buffer descriptors. */ +struct tulip_rx_desc { + s32 status; + s32 length; + u32 buffer1; + u32 buffer2; +}; + + +struct tulip_tx_desc { + s32 status; + s32 length; + u32 buffer1; + u32 buffer2; /* We use only buffer 1. */ +}; + + +enum desc_status_bits { + DescOwned = 0x80000000, + RxDescFatalErr = 0x8000, + RxWholePkt = 0x0300, +}; + + +/* Keep the ring sizes a power of two for efficiency. + Making the Tx ring too large decreases the effectiveness of channel + bonding and packet priority. + There are no ill effects from too-large receive rings. */ +#define TX_RING_SIZE 16 +#define RX_RING_SIZE 32 + + +#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer. */ + + +/* Ring-wrap flag in length field, use for last ring entry. + 0x01000000 means chain on buffer2 address, + 0x02000000 means use the ring start address in CSR2/3. + Note: Some work-alike chips do not function correctly in chained mode. + The ASIX chip works only in chained mode. + Thus we indicates ring mode, but always write the 'next' field for + chained mode as well. +*/ +#define DESC_RING_WRAP 0x02000000 + + +/* EEPROM_Ctrl bits. */ +#define EE_SHIFT_CLK 0x02 /* EEPROM shift clock. */ +#define EE_CS 0x01 /* EEPROM chip select. */ +#define EE_DATA_WRITE 0x04 /* Data from the Tulip to EEPROM. */ +#define EE_WRITE_0 0x01 +#define EE_WRITE_1 0x05 +#define EE_DATA_READ 0x08 /* Data from the EEPROM chip. */ +#define EE_ENB (0x4800 | EE_CS) + +/* Delay between EEPROM clock transitions. + Even at 33Mhz current PCI implementations don't overrun the EEPROM clock. + We add a bus turn-around to insure that this remains true. */ +#define eeprom_delay() inl(ee_addr) + +/* The EEPROM commands include the alway-set leading bit. */ +#define EE_READ_CMD (6) + +#define EEPROM_SIZE 128 /* 2 << EEPROM_ADDRLEN */ + + +/* The maximum data clock rate is 2.5 Mhz. The minimum timing is usually + met by back-to-back PCI I/O cycles, but we insert a delay to avoid + "overclocking" issues or future 66Mhz PCI. */ +#define mdio_delay() inl(mdio_addr) + +/* Read and write the MII registers using software-generated serial + MDIO protocol. It is just different enough from the EEPROM protocol + to not share code. The maxium data clock rate is 2.5 Mhz. */ +#define MDIO_SHIFT_CLK 0x10000 +#define MDIO_DATA_WRITE0 0x00000 +#define MDIO_DATA_WRITE1 0x20000 +#define MDIO_ENB 0x00000 /* Ignore the 0x02000 databook setting. */ +#define MDIO_ENB_IN 0x40000 +#define MDIO_DATA_READ 0x80000 + + +#define RUN_AT(x) (jiffies + (x)) + + +#if defined(__i386__) /* AKA get_unaligned() */ +#define get_u16(ptr) (*(u16 *)(ptr)) +#else +#define get_u16(ptr) (((u8*)(ptr))[0] + (((u8*)(ptr))[1]<<8)) +#endif + + +/* Condensed operations for readability. */ +#define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr)) +#define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr)) + + +struct medialeaf { + u8 type; + u8 media; + unsigned char *leafdata; +}; + + +struct mediatable { + u16 defaultmedia; + u8 leafcount; + u8 csr12dir; /* General purpose pin directions. */ + unsigned has_mii:1; + unsigned has_nonmii:1; + unsigned has_reset:6; + u32 csr15dir; + u32 csr15val; /* 21143 NWay setting. */ + struct medialeaf mleaf[0]; +}; + + +struct mediainfo { + struct mediainfo *next; + int info_type; + int index; + unsigned char *info; +}; + + +struct tulip_private { + const char *product_name; + struct net_device *next_module; + struct tulip_rx_desc rx_ring[RX_RING_SIZE]; + struct tulip_tx_desc tx_ring[TX_RING_SIZE]; + /* The saved address of a sent-in-place packet/buffer, for skfree(). */ + struct sk_buff *tx_skbuff[TX_RING_SIZE]; + /* The addresses of receive-in-place skbuffs. */ + struct sk_buff *rx_skbuff[RX_RING_SIZE]; + char *rx_buffs; /* Address of temporary Rx buffers. */ + u16 setup_frame[96]; /* Pseudo-Tx frame to init address table. */ + int chip_id; + int revision; + int flags; + struct net_device_stats stats; + struct timer_list timer; /* Media selection timer. */ + spinlock_t lock; + unsigned int cur_rx, cur_tx; /* The next free ring entry */ + unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */ + unsigned int tx_full:1; /* The Tx queue is full. */ + unsigned int full_duplex:1; /* Full-duplex operation requested. */ + unsigned int full_duplex_lock:1; + unsigned int fake_addr:1; /* Multiport board faked address. */ + unsigned int default_port:4; /* Last dev->if_port value. */ + unsigned int media2:4; /* Secondary monitored media port. */ + unsigned int medialock:1; /* Don't sense media type. */ + unsigned int mediasense:1; /* Media sensing in progress. */ + unsigned int nway:1, nwayset:1; /* 21143 internal NWay. */ + unsigned int csr0; /* CSR0 setting. */ + unsigned int csr6; /* Current CSR6 control settings. */ + unsigned char eeprom[EEPROM_SIZE]; /* Serial EEPROM contents. */ + void (*link_change) (struct net_device * dev, int csr5); + u16 to_advertise; /* NWay capabilities advertised. */ + u16 lpar; /* 21143 Link partner ability. */ + u16 advertising[4]; + signed char phys[4], mii_cnt; /* MII device addresses. */ + struct mediatable *mtable; + int cur_index; /* Current media index. */ + int saved_if_port; + struct pci_dev *pdev; + int ttimer; + int susp_rx; + unsigned long nir; + unsigned long base_addr; + int pad0, pad1; /* Used for 8-byte alignment */ +}; + + +struct eeprom_fixup { + char *name; + unsigned char addr0; + unsigned char addr1; + unsigned char addr2; + u16 newtable[32]; /* Max length below. */ +}; + + +/* 21142.c */ +extern u16 t21142_csr14[]; +void t21142_timer(unsigned long data); +void t21142_start_nway(struct net_device *dev); +void t21142_lnk_change(struct net_device *dev, int csr5); + +/* eeprom.c */ +void tulip_parse_eeprom(struct net_device *dev); +int tulip_read_eeprom(long ioaddr, int location, int addr_len); + +/* interrupt.c */ +extern int tulip_max_interrupt_work; +extern int tulip_rx_copybreak; +void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs); + +/* media.c */ +int tulip_mdio_read(struct net_device *dev, int phy_id, int location); +void tulip_mdio_write(struct net_device *dev, int phy_id, int location, int value); +void tulip_select_media(struct net_device *dev, int startup); +int tulip_check_duplex(struct net_device *dev); + +/* pnic.c */ +void pnic_do_nway(struct net_device *dev); +void pnic_lnk_change(struct net_device *dev, int csr5); +void pnic_timer(unsigned long data); + +/* timer.c */ +void tulip_timer(unsigned long data); +void mxic_timer(unsigned long data); +void comet_timer(unsigned long data); + +/* tulip_core.c */ +extern int tulip_debug; +extern const char * const medianame[]; +extern const char tulip_media_cap[]; +extern struct tulip_chip_table tulip_tbl[]; +extern u8 t21040_csr13[]; +extern u16 t21041_csr13[]; +extern u16 t21041_csr14[]; +extern u16 t21041_csr15[]; +void tulip_outl_CSR6 (struct tulip_private *tp, u32 newcsr6); + + +#endif /* __NET_TULIP_H__ */ diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c new file mode 100644 index 000000000..3be78468b --- /dev/null +++ b/drivers/net/tulip/tulip_core.c @@ -0,0 +1,1391 @@ +/* tulip_core.c: A DEC 21040-family ethernet driver for Linux. */ + +/* + Maintained by Jeff Garzik + Copyright 2000 The Linux Kernel Team + Written/copyright 1994-1999 by Donald Becker. + + This software may be used and distributed according to the terms + of the GNU Public License, incorporated herein by reference. + + Please read Documentation/networking/tulip.txt for more + information. + + For this specific driver variant please use linux-kernel for + bug reports. + + Additional information available at + http://cesdis.gsfc.nasa.gov/linux/drivers/tulip.html + +*/ + +static const char version[] = "Linux Tulip driver version 0.9.3 (Feb 23, 2000)\n"; + +#include +#include "tulip.h" +#include +#include +#include +#include +#include +#include + + +/* A few user-configurable values. */ + +/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ +static int max_interrupt_work = 25; + +#define MAX_UNITS 8 +/* Used to pass the full-duplex flag, etc. */ +static int full_duplex[MAX_UNITS] = {0, }; +static int options[MAX_UNITS] = {0, }; +static int mtu[MAX_UNITS] = {0, }; /* Jumbo MTU for interfaces. */ + +/* The possible media types that can be set in options[] are: */ +const char * const medianame[] = { + "10baseT", "10base2", "AUI", "100baseTx", + "10baseT-FD", "100baseTx-FD", "100baseT4", "100baseFx", + "100baseFx-FD", "MII 10baseT", "MII 10baseT-FD", "MII", + "10baseT(forced)", "MII 100baseTx", "MII 100baseTx-FD", "MII 100baseT4", +}; + +/* Set the copy breakpoint for the copy-only-tiny-buffer Rx structure. */ +#ifdef __alpha__ +static int rx_copybreak = 1518; +#else +static int rx_copybreak = 100; +#endif + +/* + Set the bus performance register. + Typical: Set 16 longword cache alignment, no burst limit. + Cache alignment bits 15:14 Burst length 13:8 + 0000 No alignment 0x00000000 unlimited 0800 8 longwords + 4000 8 longwords 0100 1 longword 1000 16 longwords + 8000 16 longwords 0200 2 longwords 2000 32 longwords + C000 32 longwords 0400 4 longwords + Warning: many older 486 systems are broken and require setting 0x00A04800 + 8 longword cache alignment, 8 longword burst. + ToDo: Non-Intel setting could be better. +*/ + +#if defined(__alpha__) +static int csr0 = 0x01A00000 | 0xE000; +#elif defined(__i386__) || defined(__powerpc__) || defined(__sparc__) +static int csr0 = 0x01A00000 | 0x8000; +#else +#warning Processor architecture undefined! +static int csr0 = 0x00A00000 | 0x4800; +#endif + +/* Operational parameters that usually are not changed. */ +/* Time in jiffies before concluding the transmitter is hung. */ +#define TX_TIMEOUT (4*HZ) + + +/* Kernel compatibility defines, some common to David Hind's PCMCIA package. + This is only in the support-all-kernels source code. */ + +MODULE_AUTHOR("The Linux Kernel Team"); +MODULE_DESCRIPTION("Digital 21*4* Tulip ethernet driver"); +MODULE_PARM(tulip_debug, "i"); +MODULE_PARM(max_interrupt_work, "i"); +MODULE_PARM(rx_copybreak, "i"); +MODULE_PARM(csr0, "i"); +MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); + +#define TULIP_MODULE_NAME "tulip" +#define PFX TULIP_MODULE_NAME ": " + +#ifdef TULIP_DEBUG +int tulip_debug = TULIP_DEBUG; +#else +int tulip_debug = 1; +#endif + + + +/* + * This table use during operation for capabilities and media timer. + * + * It is indexed via the values in 'enum chips' + */ + +struct tulip_chip_table tulip_tbl[] = { + { "Digital DC21040 Tulip", 128, 0x0001ebef, 0, tulip_timer }, + { "Digital DC21041 Tulip", 128, 0x0001ebff, HAS_MEDIA_TABLE, tulip_timer }, + { "Digital DS21140 Tulip", 128, 0x0001ebef, + HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, tulip_timer }, + { "Digital DS21143 Tulip", 128, 0x0801fbff, + HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI | HAS_NWAY143, + t21142_timer }, + { "Lite-On 82c168 PNIC", 256, 0x0001ebef, + HAS_MII | HAS_PNICNWAY, pnic_timer }, + { "NETGEAR NGMC169 MAC", 256, 0x0001ebef, + HAS_MII | HAS_PNICNWAY, pnic_timer }, + { "Macronix 98713 PMAC", 128, 0x0001ebef, + HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer }, + { "Macronix 98715 PMAC", 256, 0x0001ebef, + HAS_MEDIA_TABLE, mxic_timer }, + { "Macronix 98725 PMAC", 256, 0x0001ebef, + HAS_MEDIA_TABLE, mxic_timer }, + { "ASIX AX88140", 128, 0x0001fbff, + HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | MC_HASH_ONLY, tulip_timer }, + { "Lite-On PNIC-II", 256, 0x0801fbff, + HAS_MII | HAS_NWAY143 | HAS_8023X, t21142_timer }, + { "ADMtek Comet", 256, 0x0001abef, + MC_HASH_ONLY, comet_timer }, + { "Compex 9881 PMAC", 128, 0x0001ebef, + HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer }, + { "Intel DS21145 Tulip", 128, 0x0801fbff, + HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_NWAY143, + t21142_timer }, + { "Xircom tulip work-alike", 128, 0x0801fbff, + HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI | HAS_NWAY143, + t21142_timer }, + {0}, +}; + + +static struct pci_device_id tulip_pci_tbl[] __devinitdata = { + { 0x1011, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21040 }, + { 0x1011, 0x0014, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21041 }, + { 0x1011, 0x0009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21140 }, + { 0x1011, 0x0019, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21143 }, + { 0x11AD, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, LC82C168 }, + { 0x1385, 0xf004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, NGMC169 }, + { 0x10d9, 0x0512, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98713 }, + { 0x10d9, 0x0531, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98715 }, + { 0x10d9, 0x0531, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98725 }, + { 0x125B, 0x1400, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AX88140 }, + { 0x11AD, 0xc115, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PNIC2 }, + { 0x1317, 0x0981, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, + { 0x11F6, 0x9881, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMPEX9881 }, + { 0x8086, 0x0039, PCI_ANY_ID, PCI_ANY_ID, 0, 0, I21145 }, + { 0x115d, 0x0003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, X3201_3 }, + {0}, +}; +MODULE_DEVICE_TABLE(pci,tulip_pci_tbl); + + +/* A full-duplex map for media types. */ +const char tulip_media_cap[] = +{0,0,0,16, 3,19,16,24, 27,4,7,5, 0,20,23,20 }; +u8 t21040_csr13[] = {2,0x0C,8,4, 4,0,0,0, 0,0,0,0, 4,0,0,0}; + +/* 21041 transceiver register settings: 10-T, 10-2, AUI, 10-T, 10T-FD*/ +u16 t21041_csr13[] = { 0xEF01, 0xEF09, 0xEF09, 0xEF01, 0xEF09, }; +u16 t21041_csr14[] = { 0xFFFF, 0xF7FD, 0xF7FD, 0x7F3F, 0x7F3D, }; +u16 t21041_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, }; + + +static void tulip_tx_timeout(struct net_device *dev); +static void tulip_init_ring(struct net_device *dev); +static int tulip_start_xmit(struct sk_buff *skb, struct net_device *dev); +static int tulip_open(struct net_device *dev); +static int tulip_close(struct net_device *dev); +static void tulip_up(struct net_device *dev); +static void tulip_down(struct net_device *dev); +static struct net_device_stats *tulip_get_stats(struct net_device *dev); +static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +static void set_rx_mode(struct net_device *dev); + + +/* The Xircom cards are picky about when certain bits in CSR6 can be + manipulated. Keith Owens . */ + +void tulip_outl_CSR6 (struct tulip_private *tp, u32 newcsr6) +{ + long ioaddr = tp->base_addr; + const int strict_bits = 0x0060e202; + int csr5, csr5_22_20, csr5_19_17, currcsr6, attempts = 200; + + /* common path */ + if (tp->chip_id != X3201_3) { + outl (newcsr6, ioaddr + CSR6); + return; + } + + newcsr6 &= 0x726cfeca; /* mask out the reserved CSR6 bits that always */ + /* read 0 on the Xircom cards */ + newcsr6 |= 0x320c0000; /* or in the reserved bits that always read 1 */ + currcsr6 = inl (ioaddr + CSR6); + if (((newcsr6 & strict_bits) == (currcsr6 & strict_bits)) || + ((currcsr6 & ~0x2002) == 0)) + goto out_write; + + /* make sure the transmitter and receiver are stopped first */ + currcsr6 &= ~0x2002; + while (1) { + csr5 = inl (ioaddr + CSR5); + if (csr5 == 0xffffffff) + break; /* cannot read csr5, card removed? */ + csr5_22_20 = csr5 & 0x700000; + csr5_19_17 = csr5 & 0x0e0000; + if ((csr5_22_20 == 0 || csr5_22_20 == 0x600000) && + (csr5_19_17 == 0 || csr5_19_17 == 0x80000 || csr5_19_17 == 0xc0000)) + break; /* both are stopped or suspended */ + if (!--attempts) { + printk (KERN_INFO "tulip.c: tulip_outl_CSR6 too many attempts," + "csr5=0x%08x\n", csr5); + goto out_write; + } + outl (currcsr6, ioaddr + CSR6); + udelay (1); + } + +out_write: + /* now it is safe to change csr6 */ + outl (newcsr6, ioaddr + CSR6); +} + + +static void tulip_up(struct net_device *dev) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + int next_tick = 3*HZ; + int i; + + /* Wake the chip from sleep/snooze mode. */ + if (tp->flags & HAS_ACPI) + pci_write_config_dword(tp->pdev, 0x40, 0); + + /* On some chip revs we must set the MII/SYM port before the reset!? */ + if (tp->mii_cnt || (tp->mtable && tp->mtable->has_mii)) + tulip_outl_CSR6 (tp, 0x00040000); + + /* Reset the chip, holding bit 0 set at least 50 PCI cycles. */ + outl(0x00000001, ioaddr + CSR0); + + /* Deassert reset. + Wait the specified 50 PCI cycles after a reset by initializing + Tx and Rx queues and the address filter list. */ + outl(tp->csr0, ioaddr + CSR0); + + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: tulip_up(), irq==%d.\n", dev->name, dev->irq); + + if (tp->flags & MC_HASH_ONLY) { + u32 addr_low = cpu_to_le32(get_unaligned((u32 *)dev->dev_addr)); + u32 addr_high = cpu_to_le32(get_unaligned((u16 *)(dev->dev_addr+4))); + if (tp->chip_id == AX88140) { + outl(0, ioaddr + CSR13); + outl(addr_low, ioaddr + CSR14); + outl(1, ioaddr + CSR13); + outl(addr_high, ioaddr + CSR14); + } else if (tp->chip_id == COMET) { + outl(addr_low, ioaddr + 0xA4); + outl(addr_high, ioaddr + 0xA8); + outl(0, ioaddr + 0xAC); + outl(0, ioaddr + 0xB0); + } + } else { + /* This is set_rx_mode(), but without starting the transmitter. */ + u16 *eaddrs = (u16 *)dev->dev_addr; + u16 *setup_frm = &tp->setup_frame[15*6]; + + /* 21140 bug: you must add the broadcast address. */ + memset(tp->setup_frame, 0xff, sizeof(tp->setup_frame)); + /* Fill the final entry of the table with our physical address. */ + *setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0]; + *setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1]; + *setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2]; + /* Put the setup frame on the Tx list. */ + tp->tx_ring[0].length = cpu_to_le32(0x08000000 | 192); + tp->tx_ring[0].buffer1 = virt_to_le32desc(tp->setup_frame); + tp->tx_ring[0].status = cpu_to_le32(DescOwned); + + tp->cur_tx++; + } + + outl(virt_to_bus(tp->rx_ring), ioaddr + CSR3); + outl(virt_to_bus(tp->tx_ring), ioaddr + CSR4); + + tp->saved_if_port = dev->if_port; + if (dev->if_port == 0) + dev->if_port = tp->default_port; + + /* Allow selecting a default media. */ + i = 0; + if (tp->mtable == NULL) + goto media_picked; + if (dev->if_port) { + int looking_for = tulip_media_cap[dev->if_port] & MediaIsMII ? 11 : + (dev->if_port == 12 ? 0 : dev->if_port); + for (i = 0; i < tp->mtable->leafcount; i++) + if (tp->mtable->mleaf[i].media == looking_for) { + printk(KERN_INFO "%s: Using user-specified media %s.\n", + dev->name, medianame[dev->if_port]); + goto media_picked; + } + } + if ((tp->mtable->defaultmedia & 0x0800) == 0) { + int looking_for = tp->mtable->defaultmedia & 15; + for (i = 0; i < tp->mtable->leafcount; i++) + if (tp->mtable->mleaf[i].media == looking_for) { + printk(KERN_INFO "%s: Using EEPROM-set media %s.\n", + dev->name, medianame[looking_for]); + goto media_picked; + } + } + /* Start sensing first non-full-duplex media. */ + for (i = tp->mtable->leafcount - 1; + (tulip_media_cap[tp->mtable->mleaf[i].media] & MediaAlwaysFD) && i > 0; i--) + ; +media_picked: + + tp->csr6 = 0; + tp->cur_index = i; + tp->nwayset = 0; + if (dev->if_port == 0 && tp->chip_id == DC21041) { + tp->nway = 1; + } + if (dev->if_port == 0 && tp->chip_id == DC21142) { + if (tp->mii_cnt) { + tulip_select_media(dev, 1); + if (tulip_debug > 1) + printk(KERN_INFO "%s: Using MII transceiver %d, status " + "%4.4x.\n", + dev->name, tp->phys[0], tulip_mdio_read(dev, tp->phys[0], 1)); + tulip_outl_CSR6(tp, 0x82020000); + tp->csr6 = 0x820E0000; + dev->if_port = 11; + outl(0x0000, ioaddr + CSR13); + outl(0x0000, ioaddr + CSR14); + } else + t21142_start_nway(dev); + } else if (tp->chip_id == PNIC2) { + t21142_start_nway(dev); + } else if (tp->chip_id == LC82C168 && ! tp->medialock) { + if (tp->mii_cnt) { + dev->if_port = 11; + tp->csr6 = 0x814C0000 | (tp->full_duplex ? 0x0200 : 0); + outl(0x0001, ioaddr + CSR15); + } else if (inl(ioaddr + CSR5) & TPLnkPass) + pnic_do_nway(dev); + else { + /* Start with 10mbps to do autonegotiation. */ + outl(0x32, ioaddr + CSR12); + tp->csr6 = 0x00420000; + outl(0x0001B078, ioaddr + 0xB8); + outl(0x0201B078, ioaddr + 0xB8); + next_tick = 1*HZ; + } + } else if ((tp->chip_id == MX98713 || tp->chip_id == COMPEX9881) + && ! tp->medialock) { + dev->if_port = 0; + tp->csr6 = 0x01880000 | (tp->full_duplex ? 0x0200 : 0); + outl(0x0f370000 | inw(ioaddr + 0x80), ioaddr + 0x80); + } else if (tp->chip_id == MX98715 || tp->chip_id == MX98725) { + /* Provided by BOLO, Macronix - 12/10/1998. */ + dev->if_port = 0; + tp->csr6 = 0x01a80200; + outl(0x0f370000 | inw(ioaddr + 0x80), ioaddr + 0x80); + outl(0x11000 | inw(ioaddr + 0xa0), ioaddr + 0xa0); + } else if (tp->chip_id == DC21143 && + tulip_media_cap[dev->if_port] & MediaIsMII) { + /* We must reset the media CSRs when we force-select MII mode. */ + outl(0x0000, ioaddr + CSR13); + outl(0x0000, ioaddr + CSR14); + outl(0x0008, ioaddr + CSR15); + } else if (tp->chip_id == COMET) { + dev->if_port = 0; + tp->csr6 = 0x00040000; + } else if (tp->chip_id == AX88140) { + tp->csr6 = tp->mii_cnt ? 0x00040100 : 0x00000100; + } else + tulip_select_media(dev, 1); + + /* Start the chip's Tx to process setup frame. */ + tulip_outl_CSR6(tp, tp->csr6); + tulip_outl_CSR6(tp, tp->csr6 | 0x2000); + + /* Enable interrupts by setting the interrupt mask. */ + outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR5); + outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7); + tulip_outl_CSR6(tp, tp->csr6 | 0x2002); + outl(0, ioaddr + CSR2); /* Rx poll demand */ + + if (tulip_debug > 2) { + printk(KERN_DEBUG "%s: Done tulip_open(), CSR0 %8.8x, CSR5 %8.8x CSR6 %8.8x.\n", + dev->name, inl(ioaddr + CSR0), inl(ioaddr + CSR5), + inl(ioaddr + CSR6)); + } + /* Set the timer to switch to check for link beat and perhaps switch + to an alternate media type. */ + init_timer(&tp->timer); + tp->timer.expires = RUN_AT(next_tick); + tp->timer.data = (unsigned long)dev; + tp->timer.function = tulip_tbl[tp->chip_id].media_timer; + add_timer(&tp->timer); + + netif_device_attach(dev); +} + + +static int +tulip_open(struct net_device *dev) +{ + MOD_INC_USE_COUNT; + + if (request_irq(dev->irq, &tulip_interrupt, SA_SHIRQ, dev->name, dev)) { + MOD_DEC_USE_COUNT; + return -EBUSY; + } + + tulip_init_ring (dev); + + tulip_up (dev); + + return 0; +} + + +static void tulip_tx_timeout(struct net_device *dev) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + unsigned long flags; + + spin_lock_irqsave (&tp->lock, flags); + + if (tulip_media_cap[dev->if_port] & MediaIsMII) { + /* Do nothing -- the media monitor should handle this. */ + if (tulip_debug > 1) + printk(KERN_WARNING "%s: Transmit timeout using MII device.\n", + dev->name); + } else if (tp->chip_id == DC21040) { + if ( !tp->medialock && inl(ioaddr + CSR12) & 0x0002) { + dev->if_port = (dev->if_port == 2 ? 0 : 2); + printk(KERN_INFO "%s: 21040 transmit timed out, switching to " + "%s.\n", + dev->name, medianame[dev->if_port]); + tulip_select_media(dev, 0); + } + goto out; + } else if (tp->chip_id == DC21041) { + int csr12 = inl(ioaddr + CSR12); + + printk(KERN_WARNING "%s: 21041 transmit timed out, status %8.8x, " + "CSR12 %8.8x, CSR13 %8.8x, CSR14 %8.8x, resetting...\n", + dev->name, inl(ioaddr + CSR5), csr12, + inl(ioaddr + CSR13), inl(ioaddr + CSR14)); + tp->mediasense = 1; + if ( ! tp->medialock) { + if (dev->if_port == 1 || dev->if_port == 2) + if (csr12 & 0x0004) { + dev->if_port = 2 - dev->if_port; + } else + dev->if_port = 0; + else + dev->if_port = 1; + tulip_select_media(dev, 0); + } + } else if (tp->chip_id == DC21140 || tp->chip_id == DC21142 + || tp->chip_id == MX98713 || tp->chip_id == COMPEX9881) { + printk(KERN_WARNING "%s: 21140 transmit timed out, status %8.8x, " + "SIA %8.8x %8.8x %8.8x %8.8x, resetting...\n", + dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR12), + inl(ioaddr + CSR13), inl(ioaddr + CSR14), inl(ioaddr + CSR15)); + if ( ! tp->medialock && tp->mtable) { + do + --tp->cur_index; + while (tp->cur_index >= 0 + && (tulip_media_cap[tp->mtable->mleaf[tp->cur_index].media] + & MediaIsFD)); + if (--tp->cur_index < 0) { + /* We start again, but should instead look for default. */ + tp->cur_index = tp->mtable->leafcount - 1; + } + tulip_select_media(dev, 0); + printk(KERN_WARNING "%s: transmit timed out, switching to %s " + "media.\n", dev->name, medianame[dev->if_port]); + } + } else { + printk(KERN_WARNING "%s: Transmit timed out, status %8.8x, CSR12 " + "%8.8x, resetting...\n", + dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR12)); + dev->if_port = 0; + } + +#if defined(way_too_many_messages) + if (tulip_debug > 3) { + int i; + for (i = 0; i < RX_RING_SIZE; i++) { + u8 *buf = (u8 *)(tp->rx_ring[i].buffer1); + int j; + printk(KERN_DEBUG "%2d: %8.8x %8.8x %8.8x %8.8x " + "%2.2x %2.2x %2.2x.\n", + i, (unsigned int)tp->rx_ring[i].status, + (unsigned int)tp->rx_ring[i].length, + (unsigned int)tp->rx_ring[i].buffer1, + (unsigned int)tp->rx_ring[i].buffer2, + buf[0], buf[1], buf[2]); + for (j = 0; buf[j] != 0xee && j < 1600; j++) + if (j < 100) printk(" %2.2x", buf[j]); + printk(" j=%d.\n", j); + } + printk(KERN_DEBUG " Rx ring %8.8x: ", (int)tp->rx_ring); + for (i = 0; i < RX_RING_SIZE; i++) + printk(" %8.8x", (unsigned int)tp->rx_ring[i].status); + printk("\n" KERN_DEBUG " Tx ring %8.8x: ", (int)tp->tx_ring); + for (i = 0; i < TX_RING_SIZE; i++) + printk(" %8.8x", (unsigned int)tp->tx_ring[i].status); + printk("\n"); + } +#endif + + /* Stop and restart the chip's Tx processes . */ + tulip_outl_CSR6(tp, tp->csr6 | 0x0002); + tulip_outl_CSR6(tp, tp->csr6 | 0x2002); + /* Trigger an immediate transmit demand. */ + outl(0, ioaddr + CSR1); + + tp->stats.tx_errors++; + +out: + dev->trans_start = jiffies; + netif_start_queue (dev); + spin_unlock_irqrestore (&tp->lock, flags); +} + + +/* Initialize the Rx and Tx rings, along with various 'dev' bits. */ +static void tulip_init_ring(struct net_device *dev) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + int i; + + tp->tx_full = 0; + tp->cur_rx = tp->cur_tx = 0; + tp->dirty_rx = tp->dirty_tx = 0; + tp->susp_rx = 0; + tp->ttimer = 0; + tp->nir = 0; + + for (i = 0; i < RX_RING_SIZE; i++) { + tp->rx_ring[i].status = 0x00000000; + tp->rx_ring[i].length = cpu_to_le32(PKT_BUF_SZ); + tp->rx_ring[i].buffer2 = virt_to_le32desc(&tp->rx_ring[i+1]); + tp->rx_skbuff[i] = NULL; + } + /* Mark the last entry as wrapping the ring. */ + tp->rx_ring[i-1].length = cpu_to_le32(PKT_BUF_SZ | DESC_RING_WRAP); + tp->rx_ring[i-1].buffer2 = virt_to_le32desc(&tp->rx_ring[0]); + + for (i = 0; i < RX_RING_SIZE; i++) { + /* Note the receive buffer must be longword aligned. + dev_alloc_skb() provides 16 byte alignment. But do *not* + use skb_reserve() to align the IP header! */ + struct sk_buff *skb = dev_alloc_skb(PKT_BUF_SZ); + tp->rx_skbuff[i] = skb; + if (skb == NULL) + break; + skb->dev = dev; /* Mark as being used by this device. */ + tp->rx_ring[i].status = cpu_to_le32(DescOwned); /* Owned by Tulip chip */ + tp->rx_ring[i].buffer1 = virt_to_le32desc(skb->tail); + } + tp->dirty_rx = (unsigned int)(i - RX_RING_SIZE); + + /* The Tx buffer descriptor is filled in as needed, but we + do need to clear the ownership bit. */ + for (i = 0; i < TX_RING_SIZE; i++) { + tp->tx_skbuff[i] = 0; + tp->tx_ring[i].status = 0x00000000; + tp->tx_ring[i].buffer2 = virt_to_le32desc(&tp->tx_ring[i+1]); + } + tp->tx_ring[i-1].buffer2 = virt_to_le32desc(&tp->tx_ring[0]); +} + +static int +tulip_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + int entry; + u32 flag; + unsigned long cpuflags; + + /* Caution: the write order is important here, set the field + with the ownership bits last. */ + + spin_lock_irqsave(&tp->lock, cpuflags); + + /* Calculate the next Tx descriptor entry. */ + entry = tp->cur_tx % TX_RING_SIZE; + + tp->tx_skbuff[entry] = skb; + tp->tx_ring[entry].buffer1 = virt_to_le32desc(skb->data); + + if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE/2) {/* Typical path */ + flag = 0x60000000; /* No interrupt */ + } else if (tp->cur_tx - tp->dirty_tx == TX_RING_SIZE/2) { + flag = 0xe0000000; /* Tx-done intr. */ + } else if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE - 2) { + flag = 0x60000000; /* No Tx-done intr. */ + } else { /* Leave room for set_rx_mode() to fill entries. */ + tp->tx_full = 1; + flag = 0xe0000000; /* Tx-done intr. */ + netif_stop_queue(dev); + } + if (entry == TX_RING_SIZE-1) + flag = 0xe0000000 | DESC_RING_WRAP; + + tp->tx_ring[entry].length = cpu_to_le32(skb->len | flag); + tp->tx_ring[entry].status = cpu_to_le32(DescOwned); + tp->cur_tx++; + + /* Trigger an immediate transmit demand. */ + outl(0, dev->base_addr + CSR1); + + spin_unlock_irqrestore(&tp->lock, cpuflags); + + dev->trans_start = jiffies; + + return 0; +} + +static void tulip_down (struct net_device *dev) +{ + long ioaddr = dev->base_addr; + struct tulip_private *tp = (struct tulip_private *) dev->priv; + unsigned long flags; + + netif_device_detach (dev); + + del_timer (&tp->timer); + + spin_lock_irqsave (&tp->lock, flags); + + /* Disable interrupts by clearing the interrupt mask. */ + outl (0x00000000, ioaddr + CSR7); + + /* Stop the Tx and Rx processes. */ + tulip_outl_CSR6 (tp, inl (ioaddr + CSR6) & ~0x2002); + + /* 21040 -- Leave the card in 10baseT state. */ + if (tp->chip_id == DC21040) + outl (0x00000004, ioaddr + CSR13); + + if (inl (ioaddr + CSR6) != 0xffffffff) + tp->stats.rx_missed_errors += inl (ioaddr + CSR8) & 0xffff; + + spin_unlock_irqrestore (&tp->lock, flags); + + dev->if_port = tp->saved_if_port; + + /* Leave the driver in snooze, not sleep, mode. */ + if (tp->flags & HAS_ACPI) + pci_write_config_dword (tp->pdev, 0x40, 0x40000000); +} + + +static int tulip_close (struct net_device *dev) +{ + long ioaddr = dev->base_addr; + struct tulip_private *tp = (struct tulip_private *) dev->priv; + int i; + + tulip_down (dev); + + if (tulip_debug > 1) + printk (KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n", + dev->name, inl (ioaddr + CSR5)); + + free_irq (dev->irq, dev); + + /* Free all the skbuffs in the Rx queue. */ + for (i = 0; i < RX_RING_SIZE; i++) { + struct sk_buff *skb = tp->rx_skbuff[i]; + tp->rx_skbuff[i] = 0; + tp->rx_ring[i].status = 0; /* Not owned by Tulip chip. */ + tp->rx_ring[i].length = 0; + tp->rx_ring[i].buffer1 = 0xBADF00D0; /* An invalid address. */ + if (skb) { + dev_kfree_skb (skb); + } + } + for (i = 0; i < TX_RING_SIZE; i++) { + if (tp->tx_skbuff[i]) + dev_kfree_skb (tp->tx_skbuff[i]); + tp->tx_skbuff[i] = 0; + } + + MOD_DEC_USE_COUNT; + + return 0; +} + +static struct enet_statistics *tulip_get_stats(struct net_device *dev) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + + if (netif_running(dev)) { + unsigned long flags; + + spin_lock_irqsave (&tp->lock, flags); + + tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff; + + spin_unlock_irqrestore(&tp->lock, flags); + } + + return &tp->stats; +} + + +/* Provide ioctl() calls to examine the MII xcvr state. */ +static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + u16 *data = (u16 *)&rq->ifr_data; + int phy = tp->phys[0] & 0x1f; + long flags; + + switch(cmd) { + case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ + if (tp->mii_cnt) + data[0] = phy; + else if (tp->flags & HAS_NWAY143) + data[0] = 32; + else if (tp->chip_id == COMET) + data[0] = 1; + else + return -ENODEV; + case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ + if (data[0] == 32 && (tp->flags & HAS_NWAY143)) { + int csr12 = inl(ioaddr + CSR12); + int csr14 = inl(ioaddr + CSR14); + switch (data[1]) { + case 0: { + data[3] = (csr14<<5) & 0x1000; + break; } + case 1: + data[3] = 0x7848 + ((csr12&0x7000) == 0x5000 ? 0x20 : 0) + + (csr12&0x06 ? 0x04 : 0); + break; + case 4: { + data[3] = ((csr14>>9)&0x07C0) + + ((inl(ioaddr + CSR6)>>3)&0x0040) + ((csr14>>1)&0x20) + 1; + break; + } + case 5: data[3] = csr12 >> 16; break; + default: data[3] = 0; break; + } + } else { + spin_lock_irqsave (&tp->lock, flags); + data[3] = tulip_mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f); + spin_unlock_irqrestore (&tp->lock, flags); + } + return 0; + case SIOCDEVPRIVATE+2: /* Write the specified MII register */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + if (data[0] == 32 && (tp->flags & HAS_NWAY143)) { + if (data[1] == 5) + tp->to_advertise = data[2]; + } else { + spin_lock_irqsave (&tp->lock, flags); + tulip_mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]); + spin_unlock_irqrestore(&tp->lock, flags); + } + return 0; + default: + return -EOPNOTSUPP; + } + + return -EOPNOTSUPP; +} + + +/* Set or clear the multicast filter for this adaptor. + Note that we only use exclusion around actually queueing the + new frame, not around filling tp->setup_frame. This is non-deterministic + when re-entered but still correct. */ + +/* The little-endian AUTODIN32 ethernet CRC calculation. + N.B. Do not use for bulk data, use a table-based routine instead. + This is common code and should be moved to net/core/crc.c */ +static unsigned const ethernet_polynomial_le = 0xedb88320U; +static inline u32 ether_crc_le(int length, unsigned char *data) +{ + u32 crc = 0xffffffff; /* Initial value. */ + while(--length >= 0) { + unsigned char current_octet = *data++; + int bit; + for (bit = 8; --bit >= 0; current_octet >>= 1) { + if ((crc ^ current_octet) & 1) { + crc >>= 1; + crc ^= ethernet_polynomial_le; + } else + crc >>= 1; + } + } + return crc; +} +static unsigned const ethernet_polynomial = 0x04c11db7U; +static inline u32 ether_crc(int length, unsigned char *data) +{ + int crc = -1; + + while(--length >= 0) { + unsigned char current_octet = *data++; + int bit; + for (bit = 0; bit < 8; bit++, current_octet >>= 1) + crc = (crc << 1) ^ + ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0); + } + return crc; +} + +static void set_rx_mode(struct net_device *dev) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + int csr6 = inl(ioaddr + CSR6) & ~0x00D5; + + tp->csr6 &= ~0x00D5; + if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ + tp->csr6 |= 0x00C0; + csr6 |= 0x00C0; + /* Unconditionally log net taps. */ + printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name); + } else if ((dev->mc_count > 1000) || (dev->flags & IFF_ALLMULTI)) { + /* Too many to filter well -- accept all multicasts. */ + tp->csr6 |= 0x0080; + csr6 |= 0x0080; + } else if (tp->flags & MC_HASH_ONLY) { + /* Some work-alikes have only a 64-entry hash filter table. */ + /* Should verify correctness on big-endian/__powerpc__ */ + struct dev_mc_list *mclist; + int i; + u32 mc_filter[2]; /* Multicast hash filter */ + if (dev->mc_count > 64) { /* Arbitrary non-effective limit. */ + tp->csr6 |= 0x0080; + csr6 |= 0x0080; + } else { + mc_filter[1] = mc_filter[0] = 0; + for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + i++, mclist = mclist->next) + set_bit(ether_crc(ETH_ALEN, mclist->dmi_addr)>>26, mc_filter); + if (tp->chip_id == AX88140) { + outl(2, ioaddr + CSR13); + outl(mc_filter[0], ioaddr + CSR14); + outl(3, ioaddr + CSR13); + outl(mc_filter[1], ioaddr + CSR14); + } else if (tp->chip_id == COMET) { /* Has a simple hash filter. */ + outl(mc_filter[0], ioaddr + 0xAC); + outl(mc_filter[1], ioaddr + 0xB0); + } + } + } else { + u16 *eaddrs, *setup_frm = tp->setup_frame; + struct dev_mc_list *mclist; + u32 tx_flags = 0x08000000 | 192; + int i; + unsigned long flags; + + /* Note that only the low-address shortword of setup_frame is valid! + The values are doubled for big-endian architectures. */ + if (dev->mc_count > 14) { /* Must use a multicast hash table. */ + u16 hash_table[32]; + tx_flags = 0x08400000 | 192; /* Use hash filter. */ + memset(hash_table, 0, sizeof(hash_table)); + set_bit(255, hash_table); /* Broadcast entry */ + /* This should work on big-endian machines as well. */ + for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + i++, mclist = mclist->next) + set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x1ff, + hash_table); + for (i = 0; i < 32; i++) + *setup_frm++ = *setup_frm++ = hash_table[i]; + setup_frm = &tp->setup_frame[13*6]; + } else { + /* We have <= 14 addresses so we can use the wonderful + 16 address perfect filtering of the Tulip. */ + for (i = 0, mclist = dev->mc_list; i < dev->mc_count; + i++, mclist = mclist->next) { + eaddrs = (u16 *)mclist->dmi_addr; + *setup_frm++ = *setup_frm++ = *eaddrs++; + *setup_frm++ = *setup_frm++ = *eaddrs++; + *setup_frm++ = *setup_frm++ = *eaddrs++; + } + /* Fill the unused entries with the broadcast address. */ + memset(setup_frm, 0xff, (15-i)*12); + setup_frm = &tp->setup_frame[15*6]; + } + + /* Fill the final entry with our physical address. */ + eaddrs = (u16 *)dev->dev_addr; + *setup_frm++ = *setup_frm++ = eaddrs[0]; + *setup_frm++ = *setup_frm++ = eaddrs[1]; + *setup_frm++ = *setup_frm++ = eaddrs[2]; + + spin_lock_irqsave(&tp->lock, flags); + + if (tp->cur_tx - tp->dirty_tx > TX_RING_SIZE - 2) { + /* Same setup recently queued, we need not add it. */ + } else { + unsigned int entry; + + /* Now add this frame to the Tx list. */ + + entry = tp->cur_tx++ % TX_RING_SIZE; + + if (entry != 0) { + /* Avoid a chip errata by prefixing a dummy entry. */ + tp->tx_skbuff[entry] = 0; + tp->tx_ring[entry].length = + (entry == TX_RING_SIZE-1) ? cpu_to_le32(DESC_RING_WRAP) : 0; + tp->tx_ring[entry].buffer1 = 0; + tp->tx_ring[entry].status = cpu_to_le32(DescOwned); + entry = tp->cur_tx++ % TX_RING_SIZE; + } + + tp->tx_skbuff[entry] = 0; + /* Put the setup frame on the Tx list. */ + if (entry == TX_RING_SIZE-1) + tx_flags |= DESC_RING_WRAP; /* Wrap ring. */ + tp->tx_ring[entry].length = cpu_to_le32(tx_flags); + tp->tx_ring[entry].buffer1 = virt_to_le32desc(tp->setup_frame); + tp->tx_ring[entry].status = cpu_to_le32(DescOwned); + if (tp->cur_tx - tp->dirty_tx >= TX_RING_SIZE - 2) { + netif_stop_queue(dev); + tp->tx_full = 1; + } + + /* Trigger an immediate transmit demand. */ + outl(0, ioaddr + CSR1); + + } + + spin_unlock_irqrestore(&tp->lock, flags); + } + tulip_outl_CSR6(tp, csr6 | 0x0000); +} + + +static int __devinit tulip_init_one (struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + static int did_version = 0; /* Already printed version info. */ + struct tulip_private *tp; + /* See note below on the multiport cards. */ + static unsigned char last_phys_addr[6] = {0x00, 'L', 'i', 'n', 'u', 'x'}; + static int last_irq = 0; + static int multiport_cnt = 0; /* For four-port boards w/one EEPROM */ + u8 chip_rev; + int i, irq; + unsigned short sum; + u8 ee_data[EEPROM_SIZE]; + struct net_device *dev; + long ioaddr; + static int board_idx = -1; + int chip_idx = ent->driver_data; + + board_idx++; + + if (tulip_debug > 0 && did_version++ == 0) + printk (KERN_INFO "%s", version); + + if( pdev->subsystem_vendor == 0x1376 ){ + printk (KERN_ERR PFX "skipping LMC card.\n"); + return -ENODEV; + } + + ioaddr = pci_resource_start (pdev, 0); + irq = pdev->irq; + + /* init_etherdev ensures qword aligned structures */ + dev = init_etherdev (NULL, sizeof (*tp)); + if (!dev) { + printk (KERN_ERR PFX "ether device alloc failed, aborting\n"); + return -ENOMEM; + } + + /* We do a request_region() only to register /proc/ioports info. */ + /* Note that proper size is tulip_tbl[chip_idx].chip_name, but... */ + if (!request_region (ioaddr, tulip_tbl[chip_idx].io_size, dev->name)) { + printk (KERN_ERR PFX "I/O ports (0x%x@0x%lx) unavailable, " + "aborting\n", tulip_tbl[chip_idx].io_size, ioaddr); + goto err_out_free_netdev; + } + + if (pci_enable_device(pdev)) { + printk (KERN_ERR PFX "cannot enable PCI device (id %04x:%04x, " + "bus %d, devfn %d), aborting\n", + pdev->vendor, pdev->device, + pdev->bus->number, pdev->devfn); + goto err_out_free_netdev; + } + + pci_set_master(pdev); + + pci_read_config_byte (pdev, PCI_REVISION_ID, &chip_rev); + + /* + * initialize priviate data structure 'tp' + * it is zeroed and aligned in init_etherdev + */ + tp = dev->priv; + + tp->chip_id = chip_idx; + tp->flags = tulip_tbl[chip_idx].flags; + tp->pdev = pdev; + tp->base_addr = ioaddr; + tp->revision = chip_rev; + spin_lock_init(&tp->lock); + +#ifdef TULIP_FULL_DUPLEX + tp->full_duplex = 1; + tp->full_duplex_lock = 1; +#endif +#ifdef TULIP_DEFAULT_MEDIA + tp->default_port = TULIP_DEFAULT_MEDIA; +#endif +#ifdef TULIP_NO_MEDIA_SWITCH + tp->medialock = 1; +#endif + + printk(KERN_INFO "%s: %s rev %d at %#3lx,", + dev->name, tulip_tbl[chip_idx].chip_name, chip_rev, ioaddr); + + /* Stop the chip's Tx and Rx processes. */ + tulip_outl_CSR6(tp, inl(ioaddr + CSR6) & ~0x2002); + /* Clear the missed-packet counter. */ + (volatile int)inl(ioaddr + CSR8); + + if (chip_idx == DC21041 && inl(ioaddr + CSR9) & 0x8000) { + printk(" 21040 compatible mode,"); + chip_idx = DC21040; + } + + /* The station address ROM is read byte serially. The register must + be polled, waiting for the value to be read bit serially from the + EEPROM. + */ + sum = 0; + if (chip_idx == DC21040) { + outl(0, ioaddr + CSR9); /* Reset the pointer with a dummy write. */ + for (i = 0; i < 6; i++) { + int value, boguscnt = 100000; + do + value = inl(ioaddr + CSR9); + while (value < 0 && --boguscnt > 0); + dev->dev_addr[i] = value; + sum += value & 0xff; + } + } else if (chip_idx == LC82C168) { + for (i = 0; i < 3; i++) { + int value, boguscnt = 100000; + outl(0x600 | i, ioaddr + 0x98); + do + value = inl(ioaddr + CSR9); + while (value < 0 && --boguscnt > 0); + put_unaligned(le16_to_cpu(value), ((u16*)dev->dev_addr) + i); + sum += value & 0xffff; + } + } else if (chip_idx == COMET) { + /* No need to read the EEPROM. */ + put_unaligned(inl(ioaddr + 0xA4), (u32 *)dev->dev_addr); + put_unaligned(inl(ioaddr + 0xA8), (u16 *)(dev->dev_addr + 4)); + for (i = 0; i < 6; i ++) + sum += dev->dev_addr[i]; + } else { + /* A serial EEPROM interface, we read now and sort it out later. */ + int sa_offset = 0; + int ee_addr_size = tulip_read_eeprom(ioaddr, 0xff, 8) & 0x40000 ? 8 : 6; + + for (i = 0; i < sizeof(ee_data)/2; i++) + ((u16 *)ee_data)[i] = + le16_to_cpu(tulip_read_eeprom(ioaddr, i, ee_addr_size)); + + /* DEC now has a specification (see Notes) but early board makers + just put the address in the first EEPROM locations. */ + /* This does memcmp(eedata, eedata+16, 8) */ + for (i = 0; i < 8; i ++) + if (ee_data[i] != ee_data[16+i]) + sa_offset = 20; + if (ee_data[0] == 0xff && ee_data[1] == 0xff && ee_data[2] == 0) { + sa_offset = 2; /* Grrr, damn Matrox boards. */ + multiport_cnt = 4; + } + for (i = 0; i < 6; i ++) { + dev->dev_addr[i] = ee_data[i + sa_offset]; + sum += ee_data[i + sa_offset]; + } + } + /* Lite-On boards have the address byte-swapped. */ + if ((dev->dev_addr[0] == 0xA0 || dev->dev_addr[0] == 0xC0) + && dev->dev_addr[1] == 0x00) + for (i = 0; i < 6; i+=2) { + char tmp = dev->dev_addr[i]; + dev->dev_addr[i] = dev->dev_addr[i+1]; + dev->dev_addr[i+1] = tmp; + } + /* On the Zynx 315 Etherarray and other multiport boards only the + first Tulip has an EEPROM. + The addresses of the subsequent ports are derived from the first. + Many PCI BIOSes also incorrectly report the IRQ line, so we correct + that here as well. */ + if (sum == 0 || sum == 6*0xff) { + printk(" EEPROM not present,"); + for (i = 0; i < 5; i++) + dev->dev_addr[i] = last_phys_addr[i]; + dev->dev_addr[i] = last_phys_addr[i] + 1; +#if defined(__i386__) /* Patch up x86 BIOS bug. */ + if (last_irq) + irq = last_irq; +#endif + } + + for (i = 0; i < 6; i++) + printk("%c%2.2X", i ? ':' : ' ', last_phys_addr[i] = dev->dev_addr[i]); + printk(", IRQ %d.\n", irq); + last_irq = irq; + + pdev->driver_data = dev; + dev->base_addr = ioaddr; + dev->irq = irq; + tp->csr0 = csr0; + + /* BugFixes: The 21143-TD hangs with PCI Write-and-Invalidate cycles. + And the ASIX must have a burst limit or horrible things happen. */ + if (chip_idx == DC21143 && chip_rev == 65) + tp->csr0 &= ~0x01000000; + else if (chip_idx == AX88140) + tp->csr0 |= 0x2000; + + /* The lower four bits are the media type. */ + if (board_idx >= 0 && board_idx < MAX_UNITS) { + tp->default_port = options[board_idx] & 15; + if ((options[board_idx] & 0x90) || full_duplex[board_idx] > 0) + tp->full_duplex = 1; + if (mtu[board_idx] > 0) + dev->mtu = mtu[board_idx]; + } + if (dev->mem_start) + tp->default_port = dev->mem_start; + if (tp->default_port) { + tp->medialock = 1; + if (tulip_media_cap[tp->default_port] & MediaAlwaysFD) + tp->full_duplex = 1; + } + if (tp->full_duplex) + tp->full_duplex_lock = 1; + + if (tulip_media_cap[tp->default_port] & MediaIsMII) { + u16 media2advert[] = { 0x20, 0x40, 0x03e0, 0x60, 0x80, 0x100, 0x200 }; + tp->to_advertise = media2advert[tp->default_port - 9]; + } else if (tp->flags & HAS_8023X) + tp->to_advertise = 0x05e1; + else + tp->to_advertise = 0x01e1; + + /* This is logically part of probe1(), but too complex to write inline. */ + if (tp->flags & HAS_MEDIA_TABLE) { + memcpy(tp->eeprom, ee_data, sizeof(tp->eeprom)); + tulip_parse_eeprom(dev); + } + + if ((tp->flags & ALWAYS_CHECK_MII) || + (tp->mtable && tp->mtable->has_mii) || + ( ! tp->mtable && (tp->flags & HAS_MII))) { + int phy, phy_idx; + if (tp->mtable && tp->mtable->has_mii) { + for (i = 0; i < tp->mtable->leafcount; i++) + if (tp->mtable->mleaf[i].media == 11) { + tp->cur_index = i; + tp->saved_if_port = dev->if_port; + tulip_select_media(dev, 1); + dev->if_port = tp->saved_if_port; + break; + } + } + /* Find the connected MII xcvrs. + Doing this in open() would allow detecting external xcvrs later, + but takes much time. */ + for (phy = 0, phy_idx = 0; phy < 32 && phy_idx < sizeof(tp->phys); + phy++) { + int mii_status = tulip_mdio_read(dev, phy, 1); + if ((mii_status & 0x8301) == 0x8001 || + ((mii_status & 0x8000) == 0 && (mii_status & 0x7800) != 0)) { + int mii_reg0 = tulip_mdio_read(dev, phy, 0); + int mii_advert = tulip_mdio_read(dev, phy, 4); + int reg4 = ((mii_status>>6) & tp->to_advertise) | 1; + tp->phys[phy_idx] = phy; + tp->advertising[phy_idx++] = reg4; + printk(KERN_INFO "%s: MII transceiver #%d " + "config %4.4x status %4.4x advertising %4.4x.\n", + dev->name, phy, mii_reg0, mii_status, mii_advert); + /* Fixup for DLink with miswired PHY. */ + if (mii_advert != reg4) { + printk(KERN_DEBUG "%s: Advertising %4.4x on PHY %d," + " previously advertising %4.4x.\n", + dev->name, reg4, phy, mii_advert); + printk(KERN_DEBUG "%s: Advertising %4.4x (to advertise" + " is %4.4x).\n", + dev->name, reg4, tp->to_advertise); + tulip_mdio_write(dev, phy, 4, reg4); + } + /* Enable autonegotiation: some boards default to off. */ + tulip_mdio_write(dev, phy, 0, mii_reg0 | + (tp->full_duplex ? 0x1100 : 0x1000) | + (tulip_media_cap[tp->default_port]&MediaIs100 ? 0x2000:0)); + } + } + tp->mii_cnt = phy_idx; + if (tp->mtable && tp->mtable->has_mii && phy_idx == 0) { + printk(KERN_INFO "%s: ***WARNING***: No MII transceiver found!\n", + dev->name); + tp->phys[0] = 1; + } + } + + /* The Tulip-specific entries in the device structure. */ + dev->open = tulip_open; + dev->hard_start_xmit = tulip_start_xmit; + dev->tx_timeout = tulip_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; + dev->stop = tulip_close; + dev->get_stats = tulip_get_stats; + dev->do_ioctl = private_ioctl; + dev->set_multicast_list = set_rx_mode; + + if ((tp->flags & HAS_NWAY143) || tp->chip_id == DC21041) + tp->link_change = t21142_lnk_change; + else if (tp->flags & HAS_PNICNWAY) + tp->link_change = pnic_lnk_change; + + /* Reset the xcvr interface and turn on heartbeat. */ + switch (chip_idx) { + case DC21041: + tp->to_advertise = 0x0061; + outl(0x00000000, ioaddr + CSR13); + outl(0xFFFFFFFF, ioaddr + CSR14); + outl(0x00000008, ioaddr + CSR15); /* Listen on AUI also. */ + tulip_outl_CSR6(tp, inl(ioaddr + CSR6) | 0x0200); + outl(0x0000EF05, ioaddr + CSR13); + break; + case DC21040: + outl(0x00000000, ioaddr + CSR13); + outl(0x00000004, ioaddr + CSR13); + break; + case DC21140: + default: + if (tp->mtable) + outl(tp->mtable->csr12dir | 0x100, ioaddr + CSR12); + break; + case DC21142: + case PNIC2: + if (tp->mii_cnt || tulip_media_cap[dev->if_port] & MediaIsMII) { + tulip_outl_CSR6(tp, 0x82020000); + outl(0x0000, ioaddr + CSR13); + outl(0x0000, ioaddr + CSR14); + tulip_outl_CSR6(tp, 0x820E0000); + } else + t21142_start_nway(dev); + break; + case LC82C168: + if ( ! tp->mii_cnt) { + tp->nway = 1; + tp->nwayset = 0; + tulip_outl_CSR6(tp, 0x00420000); + outl(0x30, ioaddr + CSR12); + tulip_outl_CSR6(tp, 0x0001F078); + tulip_outl_CSR6(tp, 0x0201F078); /* Turn on autonegotiation. */ + } + break; + case MX98713: case COMPEX9881: + tulip_outl_CSR6(tp, 0x00000000); + outl(0x000711C0, ioaddr + CSR14); /* Turn on NWay. */ + outl(0x00000001, ioaddr + CSR13); + break; + case MX98715: case MX98725: + tulip_outl_CSR6(tp, 0x01a80000); + outl(0xFFFFFFFF, ioaddr + CSR14); + outl(0x00001000, ioaddr + CSR12); + break; + case COMET: + /* No initialization necessary. */ + break; + } + + /* put the chip in snooze mode until opened */ + if (tulip_tbl[chip_idx].flags & HAS_ACPI) + pci_write_config_dword(pdev, 0x40, 0x40000000); + + return 0; + +err_out_free_netdev: + unregister_netdev (dev); + kfree (dev); + return -ENODEV; +} + + +static void tulip_suspend (struct pci_dev *pdev) +{ + struct net_device *dev = pdev->driver_data; + + if (dev && netif_device_present (dev)) + tulip_down (dev); +} + + +static void tulip_resume (struct pci_dev *pdev) +{ + struct net_device *dev = pdev->driver_data; + + if (dev && !netif_device_present (dev)) + tulip_up (dev); +} + + +static void __devexit tulip_remove_one (struct pci_dev *pdev) +{ + struct net_device *dev = pdev->driver_data; + + if (dev) { + struct tulip_private *tp = (struct tulip_private *)dev->priv; + unregister_netdev(dev); + release_region(dev->base_addr, + tulip_tbl[tp->chip_id].io_size); + kfree(dev); + } +} + + +static struct pci_driver tulip_driver = { + name: TULIP_MODULE_NAME, + id_table: tulip_pci_tbl, + probe: tulip_init_one, + remove: tulip_remove_one, + suspend: tulip_suspend, + resume: tulip_resume, +}; + + +static int __init tulip_init (void) +{ + /* copy module parms into globals */ + tulip_rx_copybreak = rx_copybreak; + tulip_max_interrupt_work = max_interrupt_work; + + /* probe for and init boards */ + return pci_module_init (&tulip_driver); +} + + +static void __exit tulip_cleanup (void) +{ + pci_unregister_driver (&tulip_driver); +} + + +module_init(tulip_init); +module_exit(tulip_cleanup); diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c index 873a561ef..72aeae112 100644 --- a/drivers/net/wan/cosa.c +++ b/drivers/net/wan/cosa.c @@ -1,4 +1,4 @@ -/* $Id: cosa.c,v 1.28 1999/10/11 21:06:58 kas Exp $ */ +/* $Id: cosa.c,v 1.30 2000/02/21 15:19:49 kas Exp $ */ /* * Copyright (C) 1995-1997 Jan "Yenya" Kasprzak @@ -222,6 +222,8 @@ static int cosa_major = 117; #undef DEBUG_IRQS 1 /* Print the message when the IRQ is received */ #undef DEBUG_IO 1 /* Dump the I/O traffic */ +#define TX_TIMEOUT (5*HZ) + /* Maybe the following should be allocated dynamically */ static struct cosa_data cosa_cards[MAX_CARDS]; static int nr_cards = 0; @@ -286,6 +288,7 @@ static void sppp_channel_init(struct channel_data *chan); static void sppp_channel_delete(struct channel_data *chan); static int cosa_sppp_open(struct net_device *d); static int cosa_sppp_close(struct net_device *d); +static void cosa_sppp_timeout(struct net_device *d); static int cosa_sppp_tx(struct sk_buff *skb, struct net_device *d); static char *sppp_setup_rx(struct channel_data *channel, int size); static int sppp_rx_done(struct channel_data *channel); @@ -370,7 +373,7 @@ static int __init cosa_init(void) { int i; - printk(KERN_INFO "cosa v1.06 (c) 1997-8 Jan Kasprzak \n"); + printk(KERN_INFO "cosa v1.07 (c) 1997-2000 Jan Kasprzak \n"); #ifdef __SMP__ printk(KERN_INFO "cosa: SMP found. Please mail any success/failure reports to the author.\n"); #endif @@ -406,7 +409,6 @@ static int __init cosa_init(void) #ifdef MODULE void cleanup_module (void) { - int i; struct cosa_data *cosa; printk(KERN_INFO "Unloading the cosa module\n"); @@ -595,6 +597,8 @@ static void sppp_channel_init(struct channel_data *chan) d->hard_start_xmit = cosa_sppp_tx; d->do_ioctl = cosa_sppp_ioctl; d->get_stats = cosa_net_stats; + d->tx_timeout = cosa_sppp_timeout; + d->watchdog_timeo = TX_TIMEOUT; dev_init_buffers(d); if (register_netdev(d) == -1) { printk(KERN_WARNING "%s: register_netdev failed.\n", d->name); @@ -609,7 +613,6 @@ static void sppp_channel_delete(struct channel_data *chan) unregister_netdev(chan->pppdev.dev); } - static int cosa_sppp_open(struct net_device *d) { struct channel_data *chan = d->priv; @@ -646,7 +649,7 @@ static int cosa_sppp_open(struct net_device *d) return err; } - d->tbusy = 0; + netif_start_queue(d); cosa_enable_rx(chan); return 0; } @@ -655,41 +658,39 @@ static int cosa_sppp_tx(struct sk_buff *skb, struct net_device *dev) { struct channel_data *chan = dev->priv; - if (dev->tbusy) { - if (time_before(jiffies, dev->trans_start+2*HZ)) - return 1; /* Two seconds timeout */ - if (test_bit(RXBIT, &chan->cosa->rxtx)) { - chan->stats.rx_errors++; - chan->stats.rx_missed_errors++; - } else { - chan->stats.tx_errors++; - chan->stats.tx_aborted_errors++; - } - cosa_kick(chan->cosa); - if (chan->tx_skb) { - dev_kfree_skb(chan->tx_skb); - chan->tx_skb = 0; - } - dev->tbusy = 0; - } - if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { - printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name); - return 1; - } - + netif_stop_queue(dev); + chan->tx_skb = skb; - dev->trans_start = jiffies; cosa_start_tx(chan, skb->data, skb->len); return 0; } +static void cosa_sppp_timeout(struct net_device *dev) +{ + struct channel_data *chan = dev->priv; + + if (test_bit(RXBIT, &chan->cosa->rxtx)) { + chan->stats.rx_errors++; + chan->stats.rx_missed_errors++; + } else { + chan->stats.tx_errors++; + chan->stats.tx_aborted_errors++; + } + cosa_kick(chan->cosa); + if (chan->tx_skb) { + dev_kfree_skb(chan->tx_skb); + chan->tx_skb = 0; + } + netif_wake_queue(dev); +} + static int cosa_sppp_close(struct net_device *d) { struct channel_data *chan = d->priv; int flags; + netif_stop_queue(d); sppp_close(d); - d->tbusy = 1; cosa_disable_rx(chan); spin_lock_irqsave(&chan->cosa->lock, flags); if (chan->rx_skb) { @@ -760,8 +761,7 @@ static int sppp_tx_done(struct channel_data *chan, int size) chan->tx_skb = 0; chan->stats.tx_packets++; chan->stats.tx_bytes += size; - chan->pppdev.dev->tbusy = 0; - mark_bh(NET_BH); + netif_wake_queue(chan->pppdev.dev); return 1; } @@ -1350,14 +1350,14 @@ static void put_driver_status_nolock(struct cosa_data *cosa) static void cosa_kick(struct cosa_data *cosa) { unsigned flags, flags1; - char *s = "Unknown"; + char *s = "(probably) IRQ"; if (test_bit(RXBIT, &cosa->rxtx)) - s = "RX"; + s = "RX DMA"; if (test_bit(TXBIT, &cosa->rxtx)) - s = "TX"; + s = "TX DMA"; - printk(KERN_INFO "%s: %s DMA timeout - restarting.\n", cosa->name, s); + printk(KERN_INFO "%s: %s timeout - restarting.\n", cosa->name, s); spin_lock_irqsave(&cosa->lock, flags); cosa->rxtx = 0; diff --git a/drivers/net/wan/syncppp.c b/drivers/net/wan/syncppp.c index 6113365c1..e039bbc28 100644 --- a/drivers/net/wan/syncppp.c +++ b/drivers/net/wan/syncppp.c @@ -50,6 +50,7 @@ #include #include #include +#include #include "syncppp.h" #define MAXALIVECNT 6 /* max. alive packets */ @@ -126,6 +127,7 @@ struct cisco_packet { static struct sppp *spppq; static struct timer_list sppp_keepalive_timer; +static spinlock_t spppq_lock; static void sppp_keepalive (unsigned long dummy); static void sppp_cp_send (struct sppp *sp, u16 proto, u8 type, @@ -359,8 +361,8 @@ static void sppp_keepalive (unsigned long dummy) { struct sppp *sp; unsigned long flags; - save_flags(flags); - cli(); + + spin_lock_irqsave(&spppq_lock, flags); for (sp=spppq; sp; sp=sp->pp_next) { @@ -402,7 +404,7 @@ static void sppp_keepalive (unsigned long dummy) sp->lcp.echoid, 4, &nmagic); } } - restore_flags(flags); + spin_unlock_irqrestore(&spppq_lock, flags); sppp_keepalive_timer.expires=jiffies+10*HZ; add_timer(&sppp_keepalive_timer); } @@ -915,7 +917,9 @@ void sppp_attach(struct ppp_device *pd) { struct net_device *dev = pd->dev; struct sppp *sp = &pd->sppp; - + unsigned long flags; + + spin_lock_irqsave(&spppq_lock, flags); /* Initialize keepalive handler. */ if (! spppq) { @@ -927,6 +931,7 @@ void sppp_attach(struct ppp_device *pd) /* Insert new entry into the keepalive list. */ sp->pp_next = spppq; spppq = sp; + spin_unlock_irqrestore(&spppq_lock, flags); sp->pp_loopcnt = 0; sp->pp_alivecnt = 0; @@ -971,7 +976,9 @@ EXPORT_SYMBOL(sppp_attach); void sppp_detach (struct net_device *dev) { struct sppp **q, *p, *sp = (struct sppp *)sppp_of(dev); + unsigned long flags; + spin_lock_irqsave(&spppq_lock, flags); /* Remove the entry from the keepalive list. */ for (q = &spppq; (p = *q); q = &p->pp_next) if (p == sp) { @@ -983,6 +990,7 @@ void sppp_detach (struct net_device *dev) if (! spppq) del_timer(&sppp_keepalive_timer); sppp_clear_timeout (sp); + spin_unlock_irqrestore(&spppq_lock, flags); } EXPORT_SYMBOL(sppp_detach); @@ -1292,6 +1300,7 @@ void sync_ppp_init(void) { printk(KERN_INFO "Cronyx Ltd, Synchronous PPP and CISCO HDLC (c) 1994\n"); printk(KERN_INFO "Linux port (c) 1998 Building Number Three Ltd & Jan \"Yenya\" Kasprzak.\n"); + spin_lock_init(&spppq_lock); sppp_packet_type.type=htons(ETH_P_WAN_PPP); dev_add_pack(&sppp_packet_type); } diff --git a/drivers/net/wavelan.c b/drivers/net/wavelan.c index cd5b7caa0..17b285ba4 100644 --- a/drivers/net/wavelan.c +++ b/drivers/net/wavelan.c @@ -24,24 +24,24 @@ /*------------------------------------------------------------------*/ /* - * Wrapper for disabling interrupts. + * Wrapper for disabling interrupts and locking the driver. + * (note : inline, so optimised away) */ - -static inline unsigned long wv_splhi(void) +static inline void wv_splhi(net_local * lp, + unsigned long * pflags) { - unsigned long flags; - save_flags(flags); - cli(); - return (flags); + spin_lock_irqsave(&lp->spinlock, *pflags); + /* Note : above does the cli(); itself */ } /*------------------------------------------------------------------*/ /* - * Wrapper for re-enabling interrupts. + * Wrapper for re-enabling interrupts and un-locking the driver. */ -static inline void wv_splx(unsigned long flags) +static inline void wv_splx(net_local * lp, + unsigned long * pflags) { - restore_flags(flags); + spin_unlock_irqrestore(&lp->spinlock, *pflags); } /*------------------------------------------------------------------*/ @@ -180,13 +180,12 @@ static inline void wv_ints_off(device * dev) unsigned long ioaddr = dev->base_addr; unsigned long flags; - save_flags(flags); - cli(); + wv_splhi(lp, &flags); lp->hacr &= ~HACR_INTRON; hacr_write(ioaddr, lp->hacr); - restore_flags(flags); + wv_splx(lp, &flags); } /* wv_ints_off */ /*------------------------------------------------------------------*/ @@ -199,11 +198,12 @@ static inline void wv_ints_on(device * dev) unsigned long ioaddr = dev->base_addr; unsigned long flags; - save_flags(flags); - cli(); + wv_splhi(lp, &flags); + lp->hacr |= HACR_INTRON; hacr_write(ioaddr, lp->hacr); - restore_flags(flags); + + wv_splx(lp, &flags); } /* wv_ints_on */ /******************* MODEM MANAGEMENT SUBROUTINES *******************/ @@ -707,7 +707,7 @@ wv_config_complete(device * dev, unsigned long ioaddr, net_local * lp) printk(KERN_INFO "%s: wv_config_complete(): configure failed; status = 0x%x\n", dev->name, status); -#endif /* DEBUG_CONFIG_ERROR */ +#endif /* DEBUG_CONFIG_ERROR */ ret = 1; /* Ready to be scrapped */ } @@ -723,6 +723,8 @@ wv_config_complete(device * dev, unsigned long ioaddr, net_local * lp) /* * Command completion interrupt. * Reclaim as many freed tx buffers as we can. + * (called in wavelan_interrupt()). + * Note : the spinlock is already grabbed for us. */ static int wv_complete(device * dev, unsigned long ioaddr, net_local * lp) { @@ -870,16 +872,20 @@ static inline void wv_82586_reconfig(device * dev) { net_local *lp = (net_local *) dev->priv; + /* Arm the flag, will be cleard in wv_82586_config() */ + lp->reconfig_82586 = 1; + /* Check if we can do it now ! */ - if (!netif_running(dev) && netif_queue_stopped(dev)) { - lp->reconfig_82586 = 1; + if((netif_running(dev)) && !(netif_queue_stopped(dev))) + /* May fail */ + wv_82586_config(dev); + else { #ifdef DEBUG_CONFIG_INFO printk(KERN_DEBUG "%s: wv_82586_reconfig(): delayed (state = %lX)\n", dev->name, dev->state); #endif - } else - wv_82586_config(dev); + } } /********************* DEBUG & INFO SUBROUTINES *********************/ @@ -1806,9 +1812,9 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is #endif /* Disable interrupts and save flags. */ - save_flags(flags); - cli(); + wv_splhi(lp, &flags); /* FIXME: can't copy*user when cli this is broken! */ + /* Note : is it still valid ? Jean II */ /* Look what is the request */ switch (cmd) { @@ -2271,7 +2277,7 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is } /* Enable interrupts and restore flags. */ - restore_flags(flags); + wv_splx(lp, &flags); #ifdef DEBUG_IOCTL_TRACE printk(KERN_DEBUG "%s: <-wavelan_ioctl()\n", dev->name); @@ -2297,15 +2303,12 @@ static iw_stats *wavelan_get_wireless_stats(device * dev) dev->name); #endif - /* Disable interrupts and save flags. */ - save_flags(flags); - cli(); - + /* Check */ if (lp == (net_local *) NULL) - { - restore_flags(flags); return (iw_stats *) NULL; - } + + /* Disable interrupts and save flags. */ + wv_splhi(lp, &flags); wstats = &lp->wstats; @@ -2333,7 +2336,7 @@ static iw_stats *wavelan_get_wireless_stats(device * dev) wstats->discard.misc = 0L; /* Enable interrupts and restore flags. */ - restore_flags(flags); + wv_splx(lp, &flags); #ifdef DEBUG_IOCTL_TRACE printk(KERN_DEBUG "%s: <-wavelan_get_wireless_stats()\n", @@ -2455,7 +2458,8 @@ wv_packet_read(device * dev, u16 buf_off, int sksize) /* * Transfer as many packets as we can * from the device RAM. - * Called by the interrupt handler. + * (called in wavelan_interrupt()). + * Note : the spinlock is already grabbed for us. */ static inline void wv_receive(device * dev) { @@ -2640,7 +2644,7 @@ static inline void wv_receive(device * dev) * * (called in wavelan_packet_xmit()) */ -static inline void wv_packet_write(device * dev, void *buf, short length) +static inline int wv_packet_write(device * dev, void *buf, short length) { net_local *lp = (net_local *) dev->priv; unsigned long ioaddr = dev->base_addr; @@ -2665,9 +2669,18 @@ static inline void wv_packet_write(device * dev, void *buf, short length) if (clen < ETH_ZLEN) clen = ETH_ZLEN; - save_flags(flags); - cli(); - + wv_splhi(lp, &flags); + + /* Check nothing bad has happened */ + if (lp->tx_n_in_use == (NTXBLOCKS - 1)) { +#ifdef DEBUG_TX_ERROR + printk(KERN_INFO "%s: wv_packet_write(): Tx queue full.\n", + dev->name); +#endif + wv_splx(lp, &flags); + return 1; + } + /* Calculate addresses of next block and previous block. */ txblock = lp->tx_first_free; txpred = txblock - TXBLOCKZ; @@ -2736,20 +2749,13 @@ static inline void wv_packet_write(device * dev, void *buf, short length) /* Keep stats up to date. */ lp->stats.tx_bytes += length; - /* If watchdog not already active, activate it... */ - if (lp->watchdog.prev == (timer_list *) NULL) { - /* Set timer to expire in WATCHDOG_JIFFIES. */ - lp->watchdog.expires = jiffies + WATCHDOG_JIFFIES; - add_timer(&lp->watchdog); - } - if (lp->tx_first_in_use == I82586NULL) lp->tx_first_in_use = txblock; if (lp->tx_n_in_use < NTXBLOCKS - 1) netif_wake_queue(dev); - restore_flags(flags); + wv_splx(lp, &flags); #ifdef DEBUG_TX_INFO wv_packet_info((u8 *) buf, length, dev->name, @@ -2759,6 +2765,8 @@ static inline void wv_packet_write(device * dev, void *buf, short length) #ifdef DEBUG_TX_TRACE printk(KERN_DEBUG "%s: <-wv_packet_write()\n", dev->name); #endif + + return 0; } /*------------------------------------------------------------------*/ @@ -2781,7 +2789,6 @@ static int wavelan_packet_xmit(struct sk_buff *skb, device * dev) * Block a timer-based transmit from overlapping. * In other words, prevent reentering this routine. */ - netif_stop_queue(dev); /* If somebody has asked to reconfigure the controller, @@ -2789,13 +2796,18 @@ static int wavelan_packet_xmit(struct sk_buff *skb, device * dev) */ if (lp->reconfig_82586) { wv_82586_config(dev); + /* Check that we can continue */ + if (lp->tx_n_in_use == (NTXBLOCKS - 1)) + return 1; } #ifdef DEBUG_TX_ERROR if (skb->next) printk(KERN_INFO "skb has next\n"); #endif - wv_packet_write(dev, skb->data, skb->len); + /* Write packet on the card */ + if(wv_packet_write(dev, skb->data, skb->len)) + return 1; /* We failed */ dev_kfree_skb(skb); @@ -3161,7 +3173,7 @@ static inline int wv_cu_start(device * dev) } lp->tx_n_in_use = 0; - netif_wake_queue(dev); + netif_start_queue(dev); #ifdef DEBUG_CONFIG_TRACE printk(KERN_DEBUG "%s: <-wv_cu_start()\n", dev->name); #endif @@ -3310,7 +3322,7 @@ static inline int wv_82586_start(device * dev) * as usual to the NOP command. * Note that only the last command (mc_set) will generate an interrupt. * - * (called by wv_hw_reset(), wv_82586_reconfig()) + * (called by wv_hw_reset(), wv_82586_reconfig(), wavelan_packet_xmit()) */ static void wv_82586_config(device * dev) { @@ -3336,9 +3348,18 @@ static void wv_82586_config(device * dev) printk(KERN_DEBUG "%s: ->wv_82586_config()\n", dev->name); #endif - save_flags(flags); - cli(); + wv_splhi(lp, &flags); + /* Check nothing bad has happened */ + if (lp->tx_n_in_use == (NTXBLOCKS - 1)) { +#ifdef DEBUG_CONFIG_ERROR + printk(KERN_INFO "%s: wv_82586_config(): Tx queue full.\n", + dev->name); +#endif + wv_splx(lp, &flags); + return; + } + /* Calculate addresses of next block and previous block. */ txblock = lp->tx_first_free; txpred = txblock - TXBLOCKZ; @@ -3467,22 +3488,17 @@ static void wv_82586_config(device * dev) (unsigned char *) &nop.nop_h.ac_link, sizeof(nop.nop_h.ac_link)); - /* If watchdog not already active, activate it... */ - if (lp->watchdog.prev == (timer_list *) NULL) { - /* set timer to expire in WATCHDOG_JIFFIES */ - lp->watchdog.expires = jiffies + WATCHDOG_JIFFIES; - add_timer(&lp->watchdog); - } - + /* Job done, clear the flag */ lp->reconfig_82586 = 0; if (lp->tx_first_in_use == I82586NULL) lp->tx_first_in_use = txblock; - if (lp->tx_n_in_use < NTXBLOCKS - 1) - netif_wake_queue(dev); + if (lp->tx_n_in_use == (NTXBLOCKS - 1)) + netif_stop_queue(dev); + + wv_splx(lp, &flags); - restore_flags(flags); #ifdef DEBUG_CONFIG_TRACE printk(KERN_DEBUG "%s: <-wv_82586_config()\n", dev->name); #endif @@ -3539,10 +3555,6 @@ static int wv_hw_reset(device * dev) (unsigned int) dev); #endif - /* If watchdog was activated, kill it! */ - if (lp->watchdog.prev != (timer_list *) NULL) - del_timer(&lp->watchdog); - /* Increase the number of resets done. */ lp->nresets++; @@ -3637,8 +3649,19 @@ static void wavelan_interrupt(int irq, void *dev_id, struct pt_regs *regs) lp = (net_local *) dev->priv; ioaddr = dev->base_addr; - /* Prevent reentrance. What should we do here? */ +#ifdef DEBUG_INTERRUPT_ERROR + /* Check state of our spinlock (it should be cleared) */ + if(spin_is_locked(&lp->spinlock)) + printk(KERN_INFO + "%s: wavelan_interrupt(): spinlock is already locked !!!\n", + dev->name); +#endif + + /* Prevent reentrancy. It is safe because wv_splhi disable interrupts + * before aquiring the spinlock */ + spin_lock(&lp->spinlock); + /* Check modem interupt */ if ((hasr = hasr_read(ioaddr)) & HASR_MMC_INTR) { u8 dce_status; @@ -3655,6 +3678,7 @@ static void wavelan_interrupt(int irq, void *dev_id, struct pt_regs *regs) #endif } + /* Check if not controller interrupt */ if ((hasr & HASR_82586_INTR) == 0) { #ifdef DEBUG_INTERRUPT_ERROR printk(KERN_INFO @@ -3689,15 +3713,6 @@ static void wavelan_interrupt(int irq, void *dev_id, struct pt_regs *regs) dev->name); #endif wv_complete(dev, ioaddr, lp); - - /* If watchdog was activated, kill it ! */ - if (lp->watchdog.prev != (timer_list *) NULL) - del_timer(&lp->watchdog); - if (lp->tx_n_in_use > 0) { - /* set timer to expire in WATCHDOG_JIFFIES */ - lp->watchdog.expires = jiffies + WATCHDOG_JIFFIES; - add_timer(&lp->watchdog); - } } /* Frame received. */ @@ -3710,9 +3725,13 @@ static void wavelan_interrupt(int irq, void *dev_id, struct pt_regs *regs) wv_receive(dev); } + /* Release spinlock here so that wv_hw_reset() can grab it */ + spin_unlock (&lp->lock); + /* Check the state of the command unit. */ if (((status & SCB_ST_CNA) == SCB_ST_CNA) || - (((status & SCB_ST_CUS) != SCB_ST_CUS_ACTV) && netif_running(dev))) { + (((status & SCB_ST_CUS) != SCB_ST_CUS_ACTV) && + (netif_running(dev)))) { #ifdef DEBUG_INTERRUPT_ERROR printk(KERN_INFO "%s: wavelan_interrupt(): CU inactive -- restarting\n", @@ -3723,7 +3742,8 @@ static void wavelan_interrupt(int irq, void *dev_id, struct pt_regs *regs) /* Check the state of the command unit. */ if (((status & SCB_ST_RNR) == SCB_ST_RNR) || - (((status & SCB_ST_RUS) != SCB_ST_RUS_RDY) && netif_running(dev))) { + (((status & SCB_ST_RUS) != SCB_ST_RUS_RDY) && + (netif_running(dev)))) { #ifdef DEBUG_INTERRUPT_ERROR printk(KERN_INFO "%s: wavelan_interrupt(): RU not ready -- restarting\n", @@ -3739,26 +3759,16 @@ static void wavelan_interrupt(int irq, void *dev_id, struct pt_regs *regs) /*------------------------------------------------------------------*/ /* - * Watchdog: when we start a transmission, we set a timer in the + * Watchdog: when we start a transmission, a timer is set for us in the * kernel. If the transmission completes, this timer is disabled. If - * the timer expires, we try to unlock the hardware. - * - * Note: this watchdog doesn't work on the same principle as the - * watchdog in the previous version of the ISA driver. I made it this - * way because the overhead of add_timer() and del_timer() is nothing - * and because it avoids calling the watchdog, saving some CPU. + * the timer expires, we are called and we try to unlock the hardware. */ -static void wavelan_watchdog(unsigned long a) +static void wavelan_watchdog(device * dev) { - device *dev; - net_local *lp; - unsigned long ioaddr; - unsigned long flags; - unsigned int nreaped; - - dev = (device *) a; - ioaddr = dev->base_addr; - lp = (net_local *) dev->priv; + net_local * lp = (net_local *)dev->priv; + u_long ioaddr = dev->base_addr; + unsigned long flags; + unsigned int nreaped; #ifdef DEBUG_INTERRUPT_TRACE printk(KERN_DEBUG "%s: ->wavelan_watchdog()\n", dev->name); @@ -3769,18 +3779,16 @@ static void wavelan_watchdog(unsigned long a) dev->name); #endif - save_flags(flags); - cli(); - - dev = (device *) a; - ioaddr = dev->base_addr; - lp = (net_local *) dev->priv; + wv_splhi(lp, &flags); + /* Check that we came here for something */ if (lp->tx_n_in_use <= 0) { - restore_flags(flags); + wv_splx(lp, &flags); return; } + /* Try to see if some buffers are not free (in case we missed + * an interrupt */ nreaped = wv_complete(dev, ioaddr, lp); #ifdef DEBUG_INTERRUPT_INFO @@ -3811,15 +3819,13 @@ static void wavelan_watchdog(unsigned long a) dev->name); #endif wv_hw_reset(dev); - } else - /* Reset watchdog for next transmission. */ - if (lp->tx_n_in_use > 0) { - /* set timer to expire in WATCHDOG_JIFFIES */ - lp->watchdog.expires = jiffies + WATCHDOG_JIFFIES; - add_timer(&lp->watchdog); } - restore_flags(flags); + /* At this point, we should have some free Tx buffer ;-) */ + if (lp->tx_n_in_use < NTXBLOCKS - 1) + netif_wake_queue(dev); + + wv_splx(lp, &flags); #ifdef DEBUG_INTERRUPT_TRACE printk(KERN_DEBUG "%s: <-wavelan_watchdog()\n", dev->name); @@ -3840,7 +3846,8 @@ static void wavelan_watchdog(unsigned long a) */ static int wavelan_open(device * dev) { - unsigned long flags; + net_local * lp = (net_local *)dev->priv; + unsigned long flags; #ifdef DEBUG_CALLBACK_TRACE printk(KERN_DEBUG "%s: ->wavelan_open(dev=0x%x)\n", dev->name, @@ -3865,8 +3872,7 @@ static int wavelan_open(device * dev) return -EAGAIN; } - save_flags(flags); - cli(); + wv_splhi(lp, &flags); if (wv_hw_reset(dev) != -1) { netif_start_queue(dev); @@ -3879,7 +3885,7 @@ static int wavelan_open(device * dev) #endif return -EAGAIN; } - restore_flags(flags); + wv_splx(lp, &flags); MOD_INC_USE_COUNT; @@ -3896,8 +3902,6 @@ static int wavelan_open(device * dev) */ static int wavelan_close(device * dev) { - net_local *lp = (net_local *) dev->priv; - #ifdef DEBUG_CALLBACK_TRACE printk(KERN_DEBUG "%s: ->wavelan_close(dev=0x%x)\n", dev->name, (unsigned int) dev); @@ -3905,10 +3909,6 @@ static int wavelan_close(device * dev) netif_stop_queue(dev); - /* If watchdog was activated, kill it! */ - if (lp->watchdog.prev != (timer_list *) NULL) - del_timer(&lp->watchdog); - /* * Flush the Tx and disable Rx. */ @@ -4001,11 +4001,13 @@ static int __init wavelan_config(device * dev) lp->hacr = HACR_DEFAULT; - lp->watchdog.function = wavelan_watchdog; - lp->watchdog.data = (unsigned long) dev; + /* Multicast stuff */ lp->promiscuous = 0; lp->mc_count = 0; + /* Init spinlock */ + spin_lock_init(&lp->lock); + /* * Fill in the fields of the device structure * with generic Ethernet values. @@ -4017,6 +4019,8 @@ static int __init wavelan_config(device * dev) dev->hard_start_xmit = wavelan_packet_xmit; dev->get_stats = wavelan_get_stats; dev->set_multicast_list = &wavelan_set_multicast_list; + dev->tx_timeout = &wavelan_watchdog; + dev->watchdog_timeo = WATCHDOG_JIFFIES; #ifdef SET_MAC_ADDRESS dev->set_mac_address = &wavelan_set_mac_address; #endif /* SET_MAC_ADDRESS */ diff --git a/drivers/net/wavelan.p.h b/drivers/net/wavelan.p.h index e4b722cf1..3e20776fb 100644 --- a/drivers/net/wavelan.p.h +++ b/drivers/net/wavelan.p.h @@ -34,6 +34,25 @@ * I try to maintain a web page with the Wireless LAN Howto at : * http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Wavelan.html * + * SMP + * --- + * We now *should* be SMP compliant. + * I don't have a SMP box to verify that (my Pentium 90 is not), so + * someone has to certify that from me. + * Anyway, I spent enough time chasing interrupt re-entrancy during + * errors or reconfigure, and I designed the locked/unlocked sections + * of the driver with great care, and with the recent addition of + * the spinlock (thanks to the new API), we should be quite close to + * the truth. + * The SMP/IRQ locking is quite coarse and conservative (i.e. not fast), + * but better safe than sorry (especially at 2 Mb/s ;-). + * + * I have also looked into disabling only our interrupt on the card + * (via HACR) instead of all interrupts in the processor (via cli), + * so that other driver are not impacted, and it look like it's + * possible, but it's very tricky to do right (full of races). As + * the gain would be mostly for SMP systems, it can wait... + * * Debugging and options * --------------------- * You will find below a set of '#define" allowing a very fine control @@ -171,7 +190,7 @@ * * Thanks go also to: * James Ashton , - * Alan Cox , + * Alan Cox , * Allan Creighton , * Matthew Geier , * Remo di Giovanni , @@ -188,8 +207,9 @@ * * Additional Credits: * - * My development has been done under Linux 2.0.x (Debian 1.1) with - * an HP Vectra XP/60. + * My development has been done initially under Debian 1.1 (Linux 2.0.x) + * and now under Debian 2.2, initially with an HP Vectra XP/60, and now + * an HP Vectra XP/90. * */ @@ -305,6 +325,21 @@ * - Fix check for root permission (break instead of exit) * - New nwid & encoding setting (Wireless Extension 9) * + * Changes made for release in 2.3.49 : + * ---------------------------------- + * - Indentation reformating (Alan) + * - Update to new network API (softnet - 2.3.43) : + * o replace dev->tbusy (Alan) + * o replace dev->tstart (Alan) + * o remove dev->interrupt (Alan) + * o add SMP locking via spinlock in splxx (me) + * o add spinlock in interrupt handler (me) + * o use kernel watchdog instead of ours (me) + * o increase watchdog timeout (kernel is more sensitive) (me) + * o verify that all the changes make sense and work (me) + * - Fixup a potential gotcha when reconfiguring and thighten a bit + * the interactions with Tx queue. + * * Wishes & dreams: * ---------------- * - roaming (see Pcmcia driver) @@ -395,11 +430,11 @@ /************************ CONSTANTS & MACROS ************************/ #ifdef DEBUG_VERSION_SHOW -static const char *version = "wavelan.c : v21 (wireless extensions) 16/10/99\n"; +static const char *version = "wavelan.c : v22 (wireless extensions) 21/02/00\n"; #endif /* Watchdog temporisation */ -#define WATCHDOG_JIFFIES (256*HZ/100) +#define WATCHDOG_JIFFIES (512*HZ/100) /* Macro to get the number of elements in an array */ #define NELS(a) (sizeof(a) / sizeof(a[0])) @@ -441,12 +476,12 @@ struct net_local { net_local * next; /* linked list of the devices */ device * dev; /* reverse link */ + spinlock_t spinlock; /* Serialize access to the hardware (SMP) */ en_stats stats; /* Ethernet interface statistics */ int nresets; /* number of hardware resets */ u_char reconfig_82586; /* We need to reconfigure the controller. */ u_char promiscuous; /* promiscuous mode */ int mc_count; /* number of multicast addresses */ - timer_list watchdog; /* to avoid blocking state */ u_short hacr; /* current host interface state */ int tx_n_in_use; @@ -475,10 +510,12 @@ struct net_local /**************************** PROTOTYPES ****************************/ /* ----------------------- MISC. SUBROUTINES ------------------------ */ -static inline unsigned long /* flags */ - wv_splhi(void); /* Disable interrupts */ static inline void - wv_splx(unsigned long); /* Enable interrupts: flags */ + wv_splhi(net_local *, /* Disable interrupts, lock driver */ + unsigned long *); /* flags */ +static inline void + wv_splx(net_local *, /* Enable interrupts, unlock driver */ + unsigned long *); /* flags */ static u_char wv_irq_to_psa(int); static int @@ -580,7 +617,7 @@ static inline void int), wv_receive(device *); /* Read all packets waiting. */ /* --------------------- PACKET TRANSMISSION --------------------- */ -static inline void +static inline int wv_packet_write(device *, /* Write a packet to the Tx buffer. */ void *, short); @@ -607,7 +644,7 @@ static void void *, struct pt_regs *); static void - wavelan_watchdog(u_long); /* transmission watchdog */ + wavelan_watchdog(device *); /* transmission watchdog */ /* ------------------- CONFIGURATION CALLBACKS ------------------- */ static int wavelan_open(device *), /* Open the device. */ diff --git a/drivers/parport/daisy.c b/drivers/parport/daisy.c index 830d9d400..c4003dd27 100644 --- a/drivers/parport/daisy.c +++ b/drivers/parport/daisy.c @@ -1,7 +1,7 @@ /* * IEEE 1284.3 Parallel port daisy chain and multiplexor code * - * Copyright (C) 1999 Tim Waugh + * Copyright (C) 1999, 2000 Tim Waugh * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -12,6 +12,7 @@ * 31-01-1999: Make port-cloning transparent. * 13-02-1999: Move DeviceID technique from parport_probe. * 13-03-1999: Get DeviceID from non-IEEE 1284.3 devices too. + * 22-02-2000: Count devices that are actually detected. * */ @@ -80,9 +81,11 @@ static struct parport *clone_parport (struct parport *real, int muxport) return extra; } -/* Discover the IEEE1284.3 topology on a port -- muxes and daisy chains. */ +/* Discover the IEEE1284.3 topology on a port -- muxes and daisy chains. + * Return value is number of devices actually detected. */ int parport_daisy_init (struct parport *port) { + int detected = 0; char *deviceid; static const char *th[] = { /*0*/"th", "st", "nd", "rd", "th" }; int num_ports; @@ -128,7 +131,7 @@ int parport_daisy_init (struct parport *port) select_port (port); parport_daisy_deselect_all (port); - assign_addrs (port); + detected += assign_addrs (port); /* Count the potential legacy device at the end. */ add_dev (numdevs++, port, -1); @@ -136,25 +139,31 @@ int parport_daisy_init (struct parport *port) /* Find out the legacy device's IEEE 1284 device ID. */ deviceid = kmalloc (1000, GFP_KERNEL); if (deviceid) { - parport_device_id (numdevs - 1, deviceid, 1000); + if (parport_device_id (numdevs - 1, deviceid, 1000) > 2) + detected++; + kfree (deviceid); } - return 0; + return detected; } /* Forget about devices on a physical port. */ void parport_daisy_fini (struct parport *port) { struct daisydev *dev, *prev = topology; - while (prev && prev->port == port) - prev = topology = topology->next; + while (prev && prev->port == port) { + topology = topology->next; + kfree (prev); + prev = topology; + } while (prev) { dev = prev->next; if (dev && dev->port == port) prev->next = dev->next; + kfree (dev); prev = prev->next; } @@ -162,7 +171,8 @@ void parport_daisy_fini (struct parport *port) someone enumerate through all IEEE1284.3 devices in the topology?. */ if (!topology) numdevs = 0; - return; } + return; +} /* Find a device by canonical device number. */ struct pardevice *parport_open (int devnum, const char *name, @@ -371,7 +381,7 @@ static int assign_addrs (struct parport *port) | PARPORT_STATUS_ERROR)) { DPRINTK (KERN_DEBUG "%s: assign_addrs: aa5500ff(%02x)\n", port->name, s); - return -ENXIO; + return 0; } parport_write_data (port, 0x87); udelay (2); @@ -382,7 +392,7 @@ static int assign_addrs (struct parport *port) if (s != (PARPORT_STATUS_SELECT | PARPORT_STATUS_ERROR)) { DPRINTK (KERN_DEBUG "%s: assign_addrs: aa5500ff87(%02x)\n", port->name, s); - return -ENXIO; + return 0; } parport_write_data (port, 0x78); udelay (2); @@ -421,7 +431,7 @@ static int assign_addrs (struct parport *port) parport_device_id (thisdev, deviceid, 1000); kfree (deviceid); - return 0; + return numdevs - thisdev; } /* Find a device with a particular manufacturer and model string, diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c index beb0a68b7..cf0e092bf 100644 --- a/drivers/parport/parport_pc.c +++ b/drivers/parport/parport_pc.c @@ -681,6 +681,7 @@ size_t parport_pc_compat_write_block_pio (struct parport *port, /* Set up parallel port FIFO mode.*/ parport_pc_data_forward (port); /* Must be in PS2 mode */ + parport_pc_frob_control (port, PARPORT_CONTROL_STROBE, 0); change_mode (port, ECR_PPF); /* Parallel port FIFO */ port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA; @@ -747,6 +748,10 @@ size_t parport_pc_ecp_write_block_pio (struct parport *port, /* Set up ECP parallel port mode.*/ parport_pc_data_forward (port); /* Must be in PS2 mode */ + parport_pc_frob_control (port, + PARPORT_CONTROL_STROBE | + PARPORT_CONTROL_AUTOFD, + 0); change_mode (port, ECR_ECP); /* ECP FIFO */ port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA; @@ -850,6 +855,10 @@ size_t parport_pc_ecp_read_block_pio (struct parport *port, /* Set up ECP parallel port mode.*/ parport_pc_data_reverse (port); /* Must be in PS2 mode */ + parport_pc_frob_control (port, + PARPORT_CONTROL_STROBE | + PARPORT_CONTROL_AUTOFD, + 0); change_mode (port, ECR_ECP); /* ECP FIFO */ port->ieee1284.phase = IEEE1284_PH_REV_DATA; @@ -989,7 +998,7 @@ struct parport_operations parport_pc_ops = /* * Checks for port existence, all ports support SPP MODE */ -static int __maybe_init parport_SPP_supported(struct parport *pb) +static int __devinit parport_SPP_supported(struct parport *pb) { unsigned char r, w; @@ -1066,7 +1075,7 @@ static int __maybe_init parport_SPP_supported(struct parport *pb) * two bits of ECR aren't writable, so we check by writing ECR and * reading it back to see if it's what we expect. */ -static int __maybe_init parport_ECR_present(struct parport *pb) +static int __devinit parport_ECR_present(struct parport *pb) { struct parport_pc_private *priv = pb->private_data; unsigned char r = 0xc; @@ -1118,7 +1127,7 @@ static int __maybe_init parport_ECR_present(struct parport *pb) * be misdetected here is rather academic. */ -static int __maybe_init parport_PS2_supported(struct parport *pb) +static int __devinit parport_PS2_supported(struct parport *pb) { int ok = 0; @@ -1146,7 +1155,7 @@ static int __maybe_init parport_PS2_supported(struct parport *pb) return ok; } -static int __maybe_init parport_ECP_supported(struct parport *pb) +static int __devinit parport_ECP_supported(struct parport *pb) { int i; int config; @@ -1257,7 +1266,7 @@ static int __maybe_init parport_ECP_supported(struct parport *pb) return 1; } -static int __maybe_init parport_ECPPS2_supported(struct parport *pb) +static int __devinit parport_ECPPS2_supported(struct parport *pb) { const struct parport_pc_private *priv = pb->private_data; int result; @@ -1277,7 +1286,7 @@ static int __maybe_init parport_ECPPS2_supported(struct parport *pb) /* EPP mode detection */ -static int __maybe_init parport_EPP_supported(struct parport *pb) +static int __devinit parport_EPP_supported(struct parport *pb) { const struct parport_pc_private *priv = pb->private_data; @@ -1320,7 +1329,7 @@ static int __maybe_init parport_EPP_supported(struct parport *pb) return 1; } -static int __maybe_init parport_ECPEPP_supported(struct parport *pb) +static int __devinit parport_ECPEPP_supported(struct parport *pb) { struct parport_pc_private *priv = pb->private_data; int result; @@ -1351,18 +1360,18 @@ static int __maybe_init parport_ECPEPP_supported(struct parport *pb) #else /* No IEEE 1284 support */ /* Don't bother probing for modes we know we won't use. */ -static int __maybe_init parport_PS2_supported(struct parport *pb) { return 0; } -static int __maybe_init parport_ECP_supported(struct parport *pb) { return 0; } -static int __maybe_init parport_EPP_supported(struct parport *pb) { return 0; } -static int __maybe_init parport_ECPEPP_supported(struct parport *pb){return 0;} -static int __maybe_init parport_ECPPS2_supported(struct parport *pb){return 0;} +static int __devinit parport_PS2_supported(struct parport *pb) { return 0; } +static int __devinit parport_ECP_supported(struct parport *pb) { return 0; } +static int __devinit parport_EPP_supported(struct parport *pb) { return 0; } +static int __devinit parport_ECPEPP_supported(struct parport *pb){return 0;} +static int __devinit parport_ECPPS2_supported(struct parport *pb){return 0;} #endif /* No IEEE 1284 support */ /* --- IRQ detection -------------------------------------- */ /* Only if supports ECP mode */ -static int __maybe_init programmable_irq_support(struct parport *pb) +static int __devinit programmable_irq_support(struct parport *pb) { int irq, intrLine; unsigned char oecr = inb (ECONTROL (pb)); @@ -1379,7 +1388,7 @@ static int __maybe_init programmable_irq_support(struct parport *pb) return irq; } -static int __maybe_init irq_probe_ECP(struct parport *pb) +static int __devinit irq_probe_ECP(struct parport *pb) { int i; unsigned long irqs; @@ -1408,7 +1417,7 @@ static int __maybe_init irq_probe_ECP(struct parport *pb) * This detection seems that only works in National Semiconductors * This doesn't work in SMC, LGS, and Winbond */ -static int __maybe_init irq_probe_EPP(struct parport *pb) +static int __devinit irq_probe_EPP(struct parport *pb) { #ifndef ADVANCED_DETECT return PARPORT_IRQ_NONE; @@ -1448,7 +1457,7 @@ static int __maybe_init irq_probe_EPP(struct parport *pb) #endif /* Advanced detection */ } -static int __maybe_init irq_probe_SPP(struct parport *pb) +static int __devinit irq_probe_SPP(struct parport *pb) { /* Don't even try to do this. */ return PARPORT_IRQ_NONE; @@ -1461,7 +1470,7 @@ static int __maybe_init irq_probe_SPP(struct parport *pb) * When ECP is available we can autoprobe for IRQs. * NOTE: If we can autoprobe it, we can register the IRQ. */ -static int __maybe_init parport_irq_probe(struct parport *pb) +static int __devinit parport_irq_probe(struct parport *pb) { const struct parport_pc_private *priv = pb->private_data; @@ -1495,7 +1504,7 @@ out: /* --- DMA detection -------------------------------------- */ /* Only if supports ECP mode */ -static int __maybe_init programmable_dma_support (struct parport *p) +static int __devinit programmable_dma_support (struct parport *p) { unsigned char oecr = inb (ECONTROL (p)); int dma; @@ -1510,7 +1519,7 @@ static int __maybe_init programmable_dma_support (struct parport *p) return dma; } -static int __maybe_init parport_dma_probe (struct parport *p) +static int __devinit parport_dma_probe (struct parport *p) { const struct parport_pc_private *priv = p->private_data; if (priv->ecr) @@ -1521,7 +1530,7 @@ static int __maybe_init parport_dma_probe (struct parport *p) /* --- Initialisation code -------------------------------- */ -struct parport *__maybe_init parport_pc_probe_port (unsigned long int base, +struct parport *__devinit parport_pc_probe_port (unsigned long int base, unsigned long int base_hi, int irq, int dma, struct pci_dev *dev) @@ -1693,9 +1702,7 @@ struct parport *__maybe_init parport_pc_probe_port (unsigned long int base, #endif /* CONFIG_PARPORT_PC_FIFO */ } - /* Done probing. Now put the port into a sensible start-up state. - * SELECT | INIT also puts IEEE1284-compliant devices into - * compatibility mode. */ + /* Done probing. Now put the port into a sensible start-up state. */ if (priv->ecr) /* * Put the ECP detected port in PS2 mode. @@ -1714,9 +1721,143 @@ struct parport *__maybe_init parport_pc_probe_port (unsigned long int base, return p; } + +static int __devinit sio_via_686a_probe (struct pci_dev *pdev) +{ + u8 dma, irq, tmp; + unsigned port1, port2, have_eppecp; + + /* + * unlock super i/o configuration, set 0x85_1 + */ + pci_read_config_byte (pdev, 0x85, &tmp); + tmp |= (1 << 1); + pci_write_config_byte (pdev, 0x85, tmp); + + /* + * Super I/O configuration, index port == 3f0h, data port == 3f1h + */ + + /* 0xE2_1-0: Parallel Port Mode / Enable */ + outb (0xE2, 0x3F0); + tmp = inb (0x3F1); + + if ((tmp & 0x03) == 0x03) { + printk (KERN_INFO "parport_pc: Via 686A parallel port disabled in BIOS\n"); + return 0; + } + + /* 0xE6: Parallel Port I/O Base Address, bits 9-2 */ + outb (0xE6, 0x3F0); + port1 = inb (0x3F1) << 2; + + switch (port1) { + case 0x3bc: port2 = 0x7bc; break; + case 0x378: port2 = 0x778; break; + case 0x278: port2 = 0x678; break; + default: + printk (KERN_INFO "parport_pc: Via 686A weird parport base 0x%X, ignoring\n", + port1); + return 0; + } + + /* 0xF0_5: EPP+ECP enable */ + outb (0xF0, 0x3F0); + have_eppecp = (inb (0x3F1) & (1 << 5)); + + /* + * lock super i/o configuration, clear 0x85_1 + */ + pci_read_config_byte (pdev, 0x85, &tmp); + tmp &= ~(1 << 1); + pci_write_config_byte (pdev, 0x85, tmp); + + /* + * Get DMA and IRQ from PCI->ISA bridge PCI config registers + */ + + /* 0x50_3-2: PnP Routing for Parallel Port DRQ */ + pci_read_config_byte (pdev, 0x50, &dma); + dma = ((dma >> 2) & 0x03); + + /* 0x51_7-4: PnP Routing for Parallel Port IRQ */ + pci_read_config_byte (pdev, 0x51, &irq); + irq = ((irq >> 4) & 0x0F); + + /* filter bogus IRQs */ + switch (irq) { + case 0: + case 2: + case 8: + case 13: + irq = PARPORT_IRQ_NONE; + break; + + default: /* do nothing */ + break; + } + + /* if ECP not enabled, DMA is not enabled, assumed bogus 'dma' value */ + if (!have_eppecp) + dma = PARPORT_DMA_NONE; + + /* finally, do the probe with values obtained */ + if (parport_pc_probe_port (port1, port2, irq, dma, NULL)) { + printk (KERN_INFO "parport_pc: Via 686A parallel port: io=0x%X, irq=%d, dma=%d\n", + port1, irq, dma); + return 1; + } + + printk (KERN_WARNING "parport_pc: Strange, can't probe Via 686A parallel port: io=0x%X, irq=%d, dma=%d\n", + port1, irq, dma); + return 0; +} + + +enum parport_pc_sio_types { + sio_via_686a = 0, /* Via VT82C686A motherboard Super I/O */ +}; + + +/* each element directly indexed from enum list, above */ +static struct parport_pc_superio { + int (*probe) (struct pci_dev *pdev); +} parport_pc_superio_info[] __devinitdata = { + { sio_via_686a_probe, }, +}; + + +static struct pci_device_id parport_pc_pci_tbl[] __devinitdata = { + { 0x1106, 0x0686, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sio_via_686a }, + { 0, }, /* terminate list */ +}; + + +static int __devinit parport_pc_init_superio(void) +{ + const struct pci_device_id *id; + struct pci_dev *pdev; + + pci_for_each_dev(pdev) { + id = pci_match_device (parport_pc_pci_tbl, pdev); + if (id == NULL) + continue; + + return parport_pc_superio_info[id->driver_data].probe (pdev); + } + + return 0; /* zero devices found */ +} + + /* Look for PCI parallel port cards. */ static int __init parport_pc_init_pci (int irq, int dma) { +#ifndef PCI_VENDOR_ID_AFAVLAB +#define PCI_VENDOR_ID_AFAVLAB 0x14db +#define PCI_DEVICE_ID_AFAVLAB_TK9902 0x2120 +#endif + struct { unsigned int vendor; unsigned int device; @@ -1800,6 +1941,9 @@ static int __init parport_pc_init_pci (int irq, int dma) { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_SUBVENDOR_ID_EXSYS, PCI_SUBDEVICE_ID_EXSYS_4014, 2, { { 4, -1 }, { 5, -1 }, } }, + { PCI_VENDOR_ID_AFAVLAB, PCI_DEVICE_ID_AFAVLAB_TK9902, + PCI_ANY_ID, PCI_ANY_ID, + 1, { { 0, 1 }, } }, { 0, } }; diff --git a/drivers/parport/probe.c b/drivers/parport/probe.c index 6772ea6d8..9ab6d97e2 100644 --- a/drivers/parport/probe.c +++ b/drivers/parport/probe.c @@ -150,13 +150,11 @@ ssize_t parport_device_id (int devnum, char *buffer, size_t len) if (!retval) { int idlen; unsigned char length[2]; - mm_segment_t oldfs = get_fs (); - set_fs (get_ds ()); /* First two bytes are MSB,LSB of inclusive length. */ retval = parport_read (dev->port, length, 2); - if (retval != 2) goto restore_fs; + if (retval != 2) goto end_id; idlen = (length[0] << 8) + length[1] - 2; if (idlen < len) @@ -169,8 +167,8 @@ ssize_t parport_device_id (int devnum, char *buffer, size_t len) len); /* Some printer manufacturers mistakenly believe that - the length field is supposed to be _exclusive_. */ - /* In addition, there are broken devices out there + the length field is supposed to be _exclusive_. + In addition, there are broken devices out there that don't even finish off with a semi-colon. */ if (buffer[len - 1] != ';') { ssize_t diff; @@ -196,9 +194,8 @@ ssize_t parport_device_id (int devnum, char *buffer, size_t len) } } - restore_fs: + end_id: buffer[len] = '\0'; - set_fs (oldfs); parport_negotiate (dev->port, IEEE1284_MODE_COMPAT); } parport_release (dev); diff --git a/drivers/parport/share.c b/drivers/parport/share.c index 8059dfa22..fe5ea143b 100644 --- a/drivers/parport/share.c +++ b/drivers/parport/share.c @@ -247,7 +247,19 @@ void parport_announce_port (struct parport *port) { #ifdef CONFIG_PARPORT_1284 /* Analyse the IEEE1284.3 topology of the port. */ - parport_daisy_init (port); + if (parport_daisy_init (port) == 0) { + /* No devices were detected. Perhaps they are in some + funny state; let's try to reset them and see if + they wake up. */ + parport_daisy_fini (port); + parport_write_control (port, PARPORT_CONTROL_SELECT); + udelay (50); + parport_write_control (port, + PARPORT_CONTROL_SELECT | + PARPORT_CONTROL_INIT); + udelay (50); + parport_daisy_init (port); + } #endif /* Let drivers know that a new port has arrived. */ diff --git a/drivers/pci/pci.ids b/drivers/pci/pci.ids index 9556874c1..1dfedc0dd 100644 --- a/drivers/pci/pci.ids +++ b/drivers/pci/pci.ids @@ -2682,6 +2682,7 @@ 13c0 Microgate Corporation 0010 SyncLink WAN Adapter 13c1 3ware Inc + 1000 3ware ATA-RAID 13c2 Technotrend Systemtechnik GmbH 13c3 Janz Computer AG 13c4 Phase Metrics @@ -3424,6 +3425,7 @@ 71a0 440GX - 82443GX Host bridge 71a1 440GX - 82443GX AGP bridge 71a2 440GX - 82443GX Host bridge (AGP disabled) + 7601 82372FB PIIX4 IDE 7602 82372FB [PCI-to-USB UHCI] 7800 i740 1092 0100 Stealth II G460 diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c index 36c3be081..067e25647 100644 --- a/drivers/pci/proc.c +++ b/drivers/pci/proc.c @@ -197,10 +197,6 @@ static struct file_operations proc_bus_pci_operations = { write: proc_bus_pci_write, }; -static struct inode_operations proc_bus_pci_inode_operations = { - &proc_bus_pci_operations, /* default base directory file-ops */ -}; - #if BITS_PER_LONG == 32 #define LONG_FORMAT "\t%08lx" #else @@ -265,7 +261,7 @@ int pci_proc_attach_device(struct pci_dev *dev) e = dev->procent = create_proc_entry(name, S_IFREG | S_IRUGO | S_IWUSR, de); if (!e) return -ENOMEM; - e->ops = &proc_bus_pci_inode_operations; + e->proc_fops = &proc_bus_pci_operations; e->data = dev; e->size = PCI_CFG_SPACE_SIZE; return 0; diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c index 18d47d9a8..6ea612b84 100644 --- a/drivers/pcmcia/i82365.c +++ b/drivers/pcmcia/i82365.c @@ -165,25 +165,6 @@ typedef struct vg46x_state_t { u_char ctl, ema; } vg46x_state_t; -typedef struct ti113x_state_t { - u_int sysctl; - u_char cardctl, devctl, diag; -} ti113x_state_t; - -typedef struct rl5c4xx_state_t { - u_short misc, ctl, io, mem; -} rl5c4xx_state_t; - -typedef struct o2micro_state_t { - u_char mode_a, mode_b, mode_c, mode_d; - u_char mhpg, fifo, mode_e; -} o2micro_state_t; - -typedef struct topic_state_t { - u_char slot, ccr, cdr; - u_int rcr; -} topic_state_t; - typedef struct socket_info_t { u_short type, flags; socket_cap_t cap; @@ -276,22 +257,6 @@ static pcic_t pcic[] = { /*====================================================================*/ -/* Some PCI shortcuts */ - -#define config_readb(sock, r, v) pci_read_config_byte((sock)->pdev, r, v) -#define config_readw(sock, r, v) pci_read_config_word((sock)->pdev, r, v) -#define config_readl(sock, r, v) pci_read_config_dword((sock)->pdev, r, v) -#define config_writeb(sock, r, v) pci_write_config_byte((sock)->pdev, r, v) -#define config_writew(sock, r, v) pci_write_config_word((sock)->pdev, r, v) -#define config_writel(sock, r, v) pci_write_config_dword((sock)->pdev, r, v) - -#define cb_readb(s, r) readb(socket[s].cb_virt + (r)) -#define cb_readl(s, r) readl(socket[s].cb_virt + (r)) -#define cb_writeb(s, r, v) writeb(v, socket[s].cb_virt + (r)) -#define cb_writel(s, r, v) writel(v, socket[s].cb_virt + (r)) - -/*====================================================================*/ - static u_char i365_get(u_short sock, u_short reg) { { diff --git a/drivers/pcmcia/yenta.c b/drivers/pcmcia/yenta.c index 28821cbcf..3531348bb 100644 --- a/drivers/pcmcia/yenta.c +++ b/drivers/pcmcia/yenta.c @@ -17,6 +17,12 @@ #include "yenta.h" #include "i82365.h" +#if 0 +#define DEBUG(x,args...) printk(__FUNCTION__ ": " x,##args) +#else +#define DEBUG(x,args...) +#endif + /* Don't ask.. */ #define to_cycles(ns) ((ns)/120) #define to_ns(cycles) ((cycles)*120) @@ -26,13 +32,24 @@ * regular memory space ("cb_xxx"), configuration space * ("config_xxx") and compatibility space ("exca_xxxx") */ -#define cb_readl(sock,reg) readl((sock)->base + (reg)) -#define cb_writel(sock,reg,val) writel(val,(sock)->base + (reg)) +static inline u32 cb_readl(pci_socket_t *socket, unsigned reg) +{ + u32 val = readl(socket->base + reg); + DEBUG("%p %04x %08x\n", socket, reg, val); + return val; +} + +static inline void cb_writel(pci_socket_t *socket, unsigned reg, u32 val) +{ + DEBUG("%p %04x %08x\n", socket, reg, val); + writel(val, socket->base + reg); +} static inline u8 config_readb(pci_socket_t *socket, unsigned offset) { u8 val; pci_read_config_byte(socket->dev, offset, &val); + DEBUG("%p %04x %02x\n", socket, offset, val); return val; } @@ -40,6 +57,7 @@ static inline u16 config_readw(pci_socket_t *socket, unsigned offset) { u16 val; pci_read_config_word(socket->dev, offset, &val); + DEBUG("%p %04x %04x\n", socket, offset, val); return val; } @@ -47,25 +65,55 @@ static inline u32 config_readl(pci_socket_t *socket, unsigned offset) { u32 val; pci_read_config_dword(socket->dev, offset, &val); + DEBUG("%p %04x %08x\n", socket, offset, val); return val; } -#define config_writeb(s,off,val) pci_write_config_byte((s)->dev, (off), (val)) -#define config_writew(s,off,val) pci_write_config_word((s)->dev, (off), (val)) -#define config_writel(s,off,val) pci_write_config_dword((s)->dev, (off), (val)) +static inline void config_writeb(pci_socket_t *socket, unsigned offset, u8 val) +{ + DEBUG("%p %04x %02x\n", socket, offset, val); + pci_write_config_byte(socket->dev, offset, val); +} + +static inline void config_writew(pci_socket_t *socket, unsigned offset, u16 val) +{ + DEBUG("%p %04x %04x\n", socket, offset, val); + pci_write_config_word(socket->dev, offset, val); +} -#define exca_readb(sock,reg) readb((sock)->base + 0x800 + (reg)) -#define exca_writeb(sock,reg,v) writeb((v), (sock)->base + 0x800 + (reg)) +static inline void config_writel(pci_socket_t *socket, unsigned offset, u32 val) +{ + DEBUG("%p %04x %08x\n", socket, offset, val); + pci_write_config_dword(socket->dev, offset, val); +} + +static inline u8 exca_readb(pci_socket_t *socket, unsigned reg) +{ + u8 val = readb(socket->base + 0x800 + reg); + DEBUG("%p %04x %02x\n", socket, reg, val); + return val; +} + +static inline u8 exca_readw(pci_socket_t *socket, unsigned reg) +{ + u16 val; + val = readb(socket->base + 0x800 + reg); + val |= readb(socket->base + 0x800 + reg + 1) << 8; + DEBUG("%p %04x %04x\n", socket, reg, val); + return val; +} -static u16 exca_readw(pci_socket_t *socket, unsigned reg) +static inline void exca_writeb(pci_socket_t *socket, unsigned reg, u8 val) { - return exca_readb(socket, reg) | (exca_readb(socket, reg+1) << 8); + DEBUG("%p %04x %02x\n", socket, reg, val); + writeb(val, socket->base + 0x800 + reg); } static void exca_writew(pci_socket_t *socket, unsigned reg, u16 val) { - exca_writeb(socket, reg, val); - exca_writeb(socket, reg+1, val >> 8); + DEBUG("%p %04x %04x\n", socket, reg, val); + writeb(val, socket->base + 0x800 + reg); + writeb(val >> 8, socket->base + 0x800 + reg + 1); } /* diff --git a/drivers/pnp/isapnp_proc.c b/drivers/pnp/isapnp_proc.c index d9f73819f..658fa2ede 100644 --- a/drivers/pnp/isapnp_proc.c +++ b/drivers/pnp/isapnp_proc.c @@ -210,11 +210,6 @@ static struct file_operations isapnp_info_entry_operations = release: isapnp_info_entry_release, }; -static struct inode_operations isapnp_info_entry_inode_operations = -{ - &isapnp_info_entry_operations, /* default sound info directory file-ops */ -}; - static loff_t isapnp_proc_bus_lseek(struct file *file, loff_t off, int whence) { loff_t new; @@ -274,11 +269,6 @@ static struct file_operations isapnp_proc_bus_file_operations = read: isapnp_proc_bus_read, }; -static struct inode_operations isapnp_proc_bus_inode_operations = -{ - &isapnp_proc_bus_file_operations, -}; - static int isapnp_proc_attach_device(struct pci_dev *dev) { struct pci_bus *bus = dev->bus; @@ -295,7 +285,7 @@ static int isapnp_proc_attach_device(struct pci_dev *dev) e = dev->procent = create_proc_entry(name, S_IFREG | S_IRUGO, de); if (!e) return -ENOMEM; - e->ops = &isapnp_proc_bus_inode_operations; + e->proc_fops = &isapnp_proc_bus_file_operations; e->data = dev; e->size = 256; return 0; @@ -378,7 +368,7 @@ int __init isapnp_proc_init(void) isapnp_proc_entry = NULL; p = create_proc_entry("isapnp", S_IFREG | S_IRUGO | S_IWUSR, &proc_root); if (p) - p->ops = &isapnp_info_entry_inode_operations; + p->proc_fops = &isapnp_info_entry_operations; isapnp_proc_entry = p; isapnp_proc_bus_dir = proc_mkdir("isapnp", proc_bus); isapnp_proc_devices_entry = create_proc_info_entry("devices", 0, diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c index 5477bb1ac..42b86930d 100644 --- a/drivers/scsi/3w-xxxx.c +++ b/drivers/scsi/3w-xxxx.c @@ -85,7 +85,7 @@ static void tw_copy_mem_info(TW_Info *info, char *data, int len); static void tw_interrupt(int irq, void *dev_instance, struct pt_regs *regs); /* Globals */ -char *tw_driver_version="0.4.001"; +char *tw_driver_version="1.0.000"; TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT]; int tw_device_extension_count = 0; @@ -2051,12 +2051,16 @@ int tw_scsiop_read_write(TW_Device_Extension *tw_dev, int request_id) command_packet->status = 0; command_packet->flags = 0; + if ((srb->cmnd[0] == WRITE_6) || (srb->cmnd[0] == WRITE_10)) { + if ((srb->cmnd[1] & 0x8) || (srb->cmnd[1] & 0x10)) + command_packet->flags = 1; + } + if (srb->cmnd[0] == READ_6 || srb->cmnd[0] == WRITE_6) { lba = ((u32)srb->cmnd[1] << 16) | ((u32)srb->cmnd[2] << 8) | (u32)srb->cmnd[3]; num_sectors = (u32)srb->cmnd[4]; } else { - lba = ((u32)srb->cmnd[2] << 24) | ((u32)srb->cmnd[3] << 16) | - ((u32)srb->cmnd[4] << 8) | (u32)srb->cmnd[5]; + lba = ((u32)srb->cmnd[2] << 24) | ((u32)srb->cmnd[3] << 16) | ((u32)srb->cmnd[4] << 8) | (u32)srb->cmnd[5]; num_sectors = (u32)srb->cmnd[8] | ((u32)srb->cmnd[7] << 8); } diff --git a/drivers/scsi/ChangeLog.sym53c8xx b/drivers/scsi/ChangeLog.sym53c8xx index ed169320a..4abf98759 100644 --- a/drivers/scsi/ChangeLog.sym53c8xx +++ b/drivers/scsi/ChangeLog.sym53c8xx @@ -1,3 +1,17 @@ +Sun Feb 20 11:00 2000 Gerard Roudier (groudier@club-internet.fr) + * version sym53c8xx-1.5j + - Add support for the new dynamic dma mapping kernel interface. + Requires Linux-2.3.47 (tested with pre-2.3.47-6). + Many thanks to David S. Miller for his preliminary changes + that have been useful guidelines, for having reviewed the + code and having tested this driver version on Ultra-Sparc. + - 2 tiny bugs fixed in the PCI wrapper that provides support + for early kernels without pci device structure. + - Get data transfer direction from the scsi command structure + (Scsi_Cmnd) with kernels that provide this information. + - Fix an old bug that only affected 896 rev. 1 when driver + profile support option was set in kernel configuration. + Sat Jan 8 22:00 2000 Gerard Roudier (groudier@club-internet.fr) * version sym53c8xx-1.5h - Add year 2000 copyright. diff --git a/drivers/scsi/Config.in b/drivers/scsi/Config.in index 9faa91e1b..4395cd682 100644 --- a/drivers/scsi/Config.in +++ b/drivers/scsi/Config.in @@ -44,6 +44,19 @@ if [ "$CONFIG_DECSTATION" = "y" ]; then dep_tristate 'DEC SII Scsi Driver' CONFIG_SCSI_DECSII $CONFIG_SCSI fi +if [ "$CONFIG_SGI_IP22" = "y" ]; then + dep_tristate 'SGI WD93C93 SCSI Driver' CONFIG_SCSI_SGIWD93 $CONFIG_SCSI +fi +if [ "$CONFIG_DECSTATION" = "y" ]; then + if [ "$CONFIG_TC" = "y" ]; then + dep_tristate 'DEC NCR53C94 Scsi Driver' CONFIG_SCSI_DECNCR $CONFIG_SCSI + fi + dep_tristate 'DEC SII Scsi Driver' CONFIG_SCSI_DECSII $CONFIG_SCSI +fi + +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + dep_tristate '3ware Hardware ATA-RAID support (EXPERIMENTAL)' CONFIG_BLK_DEV_3W_XXXX_RAID $CONFIG_SCSI +fi dep_tristate '7000FASST SCSI support' CONFIG_SCSI_7000FASST $CONFIG_SCSI dep_tristate 'ACARD SCSI support' CONFIG_SCSI_ACARD $CONFIG_SCSI dep_tristate 'Adaptec AHA152X/2825 support' CONFIG_SCSI_AHA152X $CONFIG_SCSI @@ -188,9 +201,6 @@ fi if [ "$CONFIG_MIPS_JAZZ" = "y" ]; then bool 'MIPS JAZZ FAS216 SCSI support' CONFIG_JAZZ_ESP fi -if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - dep_tristate '3Ware Hardware ATA-RAID support (EXPERIMENTAL)' CONFIG_BLK_DEV_3W_XXXX_RAID $CONFIG_SCSI -fi endmenu diff --git a/drivers/scsi/eata_dma_proc.c b/drivers/scsi/eata_dma_proc.c index 725a70a4a..8768db48c 100644 --- a/drivers/scsi/eata_dma_proc.c +++ b/drivers/scsi/eata_dma_proc.c @@ -167,7 +167,7 @@ int eata_proc_info(char *buffer, char **start, off_t offset, int length, cmnd[9] = 0; scmd->cmd_len = 10; - scmd->sc_data_direction = DATA_READ; + scmd->sc_data_direction = SCSI_DATA_READ; /* * Do the command and wait for it to finish. diff --git a/drivers/scsi/pci2000.c b/drivers/scsi/pci2000.c index e07417b7e..6aef8ae63 100644 --- a/drivers/scsi/pci2000.c +++ b/drivers/scsi/pci2000.c @@ -60,9 +60,6 @@ #include #endif -struct proc_dir_entry Proc_Scsi_Pci2000 = - { PROC_SCSI_PCI2000, 7, "pci2000", S_IFDIR | S_IRUGO | S_IXUGO, 2 }; - //#define DEBUG 1 #ifdef DEBUG diff --git a/drivers/scsi/pci2000.h b/drivers/scsi/pci2000.h index a3daa5f76..15652ca9f 100644 --- a/drivers/scsi/pci2000.h +++ b/drivers/scsi/pci2000.h @@ -200,59 +200,25 @@ int Pci2000_BiosParam (Disk *disk, kdev_t dev, int geom[]); #define NULL 0 #endif -extern struct proc_dir_entry Proc_Scsi_Pci2000; - -#if LINUX_VERSION_CODE >= LINUXVERSION(2,1,75) -#define PCI2000 { \ - next: NULL, \ - module: NULL, \ - proc_dir: &Proc_Scsi_Pci2000, \ - proc_info: NULL, /* let's not bloat the kernel */ \ - name: "PCI-2000 SCSI Intelligent Disk Controller",\ - detect: Pci2000_Detect, \ - release: Pci2000_Release, \ - info: NULL, /* let's not bloat the kernel */ \ - command: Pci2000_Command, \ - queuecommand: Pci2000_QueueCommand, \ - eh_strategy_handler: NULL, \ - eh_abort_handler: NULL, \ - eh_device_reset_handler: NULL, \ - eh_bus_reset_handler: NULL, \ - eh_host_reset_handler: NULL, \ - abort: Pci2000_Abort, \ - reset: Pci2000_Reset, \ - slave_attach: NULL, \ - bios_param: Pci2000_BiosParam, \ - can_queue: 16, \ - this_id: -1, \ - sg_tablesize: 16, \ - cmd_per_lun: 1, \ - present: 0, \ - unchecked_isa_dma: 0, \ - use_clustering: DISABLE_CLUSTERING, \ - use_new_eh_code: 0 \ - } -#else -#define PCI2000 { NULL, NULL, \ - &Proc_Scsi_Pci2000,/* proc_dir_entry */ \ - NULL, \ - "PCI-2000 SCSI Intelligent Disk Controller",\ - Pci2000_Detect, \ - Pci2000_Release, \ - NULL, \ - Pci2000_Command, \ - Pci2000_QueueCommand, \ - Pci2000_Abort, \ - Pci2000_Reset, \ - NULL, \ - Pci2000_BiosParam, \ - 16, \ - -1, \ - 16, \ - 1, \ - 0, \ - 0, \ - DISABLE_CLUSTERING } -#endif +/* screen is 80 columns wide, damnit! */ +#define PCI2000 { \ + proc_name: "pci2000", \ + name: "PCI-2000 SCSI Intelligent Disk Controller", \ + detect: Pci2000_Detect, \ + release: Pci2000_Release, \ + command: Pci2000_Command, \ + queuecommand: Pci2000_QueueCommand, \ + abort: Pci2000_Abort, \ + reset: Pci2000_Reset, \ + bios_param: Pci2000_BiosParam, \ + can_queue: 16, \ + this_id: -1, \ + sg_tablesize: 16, \ + cmd_per_lun: 1, \ + present: 0, \ + unchecked_isa_dma:0, \ + use_clustering: DISABLE_CLUSTERING, \ + use_new_eh_code:0 \ +} #endif diff --git a/drivers/scsi/pci2220i.c b/drivers/scsi/pci2220i.c index 80f58cb8e..fabb61c0c 100644 --- a/drivers/scsi/pci2220i.c +++ b/drivers/scsi/pci2220i.c @@ -67,9 +67,6 @@ #define WRITE_CMD IDE_CMD_WRITE_MULTIPLE #define MAX_BUS_MASTER_BLOCKS SECTORSXFER // This is the maximum we can bus master -struct proc_dir_entry Proc_Scsi_Pci2220i = - { PROC_SCSI_PCI2220I, 8, "pci2220i", S_IFDIR | S_IRUGO | S_IXUGO, 2 }; - #ifdef DEBUG #define DEB(x) x #define STOP_HERE() {int st;for(st=0;st<100;st++){st=1;}} diff --git a/drivers/scsi/pci2220i.h b/drivers/scsi/pci2220i.h index aaa8457fc..689e62573 100644 --- a/drivers/scsi/pci2220i.h +++ b/drivers/scsi/pci2220i.h @@ -39,59 +39,23 @@ int Pci2220i_BiosParam (Disk *disk, kdev_t dev, int geom[]); #define NULL 0 #endif -extern struct proc_dir_entry Proc_Scsi_Pci2220i; - -#if LINUX_VERSION_CODE >= LINUXVERSION(2,1,75) -#define PCI2220I { \ - next: NULL, \ - module: NULL, \ - proc_dir: &Proc_Scsi_Pci2220i, \ - proc_info: NULL, /* let's not bloat the kernel */\ - name: "PCI-2220I/PCI-2240I", \ - detect: Pci2220i_Detect, \ - release: Pci2220i_Release, \ - info: NULL, /* let's not bloat the kernel */\ - command: Pci2220i_Command, \ - queuecommand: Pci2220i_QueueCommand, \ - eh_strategy_handler: NULL, \ - eh_abort_handler: NULL, \ - eh_device_reset_handler: NULL, \ - eh_bus_reset_handler: NULL, \ - eh_host_reset_handler: NULL, \ - abort: Pci2220i_Abort, \ - reset: Pci2220i_Reset, \ - slave_attach: NULL, \ - bios_param: Pci2220i_BiosParam, \ - can_queue: 1, \ - this_id: -1, \ - sg_tablesize: SG_ALL, \ - cmd_per_lun: 1, \ - present: 0, \ - unchecked_isa_dma: 0, \ - use_clustering: DISABLE_CLUSTERING, \ - use_new_eh_code: 0 \ - } -#else -#define PCI2220I { NULL, NULL, \ - &Proc_Scsi_Pci2220i,/* proc_dir_entry */\ - NULL, \ - "PCI-2220I/PCI-2240I", \ - Pci2220i_Detect, \ - Pci2220i_Release, \ - NULL, \ - Pci2220i_Command, \ - Pci2220i_QueueCommand, \ - Pci2220i_Abort, \ - Pci2220i_Reset, \ - NULL, \ - Pci2220i_BiosParam, \ - 1, \ - -1, \ - SG_ALL, \ - 1, \ - 0, \ - 0, \ - DISABLE_CLUSTERING } -#endif - +#define PCI2220I { \ + proc_name: "pci2220i", \ + name: "PCI-2220I/PCI-2240I", \ + detect: Pci2220i_Detect, \ + release: Pci2220i_Release, \ + command: Pci2220i_Command, \ + queuecommand: Pci2220i_QueueCommand, \ + abort: Pci2220i_Abort, \ + reset: Pci2220i_Reset, \ + bios_param: Pci2220i_BiosParam, \ + can_queue: 1, \ + this_id: -1, \ + sg_tablesize: SG_ALL, \ + cmd_per_lun: 1, \ + present: 0, \ + unchecked_isa_dma: 0, \ + use_clustering: DISABLE_CLUSTERING, \ + use_new_eh_code: 0 \ +} #endif diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index e216ef03a..42f208062 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c @@ -426,25 +426,6 @@ static char dummy_buffer[60] = "Please don't add commas in your insmod command!! #endif - -/* - * Our directory Entry in /proc/scsi for the user to - * access the driver. - */ - -#if 0 - -/* Need to add in proc_fs.h PROC_SCSI_QL1280 */ -#define PROC_SCSI_QL1280 PROC_SCSI_QLOGICISP - -struct proc_dir_entry proc_scsi_qla1280 = { - PROC_SCSI_QL1280, 7, "qla1280", - S_IFDIR | S_IRUGO | S_IXUGO, 2, - 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL -}; - -#endif - /* We use the Scsi_Pointer structure that's included with each command * SCSI_Cmnd as a scratchpad for our SRB. * @@ -2749,13 +2730,13 @@ qla1280_setup_chip(scsi_qla_host_t *ha) long risc_code_size; uint16_t mb[MAILBOX_REGISTER_COUNT]; #ifdef QLA1280_UNUSED + uint8_t *sp; int i; #endif uint16_t cnt; int num; - uint8_t *tbuf, *sp; + uint8_t *tbuf; u_long p_tbuf; - int i; #ifdef QL_DEBUG_LEVEL_3 ENTER("qla1280_setup_chip"); diff --git a/drivers/scsi/qlogicfc.c b/drivers/scsi/qlogicfc.c index 283fe9c3d..df9ba38d4 100644 --- a/drivers/scsi/qlogicfc.c +++ b/drivers/scsi/qlogicfc.c @@ -18,6 +18,9 @@ /* This is a version of the isp1020 driver which was modified by * Chris Loveland to support the isp2100 and isp2200 + * + * Big endian support and dynamic DMA mapping added + * by Jakub Jelinek . */ /* @@ -59,6 +62,24 @@ #include "sd.h" #include "hosts.h" + +#if 1 +/* Once pci64_ DMA mapping interface is in, kill this. */ +typedef dma_addr_t dma64_addr_t; +#define pci64_alloc_consistent(d,s,p) pci_alloc_consistent((d),(s),(p)) +#define pci64_free_consistent(d,s,c,a) pci_free_consistent((d),(s),(c),(a)) +#define pci64_map_single(d,c,s,dir) pci_map_single((d),(c),(s),(dir)) +#define pci64_map_sg(d,s,n,dir) pci_map_sg((d),(s),(n),(dir)) +#define pci64_unmap_single(d,a,s,dir) pci_unmap_single((d),(a),(s),(dir)) +#define pci64_unmap_sg(d,s,n,dir) pci_unmap_sg((d),(s),(n),(dir)) +#define pci64_dma_hi32(a) 0 +#define pci64_dma_lo32(a) (a) +#define pci64_dma_build(hi,lo) (lo) +#define sg_dma64_address(s) sg_dma_address(s) +#define sg_dma64_len(s) sg_dma_len(s) +#define PCI64_DMA_BITS 32 +#endif + #include "qlogicfc.h" /* Configuration section **************************************************** */ @@ -157,18 +178,6 @@ struct { #endif /* DEBUG ISP2x00_INTR */ -#if BITS_PER_LONG > 32 -#define virt_to_bus_low32(x) ((u32) (0xffffffff & virt_to_bus(x))) -#define virt_to_bus_high32(x) ((u32) (0xffffffff & (virt_to_bus(x)>>32))) -#define bus_to_virt_low32(x) ((u32) (0xffffffff & bus_to_virt(x))) -#define bus_to_virt_high32(x) ((u32) (0xffffffff & (bus_to_virt(x)>>32))) -#else -#define virt_to_bus_low32(x) virt_to_bus(x) -#define virt_to_bus_high32(x) 0x0 -#define bus_to_virt_low32(x) bus_to_virt(x) -#define bus_to_virt_high32(x) 0x0 -#endif - #define ISP2100_REV_ID1 1 #define ISP2100_REV_ID3 3 #define ISP2200_REV_ID5 5 @@ -230,7 +239,7 @@ struct Entry_header { }; /* entry header type commands */ -#if BITS_PER_LONG > 32 +#if PCI64_DMA_BITS > 32 #define ENTRY_COMMAND 0x19 #define ENTRY_CONTINUATION 0x0a #else @@ -247,34 +256,23 @@ struct Entry_header { #define EFLAG_BAD_HEADER 4 #define EFLAG_BAD_PAYLOAD 8 -#if BITS_PER_LONG > 32 +#if PCI64_DMA_BITS > 32 + struct dataseg { u_int d_base; u_int d_base_hi; u_int d_count; }; -struct Command_Entry { - struct Entry_header hdr; - u_int handle; - u_char target_lun; - u_char target_id; - u_short expanded_lun; - u_short control_flags; - u_short rsvd2; - u_short time_out; - u_short segment_cnt; - u_char cdb[16]; - u_int total_byte_cnt; - struct dataseg dataseg[DATASEGS_PER_COMMAND]; -}; - #else + struct dataseg { u_int d_base; u_int d_count; }; +#endif + struct Command_Entry { struct Entry_header hdr; u_int handle; @@ -290,9 +288,6 @@ struct Command_Entry { struct dataseg dataseg[DATASEGS_PER_COMMAND]; }; -#endif - - /* command entry control flag definitions */ #define CFLAG_NODISC 0x01 #define CFLAG_HEAD_TAG 0x02 @@ -302,7 +297,7 @@ struct Command_Entry { #define CFLAG_READ 0x20 #define CFLAG_WRITE 0x40 -#if BITS_PER_LONG > 32 +#if PCI64_DMA_BITS > 32 struct Continuation_Entry { struct Entry_header hdr; struct dataseg dataseg[DATASEGS_PER_CONT]; @@ -650,6 +645,9 @@ struct init_cb { #define AS_REDO_FABRIC_PORTDB 2 #define AS_REDO_LOOP_PORTDB 4 +#define RES_SIZE ((RES_QUEUE_LEN + 1)*QUEUE_ENTRY_LEN) +#define REQ_SIZE ((QLOGICFC_REQ_QUEUE_LEN + 1)*QUEUE_ENTRY_LEN) + struct isp2x00_hostdata { u_char revision; struct pci_dev *pci_dev; @@ -730,6 +728,7 @@ int isp2x00_detect(Scsi_Host_Template * tmpt) struct isp2x00_hostdata *hostdata; struct pci_dev *pdev = NULL; unsigned short device_ids[2]; + dma64_addr_t busaddr; int i; @@ -756,50 +755,43 @@ int isp2x00_detect(Scsi_Host_Template * tmpt) memset(hostdata, 0, sizeof(struct isp2x00_hostdata)); hostdata->pci_dev = pdev; - hostdata->res = (char *) kmalloc((RES_QUEUE_LEN + 1)*QUEUE_ENTRY_LEN, GFP_KERNEL); + hostdata->res = pci64_alloc_consistent(pdev, RES_SIZE + REQ_SIZE, &busaddr); + if (!hostdata->res){ - printk("qlogicfc%d : could not allocate memory for response queue.\n", hostdata->host_id); - scsi_unregister(host); - continue; - } - hostdata->req = (char *) kmalloc((QLOGICFC_REQ_QUEUE_LEN + 1)*QUEUE_ENTRY_LEN, GFP_KERNEL); - if (!hostdata->req){ - printk("qlogicfc%d : could not allocate memory for request queue.\n", hostdata->host_id); - kfree(hostdata->res); + printk("qlogicfc%d : could not allocate memory for request and response queue.\n", hostdata->host_id); scsi_unregister(host); continue; } - + hostdata->req = hostdata->res + (RES_QUEUE_LEN + 1)*QUEUE_ENTRY_LEN; hostdata->queued = 0; /* set up the control block */ hostdata->control_block.version = 0x1; - hostdata->control_block.firm_opts = 0x800e; - hostdata->control_block.max_frame_len = 2048; - hostdata->control_block.max_iocb = QLOGICFC_REQ_QUEUE_LEN; - hostdata->control_block.exec_throttle = QLOGICFC_CMD_PER_LUN; + hostdata->control_block.firm_opts = cpu_to_le16(0x800e); + hostdata->control_block.max_frame_len = cpu_to_le16(2048); + hostdata->control_block.max_iocb = cpu_to_le16(QLOGICFC_REQ_QUEUE_LEN); + hostdata->control_block.exec_throttle = cpu_to_le16(QLOGICFC_CMD_PER_LUN); hostdata->control_block.retry_delay = 5; hostdata->control_block.retry_cnt = 1; - hostdata->control_block.node_name[0] = 0x0020; - hostdata->control_block.node_name[1] = 0xE000; - hostdata->control_block.node_name[2] = 0x008B; - hostdata->control_block.node_name[3] = 0x0000; - hostdata->control_block.hard_addr = 0x0003; - hostdata->control_block.req_queue_len = QLOGICFC_REQ_QUEUE_LEN + 1; - hostdata->control_block.res_queue_len = RES_QUEUE_LEN + 1; - hostdata->control_block.res_queue_addr_lo = virt_to_bus_low32(hostdata->res); - hostdata->control_block.res_queue_addr_high = virt_to_bus_high32(hostdata->res); - hostdata->control_block.req_queue_addr_lo = virt_to_bus_low32(hostdata->req); - hostdata->control_block.req_queue_addr_high = virt_to_bus_high32(hostdata->req); - - - hostdata->control_block.add_firm_opts |= CONNECTION_PREFERENCE<<4; + hostdata->control_block.node_name[0] = cpu_to_le16(0x0020); + hostdata->control_block.node_name[1] = cpu_to_le16(0xE000); + hostdata->control_block.node_name[2] = cpu_to_le16(0x008B); + hostdata->control_block.node_name[3] = cpu_to_le16(0x0000); + hostdata->control_block.hard_addr = cpu_to_le16(0x0003); + hostdata->control_block.req_queue_len = cpu_to_le16(QLOGICFC_REQ_QUEUE_LEN + 1); + hostdata->control_block.res_queue_len = cpu_to_le16(RES_QUEUE_LEN + 1); + hostdata->control_block.res_queue_addr_lo = cpu_to_le32(pci64_dma_lo32(busaddr)); + hostdata->control_block.res_queue_addr_high = cpu_to_le32(pci64_dma_hi32(busaddr)); + hostdata->control_block.req_queue_addr_lo = cpu_to_le32(pci64_dma_lo32(busaddr + RES_SIZE)); + hostdata->control_block.req_queue_addr_high = cpu_to_le32(pci64_dma_hi32(busaddr + RES_SIZE)); + + + hostdata->control_block.add_firm_opts |= cpu_to_le16(CONNECTION_PREFERENCE<<4); hostdata->adapter_state = AS_LOOP_DOWN; hostdata->explore_timer.data = 1; hostdata->host_id = hosts; if (isp2x00_init(host) || isp2x00_reset_hardware(host)) { - kfree(hostdata->res); - kfree(hostdata->req); + pci64_free_consistent (pdev, RES_SIZE + REQ_SIZE, hostdata->res, busaddr); scsi_unregister(host); continue; } @@ -808,8 +800,7 @@ int isp2x00_detect(Scsi_Host_Template * tmpt) if (request_irq(host->irq, do_isp2x00_intr_handler, SA_INTERRUPT | SA_SHIRQ, "qlogicfc", host)) { printk("qlogicfc%d : interrupt %d already in use\n", hostdata->host_id, host->irq); - kfree(hostdata->res); - kfree(hostdata->req); + pci64_free_consistent (pdev, RES_SIZE + REQ_SIZE, hostdata->res, busaddr); scsi_unregister(host); continue; } @@ -818,8 +809,7 @@ int isp2x00_detect(Scsi_Host_Template * tmpt) "in use\n", hostdata->host_id, host->io_port, host->io_port + 0xff); free_irq(host->irq, host); - kfree(hostdata->res); - kfree(hostdata->req); + pci64_free_consistent (pdev, RES_SIZE + REQ_SIZE, hostdata->res, busaddr); scsi_unregister(host); continue; } @@ -977,12 +967,13 @@ int isp2x00_init_fabric(struct Scsi_Host *host, struct id_name_map *port_db, int u_short loop_id = 0x81; u_short scsi_id = cur_scsi_id; u_int port_id; - struct sns_cb req; - u_char sns_response[608]; + struct sns_cb *req; + u_char *sns_response; + dma64_addr_t busaddr; struct isp2x00_hostdata *hostdata; hostdata = (struct isp2x00_hostdata *) host->hostdata; - + DEBUG_FABRIC(printk("qlogicfc%d : Checking for a fabric.\n", hostdata->host_id)); param[0] = MBOX_GET_PORT_NAME; param[1] = (u16)FABRIC_PORT << 8; @@ -995,52 +986,60 @@ int isp2x00_init_fabric(struct Scsi_Host *host, struct id_name_map *port_db, int } printk("qlogicfc%d : Fabric found.\n", hostdata->host_id); + req = (struct sns_cb *)pci64_alloc_consistent(hostdata->pci_dev, sizeof(*req) + 608, &busaddr); + + if (!req){ + printk("qlogicfc%d : Could not allocate DMA resources for fabric initialization\n", hostdata->host_id); + return 0; + } + sns_response = (u_char *)(req + 1); + if (hostdata->adapter_state & AS_REDO_LOOP_PORTDB){ - memset(&req, 0, sizeof(req)); + memset(req, 0, sizeof(*req)); - req.len = 8; - req.response_low = virt_to_bus_low32(sns_response); - req.response_high = virt_to_bus_high32(sns_response); - req.sub_len = 22; - req.data[0] = 0x17; - req.data[1] = 0x02; - req.data[8] = (u_char) (hostdata->port_id & 0xff); - req.data[9] = (u_char) (hostdata->port_id >> 8 & 0xff); - req.data[10] = (u_char) (hostdata->port_id >> 16 & 0xff); - req.data[13] = 0x01; + req->len = cpu_to_le16(8); + req->response_low = cpu_to_le32(pci64_dma_lo32(busaddr + sizeof(*req))); + req->response_high = cpu_to_le32(pci64_dma_hi32(busaddr + sizeof(*req))); + req->sub_len = cpu_to_le16(22); + req->data[0] = 0x17; + req->data[1] = 0x02; + req->data[8] = (u_char) (hostdata->port_id & 0xff); + req->data[9] = (u_char) (hostdata->port_id >> 8 & 0xff); + req->data[10] = (u_char) (hostdata->port_id >> 16 & 0xff); + req->data[13] = 0x01; param[0] = MBOX_SEND_SNS; param[1] = 30; - param[2] = virt_to_bus_low32(&req) >> 16; - param[3] = virt_to_bus_low32(&req); - param[6] = virt_to_bus_high32(&req) >> 16; - param[7] = virt_to_bus_high32(&req); - + param[2] = pci64_dma_lo32(busaddr) >> 16; + param[3] = pci64_dma_lo32(busaddr); + param[6] = pci64_dma_hi32(busaddr) >> 16; + param[7] = pci64_dma_hi32(busaddr); + isp2x00_mbox_command(host, param); if (param[0] != MBOX_COMMAND_COMPLETE) - printk("qlogicfc%d : error sending RFC-4\n", hostdata->host_id); + printk("qlogicfc%d : error sending RFC-4\n", hostdata->host_id); } port_id = hostdata->port_id; while (!done) { - memset(&req, 0, sizeof(req)); - - req.len = 304; - req.response_low = virt_to_bus_low32(sns_response); - req.response_high = virt_to_bus_high32(sns_response); - req.sub_len = 6; - req.data[0] = 0x00; - req.data[1] = 0x01; - req.data[8] = (u_char) (port_id & 0xff); - req.data[9] = (u_char) (port_id >> 8 & 0xff); - req.data[10] = (u_char) (port_id >> 16 & 0xff); + memset(req, 0, sizeof(*req)); + + req->len = cpu_to_le16(304); + req->response_low = cpu_to_le32(pci64_dma_lo32(busaddr + sizeof(*req))); + req->response_high = cpu_to_le32(pci64_dma_hi32(busaddr + sizeof(*req))); + req->sub_len = cpu_to_le16(6); + req->data[0] = 0x00; + req->data[1] = 0x01; + req->data[8] = (u_char) (port_id & 0xff); + req->data[9] = (u_char) (port_id >> 8 & 0xff); + req->data[10] = (u_char) (port_id >> 16 & 0xff); param[0] = MBOX_SEND_SNS; param[1] = 14; - param[2] = virt_to_bus_low32(&req) >> 16; - param[3] = virt_to_bus_low32(&req); - param[6] = virt_to_bus_high32(&req) >> 16; - param[7] = virt_to_bus_high32(&req); + param[2] = pci64_dma_lo32(busaddr) >> 16; + param[3] = pci64_dma_lo32(busaddr); + param[6] = pci64_dma_hi32(busaddr) >> 16; + param[7] = pci64_dma_hi32(busaddr); isp2x00_mbox_command(host, param); @@ -1089,10 +1088,12 @@ int isp2x00_init_fabric(struct Scsi_Host *host, struct id_name_map *port_db, int done = 1; } else { printk("qlogicfc%d : Get All Next failed %x.\n", hostdata->host_id, param[0]); + pci64_free_consistent(hostdata->pci_dev, sizeof(*req) + 608, req, busaddr); return 0; } } + pci64_free_consistent(hostdata->pci_dev, sizeof(*req) + 608, req, busaddr); return 1; } @@ -1102,6 +1103,7 @@ int isp2x00_init_fabric(struct Scsi_Host *host, struct id_name_map *port_db, int int isp2x00_release(struct Scsi_Host *host) { struct isp2x00_hostdata *hostdata; + dma64_addr_t busaddr; ENTER("isp2x00_release"); @@ -1112,8 +1114,9 @@ int isp2x00_release(struct Scsi_Host *host) release_region(host->io_port, 0xff); - kfree(hostdata->res); - kfree(hostdata->req); + busaddr = pci64_dma_build(le32_to_cpu(hostdata->control_block.res_queue_addr_high), + le32_to_cpu(hostdata->control_block.res_queue_addr_lo)); + pci64_free_consistent(hostdata->pci_dev, RES_SIZE + REQ_SIZE, hostdata->res, busaddr); LEAVE("isp2x00_release"); @@ -1245,19 +1248,20 @@ int isp2x00_queuecommand(Scsi_Cmnd * Cmnd, void (*done) (Scsi_Cmnd *)) cmd->hdr.entry_type = ENTRY_COMMAND; cmd->hdr.entry_cnt = 1; cmd->target_lun = Cmnd->lun; - cmd->expanded_lun = Cmnd->lun; + cmd->expanded_lun = cpu_to_le16(Cmnd->lun); #if ISP2x00_PORTDB cmd->target_id = hostdata->port_db[Cmnd->target].loop_id; #else cmd->target_id = Cmnd->target; #endif - cmd->total_byte_cnt = (u_int) Cmnd->request_bufflen; + cmd->total_byte_cnt = cpu_to_le32(Cmnd->request_bufflen); cmd->time_out = 0; memcpy(cmd->cdb, Cmnd->cmnd, Cmnd->cmd_len); if (Cmnd->use_sg) { - cmd->segment_cnt = sg_count = Cmnd->use_sg; sg = (struct scatterlist *) Cmnd->request_buffer; + sg_count = pci64_map_sg(hostdata->pci_dev, sg, Cmnd->use_sg, scsi_to_pci_dma_dir(Cmnd->sc_data_direction)); + cmd->segment_cnt = cpu_to_le16(sg_count); ds = cmd->dataseg; /* fill in first two sg entries: */ n = sg_count; @@ -1265,11 +1269,11 @@ int isp2x00_queuecommand(Scsi_Cmnd * Cmnd, void (*done) (Scsi_Cmnd *)) n = DATASEGS_PER_COMMAND; for (i = 0; i < n; i++) { - ds[i].d_base = virt_to_bus_low32(sg->address); -#if BITS_PER_LONG > 32 - ds[i].d_base_hi = virt_to_bus_high32(sg->address); + ds[i].d_base = cpu_to_le32(pci64_dma_lo32(sg_dma64_address(sg))); +#if PCI64_DMA_BITS > 32 + ds[i].d_base_hi = cpu_to_le32(pci64_dma_hi32(sg_dma64_address(sg))); #endif - ds[i].d_count = sg->length; + ds[i].d_count = cpu_to_le32(sg_dma64_len(sg)); ++sg; } sg_count -= DATASEGS_PER_COMMAND; @@ -1291,22 +1295,32 @@ int isp2x00_queuecommand(Scsi_Cmnd * Cmnd, void (*done) (Scsi_Cmnd *)) if (n > DATASEGS_PER_CONT) n = DATASEGS_PER_CONT; for (i = 0; i < n; ++i) { - ds[i].d_base = virt_to_bus_low32(sg->address); -#if BITS_PER_LONG > 32 - ds[i].d_base_hi = virt_to_bus_high32(sg->address); + ds[i].d_base = cpu_to_le32(pci64_dma_lo32(sg_dma64_address(sg))); +#if PCI64_DMA_BITS > 32 + ds[i].d_base_hi = cpu_to_le32(pci64_dma_hi32(sg_dma64_address(sg))); #endif - ds[i].d_count = sg->length; + ds[i].d_count = cpu_to_le32(sg_dma64_len(sg)); ++sg; } sg_count -= n; } + } else if (Cmnd->request_bufflen) { + dma64_addr_t busaddr = pci64_map_single(hostdata->pci_dev, Cmnd->request_buffer, Cmnd->request_bufflen, + scsi_to_pci_dma_dir(Cmnd->sc_data_direction)); + + *(dma64_addr_t *)&Cmnd->SCp = busaddr; + cmd->dataseg[0].d_base = cpu_to_le32(pci64_dma_lo32(busaddr)); +#if PCI64_DMA_BITS > 32 + cmd->dataseg[0].d_base_hi = cpu_to_le32(pci64_dma_hi32(busaddr)); +#endif + cmd->dataseg[0].d_count = cpu_to_le32(Cmnd->request_bufflen); + cmd->segment_cnt = cpu_to_le16(1); } else { - cmd->dataseg[0].d_base = virt_to_bus_low32(Cmnd->request_buffer); -#if BITS_PER_LONG > 32 - cmd->dataseg[0].d_base_hi = virt_to_bus_high32(Cmnd->request_buffer); + cmd->dataseg[0].d_base = 0; +#if PCI64_DMA_BITS > 32 + cmd->dataseg[0].d_base_hi = 0; #endif - cmd->dataseg[0].d_count = (u_int) Cmnd->request_bufflen; - cmd->segment_cnt = 1; + cmd->segment_cnt = cpu_to_le16(1); /* Shouldn't this be 0? */ } switch (Cmnd->cmnd[0]) { @@ -1317,38 +1331,28 @@ int isp2x00_queuecommand(Scsi_Cmnd * Cmnd, void (*done) (Scsi_Cmnd *)) case WRITE_6: case WRITE_BUFFER: case MODE_SELECT: - cmd->control_flags = CFLAG_WRITE; - break; - case REQUEST_SENSE: - /* scsi.c expects sense info in a different buffer */ - cmd->dataseg[0].d_base = virt_to_bus_low32(Cmnd->sense_buffer); -#if BITS_PER_LONG > 32 - cmd->dataseg[0].d_base_hi = virt_to_bus_high32(Cmnd->sense_buffer); -#endif - cmd->dataseg[0].d_count = sizeof(Cmnd->sense_buffer); - cmd->segment_cnt = 1; - cmd->control_flags = CFLAG_READ; + cmd->control_flags = cpu_to_le16(CFLAG_WRITE); break; default: - cmd->control_flags = CFLAG_READ; + cmd->control_flags = cpu_to_le16(CFLAG_READ); break; } if (Cmnd->device->tagged_supported) { if ((jiffies - hostdata->tag_ages[Cmnd->target]) > (2 * SCSI_TIMEOUT)) { - cmd->control_flags |= CFLAG_ORDERED_TAG; + cmd->control_flags |= cpu_to_le16(CFLAG_ORDERED_TAG); hostdata->tag_ages[Cmnd->target] = jiffies; } else switch (Cmnd->tag) { case HEAD_OF_QUEUE_TAG: - cmd->control_flags |= CFLAG_HEAD_TAG; + cmd->control_flags |= cpu_to_le16(CFLAG_HEAD_TAG); break; case ORDERED_QUEUE_TAG: - cmd->control_flags |= CFLAG_ORDERED_TAG; + cmd->control_flags |= cpu_to_le16(CFLAG_ORDERED_TAG); break; default: - cmd->control_flags |= CFLAG_SIMPLE_TAG; + cmd->control_flags |= cpu_to_le16(CFLAG_SIMPLE_TAG); break; } } @@ -1543,6 +1547,16 @@ void isp2x00_intr_handler(int irq, void *dev_id, struct pt_regs *regs) if (sts->hdr.entry_type == ENTRY_STATUS && (Cmnd = hostdata->handle_ptrs[sts->handle])) { Cmnd->result = isp2x00_return_status(Cmnd, sts); hostdata->queued--; + + if (Cmnd->use_sg) + pci64_unmap_sg(hostdata->pci_dev, + (struct scatterlist *)Cmnd->buffer, Cmnd->use_sg, + scsi_to_pci_dma_dir(Cmnd->sc_data_direction)); + else if (Cmnd->request_bufflen) + pci64_unmap_single(hostdata->pci_dev, *(dma64_addr_t *)&Cmnd->SCp, + Cmnd->request_bufflen, + scsi_to_pci_dma_dir(Cmnd->sc_data_direction)); + /* * if any of the following are true we do not * call scsi_done. if the status is CS_ABORTED @@ -1550,7 +1564,7 @@ void isp2x00_intr_handler(int irq, void *dev_id, struct pt_regs *regs) * level should already know its aborted. */ if (hostdata->handle_serials[sts->handle] != Cmnd->serial_number - || sts->completion_status == CS_ABORTED){ + || le16_to_cpu(sts->completion_status) == CS_ABORTED){ hostdata->handle_serials[sts->handle] = 0; hostdata->handle_ptrs[sts->handle] = NULL; outw(out_ptr, host->io_port + MBOX5); @@ -1564,7 +1578,7 @@ void isp2x00_intr_handler(int irq, void *dev_id, struct pt_regs *regs) * the device may well be back in a couple of * seconds. */ - if ((hostdata->adapter_state == AS_LOOP_DOWN || sts->completion_status == CS_PORT_UNAVAILABLE || sts->completion_status == CS_PORT_LOGGED_OUT || sts->completion_status == CS_PORT_CONFIG_CHANGED) && hostdata->port_db[Cmnd->target].wwn){ + if ((hostdata->adapter_state == AS_LOOP_DOWN || sts->completion_status == cpu_to_le16(CS_PORT_UNAVAILABLE) || sts->completion_status == cpu_to_le16(CS_PORT_LOGGED_OUT) || sts->completion_status == cpu_to_le16(CS_PORT_CONFIG_CHANGED)) && hostdata->port_db[Cmnd->target].wwn){ outw(out_ptr, host->io_port + MBOX5); continue; } @@ -1575,12 +1589,11 @@ void isp2x00_intr_handler(int irq, void *dev_id, struct pt_regs *regs) hostdata->handle_ptrs[sts->handle] = NULL; - if (sts->completion_status == CS_RESET_OCCURRED - || (sts->status_flags & STF_BUS_RESET)) + if (sts->completion_status == cpu_to_le16(CS_RESET_OCCURRED) + || (sts->status_flags & cpu_to_le16(STF_BUS_RESET))) hostdata->send_marker = 1; - memset(Cmnd->sense_buffer, 0, sizeof(Cmnd->sense_buffer)); - if (sts->scsi_status & 0x0200) + if (le16_to_cpu(sts->scsi_status) & 0x0200) memcpy(Cmnd->sense_buffer, sts->req_sense_data, sizeof(Cmnd->sense_buffer)); @@ -1638,9 +1651,9 @@ static int isp2x00_return_status(Scsi_Cmnd *Cmnd, struct Status_Entry *sts) ENTER("isp2x00_return_status"); DEBUG(printk("qlogicfc : completion status = 0x%04x\n", - sts->completion_status)); + le16_to_cpu(sts->completion_status))); - switch (sts->completion_status) { + switch (le16_to_cpu(sts->completion_status)) { case CS_COMPLETE: host_status = DID_OK; break; @@ -1660,7 +1673,7 @@ static int isp2x00_return_status(Scsi_Cmnd *Cmnd, struct Status_Entry *sts) host_status = DID_ERROR; break; case CS_DATA_UNDERRUN: - if (Cmnd->underflow <= (Cmnd->request_bufflen - sts->residual)) + if (Cmnd->underflow <= (Cmnd->request_bufflen - le32_to_cpu(sts->residual))) host_status = DID_OK; else host_status = DID_ERROR; @@ -1675,17 +1688,17 @@ static int isp2x00_return_status(Scsi_Cmnd *Cmnd, struct Status_Entry *sts) break; default: printk("qlogicfc : unknown completion status 0x%04x\n", - sts->completion_status); + le16_to_cpu(sts->completion_status)); host_status = DID_ERROR; break; } DEBUG_INTR(printk("qlogicfc : host status (%s) scsi status %x\n", - reason[host_status], sts->scsi_status)); + reason[host_status], le16_to_cpu(sts->scsi_status))); LEAVE("isp2x00_return_status"); - return (sts->scsi_status & STATUS_MASK) | (host_status << 16); + return (le16_to_cpu(sts->scsi_status) & STATUS_MASK) | (host_status << 16); } @@ -1802,6 +1815,7 @@ static int isp2x00_reset_hardware(struct Scsi_Host *host) u_short param[8]; struct isp2x00_hostdata *hostdata; int loop_count; + dma64_addr_t busaddr; ENTER("isp2x00_reset_hardware"); @@ -1896,6 +1910,14 @@ static int isp2x00_reset_hardware(struct Scsi_Host *host) } #endif +#ifdef __BIG_ENDIAN + { + u64 val; + memcpy(&val, &hostdata->control_block.node_name, sizeof(u64)); + hostdata->wwn = ((val & 0xff00ff00ff00ff00ULL) >> 8) + | ((val & 0x00ff00ff00ff00ffULL) << 8); + } +#else hostdata->wwn = (u64) (hostdata->control_block.node_name[0]) << 56; hostdata->wwn |= (u64) (hostdata->control_block.node_name[0] & 0xff00) << 48; hostdata->wwn |= (u64) (hostdata->control_block.node_name[1] & 0xff00) << 24; @@ -1904,26 +1926,37 @@ static int isp2x00_reset_hardware(struct Scsi_Host *host) hostdata->wwn |= (u64) (hostdata->control_block.node_name[2] & 0xff00) << 8; hostdata->wwn |= (u64) (hostdata->control_block.node_name[3] & 0x00ff) << 8; hostdata->wwn |= (u64) (hostdata->control_block.node_name[3] & 0xff00) >> 8; +#endif + + /* FIXME: If the DMA transfer goes one way only, this should use PCI_DMA_TODEVICE and below as well. */ + busaddr = pci64_map_single(hostdata->pci_dev, &hostdata->control_block, sizeof(hostdata->control_block), + PCI_DMA_BIDIRECTIONAL); param[0] = MBOX_INIT_FIRMWARE; - param[2] = (u_short) (virt_to_bus_low32(&hostdata->control_block) >> 16); - param[3] = (u_short) (virt_to_bus_low32(&hostdata->control_block) & 0xffff); + param[2] = (u_short) (pci64_dma_lo32(busaddr) >> 16); + param[3] = (u_short) (pci64_dma_lo32(busaddr) & 0xffff); param[4] = 0; param[5] = 0; - param[6] = (u_short) (virt_to_bus_high32(&hostdata->control_block) >> 16); - param[7] = (u_short) (virt_to_bus_high32(&hostdata->control_block) & 0xffff); + param[6] = (u_short) (pci64_dma_hi32(busaddr) >> 16); + param[7] = (u_short) (pci64_dma_hi32(busaddr) & 0xffff); isp2x00_mbox_command(host, param); if (param[0] != MBOX_COMMAND_COMPLETE) { printk("qlogicfc%d.c: Ouch 0x%04x\n", hostdata->host_id, param[0]); + pci64_unmap_single(hostdata->pci_dev, busaddr, sizeof(hostdata->control_block), + PCI_DMA_BIDIRECTIONAL); return 1; } param[0] = MBOX_GET_FIRMWARE_STATE; isp2x00_mbox_command(host, param); if (param[0] != MBOX_COMMAND_COMPLETE) { printk("qlogicfc%d.c: 0x%04x\n", hostdata->host_id, param[0]); + pci64_unmap_single(hostdata->pci_dev, busaddr, sizeof(hostdata->control_block), + PCI_DMA_BIDIRECTIONAL); return 1; } + pci64_unmap_single(hostdata->pci_dev, busaddr, sizeof(hostdata->control_block), + PCI_DMA_BIDIRECTIONAL); LEAVE("isp2x00_reset_hardware"); return 0; @@ -1939,11 +1972,11 @@ static int isp2x00_get_nvram_defaults(struct Scsi_Host *host, struct init_cb *co return 1; value = isp2x00_read_nvram_word(host, 8); - control_block->node_name[0] = isp2x00_read_nvram_word(host, 9); - control_block->node_name[1] = isp2x00_read_nvram_word(host, 10); - control_block->node_name[2] = isp2x00_read_nvram_word(host, 11); - control_block->node_name[3] = isp2x00_read_nvram_word(host, 12); - control_block->hard_addr = isp2x00_read_nvram_word(host, 13); + control_block->node_name[0] = cpu_to_le16(isp2x00_read_nvram_word(host, 9)); + control_block->node_name[1] = cpu_to_le16(isp2x00_read_nvram_word(host, 10)); + control_block->node_name[2] = cpu_to_le16(isp2x00_read_nvram_word(host, 11)); + control_block->node_name[3] = cpu_to_le16(isp2x00_read_nvram_word(host, 12)); + control_block->hard_addr = cpu_to_le16(isp2x00_read_nvram_word(host, 13)); return 0; @@ -2156,12 +2189,12 @@ void isp2x00_print_status_entry(struct Status_Entry *status) printk("qlogicfc : entry count = 0x%02x, type = 0x%02x, flags = 0x%02x\n", status->hdr.entry_cnt, status->hdr.entry_type, status->hdr.flags); printk("qlogicfc : scsi status = 0x%04x, completion status = 0x%04x\n", - status->scsi_status, status->completion_status); + le16_to_cpu(status->scsi_status), le16_to_cpu(status->completion_status)); printk("qlogicfc : state flags = 0x%04x, status flags = 0x%04x\n", - status->state_flags, status->status_flags); + le16_to_cpu(status->state_flags), le16_to_cpu(status->status_flags)); printk("qlogicfc : response info length = 0x%04x, request sense length = 0x%04x\n", - status->res_info_len, status->req_sense_len); - printk("qlogicfc : residual transfer length = 0x%08x, response = 0x%02x\n", status->residual, status->res_info[3]); + le16_to_cpu(status->res_info_len), le16_to_cpu(status->req_sense_len)); + printk("qlogicfc : residual transfer length = 0x%08x, response = 0x%02x\n", le32_to_cpu(status->residual), status->res_info[3]); } diff --git a/drivers/scsi/qlogicfc.h b/drivers/scsi/qlogicfc.h index 10539d3db..e00e8c645 100644 --- a/drivers/scsi/qlogicfc.h +++ b/drivers/scsi/qlogicfc.h @@ -62,7 +62,7 @@ * determined for each queue request anew. */ -#if BITS_PER_LONG > 32 +#if PCI64_DMA_BITS > 32 #define DATASEGS_PER_COMMAND 2 #define DATASEGS_PER_CONT 5 #else diff --git a/drivers/scsi/sr_ioctl.c b/drivers/scsi/sr_ioctl.c index 32e71e06f..bbb24f4eb 100644 --- a/drivers/scsi/sr_ioctl.c +++ b/drivers/scsi/sr_ioctl.c @@ -149,7 +149,7 @@ static int test_unit_ready(int minor) sr_cmd[0] = GPCMD_TEST_UNIT_READY; sr_cmd[1] = ((scsi_CDs[minor].device->lun) << 5); sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0; - return sr_do_ioctl(minor, sr_cmd, NULL, 255, 1, SCSI_DATA_NONE); + return sr_do_ioctl(minor, sr_cmd, NULL, 0, 1, SCSI_DATA_NONE); } int sr_tray_move(struct cdrom_device_info *cdi, int pos) @@ -161,7 +161,7 @@ int sr_tray_move(struct cdrom_device_info *cdi, int pos) sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0; sr_cmd[4] = (pos == 0) ? 0x03 /* close */ : 0x02 /* eject */ ; - return sr_do_ioctl(MINOR(cdi->dev), sr_cmd, NULL, 255, 0, SCSI_DATA_NONE); + return sr_do_ioctl(MINOR(cdi->dev), sr_cmd, NULL, 0, 0, SCSI_DATA_NONE); } int sr_lock_door(struct cdrom_device_info *cdi, int lock) diff --git a/drivers/scsi/sun3_scsi.c b/drivers/scsi/sun3_scsi.c index 45f504fa3..741c86d52 100644 --- a/drivers/scsi/sun3_scsi.c +++ b/drivers/scsi/sun3_scsi.c @@ -121,10 +121,6 @@ static Scsi_Cmnd *sun3_dma_setup_done = NULL; /* minimum number of bytes to to dma on */ #define SUN3_DMA_MINSIZE 128 -static struct proc_dir_entry proc_scsi_sun3_5380 = { - PROC_SCSI_MAC, 13, "Sun3 5380 SCSI", S_IFDIR | S_IRUGO, S_IXUGO, 2 -}; - static volatile unsigned char *sun3_scsi_regp; static volatile struct sun3_dma_regs *dregs; static unsigned char *dmabuf = NULL; /* dma memory buffer */ @@ -196,7 +192,7 @@ int sun3scsi_detect(Scsi_Host_Template * tpnt) if(called) return 0; - tpnt->proc_dir = &proc_scsi_sun3_5380; + tpnt->proc_name = "Sun3 5380 SCSI"; /* setup variables */ tpnt->can_queue = diff --git a/drivers/scsi/sym53c8xx.c b/drivers/scsi/sym53c8xx.c index f56d66756..36eb7b0c1 100644 --- a/drivers/scsi/sym53c8xx.c +++ b/drivers/scsi/sym53c8xx.c @@ -55,7 +55,7 @@ */ /* -** January 9 2000, sym53c8xx 1.5h +** February 20 2000, sym53c8xx 1.5j ** ** Supported SCSI features: ** Synchronous data transfers @@ -84,7 +84,7 @@ /* ** Name and version of the driver */ -#define SCSI_NCR_DRIVER_NAME "sym53c8xx - version 1.5h" +#define SCSI_NCR_DRIVER_NAME "sym53c8xx - version 1.5j" /* #define DEBUG_896R1 */ #define SCSI_NCR_OPTIMIZE_896 @@ -174,6 +174,15 @@ typedef u64 u_int64; #include "sym53c8xx.h" +/* +** Hmmm... What complex some PCI-HOST bridges actually are, +** despite the fact that the PCI specifications are looking +** so smart and simple! ;-) +*/ +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,47) +#define SCSI_NCR_DYNAMIC_DMA_MAPPING +#endif + /*========================================================== ** ** A la VMS/CAM-3 queue management. @@ -501,7 +510,7 @@ pci_get_base_address(struct pci_dev *pdev, int index, u_long *base) typedef unsigned int pcidev_t; #define PCIDEV_NULL (~0u) #define PciBusNumber(d) ((d)>>8) -#define PciDeviceFn(n) ((d)&0xff) +#define PciDeviceFn(d) ((d)&0xff) #define __PciDev(busn, devfn) (((busn)<<8)+(devfn)) #define pci_present pcibios_present @@ -539,7 +548,7 @@ pci_find_device(unsigned int vendor, unsigned int device, pcidev_t prev) static u_short __init PciVendorId(pcidev_t dev) { u_short vendor_id; - pcibios_read_config_word(dev, PCI_VENDOR_ID, &vendor_id); + pci_read_config_word(dev, PCI_VENDOR_ID, &vendor_id); return vendor_id; } @@ -552,7 +561,7 @@ static u_short __init PciDeviceId(pcidev_t dev) static u_int __init PciIrqLine(pcidev_t dev) { - u_short irq; + u_char irq; pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq); return irq; } @@ -651,17 +660,6 @@ spinlock_t sym53c8xx_lock = SPIN_LOCK_UNLOCKED; #endif -/* -** Address translation -** -** The driver has to provide bus memory addresses to -** the script processor. Because some architectures use -** different physical addressing scheme from the PCI BUS, -** we use virt_to_bus() instead of virt_to_phys(). -*/ - -#define vtobus(p) virt_to_bus(p) - /* ** Memory mapped IO ** @@ -736,44 +734,76 @@ static void MDELAY(long ms) { while (ms--) UDELAY(1000); } ** this allocator allows simple and fast address calculations ** from the SCRIPTS code. In addition, cache line alignment ** is guaranteed for power of 2 cache line size. +** Enhanced in linux-2.3.44 to provide a memory pool per pcidev +** to support dynamic dma mapping. (I would have preferred a +** real bus astraction, btw). */ -#define MEMO_SHIFT 4 /* 16 bytes minimum memory chunk */ -#define MEMO_PAGE_ORDER 0 /* 1 PAGE maximum (for now (ever?) */ -typedef unsigned long addr; /* Enough bits to bit-hack addresses */ - -#define MEMO_FREE_UNUSED /* Free unused pages immediately */ - -struct m_link { - struct m_link *next; /* Simple links are enough */ -}; - -#ifndef GFP_DMA_32BIT -#define GFP_DMA_32BIT 0 /* Will this flag ever exist */ -#endif - #if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,0) -#define GetPages(order) __get_free_pages(GFP_ATOMIC | GFP_DMA_32BIT, order) +#define __GetFreePages(flags, order) __get_free_pages(flags, order) #else -#define GetPages(order) __get_free_pages(GFP_ATOMIC | GFP_DMA_32BIT, order, 0) +#define __GetFreePages(flags, order) __get_free_pages(flags, order, 0) #endif -/* -** Lists of available memory chunks. -** Starts with 16 bytes chunks until 1 PAGE chunks. -*/ -static struct m_link h[PAGE_SHIFT-MEMO_SHIFT+MEMO_PAGE_ORDER+1]; +#define MEMO_SHIFT 4 /* 16 bytes minimum memory chunk */ +#if PAGE_SIZE >= 8192 +#define MEMO_PAGE_ORDER 0 /* 1 PAGE maximum */ +#else +#define MEMO_PAGE_ORDER 1 /* 2 PAGES maximum */ +#endif +#define MEMO_FREE_UNUSED /* Free unused pages immediately */ +#define MEMO_WARN 1 +#define MEMO_GFP_FLAGS GFP_ATOMIC +#define MEMO_CLUSTER_SHIFT (PAGE_SHIFT+MEMO_PAGE_ORDER) +#define MEMO_CLUSTER_SIZE (1UL << MEMO_CLUSTER_SHIFT) +#define MEMO_CLUSTER_MASK (MEMO_CLUSTER_SIZE-1) + +typedef u_long m_addr_t; /* Enough bits to bit-hack addresses */ +typedef pcidev_t m_bush_t; /* Something that addresses DMAable */ + +typedef struct m_link { /* Link between free memory chunks */ + struct m_link *next; +} m_link_s; + +#ifdef SCSI_NCR_DYNAMIC_DMA_MAPPING +typedef struct m_vtob { /* Virtual to Bus address translation */ + struct m_vtob *next; + m_addr_t vaddr; + m_addr_t baddr; +} m_vtob_s; +#define VTOB_HASH_SHIFT 5 +#define VTOB_HASH_SIZE (1UL << VTOB_HASH_SHIFT) +#define VTOB_HASH_MASK (VTOB_HASH_SIZE-1) +#define VTOB_HASH_CODE(m) \ + ((((m_addr_t) (m)) >> MEMO_CLUSTER_SHIFT) & VTOB_HASH_MASK) +#endif + +typedef struct m_pool { /* Memory pool of a given kind */ +#ifdef SCSI_NCR_DYNAMIC_DMA_MAPPING + m_bush_t bush; + m_addr_t (*getp)(struct m_pool *); + void (*freep)(struct m_pool *, m_addr_t); +#define M_GETP() mp->getp(mp) +#define M_FREEP(p) mp->freep(mp, p) +#define GetPages() __GetFreePages(MEMO_GFP_FLAGS, MEMO_PAGE_ORDER) +#define FreePages(p) free_pages(p, MEMO_PAGE_ORDER) + int nump; + m_vtob_s *(vtob[VTOB_HASH_SIZE]); + struct m_pool *next; +#else +#define M_GETP() __GetFreePages(MEMO_GFP_FLAGS, MEMO_PAGE_ORDER) +#define M_FREEP(p) free_pages(p, MEMO_PAGE_ORDER) +#endif /* SCSI_NCR_DYNAMIC_DMA_MAPPING */ + struct m_link h[PAGE_SHIFT-MEMO_SHIFT+MEMO_PAGE_ORDER+1]; +} m_pool_s; -/* -** Allocate a memory area aligned on the lowest power of 2 -** greater than the requested size. -*/ -static void *__m_alloc(int size) +static void *___m_alloc(m_pool_s *mp, int size) { int i = 0; int s = (1 << MEMO_SHIFT); int j; - addr a ; + m_addr_t a; + m_link_s *h = mp->h; if (size > (PAGE_SIZE << MEMO_PAGE_ORDER)) return 0; @@ -786,7 +816,7 @@ static void *__m_alloc(int size) j = i; while (!h[j].next) { if (s == (PAGE_SIZE << MEMO_PAGE_ORDER)) { - h[j].next = (struct m_link *) GetPages(MEMO_PAGE_ORDER); + h[j].next = (m_link_s *) M_GETP(); if (h[j].next) h[j].next->next = 0; break; @@ -794,36 +824,32 @@ static void *__m_alloc(int size) ++j; s <<= 1; } - a = (addr) h[j].next; + a = (m_addr_t) h[j].next; if (a) { h[j].next = h[j].next->next; while (j > i) { j -= 1; s >>= 1; - h[j].next = (struct m_link *) (a+s); + h[j].next = (m_link_s *) (a+s); h[j].next->next = 0; } } #ifdef DEBUG - printk("m_alloc(%d) = %p\n", size, (void *) a); + printk("___m_alloc(%d) = %p\n", size, (void *) a); #endif return (void *) a; } -/* -** Free a memory area allocated using m_alloc(). -** Coalesce buddies. -** Free pages that become unused if MEMO_FREE_UNUSED is defined. -*/ -static void __m_free(void *ptr, int size) +static void ___m_free(m_pool_s *mp, void *ptr, int size) { int i = 0; int s = (1 << MEMO_SHIFT); - struct m_link *q; - addr a, b; + m_link_s *q; + m_addr_t a, b; + m_link_s *h = mp->h; #ifdef DEBUG - printk("m_free(%p, %d)\n", ptr, size); + printk("___m_free(%p, %d)\n", ptr, size); #endif if (size > (PAGE_SIZE << MEMO_PAGE_ORDER)) @@ -834,23 +860,23 @@ static void __m_free(void *ptr, int size) ++i; } - a = (addr) ptr; + a = (m_addr_t) ptr; while (1) { #ifdef MEMO_FREE_UNUSED if (s == (PAGE_SIZE << MEMO_PAGE_ORDER)) { - free_pages(a, MEMO_PAGE_ORDER); + M_FREEP(a); break; } #endif b = a ^ s; q = &h[i]; - while (q->next && q->next != (struct m_link *) b) { + while (q->next && q->next != (m_link_s *) b) { q = q->next; } if (!q->next) { - ((struct m_link *) a)->next = h[i].next; - h[i].next = (struct m_link *) a; + ((m_link_s *) a)->next = h[i].next; + h[i].next = (m_link_s *) a; break; } q->next = q->next->next; @@ -860,45 +886,338 @@ static void __m_free(void *ptr, int size) } } -#define MEMO_WARN 1 - -/* -** The memory pool is shared by all instances. -** We use a global SMP LOCK to be SMP safe. -*/ - -static void *m_calloc(int size, char *name, int uflags) +static void *__m_calloc2(m_pool_s *mp, int size, char *name, int uflags) { - u_long flags; void *p; - NCR_LOCK_DRIVER(flags); - p = __m_alloc(size); - NCR_UNLOCK_DRIVER(flags); + p = ___m_alloc(mp, size); if (DEBUG_FLAGS & DEBUG_ALLOC) printk ("new %-10s[%4d] @%p.\n", name, size, p); if (p) - memset(p, 0, size); + bzero(p, size); else if (uflags & MEMO_WARN) printk (NAME53C8XX ": failed to allocate %s[%d]\n", name, size); return p; } +#define __m_calloc(mp, s, n) __m_calloc2(mp, s, n, MEMO_WARN) + +static void __m_free(m_pool_s *mp, void *ptr, int size, char *name) +{ + if (DEBUG_FLAGS & DEBUG_ALLOC) + printk ("freeing %-10s[%4d] @%p.\n", name, size, ptr); + + ___m_free(mp, ptr, size); + +} + +/* + * With pci bus iommu support, we use a default pool of unmapped memory + * for memory we donnot need to DMA from/to and one pool per pcidev for + * memory accessed by the PCI chip. `mp0' is the default not DMAable pool. + */ + +#ifndef SCSI_NCR_DYNAMIC_DMA_MAPPING + +static m_pool_s mp0; + +#else + +static m_addr_t ___mp0_getp(m_pool_s *mp) +{ + m_addr_t m = GetPages(); + if (m) + ++mp->nump; + return m; +} + +static void ___mp0_freep(m_pool_s *mp, m_addr_t m) +{ + FreePages(m); + --mp->nump; +} + +static m_pool_s mp0 = {0, ___mp0_getp, ___mp0_freep}; + +#endif /* SCSI_NCR_DYNAMIC_DMA_MAPPING */ + +static void *m_calloc(int size, char *name) +{ + u_long flags; + void *m; + NCR_LOCK_DRIVER(flags); + m = __m_calloc(&mp0, size, name); + NCR_UNLOCK_DRIVER(flags); + return m; +} + static void m_free(void *ptr, int size, char *name) { u_long flags; + NCR_LOCK_DRIVER(flags); + __m_free(&mp0, ptr, size, name); + NCR_UNLOCK_DRIVER(flags); +} - if (DEBUG_FLAGS & DEBUG_ALLOC) - printk ("freeing %-10s[%4d] @%p.\n", name, size, ptr); +/* + * DMAable pools. + */ + +#ifndef SCSI_NCR_DYNAMIC_DMA_MAPPING + +/* Without pci bus iommu support, all the memory is assumed DMAable */ + +#define __m_calloc_dma(b, s, n) m_calloc(s, n) +#define __m_free_dma(b, p, s, n) m_free(p, s, n) +#define __vtobus(b, p) virt_to_bus(p) + +#else + +/* + * With pci bus iommu support, we maintain one pool per pcidev and a + * hashed reverse table for virtual to bus physical address translations. + */ +static m_addr_t ___dma_getp(m_pool_s *mp) +{ + m_addr_t vp; + m_vtob_s *vbp; + + vbp = __m_calloc(&mp0, sizeof(*vbp), "VTOB"); + if (vbp) { + dma_addr_t daddr; + vp = (m_addr_t) pci_alloc_consistent(mp->bush, + PAGE_SIZE<vaddr = vp; + vbp->baddr = daddr; + vbp->next = mp->vtob[hc]; + mp->vtob[hc] = vbp; + ++mp->nump; + return vp; + } + } + __m_free(&mp0, vbp, sizeof(*vbp), "VTOB"); + return 0; +} + +static void ___dma_freep(m_pool_s *mp, m_addr_t m) +{ + m_vtob_s **vbpp, *vbp; + int hc = VTOB_HASH_CODE(m); + + vbpp = &mp->vtob[hc]; + while (*vbpp && (*vbpp)->vaddr != m) + vbpp = &(*vbpp)->next; + if (*vbpp) { + vbp = *vbpp; + *vbpp = (*vbpp)->next; + pci_free_consistent(mp->bush, PAGE_SIZE<vaddr, (dma_addr_t)vbp->baddr); + __m_free(&mp0, vbp, sizeof(*vbp), "VTOB"); + --mp->nump; + } +} + +static inline m_pool_s *___get_dma_pool(m_bush_t bush) +{ + m_pool_s *mp; + for (mp = mp0.next; mp && mp->bush != bush; mp = mp->next); + return mp; +} + +static m_pool_s *___cre_dma_pool(m_bush_t bush) +{ + m_pool_s *mp; + mp = __m_calloc(&mp0, sizeof(*mp), "MPOOL"); + if (mp) { + bzero(mp, sizeof(*mp)); + mp->bush = bush; + mp->getp = ___dma_getp; + mp->freep = ___dma_freep; + mp->next = mp0.next; + mp0.next = mp; + } + return mp; +} + +static void ___del_dma_pool(m_pool_s *p) +{ + struct m_pool **pp = &mp0.next; + + while (*pp && *pp != p) + pp = &(*pp)->next; + if (*pp) { + *pp = (*pp)->next; + __m_free(&mp0, p, sizeof(*p), "MPOOL"); + } +} + +static void *__m_calloc_dma(m_bush_t bush, int size, char *name) +{ + u_long flags; + struct m_pool *mp; + void *m = 0; + + NCR_LOCK_DRIVER(flags); + mp = ___get_dma_pool(bush); + if (!mp) + mp = ___cre_dma_pool(bush); + if (mp) + m = __m_calloc(mp, size, name); + if (mp && !mp->nump) + ___del_dma_pool(mp); + NCR_UNLOCK_DRIVER(flags); + + return m; +} + +static void __m_free_dma(m_bush_t bush, void *m, int size, char *name) +{ + u_long flags; + struct m_pool *mp; NCR_LOCK_DRIVER(flags); - __m_free(ptr, size); + mp = ___get_dma_pool(bush); + if (mp) + __m_free(mp, m, size, name); + if (mp && !mp->nump) + ___del_dma_pool(mp); NCR_UNLOCK_DRIVER(flags); } +static m_addr_t __vtobus(m_bush_t bush, void *m) +{ + u_long flags; + m_pool_s *mp; + int hc = VTOB_HASH_CODE(m); + m_vtob_s *vp = 0; + m_addr_t a = ((m_addr_t) m) & ~MEMO_CLUSTER_MASK; + + NCR_LOCK_DRIVER(flags); + mp = ___get_dma_pool(bush); + if (mp) { + vp = mp->vtob[hc]; + while (vp && (m_addr_t) vp->vaddr != a) + vp = vp->next; + } + NCR_UNLOCK_DRIVER(flags); + return vp ? vp->baddr + (((m_addr_t) m) - a) : 0; +} + +#endif /* SCSI_NCR_DYNAMIC_DMA_MAPPING */ + +#define _m_calloc_dma(np, s, n) __m_calloc_dma(np->pdev, s, n) +#define _m_free_dma(np, p, s, n) __m_free_dma(np->pdev, p, s, n) +#define m_calloc_dma(s, n) _m_calloc_dma(np, s, n) +#define m_free_dma(p, s, n) _m_free_dma(np, p, s, n) +#define _vtobus(np, p) __vtobus(np->pdev, p) +#define vtobus(p) _vtobus(np, p) + +/* + * Deal with DMA mapping/unmapping. + */ + +#ifndef SCSI_NCR_DYNAMIC_DMA_MAPPING + +/* Linux versions prior to pci bus iommu kernel interface */ + +#define __unmap_scsi_data(pdev, cmd) do {; } while (0) +#define __map_scsi_single_data(pdev, cmd) (__vtobus(pdev,(cmd)->request_buffer)) +#define __map_scsi_sg_data(pdev, cmd) ((cmd)->use_sg) +#define __sync_scsi_data(pdev, cmd) do {; } while (0) + +#define scsi_sg_dma_address(sc) vtobus((sc)->address) +#define scsi_sg_dma_len(sc) ((sc)->length) + +#else + +/* Linux version with pci bus iommu kernel interface */ + +/* To keep track of the dma mapping (sg/single) that has been set */ +#define __data_mapped SCp.phase +#define __data_mapping SCp.have_data_in + +static void __unmap_scsi_data(pcidev_t pdev, Scsi_Cmnd *cmd) +{ + int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); + + switch(cmd->__data_mapped) { + case 2: + pci_unmap_sg(pdev, cmd->buffer, cmd->use_sg, dma_dir); + break; + case 1: + pci_unmap_single(pdev, cmd->__data_mapping, + cmd->request_bufflen, dma_dir); + break; + } + cmd->__data_mapped = 0; +} + +static u_long __map_scsi_single_data(pcidev_t pdev, Scsi_Cmnd *cmd) +{ + dma_addr_t mapping; + int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); + + if (cmd->request_bufflen == 0) + return 0; + + mapping = pci_map_single(pdev, cmd->request_buffer, + cmd->request_bufflen, dma_dir); + cmd->__data_mapped = 1; + cmd->__data_mapping = mapping; + + return mapping; +} + +static int __map_scsi_sg_data(pcidev_t pdev, Scsi_Cmnd *cmd) +{ + int use_sg; + int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); + + if (cmd->use_sg == 0) + return 0; + + use_sg = pci_map_sg(pdev, cmd->buffer, cmd->use_sg, dma_dir); + cmd->__data_mapped = 2; + cmd->__data_mapping = use_sg; + + return use_sg; +} + +static void __sync_scsi_data(pcidev_t pdev, Scsi_Cmnd *cmd) +{ + int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); + + switch(cmd->__data_mapped) { + case 2: + pci_dma_sync_sg(pdev, cmd->buffer, cmd->use_sg, dma_dir); + break; + case 1: + pci_dma_sync_single(pdev, cmd->__data_mapping, + cmd->request_bufflen, dma_dir); + break; + } +} + +#define scsi_sg_dma_address(sc) sg_dma_address(sc) +#define scsi_sg_dma_len(sc) sg_dma_len(sc) + +#endif /* SCSI_NCR_DYNAMIC_DMA_MAPPING */ + +#define unmap_scsi_data(np, cmd) __unmap_scsi_data(np->pdev, cmd) +#define map_scsi_single_data(np, cmd) __map_scsi_single_data(np->pdev, cmd) +#define map_scsi_sg_data(np, cmd) __map_scsi_sg_data(np->pdev, cmd) +#define sync_scsi_data(np, cmd) __sync_scsi_data(np->pdev, cmd) + + +/* + * Print out some buffer. + */ static void ncr_print_hex(u_char *p, int n) { while (n-- > 0) @@ -915,21 +1234,49 @@ static void ncr_printl_hex(char *label, u_char *p, int n) /* ** Transfer direction ** -** Low-level scsi drivers under Linux do not receive the expected -** data transfer direction from upper scsi drivers. -** The driver will only check actual data direction for common -** scsi opcodes. Other ones may cause problem, since they may -** depend on device type or be vendor specific. -** I would prefer to never trust the device for data direction, -** but that is not possible. -** -** The original driver requires the expected direction to be known. -** The Linux version of the driver has been enhanced in order to -** be able to transfer data in the direction choosen by the target. +** Until some linux kernel version near 2.3.40, low-level scsi +** drivers were not told about data transfer direction. +** We check the existence of this feature that has been expected +** for a _long_ time by all SCSI driver developers by just +** testing against the definition of SCSI_DATA_UNKNOWN. Indeed +** this is a hack, but testing against a kernel version would +** have been a shame. ;-) */ +#ifdef SCSI_DATA_UNKNOWN + +#define scsi_data_direction(cmd) (cmd->sc_data_direction) + +#else + +#define SCSI_DATA_UNKNOWN 0 +#define SCSI_DATA_WRITE 1 +#define SCSI_DATA_READ 2 +#define SCSI_DATA_NONE 3 -#define XFER_IN (1) -#define XFER_OUT (2) +static __inline__ scsi_data_direction(Scsi_Cmnd *cmd) +{ + int direction; + + switch((int) cmd->cmnd[0]) { + case 0x08: /* READ(6) 08 */ + case 0x28: /* READ(10) 28 */ + case 0xA8: /* READ(12) A8 */ + direction = SCSI_DATA_READ; + break; + case 0x0A: /* WRITE(6) 0A */ + case 0x2A: /* WRITE(10) 2A */ + case 0xAA: /* WRITE(12) AA */ + direction = SCSI_DATA_WRITE; + break; + default: + direction = SCSI_DATA_UNKNOWN; + break; + } + + return direction; +} + +#endif /* SCSI_DATA_UNKNOWN */ /* ** Head of list of NCR boards @@ -1039,6 +1386,7 @@ typedef struct { ** to save data on each detected board for ncr_attach(). */ typedef struct { + pcidev_t pdev; ncr_slot slot; ncr_chip chip; ncr_nvram *nvram; @@ -1796,6 +2144,8 @@ struct ccb { **---------------------------------------------------------------- */ Scsi_Cmnd *cmd; /* SCSI command */ + u_char cdb_buf[16]; /* Copy of CDB */ + u_char sense_buf[64]; int data_len; /* Total data length */ int segments; /* Number of SG segments */ @@ -1964,6 +2314,7 @@ struct ncb { ** General controller parameters and configuration. **---------------------------------------------------------------- */ + pcidev_t pdev; u_short device_id; /* PCI device id */ u_char revision_id; /* PCI device revision id */ u_char bus; /* PCI BUS number */ @@ -1995,7 +2346,8 @@ struct ncb { ** SCRIPTS processor in order to start SCSI commands. **---------------------------------------------------------------- */ - u_int32 *squeue; /* Start queue */ + u_long p_squeue; /* Start queue BUS address */ + u_int32 *squeue; /* Start queue virtual address */ u_short squeueput; /* Next free slot of the queue */ u_short actccbs; /* Number of allocated CCBs */ u_short queuedepth; /* Start queue depth */ @@ -2045,6 +2397,7 @@ struct ncb { u_char order; /* Tag order to use */ u_char verbose; /* Verbosity for this controller*/ u_int32 ncr_cache; /* Used for cache test at init. */ + u_long p_ncb; /* BUS address of this NCB */ /*---------------------------------------------------------------- ** CCB lists and queue. @@ -2085,7 +2438,7 @@ struct ncb { ** We use a different scatter function for 896 rev 1. **---------------------------------------------------------------- */ - int (*scatter) (ccb_p, Scsi_Cmnd *); + int (*scatter) (ncb_p, ccb_p, Scsi_Cmnd *); /*---------------------------------------------------------------- ** Command abort handling. @@ -2106,6 +2459,7 @@ struct ncb { u_char release_stage; /* Synchronisation stage on release */ }; +#define NCB_PHYS(np, lbl) (np->p_ncb + offsetof(struct ncb, lbl)) #define NCB_SCRIPT_PHYS(np,lbl) (np->p_script + offsetof (struct script, lbl)) #define NCB_SCRIPTH_PHYS(np,lbl) (np->p_scripth + offsetof (struct scripth,lbl)) #define NCB_SCRIPTH0_PHYS(np,lbl) (np->p_scripth0+offsetof (struct scripth,lbl)) @@ -2336,8 +2690,8 @@ static void ncb_profile (ncb_p np, ccb_p cp); static void ncr_script_copy_and_bind (ncb_p np, ncrcmd *src, ncrcmd *dst, int len); static void ncr_script_fill (struct script * scr, struct scripth * scripth); -static int ncr_scatter_896R1 (ccb_p cp, Scsi_Cmnd *cmd); -static int ncr_scatter (ccb_p cp, Scsi_Cmnd *cmd); +static int ncr_scatter_896R1 (ncb_p np, ccb_p cp, Scsi_Cmnd *cmd); +static int ncr_scatter (ncb_p np, ccb_p cp, Scsi_Cmnd *cmd); static void ncr_getsync (ncb_p np, u_char sfac, u_char *fakp, u_char *scntl3p); static void ncr_setsync (ncb_p np, ccb_p cp, u_char scntl3, u_char sxfer); static void ncr_setup_tags (ncb_p np, u_char tn, u_char ln); @@ -4529,7 +4883,7 @@ ncr_script_copy_and_bind (ncb_p np,ncrcmd *src,ncrcmd *dst,int len) new = (old & ~RELOC_MASK) + np->p_scripth; break; case RELOC_SOFTC: - new = (old & ~RELOC_MASK) + vtobus(np); + new = (old & ~RELOC_MASK) + np->p_ncb; break; #ifdef RELOC_KVAR case RELOC_KVAR: @@ -5191,10 +5545,12 @@ ncr_attach (Scsi_Host_Template *tpnt, int unit, ncr_device *device) /* ** Allocate the host control block. */ - np = m_calloc(sizeof(struct ncb), "NCB", MEMO_WARN); + np = __m_calloc_dma(device->pdev, sizeof(struct ncb), "NCB"); if (!np) goto attach_error; NCR_INIT_LOCK_NCB(np); + np->pdev = device->pdev; + np->p_ncb = __vtobus(device->pdev, np); host_data->ncb = np; /* @@ -5218,22 +5574,23 @@ ncr_attach (Scsi_Host_Template *tpnt, int unit, ncr_device *device) ** Allocate the start queue. */ np->squeue = (ncrcmd *) - m_calloc(sizeof(ncrcmd)*(MAX_START*2), "SQUEUE", MEMO_WARN); + m_calloc_dma(sizeof(ncrcmd)*(MAX_START*2), "SQUEUE"); if (!np->squeue) goto attach_error; + np->p_squeue = vtobus(np->squeue); /* ** Allocate the done queue. */ np->dqueue = (ncrcmd *) - m_calloc(sizeof(ncrcmd)*(MAX_START*2), "DQUEUE", MEMO_WARN); + m_calloc_dma(sizeof(ncrcmd)*(MAX_START*2), "DQUEUE"); if (!np->dqueue) goto attach_error; /* ** Allocate the target bus address array. */ - np->targtbl = (u_int32 *) m_calloc(256, "TARGTBL", MEMO_WARN); + np->targtbl = (u_int32 *) m_calloc_dma(256, "TARGTBL"); if (!np->targtbl) goto attach_error; @@ -5241,11 +5598,11 @@ ncr_attach (Scsi_Host_Template *tpnt, int unit, ncr_device *device) ** Allocate SCRIPTS areas */ np->script0 = (struct script *) - m_calloc(sizeof(struct script), "SCRIPT", MEMO_WARN); + m_calloc_dma(sizeof(struct script), "SCRIPT"); if (!np->script0) goto attach_error; np->scripth0 = (struct scripth *) - m_calloc(sizeof(struct scripth), "SCRIPTH", MEMO_WARN); + m_calloc_dma(sizeof(struct scripth), "SCRIPTH"); if (!np->scripth0) goto attach_error; @@ -5457,24 +5814,24 @@ ncr_attach (Scsi_Host_Template *tpnt, int unit, ncr_device *device) */ np->idletask.start = cpu_to_scr(NCB_SCRIPT_PHYS (np, idle)); np->idletask.restart = cpu_to_scr(NCB_SCRIPTH_PHYS (np, bad_i_t_l)); - np->p_idletask = vtobus(&np->idletask); + np->p_idletask = NCB_PHYS(np, idletask); np->notask.start = cpu_to_scr(NCB_SCRIPT_PHYS (np, idle)); np->notask.restart = cpu_to_scr(NCB_SCRIPTH_PHYS (np, bad_i_t_l)); - np->p_notask = vtobus(&np->notask); + np->p_notask = NCB_PHYS(np, notask); np->bad_i_t_l.start = cpu_to_scr(NCB_SCRIPT_PHYS (np, idle)); np->bad_i_t_l.restart = cpu_to_scr(NCB_SCRIPTH_PHYS (np, bad_i_t_l)); - np->p_bad_i_t_l = vtobus(&np->bad_i_t_l); + np->p_bad_i_t_l = NCB_PHYS(np, bad_i_t_l); np->bad_i_t_l_q.start = cpu_to_scr(NCB_SCRIPT_PHYS (np, idle)); np->bad_i_t_l_q.restart = cpu_to_scr(NCB_SCRIPTH_PHYS (np,bad_i_t_l_q)); - np->p_bad_i_t_l_q = vtobus(&np->bad_i_t_l_q); + np->p_bad_i_t_l_q = NCB_PHYS(np, bad_i_t_l_q); /* ** Allocate and prepare the bad lun table. */ - np->badluntbl = m_calloc(256, "BADLUNTBL", MEMO_WARN); + np->badluntbl = m_calloc_dma(256, "BADLUNTBL"); if (!np->badluntbl) goto attach_error; @@ -5482,16 +5839,16 @@ ncr_attach (Scsi_Host_Template *tpnt, int unit, ncr_device *device) np->resel_badlun = cpu_to_scr(NCB_SCRIPTH_PHYS(np, bad_identify)); for (i = 0 ; i < 64 ; i++) - np->badluntbl[i] = cpu_to_scr(vtobus(&np->resel_badlun)); + np->badluntbl[i] = cpu_to_scr(NCB_PHYS(np, resel_badlun)); /* ** Prepare the target bus address array. */ np->scripth0->targtbl[0] = cpu_to_scr(vtobus(np->targtbl)); for (i = 0 ; i < MAX_TARGET ; i++) { - np->targtbl[i] = cpu_to_scr(vtobus(&np->target[i])); + np->targtbl[i] = cpu_to_scr(NCB_PHYS(np, target[i])); np->target[i].b_luntbl = cpu_to_scr(vtobus(np->badluntbl)); - np->target[i].b_lun0 = cpu_to_scr(vtobus(&np->resel_badlun)); + np->target[i].b_lun0 = cpu_to_scr(NCB_PHYS(np, resel_badlun)); } /* @@ -5533,7 +5890,7 @@ ncr_attach (Scsi_Host_Template *tpnt, int unit, ncr_device *device) #ifndef SCSI_NCR_PROFILE_SUPPORT #define XXX 0 #else -#define XXX 3 +#define XXX 2 #endif np->script0->dataphase[XXX] = cpu_to_scr(SCR_JUMP); np->script0->dataphase[XXX+1] = @@ -5699,21 +6056,21 @@ static void ncr_free_resources(ncb_p np) unmap_pci_mem(np->base2_va, np->base2_ws); #endif if (np->scripth0) - m_free(np->scripth0, sizeof(struct scripth), "SCRIPTH"); + m_free_dma(np->scripth0, sizeof(struct scripth), "SCRIPTH"); if (np->script0) - m_free(np->script0, sizeof(struct script), "SCRIPT"); + m_free_dma(np->script0, sizeof(struct script), "SCRIPT"); if (np->squeue) - m_free(np->squeue, sizeof(ncrcmd)*(MAX_START*2), "SQUEUE"); + m_free_dma(np->squeue, sizeof(ncrcmd)*(MAX_START*2), "SQUEUE"); if (np->dqueue) - m_free(np->dqueue, sizeof(ncrcmd)*(MAX_START*2),"DQUEUE"); + m_free_dma(np->dqueue, sizeof(ncrcmd)*(MAX_START*2),"DQUEUE"); while ((cp = np->ccbc) != NULL) { np->ccbc = cp->link_ccb; - m_free(cp, sizeof(*cp), "CCB"); + m_free_dma(cp, sizeof(*cp), "CCB"); } if (np->badluntbl) - m_free(np->badluntbl, 256,"BADLUNTBL"); + m_free_dma(np->badluntbl, 256,"BADLUNTBL"); for (target = 0; target < MAX_TARGET ; target++) { tp = &np->target[target]; @@ -5722,18 +6079,23 @@ static void ncr_free_resources(ncb_p np) if (!lp) continue; if (lp->tasktbl != &lp->tasktbl_0) - m_free(lp->tasktbl, MAX_TASKS*4, "TASKTBL"); + m_free_dma(lp->tasktbl, MAX_TASKS*4, "TASKTBL"); if (lp->cb_tags) m_free(lp->cb_tags, MAX_TAGS, "CB_TAGS"); - m_free(lp, sizeof(*lp), "LCB"); + m_free_dma(lp, sizeof(*lp), "LCB"); } #if MAX_LUN > 1 if (tp->lmp) m_free(tp->lmp, MAX_LUN * sizeof(lcb_p), "LMP"); + if (tp->luntbl) + m_free_dma(tp->luntbl, 256, "LUNTBL"); #endif } - m_free(np, sizeof(*np), "NCB"); + if (np->targtbl) + m_free_dma(np->targtbl, 256, "TARGTBL"); + + m_free_dma(np, sizeof(*np), "NCB"); } @@ -5761,13 +6123,14 @@ static inline void ncr_queue_done_cmd(ncb_p np, Scsi_Cmnd *cmd) np->done_list = cmd; } -static inline void ncr_flush_done_cmds(Scsi_Cmnd *lcmd) +static inline void ncr_flush_done_cmds(pcidev_t pdev, Scsi_Cmnd *lcmd) { Scsi_Cmnd *cmd; while (lcmd) { cmd = lcmd; lcmd = (Scsi_Cmnd *) cmd->host_scribble; + __unmap_scsi_data(pdev, cmd); cmd->scsi_done(cmd); } } @@ -6013,7 +6376,7 @@ static int ncr_queue_command (ncb_p np, Scsi_Cmnd *cmd) **---------------------------------------------------- */ - cp->segments = segments = np->scatter (cp, cp->cmd); + cp->segments = segments = np->scatter (np, cp, cp->cmd); if (segments < 0) { ncr_free_ccb(np, cp); @@ -6027,61 +6390,34 @@ static int ncr_queue_command (ncb_p np, Scsi_Cmnd *cmd) **---------------------------------------------------- */ if (!cp->data_len) - direction = 0; - else { - switch((int) cmd->cmnd[0]) { - case 0x08: /* READ(6) 08 */ - case 0x28: /* READ(10) 28 */ - case 0xA8: /* READ(12) A8 */ - direction = XFER_IN; - break; - case 0x0A: /* WRITE(6) 0A */ - case 0x2A: /* WRITE(10) 2A */ - case 0xAA: /* WRITE(12) AA */ - direction = XFER_OUT; - break; - default: - direction = (XFER_IN|XFER_OUT); - break; - } - } - - /*---------------------------------------------------- - ** - ** Set the DATA POINTER. - ** - **---------------------------------------------------- - */ - - /* - ** Default to no data transfer. - */ - lastp = goalp = NCB_SCRIPTH_PHYS (np, no_data); + direction = SCSI_DATA_NONE; + else + direction = scsi_data_direction(cmd); /* - ** Compute data out pointers, if needed. + ** If data direction is UNKNOWN, speculate DATA_READ + ** but prepare alternate pointers for WRITE in case + ** of our speculation will be just wrong. + ** SCRIPTS will swap values if needed. */ - if (direction & XFER_OUT) { + switch(direction) { + case SCSI_DATA_UNKNOWN: + case SCSI_DATA_WRITE: goalp = NCB_SCRIPT_PHYS (np, data_out2) + 8; lastp = goalp - 8 - (segments * (SCR_SG_SIZE*4)); - - /* - ** If actual data direction is unknown, save pointers - ** in header. The SCRIPTS will swap them to current - ** if target decision will be data out. - */ - if (direction & XFER_IN) { - cp->phys.header.wgoalp = cpu_to_scr(goalp); - cp->phys.header.wlastp = cpu_to_scr(lastp); - } - } - - /* - ** Compute data in pointers, if needed. - */ - if (direction & XFER_IN) { + if (direction != SCSI_DATA_UNKNOWN) + break; + cp->phys.header.wgoalp = cpu_to_scr(goalp); + cp->phys.header.wlastp = cpu_to_scr(lastp); + /* fall through */ + case SCSI_DATA_READ: goalp = NCB_SCRIPT_PHYS (np, data_in2) + 8; lastp = goalp - 8 - (segments * (SCR_SG_SIZE*4)); + break; + default: + case SCSI_DATA_NONE: + lastp = goalp = NCB_SCRIPTH_PHYS (np, no_data); + break; } /* @@ -6091,7 +6427,7 @@ static int ncr_queue_command (ncb_p np, Scsi_Cmnd *cmd) cp->phys.header.lastp = cpu_to_scr(lastp); cp->phys.header.goalp = cpu_to_scr(goalp); - if ((direction & (XFER_IN|XFER_OUT)) == (XFER_IN|XFER_OUT)) + if (direction == SCSI_DATA_UNKNOWN) cp->phys.header.savep = cpu_to_scr(NCB_SCRIPTH_PHYS (np, data_io)); else @@ -6152,7 +6488,8 @@ static int ncr_queue_command (ncb_p np, Scsi_Cmnd *cmd) /* ** command */ - cp->phys.cmd.addr = cpu_to_scr(vtobus (&cmd->cmnd[0])); + memcpy(cp->cdb_buf, cmd->cmnd, cmd->cmd_len); + cp->phys.cmd.addr = cpu_to_scr(CCB_PHYS (cp, cdb_buf[0])); cp->phys.cmd.size = cpu_to_scr(cmd->cmd_len); /* @@ -6719,6 +7056,7 @@ void ncr_complete (ncb_p np, ccb_p cp) */ if (cmd->cmnd[0] == 0x12 && !(cmd->cmnd[1] & 0x3) && cmd->cmnd[4] >= 7 && !cmd->use_sg) { + sync_scsi_data(np, cmd); /* SYNC the data */ ncr_setup_lcb (np, cp->target, cp->lun, (char *) cmd->request_buffer); } @@ -6941,7 +7279,7 @@ void ncr_init (ncb_p np, int reset, char * msg, u_long code) /* ** Clear Start Queue */ - phys = vtobus(np->squeue); + phys = np->p_squeue; np->queuedepth = MAX_START - 1; /* 1 entry needed as end marker */ for (i = 0; i < MAX_START*2; i += 2) { np->squeue[i] = cpu_to_scr(np->p_idletask); @@ -7131,7 +7469,7 @@ void ncr_init (ncb_p np, int reset, char * msg, u_long code) np->istat_sem = 0; - OUTL (nc_dsa, vtobus(np)); + OUTL (nc_dsa, np->p_ncb); OUTL (nc_dsp, phys); } @@ -8733,7 +9071,7 @@ static void ncr_sir_to_redo(ncb_p np, int num, ccb_p cp) ** them back in the LUN CCB wait queue. */ busyccbs = lp->queuedccbs; - i = (INL (nc_scratcha) - vtobus(np->squeue)) / 4; + i = (INL (nc_scratcha) - np->p_squeue) / 4; j = i; while (i != np->squeueput) { cp2 = ncr_ccb_from_dsa(np, scr_to_cpu(np->squeue[i])); @@ -8888,11 +9226,9 @@ next: /* ** sense data */ - bzero(cmd->sense_buffer, sizeof(cmd->sense_buffer)); - cp->phys.sense.addr = - cpu_to_scr(vtobus (&cmd->sense_buffer[0])); - cp->phys.sense.size = - cpu_to_scr(sizeof(cmd->sense_buffer)); + bzero(cp->sense_buf, sizeof(cp->sense_buf)); + cp->phys.sense.addr = cpu_to_scr(CCB_PHYS(cp,sense_buf[0])); + cp->phys.sense.size = cpu_to_scr(sizeof(cp->sense_buf)); /* ** requeue the command. @@ -9073,7 +9409,7 @@ static void ncr_sir_task_recovery(ncb_p np, int num) np->abrt_sel.sel_id = target; np->abrt_sel.sel_scntl3 = tp->wval; np->abrt_sel.sel_sxfer = tp->sval; - OUTL(nc_dsa, vtobus(np)); + OUTL(nc_dsa, np->p_ncb); OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, sel_for_abort)); return; } @@ -9114,7 +9450,7 @@ static void ncr_sir_task_recovery(ncb_p np, int num) ** Compute index of next position in the start ** queue the SCRIPTS will schedule. */ - i = (INL (nc_scratcha) - vtobus(np->squeue)) / 4; + i = (INL (nc_scratcha) - np->p_squeue) / 4; /* ** Remove the job from the start queue. @@ -9315,11 +9651,17 @@ static void ncr_sir_task_recovery(ncb_p np, int num) */ case SIR_AUTO_SENSE_DONE: cp = ncr_ccb_from_dsa(np, INL (nc_dsa)); + if (!cp) + break; + memcpy(cp->cmd->sense_buffer, cp->sense_buf, + sizeof(cp->cmd->sense_buffer)); p = &cp->cmd->sense_buffer[0]; if (p[0] != 0x70 || p[2] != 0x6 || p[12] != 0x29) break; +#if 0 (void) ncr_clear_tasks(np, HS_RESET, cp->target, cp->lun, -1); +#endif break; } @@ -10036,6 +10378,7 @@ void ncr_int_sir (ncb_p np) case SIR_SCRIPT_STOPPED: case SIR_TARGET_SELECTED: case SIR_ABORT_SENT: + case SIR_AUTO_SENSE_DONE: ncr_sir_task_recovery(np, num); return; /* @@ -10397,7 +10740,7 @@ static ccb_p ncr_alloc_ccb(ncb_p np) /* ** Allocate memory for this CCB. */ - cp = m_calloc(sizeof(struct ccb), "CCB", MEMO_WARN); + cp = m_calloc_dma(sizeof(struct ccb), "CCB"); if (!cp) return 0; @@ -10427,7 +10770,7 @@ static ccb_p ncr_alloc_ccb(ncb_p np) /* ** Initilialyze some other fields. */ - cp->phys.smsg_ext.addr = cpu_to_scr(vtobus(&np->msgin[2])); + cp->phys.smsg_ext.addr = cpu_to_scr(NCB_PHYS(np, msgin[2])); /* ** Chain into wakeup list and free ccb queue. @@ -10519,11 +10862,11 @@ static lcb_p ncr_alloc_lcb (ncb_p np, u_char tn, u_char ln) if (ln && !tp->luntbl) { int i; - tp->luntbl = m_calloc(256, "LUNTBL", MEMO_WARN); + tp->luntbl = m_calloc_dma(256, "LUNTBL"); if (!tp->luntbl) goto fail; for (i = 0 ; i < 64 ; i++) - tp->luntbl[i] = cpu_to_scr(vtobus(&np->resel_badlun)); + tp->luntbl[i] = cpu_to_scr(NCB_PHYS(np, resel_badlun)); tp->b_luntbl = cpu_to_scr(vtobus(tp->luntbl)); } @@ -10531,7 +10874,7 @@ static lcb_p ncr_alloc_lcb (ncb_p np, u_char tn, u_char ln) ** Allocate the table of pointers for LUN(s) > 0, if needed. */ if (ln && !tp->lmp) { - tp->lmp = m_calloc(MAX_LUN * sizeof(lcb_p), "LMP", MEMO_WARN); + tp->lmp = m_calloc(MAX_LUN * sizeof(lcb_p), "LMP"); if (!tp->lmp) goto fail; } @@ -10540,7 +10883,7 @@ static lcb_p ncr_alloc_lcb (ncb_p np, u_char tn, u_char ln) ** Allocate the lcb. ** Make it available to the chip. */ - lp = m_calloc(sizeof(struct lcb), "LCB", MEMO_WARN); + lp = m_calloc_dma(sizeof(struct lcb), "LCB"); if (!lp) goto fail; if (ln) { @@ -10652,7 +10995,7 @@ static lcb_p ncr_setup_lcb (ncb_p np, u_char tn, u_char ln, u_char *inq_data) ** initialyze the task table if not yet. */ if ((inq_byte7 & INQ7_QUEUE) && lp->tasktbl == &lp->tasktbl_0) { - lp->tasktbl = m_calloc(MAX_TASKS*4, "TASKTBL", MEMO_WARN); + lp->tasktbl = m_calloc_dma(MAX_TASKS*4, "TASKTBL"); if (!lp->tasktbl) { lp->tasktbl = &lp->tasktbl_0; goto fail; @@ -10661,7 +11004,7 @@ static lcb_p ncr_setup_lcb (ncb_p np, u_char tn, u_char ln, u_char *inq_data) for (i = 0 ; i < MAX_TASKS ; i++) lp->tasktbl[i] = cpu_to_scr(np->p_notask); - lp->cb_tags = m_calloc(MAX_TAGS, "CB_TAGS", MEMO_WARN); + lp->cb_tags = m_calloc(MAX_TAGS, "CB_TAGS"); if (!lp->cb_tags) goto fail; for (i = 0 ; i < MAX_TAGS ; i++) @@ -10741,7 +11084,7 @@ fail: #define CROSS_16MB(p, n) (((((u_long) p) + n - 1) ^ ((u_long) p)) & ~0xffffff) -static int ncr_scatter_no_sglist(ccb_p cp, Scsi_Cmnd *cmd) +static int ncr_scatter_no_sglist(ncb_p np, ccb_p cp, Scsi_Cmnd *cmd) { struct scr_tblmove *data = &cp->phys.data[MAX_SCATTER-1]; int segment; @@ -10749,7 +11092,8 @@ static int ncr_scatter_no_sglist(ccb_p cp, Scsi_Cmnd *cmd) cp->data_len = cmd->request_bufflen; if (cmd->request_bufflen) { - u_long baddr = vtobus(cmd->request_buffer); + u_long baddr = map_scsi_single_data(np, cmd); + SCATTER_ONE(data, baddr, cmd->request_bufflen); if (CROSS_16MB(baddr, cmd->request_bufflen)) { cp->host_flags |= HF_PM_TO_C; @@ -10780,7 +11124,7 @@ printk("He! we are crossing a 16 MB boundary (0x%lx, 0x%x)\n", ** nicely power-of-two sized and aligned. But, since this may change ** at any time, a work-around was required. */ -static int ncr_scatter_896R1(ccb_p cp, Scsi_Cmnd *cmd) +static int ncr_scatter_896R1(ncb_p np, ccb_p cp, Scsi_Cmnd *cmd) { int segn; int use_sg = (int) cmd->use_sg; @@ -10788,18 +11132,23 @@ static int ncr_scatter_896R1(ccb_p cp, Scsi_Cmnd *cmd) cp->data_len = 0; if (!use_sg) - segn = ncr_scatter_no_sglist(cp, cmd); + segn = ncr_scatter_no_sglist(np, cp, cmd); else if (use_sg > MAX_SCATTER) segn = -1; else { struct scatterlist *scatter = (struct scatterlist *)cmd->buffer; - struct scr_tblmove *data = &cp->phys.data[MAX_SCATTER - use_sg]; + struct scr_tblmove *data; + + use_sg = map_scsi_sg_data(np, cmd); + data = &cp->phys.data[MAX_SCATTER - use_sg]; for (segn = 0; segn < use_sg; segn++) { - u_long baddr = vtobus(scatter[segn].address); + u_long baddr = scsi_sg_dma_address(&scatter[segn]); + unsigned int len = scsi_sg_dma_len(&scatter[segn]); + SCATTER_ONE(&data[segn], baddr, - scatter[segn].length); + len); if (CROSS_16MB(baddr, scatter[segn].length)) { cp->host_flags |= HF_PM_TO_C; #ifdef DEBUG_896R1 @@ -10807,14 +11156,14 @@ printk("He! we are crossing a 16 MB boundary (0x%lx, 0x%x)\n", baddr, scatter[segn].length); #endif } - cp->data_len += scatter[segn].length; + cp->data_len += len; } } return segn; } -static int ncr_scatter(ccb_p cp, Scsi_Cmnd *cmd) +static int ncr_scatter(ncb_p np, ccb_p cp, Scsi_Cmnd *cmd) { int segment; int use_sg = (int) cmd->use_sg; @@ -10822,19 +11171,24 @@ static int ncr_scatter(ccb_p cp, Scsi_Cmnd *cmd) cp->data_len = 0; if (!use_sg) - segment = ncr_scatter_no_sglist(cp, cmd); + segment = ncr_scatter_no_sglist(np, cp, cmd); else if (use_sg > MAX_SCATTER) segment = -1; else { struct scatterlist *scatter = (struct scatterlist *)cmd->buffer; - struct scr_tblmove *data = &cp->phys.data[MAX_SCATTER - use_sg]; + struct scr_tblmove *data; + + use_sg = map_scsi_sg_data(np, cmd); + data = &cp->phys.data[MAX_SCATTER - use_sg]; for (segment = 0; segment < use_sg; segment++) { - u_long baddr = vtobus(scatter[segment].address); + u_long baddr = scsi_sg_dma_address(&scatter[segment]); + unsigned int len = scsi_sg_dma_len(&scatter[segment]); + SCATTER_ONE(&data[segment], baddr, - scatter[segment].length); - cp->data_len += scatter[segment].length; + len); + cp->data_len += len; } } @@ -10901,7 +11255,7 @@ static int __init ncr_snooptest (struct ncb* np) /* ** Start script (exchange values) */ - OUTL (nc_dsa, vtobus(np)); + OUTL (nc_dsa, np->p_ncb); OUTL (nc_dsp, pc); /* ** Wait 'til done (with timeout) @@ -11580,7 +11934,7 @@ if (sym53c8xx) ** overflow the kernel stack. ** 1 x 4K PAGE is enough for more than 40 devices for i386. */ - devtbl = m_calloc(PAGE_SIZE, "devtbl", MEMO_WARN); + devtbl = m_calloc(PAGE_SIZE, "devtbl"); if (!devtbl) return 0; @@ -11745,6 +12099,15 @@ sym53c8xx_pci_init(Scsi_Host_Template *tpnt, pcidev_t pdev, ncr_device *device) PciBusNumber(pdev), (int) (PciDeviceFn(pdev) & 0xf8) >> 3, (int) (PciDeviceFn(pdev) & 7)); + +#ifdef SCSI_NCR_DYNAMIC_DMA_MAPPING + if (!pci_dma_supported(pdev, (dma_addr_t) (0xffffffffUL))) { + printk(KERN_WARNING NAME53C8XX + "32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n"); + return -1; + } +#endif + /* ** Read info from the PCI config space. ** pci_read_config_xxx() functions are assumed to be used for @@ -12032,6 +12395,7 @@ sym53c8xx_pci_init(Scsi_Host_Template *tpnt, pcidev_t pdev, ncr_device *device) /* ** Initialise ncr_device structure with items required by ncr_attach. */ + device->pdev = pdev; device->slot.bus = PciBusNumber(pdev); device->slot.device_fn = PciDeviceFn(pdev); device->slot.base = base; @@ -12232,6 +12596,10 @@ printk("sym53c8xx_queue_command\n"); cmd->host_scribble = NULL; cmd->SCp.ptr = NULL; cmd->SCp.buffer = NULL; +#ifdef SCSI_NCR_DYNAMIC_DMA_MAPPING + cmd->__data_mapped = 0; + cmd->__data_mapping = 0; +#endif NCR_LOCK_NCB(np, flags); @@ -12267,6 +12635,7 @@ static void sym53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs) unsigned long flags; ncb_p np = (ncb_p) dev_id; Scsi_Cmnd *done_list; + pcidev_t pdev; #ifdef DEBUG_SYM53C8XX printk("sym53c8xx : interrupt received\n"); @@ -12276,6 +12645,7 @@ static void sym53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs) NCR_LOCK_NCB(np, flags); ncr_exception(np); + pdev = np->pdev; done_list = np->done_list; np->done_list = 0; NCR_UNLOCK_NCB(np, flags); @@ -12284,7 +12654,7 @@ static void sym53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs) if (done_list) { NCR_LOCK_SCSI_DONE(np, flags); - ncr_flush_done_cmds(done_list); + ncr_flush_done_cmds(pdev, done_list); NCR_UNLOCK_SCSI_DONE(np, flags); } } @@ -12297,17 +12667,19 @@ static void sym53c8xx_timeout(unsigned long npref) { ncb_p np = (ncb_p) npref; unsigned long flags; + pcidev_t pdev; Scsi_Cmnd *done_list; NCR_LOCK_NCB(np, flags); ncr_timeout((ncb_p) np); + pdev = np->pdev; done_list = np->done_list; np->done_list = 0; NCR_UNLOCK_NCB(np, flags); if (done_list) { NCR_LOCK_SCSI_DONE(np, flags); - ncr_flush_done_cmds(done_list); + ncr_flush_done_cmds(pdev, done_list); NCR_UNLOCK_SCSI_DONE(np, flags); } } @@ -12325,6 +12697,7 @@ int sym53c8xx_reset(Scsi_Cmnd *cmd) ncb_p np = ((struct host_data *) cmd->host->hostdata)->ncb; int sts; unsigned long flags; + pcidev_t pdev; Scsi_Cmnd *done_list; #if defined SCSI_RESET_SYNCHRONOUS && defined SCSI_RESET_ASYNCHRONOUS @@ -12369,11 +12742,12 @@ int sym53c8xx_reset(Scsi_Cmnd *cmd) #endif out: + pdev = np->pdev; done_list = np->done_list; np->done_list = 0; NCR_UNLOCK_NCB(np, flags); - ncr_flush_done_cmds(done_list); + ncr_flush_done_cmds(pdev, done_list); return sts; } @@ -12387,6 +12761,7 @@ int sym53c8xx_abort(Scsi_Cmnd *cmd) ncb_p np = ((struct host_data *) cmd->host->hostdata)->ncb; int sts; unsigned long flags; + pcidev_t pdev; Scsi_Cmnd *done_list; #if defined SCSI_RESET_SYNCHRONOUS && defined SCSI_RESET_ASYNCHRONOUS @@ -12410,11 +12785,12 @@ int sym53c8xx_abort(Scsi_Cmnd *cmd) sts = ncr_abort_command(np, cmd); out: + pdev = np->pdev; done_list = np->done_list; np->done_list = 0; NCR_UNLOCK_NCB(np, flags); - ncr_flush_done_cmds(done_list); + ncr_flush_done_cmds(pdev, done_list); return sts; } diff --git a/drivers/sound/Makefile b/drivers/sound/Makefile index b9ae751bf..41b55ea4c 100644 --- a/drivers/sound/Makefile +++ b/drivers/sound/Makefile @@ -66,7 +66,7 @@ obj-$(CONFIG_SOUND_PSS) += pss.o ad1848.o mpu401.o obj-$(CONFIG_SOUND_SB) += sb.o uart401.o obj-$(CONFIG_SOUND_SOFTOSS) += softoss2.o obj-$(CONFIG_SOUND_SGALAXY) += sgalaxy.o ad1848.o -obj-$(CONFIG_SOUND_AD1816) += ad1816.o +obj-$(CONFIG_SOUND_AD1816) += ad1816.o obj-$(CONFIG_SOUND_SSCAPE) += sscape.o ad1848.o mpu401.o obj-$(CONFIG_SOUND_TRIX) += trix.o ad1848.o sb.o uart401.o obj-$(CONFIG_SOUND_UART6850) += uart6850.o @@ -104,7 +104,7 @@ pas2-objs := pas2_card.o pas2_midi.o pas2_mixer.o pas2_pcm.o sb-objs := sb_audio.o sb_card.o sb_common.o sb_midi.o sb_mixer.o \ sb_ess.o softoss2-objs := softoss.o softoss_rs.o -vidc_mod-objs := vidc.o vidc_audio.o vidc_fill.o vidc_mixer.o vidc_synth.o +vidc_mod-objs := vidc.o vidc_fill.o wavefront-objs := wavfront.o wf_midi.o yss225.o nm256-objs := nm256_audio.o ac97.o diff --git a/drivers/sound/README.CONFIG b/drivers/sound/README.CONFIG deleted file mode 100644 index 5cd199230..000000000 --- a/drivers/sound/README.CONFIG +++ /dev/null @@ -1,75 +0,0 @@ -Sound Driver Configuration Notes -Michael Chastain, -18 Apr 1998 - -The Linux sound driver is derived from OSS/Free, a multi-platform -Unix sound driver by Hannu Savolainen. You can find out -more about OSS/Free and the commercial version, OSS/Linux, at -. - -OSS/Free comes with the configuration program 'configure.c'. We have -discarded that program in favor of a standard Linux configuration file -Config.in. - -Config.in defines a set of symbols with the form CONFIG_SOUND_*. -These are the -native symbols-. Here is a description: - - CONFIG_SOUND - - This is the master symbol. It controls whether the basic - sound-driver code is resident, modular, or not present at all. - - If the basic driver is resident, each primary and secondary - driver can be resident, modular, or not present. - - If the basic driver is modular, each primary and secondary driver - can be modular or not present. - - And if the basic driver is not present, all other drivers are - not present, too. - - Primary drivers - - These are symbols such as CONFIG_SOUND_SB, CONFIG_SOUND_SB_MODULE, - CONFIG_SOUND_TRIX, or CONFIG_SOUND_TRIX_MODULE. Each driver - that the user can directly select is a primary driver and has - the usual pair of symbols: one resident and one modular. - - Each primary driver can be either resident or modular. - - Secondary drivers - - Primary drivers require the support of secondary drivers, such - as ad1848.o and uart401.o. - - In Makefile, each primary driver has a list of required secondary - drivers. The secondary driver requirements are merged and a - single definition is emitted at the end. - - For each secondary driver: if any resident primary driver - requires it, that secondary driver will be resident. If no - resident primary driver requires it but some modular primary - driver requires it, then that secondary driver will be modular. - Otherwise that secondary driver will be not present. - - OSS/Free also contains tests for secondary drivers. The Makefile - defines symbols for these drivers in EXTRA_CFLAGS. - - CONFIG_AUDIO, CONFIG_MIDI, CONFIG_SEQUENCER - - These three drivers are like secondary drivers, but not quite. - They can not yet be separated into modules. They are always - linked into the basic sound driver, whether they are needed - or not. (This is in case a primary driver is added to the - system later, as a module, and needs these facilities. If it - were possible to modularise them, then they would get built as - additional modules at that time). - -The OSS/Free code does not use the native symbols directly, primarily -because it does not know about modules. I could edit the code, but that -would make it harder to upgrade to new versions of OSS/Free. Instead, -the OSS/Free code continues to use -legacy symbols-. - -legacy.h defines all the legacy symbols to 1. This is because, whenever -OSS/Free tests a symbol, the Makefile has already arranged for that -driver to be included. diff --git a/drivers/sound/ac97_codec.c b/drivers/sound/ac97_codec.c index 56ee3df89..175cd38e0 100644 --- a/drivers/sound/ac97_codec.c +++ b/drivers/sound/ac97_codec.c @@ -28,8 +28,7 @@ #include #include #include - -#include "ac97_codec.h" +#include static int ac97_read_mixer(struct ac97_codec *codec, int oss_channel); static void ac97_write_mixer(struct ac97_codec *codec, int oss_channel, diff --git a/drivers/sound/ac97_codec.h b/drivers/sound/ac97_codec.h deleted file mode 100644 index a614edbdb..000000000 --- a/drivers/sound/ac97_codec.h +++ /dev/null @@ -1,161 +0,0 @@ -#ifndef _AC97_CODEC_H_ -#define _AC97_CODEC_H_ - -#include "sound_config.h" -#include "sound_calls.h" - -/* AC97 1.0 */ -#define AC97_RESET 0x0000 // -#define AC97_MASTER_VOL_STEREO 0x0002 // Line Out -#define AC97_HEADPHONE_VOL 0x0004 // -#define AC97_MASTER_VOL_MONO 0x0006 // TAD Output -#define AC97_MASTER_TONE 0x0008 // -#define AC97_PCBEEP_VOL 0x000a // none -#define AC97_PHONE_VOL 0x000c // TAD Input (mono) -#define AC97_MIC_VOL 0x000e // MIC Input (mono) -#define AC97_LINEIN_VOL 0x0010 // Line Input (stereo) -#define AC97_CD_VOL 0x0012 // CD Input (stereo) -#define AC97_VIDEO_VOL 0x0014 // none -#define AC97_AUX_VOL 0x0016 // Aux Input (stereo) -#define AC97_PCMOUT_VOL 0x0018 // Wave Output (stereo) -#define AC97_RECORD_SELECT 0x001a // -#define AC97_RECORD_GAIN 0x001c -#define AC97_RECORD_GAIN_MIC 0x001e -#define AC97_GENERAL_PURPOSE 0x0020 -#define AC97_3D_CONTROL 0x0022 -#define AC97_MODEM_RATE 0x0024 -#define AC97_POWER_CONTROL 0x0026 - -/* AC'97 2.0 */ -#define AC97_EXTENDED_ID 0x0028 /* Extended Audio ID */ -#define AC97_EXTENDED_STATUS 0x002A /* Extended Audio Status */ -#define AC97_PCM_FRONT_DAC_RATE 0x002C /* PCM Front DAC Rate */ -#define AC97_PCM_SURR_DAC_RATE 0x002E /* PCM Surround DAC Rate */ -#define AC97_PCM_LFE_DAC_RATE 0x0030 /* PCM LFE DAC Rate */ -#define AC97_PCM_LR_DAC_RATE 0x0032 /* PCM LR DAC Rate */ -#define AC97_PCM_MIC_ADC_RATE 0x0034 /* PCM MIC ADC Rate */ -#define AC97_CENTER_LFE_MASTER 0x0036 /* Center + LFE Master Volume */ -#define AC97_SURROUND_MASTER 0x0038 /* Surround (Rear) Master Volume */ -#define AC97_RESERVED_3A 0x003A /* Reserved */ - -/* range 0x3c-0x58 - MODEM */ - -/* registers 0x005a - 0x007a are vendor reserved */ - -#define AC97_VENDOR_ID1 0x007c -#define AC97_VENDOR_ID2 0x007e - -/* volume control bit defines */ -#define AC97_MUTE 0x8000 -#define AC97_MICBOOST 0x0040 -#define AC97_LEFTVOL 0x3f00 -#define AC97_RIGHTVOL 0x003f - -/* record mux defines */ -#define AC97_RECMUX_MIC 0x0000 -#define AC97_RECMUX_CD 0x0101 -#define AC97_RECMUX_VIDEO 0x0202 /* not used */ -#define AC97_RECMUX_AUX 0x0303 -#define AC97_RECMUX_LINE 0x0404 -#define AC97_RECMUX_STEREO_MIX 0x0505 -#define AC97_RECMUX_MONO_MIX 0x0606 -#define AC97_RECMUX_PHONE 0x0707 - - -/* general purpose register bit defines */ -#define AC97_GP_LPBK 0x0080 /* Loopback mode */ -#define AC97_GP_MS 0x0100 /* Mic Select 0=Mic1, 1=Mic2 */ -#define AC97_GP_MIX 0x0200 /* Mono output select 0=Mix, 1=Mic */ -#define AC97_GP_RLBK 0x0400 /* Remote Loopback - Modem line codec */ -#define AC97_GP_LLBK 0x0800 /* Local Loopback - Modem Line codec */ -#define AC97_GP_LD 0x1000 /* Loudness 1=on */ -#define AC97_GP_3D 0x2000 /* 3D Enhancement 1=on */ -#define AC97_GP_ST 0x4000 /* Stereo Enhancement 1=on */ -#define AC97_GP_POP 0x8000 /* Pcm Out Path, 0=pre 3D, 1=post 3D */ - - -/* powerdown control and status bit defines */ - -/* status */ -#define AC97_PWR_MDM 0x0010 /* Modem section ready */ -#define AC97_PWR_REF 0x0008 /* Vref nominal */ -#define AC97_PWR_ANL 0x0004 /* Analog section ready */ -#define AC97_PWR_DAC 0x0002 /* DAC section ready */ -#define AC97_PWR_ADC 0x0001 /* ADC section ready */ - -/* control */ -#define AC97_PWR_PR0 0x0100 /* ADC and Mux powerdown */ -#define AC97_PWR_PR1 0x0200 /* DAC powerdown */ -#define AC97_PWR_PR2 0x0400 /* Output mixer powerdown (Vref on) */ -#define AC97_PWR_PR3 0x0800 /* Output mixer powerdown (Vref off) */ -#define AC97_PWR_PR4 0x1000 /* AC-link powerdown */ -#define AC97_PWR_PR5 0x2000 /* Internal Clk disable */ -#define AC97_PWR_PR6 0x4000 /* HP amp powerdown */ -#define AC97_PWR_PR7 0x8000 /* Modem off - if supported */ - -/* useful power states */ -#define AC97_PWR_D0 0x0000 /* everything on */ -#define AC97_PWR_D1 AC97_PWR_PR0|AC97_PWR_PR1|AC97_PWR_PR4 -#define AC97_PWR_D2 AC97_PWR_PR0|AC97_PWR_PR1|AC97_PWR_PR2|AC97_PWR_PR3|AC97_PWR_PR4 -#define AC97_PWR_D3 AC97_PWR_PR0|AC97_PWR_PR1|AC97_PWR_PR2|AC97_PWR_PR3|AC97_PWR_PR4 -#define AC97_PWR_ANLOFF AC97_PWR_PR2|AC97_PWR_PR3 /* analog section off */ - -/* Total number of defined registers. */ -#define AC97_REG_CNT 64 - - -/* OSS interface to the ac97s.. */ -#define AC97_STEREO_MASK (SOUND_MASK_VOLUME|SOUND_MASK_PCM|\ - SOUND_MASK_LINE|SOUND_MASK_CD|\ - SOUND_MASK_ALTPCM|SOUND_MASK_IGAIN|\ - SOUND_MASK_LINE1|SOUND_MASK_VIDEO) - -#define AC97_SUPPORTED_MASK (AC97_STEREO_MASK | \ - SOUND_MASK_BASS|SOUND_MASK_TREBLE|\ - SOUND_MASK_SPEAKER|SOUND_MASK_MIC|\ - SOUND_MASK_PHONEIN|SOUND_MASK_PHONEOUT) - -#define AC97_RECORD_MASK (SOUND_MASK_MIC|\ - SOUND_MASK_CD|SOUND_MASK_VIDEO|\ - SOUND_MASK_LINE1| SOUND_MASK_LINE|\ - SOUND_MASK_PHONEIN) - -#define supported_mixer(CODEC,FOO) ( CODEC->supported_mixers & (1<xfer_count = 0; -#if defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS) +#ifndef EXCLUDE_TIMERS if (dev == timer_installed && devc->timer_running) if ((fs & 0x01) != (old_fs & 0x01)) { @@ -1245,7 +1242,7 @@ static int ad1848_prepare_for_input(int dev, int bsize, int bcount) restore_flags(flags); devc->xfer_count = 0; -#if defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS) +#ifndef EXCLUDE_TIMERS if (dev == timer_installed && devc->timer_running) { if ((fs & 0x01) != (old_fs & 0x01)) @@ -1931,7 +1928,7 @@ int ad1848_init(char *name, int io_base, int irq, int dma_playback, int dma_capt } if (capabilities[devc->model].flags & CAP_F_TIMER) { -#ifndef __SMP__ +#ifndef CONFIG_SMP int x; unsigned char tmp = ad_read(devc, 16); #endif @@ -1940,7 +1937,7 @@ int ad1848_init(char *name, int io_base, int irq, int dma_playback, int dma_capt ad_write(devc, 21, 0x00); /* Timer MSB */ ad_write(devc, 20, 0x10); /* Timer LSB */ -#ifndef __SMP__ +#ifndef CONFIG_SMP ad_write(devc, 16, tmp | 0x40); /* Enable timer */ for (x = 0; x < 100000 && devc->timer_ticks == 0; x++); ad_write(devc, 16, tmp & ~0x40); /* Disable timer */ @@ -1961,7 +1958,7 @@ int ad1848_init(char *name, int io_base, int irq, int dma_playback, int dma_capt } else if (irq < 0) irq2dev[-irq] = devc->dev_no = my_dev; -#if defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS) +#ifndef EXCLUDE_TIMERS if ((capabilities[devc->model].flags & CAP_F_TIMER) && devc->irq_ok) ad1848_tmr_install(my_dev); @@ -2146,7 +2143,7 @@ interrupt_again: /* Jump back here if int status doesn't reset */ if (devc->model != MD_1848 && (alt_stat & 0x40)) /* Timer interrupt */ { devc->timer_ticks++; -#if defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS) +#ifndef EXCLUDE_TIMERS if (timer_installed == dev && devc->timer_running) sound_timer_interrupt(); #endif @@ -2583,7 +2580,7 @@ void unload_ms_sound(struct address_info *hw_config) release_region(hw_config->io_base, 4); } -#if defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS) +#ifndef EXCLUDE_TIMERS /* * Timer stuff (for /dev/music). @@ -2693,7 +2690,7 @@ static int ad1848_tmr_install(int dev) return 1; } -#endif +#endif /* EXCLUDE_TIMERS */ EXPORT_SYMBOL(ad1848_detect); @@ -2757,5 +2754,4 @@ void cleanup_module(void) unload_ms_sound(&hw_config); } -#endif -#endif +#endif /* MODULE */ diff --git a/drivers/sound/adlib_card.c b/drivers/sound/adlib_card.c index c48fb5eb8..087c57b68 100644 --- a/drivers/sound/adlib_card.c +++ b/drivers/sound/adlib_card.c @@ -65,4 +65,4 @@ void cleanup_module(void) SOUND_LOCK_END; } -#endif +#endif /* MODULE */ diff --git a/drivers/sound/audio.c b/drivers/sound/audio.c index b15a9423c..ba7231aa9 100644 --- a/drivers/sound/audio.c +++ b/drivers/sound/audio.c @@ -29,8 +29,6 @@ #include #include "sound_config.h" - -#ifdef CONFIG_AUDIO #include "ulaw.h" #include "coproc.h" @@ -517,8 +515,6 @@ void audio_init_devices(void) */ } -#endif - void reorganize_buffers(int dev, struct dma_buffparms *dmap, int recording) { /* diff --git a/drivers/sound/cs4232.c b/drivers/sound/cs4232.c index 11feddccc..0778273f9 100644 --- a/drivers/sound/cs4232.c +++ b/drivers/sound/cs4232.c @@ -176,7 +176,6 @@ int probe_cs4232(struct address_info *hw_config) * Initialize logical device 3 (MPU) */ -#if defined(CONFIG_UART401) && defined(CONFIG_MIDI) if (mpu_base != 0 && mpu_irq != 0) { CS_OUT2(0x15, 0x03); /* Select logical device 3 (MPU) */ @@ -184,7 +183,6 @@ int probe_cs4232(struct address_info *hw_config) CS_OUT2(0x22, mpu_irq); /* MPU IRQ */ CS_OUT2(0x33, 0x01); /* Activate logical dev 3 */ } -#endif if(synth_base != 0) { @@ -238,7 +236,6 @@ void attach_cs4232(struct address_info *hw_config) AD1848_REROUTE(SOUND_MIXER_LINE2, SOUND_MIXER_CD); AD1848_REROUTE(SOUND_MIXER_LINE3, SOUND_MIXER_SYNTH); /* FM synth */ } -#if defined(CONFIG_UART401) && defined(CONFIG_MIDI) if (mpu_base != 0 && mpu_irq != 0) { static struct address_info hw_config2 = { @@ -266,7 +263,6 @@ void attach_cs4232(struct address_info *hw_config) } hw_config->slots[1] = hw_config2.slots[1]; } -#endif } void unload_cs4232(struct address_info *hw_config) @@ -284,7 +280,6 @@ void unload_cs4232(struct address_info *hw_config) 0); sound_unload_audiodev(hw_config->slots[0]); -#if defined(CONFIG_UART401) && defined(CONFIG_MIDI) if (mpu_base != 0 && mpu_irq != 0 && mpu_detected) { static struct address_info hw_config2 = @@ -305,7 +300,6 @@ void unload_cs4232(struct address_info *hw_config) unload_uart401(&hw_config2); } -#endif } void unload_cs4232_mpu(struct address_info *hw_config) @@ -397,4 +391,4 @@ void cleanup_module(void) SOUND_LOCK_END; } -#endif +#endif /* MODULE */ diff --git a/drivers/sound/dev_table.c b/drivers/sound/dev_table.c index 603886504..5e9657c8a 100644 --- a/drivers/sound/dev_table.c +++ b/drivers/sound/dev_table.c @@ -43,7 +43,6 @@ static void start_services(void) return; /* No cards detected */ #endif -#ifdef CONFIG_AUDIO if (num_audiodevs) /* Audio devices present */ { int dev; @@ -52,7 +51,6 @@ static void start_services(void) } audio_init_devices(); } -#endif return; } @@ -410,7 +408,6 @@ int sound_install_audiodrv(int vers, char *name, struct audio_driver *driver, int driver_size, int flags, unsigned int format_mask, void *devc, int dma1, int dma2) { -#ifdef CONFIG_AUDIO struct audio_driver *d; struct audio_operations *op; int l, num; @@ -470,9 +467,6 @@ int sound_install_audiodrv(int vers, char *name, struct audio_driver *driver, audio_init_devices(); return num; -#else - return -EINVAL; -#endif } int sound_install_mixer(int vers, char *name, struct mixer_operations *driver, @@ -544,7 +538,6 @@ int sound_alloc_audiodev(void) int sound_alloc_mididev(void) { -#ifdef CONFIG_MIDI int i = register_sound_midi(&oss_sound_fops, -1); if(i==-1) return i; @@ -552,9 +545,6 @@ int sound_alloc_mididev(void) if(i>=num_midis) num_midis = i + 1; return i; -#else - return (-1); -#endif } int sound_alloc_synthdev(void) @@ -611,13 +601,11 @@ void sound_unload_mixerdev(int dev) void sound_unload_mididev(int dev) { -#ifdef CONFIG_MIDI if (dev != -1) { midi_devs[dev] = NULL; unregister_sound_midi((dev<<4)+2); } -#endif } void sound_unload_synthdev(int dev) diff --git a/drivers/sound/dev_table.h b/drivers/sound/dev_table.h index 427c6f4db..5c0cf1d0f 100644 --- a/drivers/sound/dev_table.h +++ b/drivers/sound/dev_table.h @@ -357,7 +357,7 @@ struct mixer_operations *mixer_devs[MAX_MIXER_DEV] = {NULL}; int num_mixers = 0; struct synth_operations *synth_devs[MAX_SYNTH_DEV+MAX_MIDI_DEV] = {NULL}; int num_synths = 0; struct midi_operations *midi_devs[MAX_MIDI_DEV] = {NULL}; int num_midis = 0; -#if defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS) && !defined(VMIDI) +#ifndef EXCLUDE_TIMERS extern struct sound_timer_operations default_sound_timer; struct sound_timer_operations *sound_timer_devs[MAX_TIMER_DEV] = { &default_sound_timer, NULL @@ -386,11 +386,9 @@ struct driver_info sound_drivers[] = #ifdef CONFIG_GUS16 {"GUS16", 0, SNDCARD_GUS16, "Ultrasound 16-bit opt.", attach_gus_db16, probe_gus_db16, unload_gus_db16}, #endif -#ifdef CONFIG_GUS {"GUS", 0, SNDCARD_GUS, "Gravis Ultrasound", attach_gus_card, probe_gus, unload_gus}, {"GUSPNP", 1, SNDCARD_GUSPNP, "GUS PnP", attach_gus_card, probe_gus, unload_gus}, #endif -#endif #ifdef CONFIG_SOUND_MSS {"MSS", 0, SNDCARD_MSS, "MS Sound System", attach_ms_sound, probe_ms_sound, unload_ms_sound}, @@ -433,11 +431,11 @@ probe_ad1816, unload_ad1816}, {"PAS16", 0, SNDCARD_PAS, "ProAudioSpectrum", attach_pas_card, probe_pas, unload_pas}, #endif -#if (defined(CONFIG_SOUND_MPU401) || defined(CONFIG_SOUND_MPU_EMU)) && defined(CONFIG_MIDI) +#if (defined(CONFIG_SOUND_MPU401) || defined(CONFIG_SOUND_MPU_EMU)) {"MPU401", 0, SNDCARD_MPU401,"Roland MPU-401", attach_mpu401, probe_mpu401, unload_mpu401}, #endif -#if defined(CONFIG_SOUND_UART401) && defined(CONFIG_MIDI) +#if defined(CONFIG_SOUND_UART401) {"UART401", 0, SNDCARD_UART401,"MPU-401 (UART)", attach_uart401, probe_uart401, unload_uart401}, #endif @@ -450,7 +448,7 @@ probe_ad1816, unload_ad1816}, {"MAUI", 0, SNDCARD_MAUI,"TB Maui", attach_maui, probe_maui, unload_maui}, #endif -#if defined(CONFIG_SOUND_UART6850) && defined(CONFIG_MIDI) +#if defined(CONFIG_SOUND_UART6850) {"MIDI6850", 0, SNDCARD_UART6850,"6860 UART Midi", attach_uart6850, probe_uart6850, unload_uart6850}, #endif @@ -461,10 +459,8 @@ probe_ad1816, unload_ad1816}, {"SBLAST", 0, SNDCARD_SB, "Sound Blaster", attach_sb_card, probe_sb, unload_sb}, {"SBPNP", 6, SNDCARD_SBPNP, "Sound Blaster PnP", attach_sb_card, probe_sb, unload_sb}, -#ifdef CONFIG_MIDI {"SBMPU", 0, SNDCARD_SB16MIDI,"SB MPU-401", attach_sbmpu, probe_sbmpu, unload_sbmpu}, #endif -#endif #ifdef CONFIG_SOUND_SSCAPE {"SSCAPE", 0, SNDCARD_SSCAPE, "Ensoniq SoundScape", attach_sscape, probe_sscape, unload_sscape}, @@ -488,7 +484,7 @@ probe_ad1816, unload_ad1816}, attach_softsyn_card, probe_softsyn, unload_softsyn}, #endif -#if defined(CONFIG_SOUND_VMIDI) && defined(CONFIG_MIDI) +#ifdef CONFIG_SOUND_VMIDI {"VMIDI", 0, SNDCARD_VMIDI,"Loopback MIDI Device", attach_v_midi, probe_v_midi, unload_v_midi}, #endif #ifdef CONFIG_SOUND_VIDC @@ -503,8 +499,6 @@ probe_ad1816, unload_ad1816}, int num_sound_drivers = sizeof(sound_drivers) / sizeof (struct driver_info); -#ifndef FULL_SOUND - /* * List of devices actually configured in the system. * @@ -632,7 +626,7 @@ struct card_info snd_installed_cards[] = {SNDCARD_MAUI, {CONFIG_MAUI_BASE, CONFIG_MAUI_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, #endif -#if defined(CONFIG_SOUND_MPU401) && defined(CONFIG_MIDI) +#ifdef CONFIG_SOUND_MPU401 {SNDCARD_MPU401, {CONFIG_MPU_BASE, CONFIG_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, #ifdef MPU2_BASE {SNDCARD_MPU401, {MPU2_BASE, MPU2_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, @@ -642,12 +636,12 @@ struct card_info snd_installed_cards[] = #endif #endif -#if defined(CONFIG_SOUND_UART6850) && defined(CONFIG_MIDI) +#ifdef CONFIG_SOUND_UART6850 {SNDCARD_UART6850, {CONFIG_U6850_BASE, CONFIG_U6850_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, #endif #ifdef CONFIG_SOUND_SB -#if defined(CONFIG_MIDI) && defined(CONFIG_SB_MPU_BASE) +#ifdef CONFIG_SB_MPU_BASE {SNDCARD_SB16MIDI,{CONFIG_SB_MPU_BASE, CONFIG_SB_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, #endif #endif @@ -666,7 +660,7 @@ struct card_info snd_installed_cards[] = {SNDCARD_ADLIB, {FM_MONO, 0, 0, -1}, SND_DEFAULT_ENABLE}, #endif -#if defined(CONFIG_SOUND_VMIDI) && defined(CONFIG_MIDI) +#ifdef CONFIG_SOUND_VMIDI {SNDCARD_VMIDI, {0, 0, 0, -1}, SND_DEFAULT_ENABLE}, #endif @@ -683,13 +677,7 @@ struct card_info snd_installed_cards[] = int num_sound_cards = sizeof(snd_installed_cards) / sizeof (struct card_info); static int max_sound_cards = sizeof(snd_installed_cards) / sizeof (struct card_info); -#else -int num_sound_cards = 0; -struct card_info snd_installed_cards[20] = {{0}}; -static int max_sound_cards = 20; -#endif - -#if defined(MODULE) || (!defined(linux) && !defined(_AIX)) +#if defined(MODULE) int trace_init = 0; #else int trace_init = 1; diff --git a/drivers/sound/dmabuf.c b/drivers/sound/dmabuf.c index e70c10841..1296da1ea 100644 --- a/drivers/sound/dmabuf.c +++ b/drivers/sound/dmabuf.c @@ -29,8 +29,6 @@ #include "sound_config.h" -#if defined(CONFIG_AUDIO) || defined(CONFIG_GUS) - #define DMAP_FREE_ON_CLOSE 0 #define DMAP_KEEP_ON_CLOSE 1 extern int sound_dmap_flag; @@ -1286,5 +1284,3 @@ void DMAbuf_deinit(int dev) sound_free_dmap(adev->dmap_in); } } - -#endif diff --git a/drivers/sound/es1371.c b/drivers/sound/es1371.c index feeb11956..95158296a 100644 --- a/drivers/sound/es1371.c +++ b/drivers/sound/es1371.c @@ -119,11 +119,11 @@ #include #include #include +#include #include #include #include #include -#include "ac97_codec.h" /* --------------------------------------------------------------------- */ @@ -376,6 +376,9 @@ static const unsigned sample_shift[] = { 0, 1, 1, 2 }; #define SND_DEV_DSP16 5 +#define ES1371_MODULE_NAME "es1371" +#define PFX ES1371_MODULE_NAME ": " + /* --------------------------------------------------------------------- */ struct es1371_state { @@ -496,7 +499,7 @@ static unsigned wait_src_ready(struct es1371_state *s) return r; udelay(1); } - printk(KERN_DEBUG "es1371: sample rate converter timeout r = 0x%08x\n", r); + printk(KERN_DEBUG PFX "sample rate converter timeout r = 0x%08x\n", r); return r; } @@ -1113,7 +1116,7 @@ static void es1371_interrupt(int irq, void *dev_id, struct pt_regs *regs) /* --------------------------------------------------------------------- */ -static const char invalid_magic[] = KERN_CRIT "es1371: invalid magic value\n"; +static const char invalid_magic[] = KERN_CRIT PFX "invalid magic value\n"; #define VALIDATE_STATE(s) \ ({ \ @@ -1216,7 +1219,7 @@ static int drain_dac1(struct es1371_state *s, int nonblock) tmo = 3 * HZ * (count + s->dma_dac1.fragsize) / 2 / s->dac1rate; tmo >>= sample_shift[(s->sctrl & SCTRL_P1FMT) >> SCTRL_SH_P1FMT]; if (!schedule_timeout(tmo + 1)) - DBG(printk(KERN_DEBUG "es1371: dac1 dma timed out??\n");) + DBG(printk(KERN_DEBUG PFX "dac1 dma timed out??\n");) } remove_wait_queue(&s->dma_dac1.wait, &wait); set_current_state(TASK_RUNNING); @@ -1251,7 +1254,7 @@ static int drain_dac2(struct es1371_state *s, int nonblock) tmo = 3 * HZ * (count + s->dma_dac2.fragsize) / 2 / s->dac2rate; tmo >>= sample_shift[(s->sctrl & SCTRL_P2FMT) >> SCTRL_SH_P2FMT]; if (!schedule_timeout(tmo + 1)) - DBG(printk(KERN_DEBUG "es1371: dac2 dma timed out??\n");) + DBG(printk(KERN_DEBUG PFX "dac2 dma timed out??\n");) } remove_wait_queue(&s->dma_dac2.wait, &wait); set_current_state(TASK_RUNNING); @@ -2502,7 +2505,7 @@ static int es1371_midi_release(struct inode *inode, struct file *file) } tmo = (count * HZ) / 3100; if (!schedule_timeout(tmo ? : 1) && tmo) - printk(KERN_DEBUG "es1371: midi timed out??\n"); + printk(KERN_DEBUG PFX "midi timed out??\n"); } remove_wait_queue(&s->midi.owait, &wait); set_current_state(TASK_RUNNING); @@ -2629,7 +2632,7 @@ static int __devinit es1371_probe(struct pci_dev *pcidev, const struct pci_devic return -1; } if (!(s = kmalloc(sizeof(struct es1371_state), GFP_KERNEL))) { - printk(KERN_WARNING "es1371: out of memory\n"); + printk(KERN_WARNING PFX "out of memory\n"); return -1; } memset(s, 0, sizeof(struct es1371_state)); @@ -2652,19 +2655,19 @@ static int __devinit es1371_probe(struct pci_dev *pcidev, const struct pci_devic s->codec.id = 0; s->codec.codec_read = rdcodec; s->codec.codec_write = wrcodec; - printk(KERN_INFO "es1371: found chip, vendor id 0x%04x device id 0x%04x revision 0x%02x\n", + printk(KERN_INFO PFX "found chip, vendor id 0x%04x device id 0x%04x revision 0x%02x\n", s->vendor, s->device, s->rev); if (!request_region(s->io, ES1371_EXTENT, "es1371")) { - printk(KERN_ERR "es1371: io ports %#lx-%#lx in use\n", s->io, s->io+ES1371_EXTENT-1); + printk(KERN_ERR PFX "io ports %#lx-%#lx in use\n", s->io, s->io+ES1371_EXTENT-1); goto err_region; } if (request_irq(s->irq, es1371_interrupt, SA_SHIRQ, "es1371", s)) { - printk(KERN_ERR "es1371: irq %u in use\n", s->irq); + printk(KERN_ERR PFX "irq %u in use\n", s->irq); goto err_irq; } pci_enable_device(pcidev); - printk(KERN_INFO "es1371: found es1371 rev %d at io %#lx irq %u\n" - KERN_INFO "es1371: features: joystick 0x%x\n", s->rev, s->io, s->irq, joystick[devindex]); + printk(KERN_INFO PFX "found es1371 rev %d at io %#lx irq %u\n" + KERN_INFO PFX "features: joystick 0x%x\n", s->rev, s->io, s->irq, joystick[devindex]); /* register devices */ if ((s->dev_audio = register_sound_dsp(&es1371_audio_fops, -1)) < 0) goto err_dev1; @@ -2683,7 +2686,7 @@ static int __devinit es1371_probe(struct pci_dev *pcidev, const struct pci_devic s->ctrl = 0; if ((joystick[devindex] & ~0x18) == 0x200) { if (check_region(joystick[devindex], JOY_EXTENT)) - printk(KERN_ERR "es1371: joystick address 0x%x already in use\n", joystick[devindex]); + printk(KERN_ERR PFX "joystick address 0x%x already in use\n", joystick[devindex]); else { s->ctrl |= CTRL_JYSTK_EN | (((joystick[devindex] >> 3) & CTRL_JOY_MASK) << CTRL_JOY_SHIFT); } @@ -2693,11 +2696,11 @@ static int __devinit es1371_probe(struct pci_dev *pcidev, const struct pci_devic /* check to see if s/pdif mode is being requested */ if (spdif[devindex]) { if (s->rev >= 4) { - printk(KERN_INFO "es1371: enabling S/PDIF output\n"); + printk(KERN_INFO PFX "enabling S/PDIF output\n"); cssr |= STAT_EN_SPDIF; s->ctrl |= CTRL_SPDIFEN_B; } else { - printk(KERN_ERR "es1371: revision %d does not support S/PDIF\n", s->rev); + printk(KERN_ERR PFX "revision %d does not support S/PDIF\n", s->rev); } } /* initialize the chips */ @@ -2731,6 +2734,7 @@ static int __devinit es1371_probe(struct pci_dev *pcidev, const struct pci_devic if (!ac97_probe_codec(&s->codec)) goto err_dev4; /* set default values */ + fs = get_fs(); set_fs(KERNEL_DS); val = SOUND_MASK_LINE; @@ -2759,7 +2763,7 @@ static int __devinit es1371_probe(struct pci_dev *pcidev, const struct pci_devic err_dev2: unregister_sound_dsp(s->dev_audio); err_dev1: - printk(KERN_ERR "es1371: cannot register misc device\n"); + printk(KERN_ERR PFX "cannot register misc device\n"); free_irq(s->irq, s); err_irq: release_region(s->io, ES1371_EXTENT); @@ -2822,7 +2826,7 @@ static int __init init_es1371(void) static void __exit cleanup_es1371(void) { - printk(KERN_INFO "es1371: unloading\n"); + printk(KERN_INFO PFX "unloading\n"); pci_unregister_driver(&es1371_driver); } diff --git a/drivers/sound/finetune.h b/drivers/sound/finetune.h deleted file mode 100644 index f3253cab9..000000000 --- a/drivers/sound/finetune.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifdef SEQUENCER_C -/* - * Copyright (C) by Hannu Savolainen 1993-1997 - * - * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) - * Version 2 (June 1991). See the "COPYING" file distributed with this software - * for more info. - */ - - - unsigned short finetune_table[128] = - { -/* 0 */ 9439, 9447, 9456, 9464, 9473, 9481, 9490, 9499, -/* 8 */ 9507, 9516, 9524, 9533, 9542, 9550, 9559, 9567, -/* 16 */ 9576, 9585, 9593, 9602, 9611, 9619, 9628, 9637, -/* 24 */ 9645, 9654, 9663, 9672, 9680, 9689, 9698, 9707, -/* 32 */ 9715, 9724, 9733, 9742, 9750, 9759, 9768, 9777, -/* 40 */ 9786, 9795, 9803, 9812, 9821, 9830, 9839, 9848, -/* 48 */ 9857, 9866, 9874, 9883, 9892, 9901, 9910, 9919, -/* 56 */ 9928, 9937, 9946, 9955, 9964, 9973, 9982, 9991, -/* 64 */ 10000, 10009, 10018, 10027, 10036, 10045, 10054, 10063, -/* 72 */ 10072, 10082, 10091, 10100, 10109, 10118, 10127, 10136, -/* 80 */ 10145, 10155, 10164, 10173, 10182, 10191, 10201, 10210, -/* 88 */ 10219, 10228, 10237, 10247, 10256, 10265, 10274, 10284, -/* 96 */ 10293, 10302, 10312, 10321, 10330, 10340, 10349, 10358, -/* 104 */ 10368, 10377, 10386, 10396, 10405, 10415, 10424, 10433, -/* 112 */ 10443, 10452, 10462, 10471, 10481, 10490, 10499, 10509, -/* 120 */ 10518, 10528, 10537, 10547, 10556, 10566, 10576, 10585 - }; -#else - extern unsigned short finetune_table[128]; -#endif diff --git a/drivers/sound/gus_card.c b/drivers/sound/gus_card.c index f1ab09179..6a42c4ce5 100644 --- a/drivers/sound/gus_card.c +++ b/drivers/sound/gus_card.c @@ -26,8 +26,6 @@ #include "sound_config.h" #include "soundmodule.h" -#ifdef CONFIG_GUS - #include "gus_hw.h" void gusintr(int irq, void *dev_id, struct pt_regs *dummy); @@ -55,9 +53,7 @@ void attach_gus_card(struct address_info *hw_config) if (hw_config->dma2 != -1 && hw_config->dma2 != hw_config->dma) if (sound_alloc_dma(hw_config->dma2, "GUS(2)")) printk(KERN_ERR "gus_card.c: Can't allocate DMA channel %d\n", hw_config->dma2); -#ifdef CONFIG_MIDI gus_midi_init(hw_config); -#endif if(request_irq(hw_config->irq, gusintr, 0, "Gravis Ultrasound", hw_config)<0) printk(KERN_ERR "gus_card.c: Unable to allocate IRQ %d\n", hw_config->irq); @@ -156,28 +152,20 @@ void gusintr(int irq, void *dev_id, struct pt_regs *dummy) } if (src & (MIDI_TX_IRQ | MIDI_RX_IRQ)) { -#ifdef CONFIG_MIDI gus_midi_interrupt(0); -#endif } if (src & (GF1_TIMER1_IRQ | GF1_TIMER2_IRQ)) { -#ifdef CONFIG_SEQUENCER if (gus_timer_enabled) sound_timer_interrupt(); gus_write8(0x45, 0); /* Ack IRQ */ gus_timer_command(4, 0x80); /* Reset IRQ flags */ -#else - gus_write8(0x45, 0); /* Stop timers */ -#endif } if (src & (WAVETABLE_IRQ | ENVELOPE_IRQ)) gus_voice_irq(); } } -#endif - /* * Some extra code for the 16 bit sampling option */ @@ -191,10 +179,8 @@ int probe_gus_db16(struct address_info *hw_config) void attach_gus_db16(struct address_info *hw_config) { -#ifdef CONFIG_GUS gus_pcm_volume = 100; gus_wave_volume = 90; -#endif hw_config->slots[3] = ad1848_init("GUS 16 bit sampling", hw_config->io_base, hw_config->irq, @@ -292,4 +278,4 @@ void cleanup_module(void) SOUND_LOCK_END; } -#endif +#endif /* MODULE */ diff --git a/drivers/sound/gus_midi.c b/drivers/sound/gus_midi.c index 7f82d3997..175eeb6a1 100644 --- a/drivers/sound/gus_midi.c +++ b/drivers/sound/gus_midi.c @@ -12,14 +12,9 @@ */ #include - #include "sound_config.h" - #include "gus_hw.h" -#ifdef CONFIG_GUS -#ifdef CONFIG_MIDI - static int midi_busy = 0, input_opened = 0; static int my_dev; static int output_used = 0; @@ -265,6 +260,3 @@ void gus_midi_interrupt(int dummy) } restore_flags(flags); } - -#endif -#endif diff --git a/drivers/sound/gus_vol.c b/drivers/sound/gus_vol.c index 3e5752d8f..783ff7d03 100644 --- a/drivers/sound/gus_vol.c +++ b/drivers/sound/gus_vol.c @@ -12,7 +12,6 @@ #include #include "sound_config.h" -#ifdef CONFIG_GUS #include "gus_linearvol.h" #define GUS_VOLUME gus_wave_volume @@ -152,5 +151,3 @@ unsigned short gus_linear_vol(int vol, int mainvol) #endif return gus_linearvol[(((vol * mainvol) / 127) * mixer_mainvol) / 100]; } - -#endif diff --git a/drivers/sound/gus_wave.c b/drivers/sound/gus_wave.c index 0dddaacaa..16eac5769 100644 --- a/drivers/sound/gus_wave.c +++ b/drivers/sound/gus_wave.c @@ -25,8 +25,6 @@ #include #include "gus_hw.h" -#ifdef CONFIG_GUS - #define GUS_BANK_SIZE (((iw_mode) ? 256*1024*1024 : 256*1024)) #define MAX_SAMPLE 150 @@ -3111,9 +3109,7 @@ void gus_wave_init(struct address_info *hw_config) hw_config->slots[0] = sdev; synth_devs[sdev] = &guswave_operations; sequencer_init(); -#ifdef CONFIG_SEQUENCER gus_tmr_install(gus_base + 8); -#endif } reset_sample_memory(); @@ -3433,8 +3429,6 @@ void guswave_dma_irq(void) } } -#ifdef CONFIG_SEQUENCER - /* * Timer stuff */ @@ -3535,6 +3529,3 @@ static void gus_tmr_install(int io_base) sound_timer_init(&gus_tmr, "GUS"); #endif } -#endif - -#endif diff --git a/drivers/sound/ics2101.c b/drivers/sound/ics2101.c index dffb83265..7cf9cc031 100644 --- a/drivers/sound/ics2101.c +++ b/drivers/sound/ics2101.c @@ -17,7 +17,6 @@ #include "sound_config.h" -#ifdef CONFIG_GUS #include #include "gus_hw.h" @@ -244,5 +243,3 @@ ics2101_mixer_init(void) } return n; } - -#endif diff --git a/drivers/sound/legacy.h b/drivers/sound/legacy.h deleted file mode 100644 index 6c3b87ce6..000000000 --- a/drivers/sound/legacy.h +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef _SOUND_LEGACY_H_ -#define _SOUND_LEGACY_H_ - -/* - * Force on additional support - */ - -#define __SGNXPRO__ -#define DESKPROXL -/* #define SM_GAMES */ -#define SM_WAVE - -/* - * Define legacy options. - */ - -#define SELECTED_SOUND_OPTIONS 0x0 - -#define HAVE_MAUI_BOOT -#define PSS_HAVE_LD -#define INCLUDE_TRIX_BOOT - -#define CONFIG_CS4232 -#define CONFIG_GUS -#define CONFIG_MAD16 -#define CONFIG_MAUI -#define CONFIG_MPU401 -#define CONFIG_MSS -#define CONFIG_OPL3SA1 -#define CONFIG_OPL3SA2 -#define CONFIG_PAS -#define CONFIG_PSS -#define CONFIG_SB -#define CONFIG_SOFTOSS -#define CONFIG_SSCAPE -#define CONFIG_AD1816 -#define CONFIG_TRIX -#define CONFIG_VMIDI -#define CONFIG_YM3812 - -#define CONFIG_AUDIO -#define CONFIG_MIDI -#define CONFIG_SEQUENCER - -#define CONFIG_AD1848 -#define CONFIG_MPU_EMU -#define CONFIG_SBDSP -#define CONFIG_UART401 - -#endif /* _SOUND_LEGACY_H */ diff --git a/drivers/sound/lowlevel/Config.in b/drivers/sound/lowlevel/Config.in index 30f1713f9..091a8df33 100644 --- a/drivers/sound/lowlevel/Config.in +++ b/drivers/sound/lowlevel/Config.in @@ -2,6 +2,15 @@ dep_tristate ' ACI mixer (miroPCM12)' CONFIG_ACI_MIXER $CONFIG_SOUND_OSS dep_tristate ' AWE32 synth' CONFIG_AWE32_SYNTH $CONFIG_SOUND_OSS +if [ "$CONFIG_AWE32_SYNTH" = "y" -o "$CONFIG_AWE32_SYNTH" = "m" ]; then + comment 'AWE32 PnP-ISA Cards are not always setup correctly' + bool 'Configure AWE32 synth Base Address and Default Memory Size' CONFIG_AWE32_SYNTH_DEFAULTS + if [ "$CONFIG_AWE32_SYNTH_DEFAULTS" = "y" ]; then + hex 'AWE32 synth Base Address 620' AWE_DEFAULT_BASE_ADDR 620 + int 'AWE32 synth Default Memory Size 512 1024 or 4096' AWE_DEFAULT_MEM_SIZE 512 + fi +fi + if [ "$CONFIG_SOUND_OSS" = "y" -o "$CONFIG_SOUND" = "m" ]; then dep_tristate ' Gallant Audio Cards (SC-6000 and SC-6600 based)' CONFIG_AEDSP16 $CONFIG_SOUND_OSS if [ "$CONFIG_AEDSP16" = "y" -o "$CONFIG_AEDSP16" = "m" ]; then diff --git a/drivers/sound/mad16.c b/drivers/sound/mad16.c index 8dc338aec..dedf7c843 100644 --- a/drivers/sound/mad16.c +++ b/drivers/sound/mad16.c @@ -86,8 +86,6 @@ static int mad16_cdsel; #endif -#ifdef CONFIG_MAD16 - #include "sb.h" static int already_initialized = 0; @@ -724,7 +722,7 @@ void attach_mad16(struct address_info *hw_config) void attach_mad16_mpu(struct address_info *hw_config) { -#if defined(CONFIG_MIDI) && defined(CONFIG_MAD16_OLDCARD) +#ifdef CONFIG_MAD16_OLDCARD if (mad_read(MC1_PORT) & 0x20) hw_config->io_base = 0x240; @@ -746,7 +744,6 @@ void attach_mad16_mpu(struct address_info *hw_config) int probe_mad16_mpu(struct address_info *hw_config) { -#if defined(CONFIG_UART401) && defined(CONFIG_MIDI) static int mpu_attached = 0; static int valid_ports[] = { 0x330, 0x320, 0x310, 0x300 @@ -766,7 +763,7 @@ int probe_mad16_mpu(struct address_info *hw_config) if (board_type < C929) /* Early chip. No MPU support. Just SB MIDI */ { -#if defined(CONFIG_MIDI) && defined(CONFIG_MAD16_OLDCARD) +#ifdef CONFIG_MAD16_OLDCARD unsigned char tmp; tmp = mad_read(MC3_PORT); @@ -899,9 +896,6 @@ int probe_mad16_mpu(struct address_info *hw_config) mad_write(MC6_PORT, tmp); /* Write MPU401 config */ return probe_uart401(hw_config); -#else - return 0; -#endif } void unload_mad16(struct address_info *hw_config) @@ -917,7 +911,7 @@ void unload_mad16(struct address_info *hw_config) void unload_mad16_mpu(struct address_info *hw_config) { -#if defined(CONFIG_MIDI) && defined(CONFIG_MAD16_OLDCARD) +#ifdef CONFIG_MAD16_OLDCARD if (board_type < C929) /* Early chip. No MPU support. Just SB MIDI */ { sb_dsp_unload(hw_config, 0); @@ -925,9 +919,7 @@ unload_mad16_mpu(struct address_info *hw_config) } #endif -#if defined(CONFIG_UART401) && defined(CONFIG_MIDI) unload_uart401(hw_config); -#endif } #ifdef MODULE @@ -1126,9 +1118,4 @@ void cleanup_module(void) SOUND_LOCK_END; } -#endif - - - -/* That's all folks */ -#endif +#endif /* MODULE */ diff --git a/drivers/sound/maui.c b/drivers/sound/maui.c index 75ea6c118..532e7573b 100644 --- a/drivers/sound/maui.c +++ b/drivers/sound/maui.c @@ -32,8 +32,6 @@ #include "soundmodule.h" #include "sound_firmware.h" -#ifdef CONFIG_MAUI - static int maui_base = 0x330; static volatile int irq_ok = 0; @@ -53,12 +51,7 @@ static int *maui_osp; static int (*orig_load_patch) (int dev, int format, const char *addr, int offs, int count, int pmgr_flag) = NULL; -#ifdef HAVE_MAUI_BOOT #include "maui_boot.h" -#else -static unsigned char *maui_os = NULL; -static int maui_osLen = 0; -#endif static int maui_wait(int mask) { @@ -190,7 +183,7 @@ failure: static int maui_init(int irq) { -#ifdef __SMP__ +#ifdef CONFIG_SMP int i; #endif unsigned char bits; @@ -221,7 +214,7 @@ static int maui_init(int irq) outb((0x80), HOST_CTRL_PORT); /* Leave reset */ outb((0xD0), HOST_CTRL_PORT); /* Cause interrupt */ -#ifdef __SMP__ +#ifdef CONFIG_SMP for (i = 0; i < 1000000 && !irq_ok; i++); if (!irq_ok) @@ -500,5 +493,4 @@ void cleanup_module(void) unload_maui(&cfg); SOUND_LOCK_END; } -#endif -#endif +#endif /* MODULE */ diff --git a/drivers/sound/midi_synth.c b/drivers/sound/midi_synth.c index 03d7d284f..6e524e21d 100644 --- a/drivers/sound/midi_synth.c +++ b/drivers/sound/midi_synth.c @@ -21,8 +21,6 @@ #include "sound_config.h" -#ifdef CONFIG_MIDI - #define _MIDI_SYNTH_C_ #include "midi_synth.h" @@ -32,9 +30,6 @@ static int sysex_state[MAX_MIDI_DEV] = {0}; static unsigned char prev_out_status[MAX_MIDI_DEV]; -#ifndef CONFIG_SEQUENCER -#define STORE(cmd) -#else #define STORE(cmd) \ { \ int len; \ @@ -42,7 +37,6 @@ static unsigned char prev_out_status[MAX_MIDI_DEV]; cmd; \ seq_input_event(obuf, len); \ } -#endif #define _seqbuf obuf #define _seqbufptr 0 @@ -709,6 +703,3 @@ midi_synth_send_sysex(int dev, unsigned char *bytes, int len) return 0; } - - -#endif diff --git a/drivers/sound/midibuf.c b/drivers/sound/midibuf.c index 426821753..32549ed2a 100644 --- a/drivers/sound/midibuf.c +++ b/drivers/sound/midibuf.c @@ -21,7 +21,6 @@ #include "sound_config.h" -#ifdef CONFIG_MIDI /* * Don't make MAX_QUEUE_SIZE larger than 4000 @@ -431,6 +430,3 @@ int MIDIbuf_avail(int dev) return DATA_AVAIL (midi_in_buf[dev]); return 0; } - - -#endif diff --git a/drivers/sound/mpu401.c b/drivers/sound/mpu401.c index 17089b0ad..b57c2dbca 100644 --- a/drivers/sound/mpu401.c +++ b/drivers/sound/mpu401.c @@ -24,15 +24,11 @@ #include "sound_config.h" #include "soundmodule.h" -#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) #include "coproc.h" -#ifdef CONFIG_SEQUENCER static int timer_mode = TMR_INTERNAL, timer_caps = TMR_INTERNAL; -#endif - struct mpu_config { int base; /* @@ -159,9 +155,6 @@ static unsigned char len_tab[] = /* # of data bytes following a status 0 /* Fx */ }; -#ifndef CONFIG_SEQUENCER -#define STORE(cmd) -#else #define STORE(cmd) \ { \ int len; \ @@ -169,7 +162,6 @@ static unsigned char len_tab[] = /* # of data bytes following a status cmd; \ seq_input_event(obuf, len); \ } -#endif #define _seqbuf obuf #define _seqbufptr 0 @@ -1225,8 +1217,6 @@ void unload_mpu401(struct address_info *hw_config) * Timer stuff ****************************************************/ -#if defined(CONFIG_SEQUENCER) - static volatile int timer_initialized = 0, timer_open = 0, tmr_running = 0; static volatile int curr_tempo, curr_timebase, hw_timebase; static int max_timebase = 8; /* 8*24=192 ppqn */ @@ -1718,9 +1708,6 @@ static int mpu_timer_init(int midi_dev) } -#endif - - EXPORT_SYMBOL(probe_mpu401); EXPORT_SYMBOL(attach_mpu401); EXPORT_SYMBOL(unload_mpu401); @@ -1762,5 +1749,4 @@ void cleanup_module(void) SOUND_LOCK_END; } -#endif -#endif +#endif /* MODULE */ diff --git a/drivers/sound/opl3.c b/drivers/sound/opl3.c index 7e005e754..acaf989ca 100644 --- a/drivers/sound/opl3.c +++ b/drivers/sound/opl3.c @@ -1204,7 +1204,7 @@ int init_module (void) void cleanup_module(void) { - if (devc) + if (devc && io != -1) { if(devc->base) release_region(devc->base,4); @@ -1217,7 +1217,7 @@ void cleanup_module(void) MODULE_PARM(io, "i"); -#endif +#endif /* MODULE */ EXPORT_SYMBOL(opl3_init); EXPORT_SYMBOL(opl3_detect); diff --git a/drivers/sound/opl3sa.c b/drivers/sound/opl3sa.c index 9e5fd5a6b..213a0a099 100644 --- a/drivers/sound/opl3sa.c +++ b/drivers/sound/opl3sa.c @@ -31,8 +31,6 @@ static int sb_initialized = 0; #endif -#ifdef CONFIG_OPL3SA1 - static int kilroy_was_here = 0; /* Don't detect twice */ static int mpu_initialized = 0; @@ -177,15 +175,12 @@ void attach_opl3sa_wss(struct address_info *hw_config) void attach_opl3sa_mpu(struct address_info *hw_config) { -#if defined(CONFIG_UART401) && defined(CONFIG_MIDI) hw_config->name = "OPL3-SA (MPU401)"; attach_uart401(hw_config); -#endif } int probe_opl3sa_mpu(struct address_info *hw_config) { -#if defined(CONFIG_UART401) && defined(CONFIG_MIDI) unsigned char conf; static signed char irq_bits[] = { -1, -1, -1, -1, -1, 1, -1, 2, -1, 3, 4 @@ -240,9 +235,6 @@ int probe_opl3sa_mpu(struct address_info *hw_config) mpu_initialized = 1; return probe_uart401(hw_config); -#else - return 0; -#endif } void unload_opl3sa_wss(struct address_info *hw_config) @@ -265,17 +257,13 @@ void unload_opl3sa_wss(struct address_info *hw_config) void unload_opl3sa_mpu(struct address_info *hw_config) { -#if defined(CONFIG_UART401) && defined(CONFIG_MIDI) unload_uart401(hw_config); -#endif } #ifdef SB_OK void unload_opl3sa_sb(struct address_info *hw_config) { -#ifdef CONFIG_SBDSP sb_dsp_unload(hw_config); -#endif } #endif @@ -334,6 +322,4 @@ void cleanup_module(void) SOUND_LOCK_END; } -#endif - -#endif +#endif /* MODULE */ diff --git a/drivers/sound/opl3sa2.c b/drivers/sound/opl3sa2.c index 68c37778f..c3fff526f 100644 --- a/drivers/sound/opl3sa2.c +++ b/drivers/sound/opl3sa2.c @@ -67,8 +67,6 @@ #define CHIPSET_OPL3SAX 4 -#ifdef CONFIG_OPL3SA2 - /* What's my version? */ static int chipset = CHIPSET_UNKNOWN; @@ -443,27 +441,19 @@ static struct mixer_operations opl3sa2_mixer_operations = int probe_opl3sa2_mpu(struct address_info *hw_config) { -#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) return probe_mpu401(hw_config); -#else - return 0; -#endif } void attach_opl3sa2_mpu(struct address_info *hw_config) { -#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) attach_mpu401(hw_config); -#endif } void unload_opl3sa2_mpu(struct address_info *hw_config) { -#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) unload_mpu401(hw_config); -#endif } @@ -706,7 +696,6 @@ int init_module(void) attach_opl3sa2(&cfg); attach_opl3sa2_mss(&mss_cfg); -#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) if(mpu_io != -1) { /* MPU config: */ @@ -720,7 +709,6 @@ int init_module(void) attach_opl3sa2_mpu(&mpu_cfg); } } -#endif SOUND_LOCK; return 0; } @@ -728,16 +716,13 @@ int init_module(void) void cleanup_module(void) { -#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) if(mpu_cfg.slots[1] != -1) { unload_opl3sa2_mpu(&mpu_cfg); } -#endif unload_opl3sa2_mss(&mss_cfg); unload_opl3sa2(&cfg); SOUND_LOCK_END; } #endif /* MODULE */ -#endif /* CONFIG_OPL3SA2 */ diff --git a/drivers/sound/pas2_card.c b/drivers/sound/pas2_card.c index 488e77a63..762871063 100644 --- a/drivers/sound/pas2_card.c +++ b/drivers/sound/pas2_card.c @@ -9,8 +9,6 @@ #include "sound_config.h" #include "soundmodule.h" -#ifdef CONFIG_PAS - static unsigned char dma_bits[] = { 4, 1, 2, 3, 0, 5, 6, 7 }; @@ -92,16 +90,12 @@ static void pasintr(int irq, void *dev_id, struct pt_regs *dummy) if (status & 0x08) { -#ifdef CONFIG_AUDIO pas_pcm_interrupt(status, 1); -#endif status &= ~0x08; } if (status & 0x10) { -#ifdef CONFIG_MIDI pas_midi_interrupt(); -#endif status &= ~0x10; } } @@ -239,7 +233,7 @@ static int config_pas_hw(struct address_info *hw_config) mix_write(0x80 | 5, 0x078B); mix_write(5, 0x078B); -#if !defined(DISABLE_SB_EMULATION) && defined(CONFIG_SB) +#if !defined(DISABLE_SB_EMULATION) { struct address_info *sb_config; @@ -351,18 +345,14 @@ void attach_pas_card(struct address_info *hw_config) } if (config_pas_hw(hw_config)) { -#ifdef CONFIG_AUDIO pas_pcm_init(hw_config); -#endif -#if !defined(MODULE) && !defined(DISABLE_SB_EMULATION) && defined(CONFIG_SB) +#if !defined(MODULE) && !defined(DISABLE_SB_EMULATION) sb_dsp_disable_midi(pas_sb_base); /* No MIDI capability */ #endif -#ifdef CONFIG_MIDI pas_midi_init(); -#endif pas_init_mixer(); } } @@ -453,5 +443,4 @@ void cleanup_module(void) } -#endif -#endif +#endif /* MODULE */ diff --git a/drivers/sound/pas2_midi.c b/drivers/sound/pas2_midi.c index d029d4c4d..0dda4df5c 100644 --- a/drivers/sound/pas2_midi.c +++ b/drivers/sound/pas2_midi.c @@ -12,12 +12,8 @@ */ #include - #include "sound_config.h" -#ifdef CONFIG_PAS -#ifdef CONFIG_MIDI - static int midi_busy = 0, input_opened = 0; static int my_dev; @@ -264,6 +260,3 @@ void pas_midi_interrupt(void) } pas_write(stat, 0x1B88); /* Acknowledge interrupts */ } - -#endif -#endif diff --git a/drivers/sound/pas2_mixer.c b/drivers/sound/pas2_mixer.c index 04a98fead..3b9b167c1 100644 --- a/drivers/sound/pas2_mixer.c +++ b/drivers/sound/pas2_mixer.c @@ -19,8 +19,6 @@ #include "sound_config.h" -#ifdef CONFIG_PAS - #ifndef DEB #define DEB(what) /* (what) */ #endif @@ -332,5 +330,3 @@ pas_init_mixer(void) } return 1; } - -#endif diff --git a/drivers/sound/pas2_pcm.c b/drivers/sound/pas2_pcm.c index dc49d04b5..c0776ae4f 100644 --- a/drivers/sound/pas2_pcm.c +++ b/drivers/sound/pas2_pcm.c @@ -18,9 +18,6 @@ #include "sound_config.h" -#ifdef CONFIG_PAS -#ifdef CONFIG_AUDIO - #ifndef DEB #define DEB(WHAT) #endif @@ -440,6 +437,3 @@ void pas_pcm_interrupt(unsigned char status, int cause) } } } - -#endif -#endif diff --git a/drivers/sound/pss.c b/drivers/sound/pss.c index 1fa943741..ffbb08b77 100644 --- a/drivers/sound/pss.c +++ b/drivers/sound/pss.c @@ -34,9 +34,6 @@ #include "sound_firmware.h" #include "soundmodule.h" -#ifdef CONFIG_PSS -#ifdef CONFIG_AUDIO - /* * PSS registers. */ @@ -82,14 +79,7 @@ #define NO_WSS_MIXER -1 #include "coproc.h" - -#ifdef PSS_HAVE_LD #include "pss_boot.h" -#else -static int pss_synthLen = 0; -static unsigned char *pss_synth = -NULL; -#endif /* If compiled into kernel, it enable or disable pss mixer */ #ifdef CONFIG_PSS_MIXER @@ -675,11 +665,7 @@ int probe_pss_mpu(struct address_info *hw_config) break; /* No more input */ } -#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) return probe_mpu401(hw_config); -#else - return 0; -#endif } static int pss_coproc_open(void *dev_info, int sub_device) @@ -926,11 +912,9 @@ static coproc_operations pss_coproc_operations = void attach_pss_mpu(struct address_info *hw_config) { -#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) attach_mpu401(hw_config); /* Slot 1 */ if (hw_config->slots[1] != -1) /* The MPU driver installed itself */ midi_devs[hw_config->slots[1]]->coproc = &pss_coproc_operations; -#endif } int probe_pss_mss(struct address_info *hw_config) @@ -1015,9 +999,7 @@ void unload_pss(struct address_info *hw_config) void unload_pss_mpu(struct address_info *hw_config) { -#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) unload_mpu401(hw_config); -#endif } void unload_pss_mss(struct address_info *hw_config) @@ -1114,6 +1096,4 @@ void cleanup_module(void) unload_pss(&cfgpss); SOUND_LOCK_END; } -#endif -#endif -#endif +#endif /* MODULE */ diff --git a/drivers/sound/sb.h b/drivers/sound/sb.h index 2cb785565..13c1cce55 100644 --- a/drivers/sound/sb.h +++ b/drivers/sound/sb.h @@ -1,7 +1,5 @@ #include -#include "legacy.h" -#ifdef CONFIG_SBDSP #define DSP_RESET (devc->base + 0x6) #define DSP_READ (devc->base + 0xA) #define DSP_WRITE (devc->base + 0xC) @@ -168,4 +166,3 @@ void sb_audio_close(int dev); extern int acer; extern sb_devc *last_sb; -#endif diff --git a/drivers/sound/sb_audio.c b/drivers/sound/sb_audio.c index 84d35b444..672b8f408 100644 --- a/drivers/sound/sb_audio.c +++ b/drivers/sound/sb_audio.c @@ -24,8 +24,6 @@ #include #include "sound_config.h" -#ifdef CONFIG_SBDSP - #include "sb_mixer.h" #include "sb.h" @@ -1126,5 +1124,3 @@ void sb_audio_init(sb_devc * devc, char *name) audio_devs[devc->dev]->mixer_dev = devc->my_mixerdev; audio_devs[devc->dev]->min_fragment = 5; } - -#endif diff --git a/drivers/sound/sb_card.c b/drivers/sound/sb_card.c index 3a4a94247..49a55288f 100644 --- a/drivers/sound/sb_card.c +++ b/drivers/sound/sb_card.c @@ -37,8 +37,6 @@ #include "sound_config.h" #include "soundmodule.h" -#ifdef CONFIG_SBDSP - #include "sb_mixer.h" #include "sb.h" @@ -113,11 +111,11 @@ iobase=0x%x irq=%d lo_dma=%d hi_dma=%d\n", } #endif - /* This is useless since is done by sb_dsp_detect - azummo*/ + /* This is useless since is done by sb_dsp_detect - azummo */ if (check_region(hw_config->io_base, 16)) { - printk(KERN_ERR "sb_card: I/O port %x is already in use\n\n", hw_config->io_base); + printk(KERN_ERR "sb_card: I/O port 0x%x is already in use\n\n", hw_config->io_base); return 0; } return sb_dsp_detect(hw_config, 0, 0); @@ -138,11 +136,10 @@ static struct address_info config; static struct address_info config_mpu; struct pci_dev *sb_dev = NULL, - *wss_dev = NULL, - *jp_dev = NULL, -/* *ide_dev = NULL, */ - *mpu_dev = NULL, - *wt_dev = NULL; + *wss_dev = NULL, + *jp_dev = NULL, + *mpu_dev = NULL, + *wt_dev = NULL; /* * Note DMA2 of -1 has the right meaning in the SB16 driver as well * as here. It will cause either an error if it is needed or a fallback @@ -153,49 +150,49 @@ int mpu_io = 0; int io = -1; int irq = -1; int dma = -1; -int dma16 = -1; /* Set this for modules that need it */ -int type = 0; /* Can set this to a specific card type */ -int mad16 = 0; /* Set mad16=1 to load this as support for mad16 */ -int trix = 0; /* Set trix=1 to load this as support for trix */ -int pas2 = 0; /* Set pas2=1 to load this as support for pas2 */ -int support = 0; /* Set support to load this as a support module */ -int sm_games = 0; /* Mixer - see sb_mixer.c */ -int acer = 0; /* Do acer notebook init */ - -#if defined CONFIGISAPNP || defined CONFIG_ISAPNP_MODULE -int isapnp = 1; -int isapnpjump = 0; -int nosbwave = 0; /* This option will be removed when the new awe_wave driver will be in the kernel tree */ +int dma16 = -1; /* Set this for modules that need it */ +int type = 0; /* Can set this to a specific card type */ +int mad16 = 0; /* Set mad16=1 to load this as support for mad16 */ +int trix = 0; /* Set trix=1 to load this as support for trix */ +int pas2 = 0; /* Set pas2=1 to load this as support for pas2 */ +int support = 0; /* Set support to load this as a support module */ +int sm_games = 0; /* Mixer - see sb_mixer.c */ +int acer = 0; /* Do acer notebook init */ + +#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE +int isapnp = 1; +int isapnpjump = 0; +int nosbwave = 0; /* This option will be removed when the new awe_wave driver will be in the kernel tree */ #else -int isapnp = 0; +int isapnp = 0; #endif MODULE_DESCRIPTION("Soundblaster driver"); -MODULE_PARM(io, "i"); -MODULE_PARM(irq, "i"); -MODULE_PARM(dma, "i"); -MODULE_PARM(dma16, "i"); -MODULE_PARM(mpu_io, "i"); -MODULE_PARM(type, "i"); -MODULE_PARM(mad16, "i"); -MODULE_PARM(support, "i"); -MODULE_PARM(trix, "i"); -MODULE_PARM(pas2, "i"); -MODULE_PARM(sm_games, "i"); -MODULE_PARM(esstype, "i"); -MODULE_PARM(acer, "i"); +MODULE_PARM(io, "i"); +MODULE_PARM(irq, "i"); +MODULE_PARM(dma, "i"); +MODULE_PARM(dma16, "i"); +MODULE_PARM(mpu_io, "i"); +MODULE_PARM(type, "i"); +MODULE_PARM(mad16, "i"); +MODULE_PARM(support, "i"); +MODULE_PARM(trix, "i"); +MODULE_PARM(pas2, "i"); +MODULE_PARM(sm_games, "i"); +MODULE_PARM(esstype, "i"); +MODULE_PARM(acer, "i"); #if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE -MODULE_PARM(isapnp, "i"); -MODULE_PARM(isapnpjump, "i"); +MODULE_PARM(isapnp, "i"); +MODULE_PARM(isapnpjump, "i"); MODULE_PARM(nosbwave, "i"); MODULE_PARM_DESC(isapnp, "When set to 0, Plug & Play support will be disabled"); -MODULE_PARM_DESC(isapnpjump, "Jumps to a specific slot in the driver's PnP table. Use the source, Luke."); -MODULE_PARM_DESC(nosbwave, "Disable SB AWE 32/64 Wavetable initialization. Use this option with the new awe_wave driver."); +MODULE_PARM_DESC(isapnpjump, "Jumps to a specific slot in the driver's PnP table. Use the source, Luke."); +MODULE_PARM_DESC(nosbwave, "Disable SB AWE 32/64 Wavetable initialization. Use this option with the new awe_wave driver."); #endif -MODULE_PARM_DESC(io, "Soundblaster i/o base address (0x220,0x240,0x260,0x280)"); +MODULE_PARM_DESC(io, "Soundblaster i/o base address (0x220,0x240,0x260,0x280)"); MODULE_PARM_DESC(irq, "IRQ (5,7,9,10)"); MODULE_PARM_DESC(dma, "8-bit DMA channel (0,1,3)"); MODULE_PARM_DESC(dma16, "16-bit DMA channel (5,6,7)"); @@ -211,7 +208,7 @@ MODULE_PARM_DESC(acer, "Set this to detect cards in some ACER notebooks"); void *smw_free = NULL; -#if defined CONFIGISAPNP || defined CONFIG_ISAPNP_MODULE +#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE /* That's useful. */ @@ -253,7 +250,7 @@ static struct pci_dev *sb_init_generic(struct pci_bus *bus, struct pci_dev *card hw_config->irq = sb_dev->irq_resource[0].start; hw_config->dma = sb_dev->dma_resource[0].start; hw_config->dma2 = sb_dev->dma_resource[1].start; - mpu_config->io_base = sb_dev->resource[1].start; + mpu_config->io_base = sb_dev->resource[1].start; } } return(sb_dev); @@ -270,8 +267,8 @@ static struct pci_dev *sb_init_ess(struct pci_bus *bus, struct pci_dev *card, st hw_config->io_base = sb_dev->resource[0].start; hw_config->irq = sb_dev->irq_resource[0].start; hw_config->dma = sb_dev->dma_resource[0].start; - hw_config->dma2 = sb_dev->dma_resource[1].start; - mpu_config->io_base = sb_dev->resource[2].start; + hw_config->dma2 = sb_dev->dma_resource[1].start; + mpu_config->io_base = sb_dev->resource[2].start; } } return(sb_dev); @@ -291,7 +288,7 @@ static struct pci_dev *sb_init_cmi(struct pci_bus *bus, struct pci_dev *card, st */ if((sb_dev = isapnp_find_dev(bus, - ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x0001), NULL))) + ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x0001), NULL))) { #ifdef CMI8330_DMA0BAD int dmahack = 0; @@ -299,9 +296,9 @@ static struct pci_dev *sb_init_cmi(struct pci_bus *bus, struct pci_dev *card, st sb_dev->prepare(sb_dev); /* This device doesn't work with DMA 0, so we must allocate - * it to prevent PnP routines to assign it to the card. + * it to prevent PnP routines to assign it to the card. * - * I know i could have inlined the following lines, but it's cleaner + * I know i could have inlined the following lines, but it's cleaner * this way. */ @@ -327,12 +324,9 @@ static struct pci_dev *sb_init_cmi(struct pci_bus *bus, struct pci_dev *card, st } #ifdef CMI8330_DMA0BAD - if(dmahack) - free_dma(0); + if(dmahack) free_dma(0); #endif - if(!sb_dev) return(NULL); - } else printk(KERN_ERR "sb: CMI8330 panic: sb base not found\n"); @@ -340,9 +334,8 @@ static struct pci_dev *sb_init_cmi(struct pci_bus *bus, struct pci_dev *card, st /* @H@0001:mpu */ -#ifdef CONFIG_MIDI if((mpu_dev = isapnp_find_dev(bus, - ISAPNP_VENDOR('@','H','@'), ISAPNP_FUNCTION(0x0001), NULL))) + ISAPNP_VENDOR('@','H','@'), ISAPNP_FUNCTION(0x0001), NULL))) { mpu_dev->prepare(mpu_dev); @@ -359,17 +352,15 @@ static struct pci_dev *sb_init_cmi(struct pci_bus *bus, struct pci_dev *card, st } else printk(KERN_ERR "sb: CMI8330 panic: mpu not found\n"); -#endif /* @P@:Gameport */ if((jp_dev = isapnp_find_dev(bus, - ISAPNP_VENDOR('@','P','@'), ISAPNP_FUNCTION(0x0001), NULL))) + ISAPNP_VENDOR('@','P','@'), ISAPNP_FUNCTION(0x0001), NULL))) { jp_dev->prepare(jp_dev); - if((jp_dev = activate_dev("CMI8330", "gameport", jp_dev))) show_base("CMI8330", "gameport", &jp_dev->resource[0]); @@ -382,7 +373,7 @@ static struct pci_dev *sb_init_cmi(struct pci_bus *bus, struct pci_dev *card, st #if defined(CONFIG_SOUND_YM3812) || defined(CONFIG_SOUND_YM3812_MODULE) if((wss_dev = isapnp_find_dev(bus, - ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x0001), NULL))) + ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x0001), NULL))) { wss_dev->prepare(wss_dev); @@ -405,7 +396,7 @@ static struct pci_dev *sb_init_cmi(struct pci_bus *bus, struct pci_dev *card, st /* Specific support for awe will be dropped when: * a) The new awe_wawe driver with PnP support will be introduced in the kernel - * b) The joystick driver will support PnP + * b) The joystick driver will support PnP - a little patch is available from me....hint, hint :-) */ static struct pci_dev *sb_init_awe(struct pci_bus *bus, struct pci_dev *card, struct address_info *hw_config, struct address_info *mpu_config) @@ -430,7 +421,7 @@ static struct pci_dev *sb_init_awe(struct pci_bus *bus, struct pci_dev *card, st mpu_config->io_base = sb_dev->resource[1].start; - show_base("AWE", "sb", &sb_dev->resource[0]); + show_base("AWE", "sb", &sb_dev->resource[0]); show_base("AWE", "mpu", &sb_dev->resource[1]); show_base("AWE", "opl3", &sb_dev->resource[2]); } @@ -445,7 +436,7 @@ static struct pci_dev *sb_init_awe(struct pci_bus *bus, struct pci_dev *card, st * CTL7001:Game SB32 */ - if( (jp_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x7002), NULL)) || + if( (jp_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x7002), NULL)) || (jp_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x7001), NULL)) ) { jp_dev->prepare(jp_dev); @@ -459,12 +450,13 @@ static struct pci_dev *sb_init_awe(struct pci_bus *bus, struct pci_dev *card, st /* CTL0022:WaveTable SB64 * CTL0021:WaveTable SB32 + * CTL0023:WaveTable Sb64 */ if( nosbwave == 0 && - ( (wt_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0023), NULL)) || - (wt_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0022), NULL)) || - (wt_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0021), NULL)) )) + ( ( wt_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0023), NULL)) || + ( wt_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0022), NULL)) || + ( wt_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0021), NULL)) )) { wt_dev->prepare(wt_dev); @@ -478,26 +470,6 @@ static struct pci_dev *sb_init_awe(struct pci_bus *bus, struct pci_dev *card, st else printk(KERN_ERR "sb: AWE panic: wavetable not found\n"); - - /* CTL2011:IDE SB32/64 - */ - -/* No reasons to enable this... or not? */ -/* - if( (ide_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x2011), NULL)) ) - { - ide_dev->prepare(ide_dev); - - if((ide_dev = activate_dev("AWE", "IDE", ide_dev))) - { - show_base("AWE", "IDE 1", &ide_dev->resource[0]); - show_base("AWE", "IDE 2", &ide_dev->resource[1]); - } - } - else - printk(KERN_ERR "sb: AWE panic: IDE not found\n"); -*/ - printk(KERN_INFO "sb: AWE mail reports to Alessandro Zummo \n"); return(sb_dev); @@ -508,31 +480,31 @@ static struct pci_dev *sb_init_awe(struct pci_bus *bus, struct pci_dev *card, st static struct { unsigned short vendor, function, flags; struct pci_dev * (*initfunc)(struct pci_bus *, struct pci_dev *, struct address_info *, struct address_info *); char *name; } isapnp_sb_list[] __initdata = { - {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0001), SBF_DEV, &sb_init_generic, "Sound Blaster 16" }, - {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), SBF_DEV, &sb_init_generic, "Sound Blaster 16" }, - {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041), SBF_DEV, &sb_init_generic, "Sound Blaster 16" }, - {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0042), SBF_DEV, &sb_init_generic, "Sound Blaster 16" }, - {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0043), SBF_DEV, &sb_init_generic, "Sound Blaster 16" }, - {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0045), SBF_DEV, &sb_init_generic, "Sound Blaster 16" }, - {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0044), 0, &sb_init_awe, "Sound Blaster 32" }, - {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0039), 0, &sb_init_awe, "Sound Blaster AWE 32" }, - {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x009D), 0, &sb_init_awe, "Sound Blaster AWE 64" }, - {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x00C5), 0, &sb_init_awe, "Sound Blaster AWE 64" }, - {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x00E4), 0, &sb_init_awe, "Sound Blaster AWE 64" }, - {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1868), SBF_DEV, &sb_init_ess, "ESS 1868" }, - {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x8611), SBF_DEV, &sb_init_ess, "ESS 1868" }, - {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1869), SBF_DEV, &sb_init_ess, "ESS 1869" }, - {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1878), SBF_DEV, &sb_init_ess, "ESS 1878" }, - {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1879), SBF_DEV, &sb_init_ess, "ESS 1879" }, - {ISAPNP_VENDOR('C','M','I'), ISAPNP_FUNCTION(0x0001), 0, &sb_init_cmi, "CMI 8330 SoundPRO" }, - {0} + {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0001), SBF_DEV, &sb_init_generic, "Sound Blaster 16" }, + {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), SBF_DEV, &sb_init_generic, "Sound Blaster 16" }, + {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041), SBF_DEV, &sb_init_generic, "Sound Blaster 16" }, + {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0042), SBF_DEV, &sb_init_generic, "Sound Blaster 16" }, + {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0043), SBF_DEV, &sb_init_generic, "Sound Blaster 16" }, + {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0045), SBF_DEV, &sb_init_generic, "Sound Blaster 16" }, + {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0044), 0, &sb_init_awe, "Sound Blaster 32" }, + {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0039), 0, &sb_init_awe, "Sound Blaster AWE 32" }, + {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x009D), 0, &sb_init_awe, "Sound Blaster AWE 64" }, + {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x00C5), 0, &sb_init_awe, "Sound Blaster AWE 64" }, + {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x00E4), 0, &sb_init_awe, "Sound Blaster AWE 64" }, + {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1868), SBF_DEV, &sb_init_ess, "ESS 1868" }, + {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x8611), SBF_DEV, &sb_init_ess, "ESS 1868" }, + {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1869), SBF_DEV, &sb_init_ess, "ESS 1869" }, + {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1878), SBF_DEV, &sb_init_ess, "ESS 1878" }, + {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1879), SBF_DEV, &sb_init_ess, "ESS 1879" }, + {ISAPNP_VENDOR('C','M','I'), ISAPNP_FUNCTION(0x0001), 0, &sb_init_cmi, "CMI 8330 SoundPRO" }, + {0} }; static int __init sb_init_isapnp(struct address_info *hw_config, struct address_info *mpu_config, struct pci_bus *bus, struct pci_dev *card, int slot) { struct pci_dev *idev = NULL; - /* You missed the init func? That's bad. */ + /* You missed the init func? That's bad. */ if(isapnp_sb_list[slot].initfunc) { char *busname = bus->name[0] ? bus->name : isapnp_sb_list[slot].name; @@ -587,9 +559,9 @@ static int __init sb_probe_isapnp(struct address_info *hw_config, struct address struct pci_bus *bus = NULL; while ((bus = isapnp_find_card( - isapnp_sb_list[i].vendor, - isapnp_sb_list[i].function, - bus))) { + isapnp_sb_list[i].vendor, + isapnp_sb_list[i].function, + bus))) { if(sb_init_isapnp(hw_config, mpu_config, bus, NULL, i)) return 0; @@ -608,9 +580,9 @@ static int __init sb_probe_isapnp(struct address_info *hw_config, struct address struct pci_dev *card = NULL; while ((card = isapnp_find_dev(NULL, - isapnp_sb_list[i].vendor, - isapnp_sb_list[i].function, - card))) { + isapnp_sb_list[i].vendor, + isapnp_sb_list[i].function, + card))) { if(sb_init_isapnp(hw_config, mpu_config, card->bus, card, i)) return 0; @@ -632,7 +604,7 @@ int init_module(void) able to disable PNP support for this single driver! */ -#if defined CONFIGISAPNP || defined CONFIG_ISAPNP_MODULE +#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE if(isapnp && (sb_probe_isapnp(&config, &config_mpu) < 0) ) { printk(KERN_NOTICE "sb_card: No ISAPnP cards found, trying standard ones...\n"); @@ -647,10 +619,10 @@ int init_module(void) return -EINVAL; } - config.io_base = io; - config.irq = irq; - config.dma = dma; - config.dma2 = dma16; + config.io_base = io; + config.irq = irq; + config.dma = dma; + config.dma2 = dma16; } config.card_subtype = type; @@ -686,7 +658,6 @@ void cleanup_module(void) if(sb_dev) sb_dev->deactivate(sb_dev); if(jp_dev) jp_dev->deactivate(jp_dev); if(wt_dev) wt_dev->deactivate(wt_dev); -/* if(ide_dev) wt_dev->deactivate(ide_dev); */ if(mpu_dev) mpu_dev->deactivate(mpu_dev); if(wss_dev) wss_dev->deactivate(wss_dev); } @@ -716,5 +687,3 @@ EXPORT_SYMBOL(sb_be_quiet); EXPORT_SYMBOL(attach_sbmpu); EXPORT_SYMBOL(probe_sbmpu); EXPORT_SYMBOL(unload_sbmpu); - -#endif diff --git a/drivers/sound/sb_common.c b/drivers/sound/sb_common.c index 37dd03f4f..bda10bfad 100644 --- a/drivers/sound/sb_common.c +++ b/drivers/sound/sb_common.c @@ -23,12 +23,6 @@ #include "sound_config.h" #include "sound_firmware.h" -#ifdef CONFIG_SBDSP - -#ifndef CONFIG_AUDIO -#error You will need to configure the sound driver with CONFIG_AUDIO option. -#endif - #include "sb_mixer.h" #include "sb.h" @@ -114,11 +108,9 @@ static void sb_intr (sb_devc *devc) { src = sb_getmixer(devc, IRQ_STAT); /* Interrupt source register */ -#if defined(CONFIG_MIDI)&& defined(CONFIG_UART401) if (src & 4) /* MPU401 interrupt */ if(devc->midi_irq_cookie) uart401intr(devc->irq, devc->midi_irq_cookie, NULL); -#endif if (!(src & 3)) return; /* Not a DSP interrupt */ @@ -139,9 +131,7 @@ static void sb_intr (sb_devc *devc) break; case IMODE_MIDI: -#ifdef CONFIG_MIDI sb_midi_interrupt(devc); -#endif break; default: @@ -284,7 +274,6 @@ static int sb16_set_dma_hw(sb_devc * devc) return 1; } -#if defined(CONFIG_MIDI) && defined(CONFIG_UART401) static void sb16_set_mpu_port(sb_devc * devc, struct address_info *hw_config) { /* @@ -307,7 +296,6 @@ static void sb16_set_mpu_port(sb_devc * devc, struct address_info *hw_config) printk(KERN_ERR "SB16: Invalid MIDI I/O port %x\n", hw_config->io_base); } } -#endif static int sb16_set_irq_hw(sb_devc * devc, int level) { @@ -807,10 +795,8 @@ int sb_dsp_init(struct address_info *hw_config) if (devc->major == 3 || devc->major == 4) sb_mixer_init(devc); -#ifdef CONFIG_MIDI if (!(devc->caps & SB_NO_MIDI)) sb_dsp_midi_init(devc); -#endif if (hw_config->name == NULL) hw_config->name = "Sound Blaster (8 BIT/MONO ONLY)"; @@ -971,8 +957,6 @@ void sb_chgmixer sb_setmixer(devc, reg, value); } -#ifdef CONFIG_MIDI - /* * MPU401 MIDI initialization. */ @@ -1200,10 +1184,8 @@ void attach_sbmpu(struct address_info *hw_config) #endif return; } -#if defined(CONFIG_UART401) attach_uart401(hw_config); last_sb->midi_irq_cookie=midi_devs[hw_config->slots[4]]->devc; -#endif } int probe_sbmpu(struct address_info *hw_config) @@ -1244,7 +1226,6 @@ int probe_sbmpu(struct address_info *hw_config) } #endif -#if defined(CONFIG_UART401) if (check_region(hw_config->io_base, 4)) { printk(KERN_ERR "sbmpu: I/O port conflict (%x)\n", hw_config->io_base); @@ -1279,9 +1260,6 @@ int probe_sbmpu(struct address_info *hw_config) return 0; } return probe_uart401(hw_config); -#else - return 0; -#endif } void unload_sbmpu(struct address_info *hw_config) @@ -1292,23 +1270,5 @@ void unload_sbmpu(struct address_info *hw_config) return; } #endif -#if defined(CONFIG_UART401) unload_uart401(hw_config); -#endif -} -#else /* !CONFIG_MIDI */ - -void unload_sbmpu(struct address_info *hw_config) -{ -} - -int probe_sbmpu(struct address_info *hw_config) -{ - return 0; } - -void attach_sbmpu(struct address_info *hw_config) -{ -} -#endif -#endif diff --git a/drivers/sound/sb_midi.c b/drivers/sound/sb_midi.c index 31a299a96..9c3cef2bb 100644 --- a/drivers/sound/sb_midi.c +++ b/drivers/sound/sb_midi.c @@ -14,9 +14,6 @@ #include #include "sound_config.h" -#ifdef CONFIG_SBDSP -#ifdef CONFIG_MIDI - #include "sb.h" #undef SB_TEST_IRQ @@ -210,6 +207,3 @@ void sb_dsp_midi_init(sb_devc * devc) midi_devs[dev]->converter->id = "SBMIDI"; sequencer_init(); } - -#endif -#endif diff --git a/drivers/sound/sb_mixer.c b/drivers/sound/sb_mixer.c index 0bad5eb58..f786b69b5 100644 --- a/drivers/sound/sb_mixer.c +++ b/drivers/sound/sb_mixer.c @@ -19,7 +19,6 @@ #include #include "sound_config.h" -#ifdef CONFIG_SBDSP #define __SB_MIXER_C__ #include "sb.h" @@ -78,27 +77,6 @@ MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0), MIX_ENT(SOUND_MIXER_RECLEV, 0x00, 0, 0, 0x00, 0, 0) }; -#ifdef __SGNXPRO__ -#if 0 -static mixer_tab sgnxpro_mix = { /* not used anywhere */ -MIX_ENT(SOUND_MIXER_VOLUME, 0x22, 7, 4, 0x22, 3, 4), -MIX_ENT(SOUND_MIXER_BASS, 0x46, 2, 3, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_TREBLE, 0x44, 2, 3, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_SYNTH, 0x26, 7, 4, 0x26, 3, 4), -MIX_ENT(SOUND_MIXER_PCM, 0x04, 7, 4, 0x04, 3, 4), -MIX_ENT(SOUND_MIXER_SPEAKER, 0x42, 2, 3, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_LINE, 0x2e, 7, 4, 0x2e, 3, 4), -MIX_ENT(SOUND_MIXER_MIC, 0x0a, 2, 3, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_CD, 0x28, 7, 4, 0x28, 3, 4), -MIX_ENT(SOUND_MIXER_IMIX, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_RECLEV, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_IGAIN, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_OGAIN, 0x00, 0, 0, 0x00, 0, 0) -}; -#endif -#endif - static mixer_tab sb16_mix = { MIX_ENT(SOUND_MIXER_VOLUME, 0x30, 7, 5, 0x31, 7, 5), MIX_ENT(SOUND_MIXER_BASS, 0x46, 7, 4, 0x47, 7, 4), @@ -763,5 +741,3 @@ int sb_mixer_init(sb_devc * devc) sb_mixer_reset(devc); return 1; } - -#endif diff --git a/drivers/sound/sb_mixer.h b/drivers/sound/sb_mixer.h index d53df66ff..1e1a1b8d2 100644 --- a/drivers/sound/sb_mixer.h +++ b/drivers/sound/sb_mixer.h @@ -24,9 +24,6 @@ * */ #include -#include "legacy.h" - -#ifdef CONFIG_SBDSP /* * Mixer registers @@ -108,6 +105,3 @@ #define ALS007_LINE 6 #define ALS007_CD 2 #define ALS007_SYNTH 7 - -#endif - diff --git a/drivers/sound/sequencer.c b/drivers/sound/sequencer.c index 8fee21c6b..0ef3b67ad 100644 --- a/drivers/sound/sequencer.c +++ b/drivers/sound/sequencer.c @@ -15,15 +15,12 @@ * Alan Cox : reformatted and fixed a pair of null pointer bugs */ #include - #include - #define SEQUENCER_C #include "sound_config.h" - -#ifdef CONFIG_SEQUENCER #include "softoss.h" + int (*softsynthp) (int cmd, int parm1, int parm2, unsigned long parm3) = NULL; #include "midi_ctrl.h" @@ -719,9 +716,7 @@ static void seq_local_event(unsigned char *event_rec) switch (cmd) { case LOCL_STARTAUDIO: -#ifdef CONFIG_AUDIO DMAbuf_start_devices(parm); -#endif break; default: @@ -1692,9 +1687,7 @@ void sequencer_init(void) if (sequencer_ok) return; -#ifdef CONFIG_MIDI MIDIbuf_init(); -#endif queue = (unsigned char *)vmalloc(SEQ_MAX_QUEUE * EV_SZ); if (queue == NULL) { @@ -1724,5 +1717,3 @@ void sequencer_unload(void) iqueue=NULL; } } - -#endif diff --git a/drivers/sound/sequencer_syms.c b/drivers/sound/sequencer_syms.c index 053cd1e01..014d77841 100644 --- a/drivers/sound/sequencer_syms.c +++ b/drivers/sound/sequencer_syms.c @@ -9,7 +9,6 @@ char sequencer_syms_symbol; #include "sound_config.h" - #include "sound_calls.h" EXPORT_SYMBOL(note_to_freq); diff --git a/drivers/sound/sgalaxy.c b/drivers/sound/sgalaxy.c index 7bbd36657..1f23125a8 100644 --- a/drivers/sound/sgalaxy.c +++ b/drivers/sound/sgalaxy.c @@ -24,8 +24,6 @@ #include "sound_config.h" #include "soundmodule.h" -#if defined(CONFIG_SGALAXY) || defined (MODULE) - static void sleep( unsigned howlong ) { current->state = TASK_INTERRUPTIBLE; @@ -182,5 +180,4 @@ void cleanup_module(void) SOUND_LOCK_END; } -#endif -#endif +#endif /* MODULE */ diff --git a/drivers/sound/softoss.c b/drivers/sound/softoss.c index 2a9302bbc..ac8e4034f 100644 --- a/drivers/sound/softoss.c +++ b/drivers/sound/softoss.c @@ -30,8 +30,6 @@ #include "sound_config.h" #include "soundmodule.h" - -#ifdef CONFIG_SOFTOSS #include "softoss.h" #include @@ -1529,5 +1527,4 @@ void cleanup_module(void) sound_unload_timerdev(devc->timerdev); SOUND_LOCK_END; } -#endif -#endif +#endif /* MODULE */ diff --git a/drivers/sound/softoss_rs.c b/drivers/sound/softoss_rs.c index 2fa95f748..75f1bbb90 100644 --- a/drivers/sound/softoss_rs.c +++ b/drivers/sound/softoss_rs.c @@ -17,8 +17,6 @@ #include "sound_config.h" - -#ifdef CONFIG_SOFTOSS #include "softoss.h" void softsynth_resample_loop(short *buf, int loops) @@ -130,4 +128,3 @@ void softsynth_resample_loop(short *buf, int loops) } } /* Mix one sample */ } -#endif diff --git a/drivers/sound/sound_config.h b/drivers/sound/sound_config.h index 18ff32e34..7621f33be 100644 --- a/drivers/sound/sound_config.h +++ b/drivers/sound/sound_config.h @@ -18,7 +18,6 @@ #include #include -#include "legacy.h" #include "os.h" #include "soundvers.h" diff --git a/drivers/sound/sound_timer.c b/drivers/sound/sound_timer.c index 60f031ac8..b32759008 100644 --- a/drivers/sound/sound_timer.c +++ b/drivers/sound/sound_timer.c @@ -17,8 +17,6 @@ #include "sound_config.h" -#if defined(CONFIG_SEQUENCER) - static volatile int initialized = 0, opened = 0, tmr_running = 0; static volatile time_t tmr_offs, tmr_ctr; static volatile unsigned long ticks_offs; @@ -318,5 +316,3 @@ void sound_timer_init(struct sound_lowlev_timer *t, char *name) strcpy(sound_timer.info.name, name); sound_timer_devs[n] = &sound_timer; } - -#endif diff --git a/drivers/sound/soundcard.c b/drivers/sound/soundcard.c index a1d682969..81f9cdb19 100644 --- a/drivers/sound/soundcard.c +++ b/drivers/sound/soundcard.c @@ -45,8 +45,11 @@ #include #include #include - #include "soundmodule.h" + +/* From obsolete legacy.h */ +#define SELECTED_SOUND_OPTIONS 0x0 + struct notifier_block *sound_locker=(struct notifier_block *)0; static int lock_depth = 0; @@ -219,9 +222,6 @@ static int sound_proc_get_info(char *buffer, char **start, off_t offset, int len } if (!sound_started) len += sprintf(buffer + len, "\n\n***** Sound driver not started *****\n\n"); -#ifndef CONFIG_AUDIO - len += sprintf(buffer + len, "\nAudio devices: NOT ENABLED IN CONFIG\n"); -#else len += sprintf(buffer + len, "\nAudio devices:\n"); for (i = 0; (i < num_audiodevs) && (pos <= offset + length); i++) { if (audio_devs[i] == NULL) @@ -234,11 +234,7 @@ static int sound_proc_get_info(char *buffer, char **start, off_t offset, int len begin = pos; } } -#endif -#ifndef CONFIG_SEQUENCER - len += sprintf(buffer + len, "\nSynth devices: NOT ENABLED IN CONFIG\n"); -#else len += sprintf(buffer + len, "\nSynth devices:\n"); for (i = 0; (i < num_synths) && (pos <= offset + length); i++) { if (synth_devs[i] == NULL) @@ -250,11 +246,7 @@ static int sound_proc_get_info(char *buffer, char **start, off_t offset, int len begin = pos; } } -#endif -#ifndef CONFIG_MIDI - len += sprintf(buffer + len, "\nMidi devices: NOT ENABLED IN CONFIG\n"); -#else len += sprintf(buffer + len, "\nMidi devices:\n"); for (i = 0; (i < num_midis) && (pos <= offset + length); i++) { if (midi_devs[i] == NULL) @@ -266,9 +258,7 @@ static int sound_proc_get_info(char *buffer, char **start, off_t offset, int len begin = pos; } } -#endif -#ifdef CONFIG_SEQUENCER len += sprintf(buffer + len, "\nTimers:\n"); for (i = 0; (i < num_sound_timers) && (pos <= offset + length); i++) { @@ -281,7 +271,6 @@ static int sound_proc_get_info(char *buffer, char **start, off_t offset, int len begin = pos; } } -#endif len += sprintf(buffer + len, "\nMixers:\n"); for (i = 0; (i < num_mixers) && (pos <= offset + length); i++) { @@ -388,25 +377,19 @@ static ssize_t sound_read(struct file *file, char *buf, size_t count, loff_t *pp ret = sndstat_file_read(file, buf, count, ppos); break; -#ifdef CONFIG_AUDIO case SND_DEV_DSP: case SND_DEV_DSP16: case SND_DEV_AUDIO: ret = audio_read(dev, file, buf, count); break; -#endif -#ifdef CONFIG_SEQUENCER case SND_DEV_SEQ: case SND_DEV_SEQ2: ret = sequencer_read(dev, file, buf, count); break; -#endif -#ifdef CONFIG_MIDI case SND_DEV_MIDIN: ret = MIDIbuf_read(dev, file, buf, count); -#endif } unlock_kernel(); return ret; @@ -420,26 +403,20 @@ static ssize_t sound_write(struct file *file, const char *buf, size_t count, lof lock_kernel(); DEB(printk("sound_write(dev=%d, count=%d)\n", dev, count)); switch (dev & 0x0f) { -#ifdef CONFIG_SEQUENCER case SND_DEV_SEQ: case SND_DEV_SEQ2: ret = sequencer_write(dev, file, buf, count); break; -#endif -#ifdef CONFIG_AUDIO case SND_DEV_DSP: case SND_DEV_DSP16: case SND_DEV_AUDIO: ret = audio_write(dev, file, buf, count); break; -#endif -#ifdef CONFIG_MIDI case SND_DEV_MIDIN: ret = MIDIbuf_write(dev, file, buf, count); break; -#endif } unlock_kernel(); return ret; @@ -483,29 +460,23 @@ static int sound_open(struct inode *inode, struct file *file) return -ENXIO; break; -#ifdef CONFIG_SEQUENCER case SND_DEV_SEQ: case SND_DEV_SEQ2: if ((retval = sequencer_open(dev, file)) < 0) return retval; break; -#endif -#ifdef CONFIG_MIDI case SND_DEV_MIDIN: if ((retval = MIDIbuf_open(dev, file)) < 0) return retval; break; -#endif -#ifdef CONFIG_AUDIO case SND_DEV_DSP: case SND_DEV_DSP16: case SND_DEV_AUDIO: if ((retval = audio_open(dev, file)) < 0) return retval; break; -#endif default: printk(KERN_ERR "Invalid minor device %d\n", dev); @@ -531,26 +502,20 @@ static int sound_release(struct inode *inode, struct file *file) case SND_DEV_CTL: break; -#ifdef CONFIG_SEQUENCER case SND_DEV_SEQ: case SND_DEV_SEQ2: sequencer_release(dev, file); break; -#endif -#ifdef CONFIG_MIDI case SND_DEV_MIDIN: MIDIbuf_release(dev, file); break; -#endif -#ifdef CONFIG_AUDIO case SND_DEV_DSP: case SND_DEV_DSP16: case SND_DEV_AUDIO: audio_release(dev, file); break; -#endif default: printk(KERN_ERR "Sound error: Releasing unknown device 0x%02x\n", dev); @@ -641,13 +606,11 @@ static int sound_ioctl(struct inode *inode, struct file *file, (dev & 0x0f) != SND_DEV_CTL) { dtype = dev & 0x0f; switch (dtype) { -#ifdef CONFIG_AUDIO case SND_DEV_DSP: case SND_DEV_DSP16: case SND_DEV_AUDIO: return sound_mixer_ioctl(audio_devs[dev >> 4]->mixer_dev, cmd, (caddr_t)arg); -#endif default: return sound_mixer_ioctl(dev >> 4, cmd, (caddr_t)arg); @@ -661,25 +624,19 @@ static int sound_ioctl(struct inode *inode, struct file *file, return set_mixer_levels((caddr_t)arg); return sound_mixer_ioctl(dev >> 4, cmd, (caddr_t)arg); -#ifdef CONFIG_SEQUENCER case SND_DEV_SEQ: case SND_DEV_SEQ2: return sequencer_ioctl(dev, file, cmd, (caddr_t)arg); -#endif -#ifdef CONFIG_AUDIO case SND_DEV_DSP: case SND_DEV_DSP16: case SND_DEV_AUDIO: return audio_ioctl(dev, file, cmd, (caddr_t)arg); break; -#endif -#ifdef CONFIG_MIDI case SND_DEV_MIDIN: return MIDIbuf_ioctl(dev, file, cmd, (caddr_t)arg); break; -#endif } return -EINVAL; @@ -692,23 +649,17 @@ static unsigned int sound_poll(struct file *file, poll_table * wait) DEB(printk("sound_poll(dev=%d)\n", dev)); switch (dev & 0x0f) { -#ifdef CONFIG_SEQUENCER case SND_DEV_SEQ: case SND_DEV_SEQ2: return sequencer_poll(dev, file, wait); -#endif -#ifdef CONFIG_MIDI case SND_DEV_MIDIN: return MIDIbuf_poll(dev, file, wait); -#endif -#ifdef CONFIG_AUDIO case SND_DEV_DSP: case SND_DEV_DSP16: case SND_DEV_AUDIO: return DMAbuf_poll(file, dev >> 4, wait); -#endif } return 0; } @@ -828,13 +779,11 @@ static const struct { umode_t mode; int *num; } dev_list[] = { /* list of minor devices */ -#ifdef CONFIG_AUDIO /* seems to be some confusion here -- this device is not in the device list */ {SND_DEV_DSP16, "dspW", S_IWUGO | S_IRUSR | S_IRGRP, &num_audiodevs}, {SND_DEV_AUDIO, "audio", S_IWUGO | S_IRUSR | S_IRGRP, &num_audiodevs}, -#endif /* CONFIG_AUDIO */ }; static char * @@ -903,12 +852,10 @@ soundcard_init(void) return; /* No cards detected */ #endif -#ifdef CONFIG_AUDIO if (num_audiodevs || modular) /* Audio devices present */ { audio_init_devices(); } -#endif #ifdef CONFIG_PROC_FS if (!create_proc_info_entry("sound", 0, NULL, sound_proc_get_info)) printk(KERN_ERR "sound: registering /proc/sound failed\n"); @@ -1000,9 +947,7 @@ void cleanup_module(void) if (chrdev_registered) destroy_special_devices(); -#ifdef CONFIG_SEQUENCER sound_stop_timer(); -#endif #ifdef CONFIG_LOWLEVEL_SOUND { @@ -1093,8 +1038,6 @@ void sound_close_dma(int chn) restore_flags(flags); } -#ifdef CONFIG_SEQUENCER - static void do_sequencer_timer(unsigned long dummy) { sequencer_timer(0); @@ -1129,7 +1072,6 @@ void sound_stop_timer(void) { del_timer(&seq_timer);; } -#endif void conf_printf(char *name, struct address_info *hw_config) { diff --git a/drivers/sound/sscape.c b/drivers/sound/sscape.c index 4dce39e81..1c06b7c31 100644 --- a/drivers/sound/sscape.c +++ b/drivers/sound/sscape.c @@ -41,9 +41,6 @@ #include #include - -#ifdef CONFIG_SSCAPE - #include "coproc.h" /* @@ -722,7 +719,6 @@ void attach_sscape(struct address_info *hw_config) } #endif -#if defined(CONFIG_MIDI) && defined(CONFIG_MPU_EMU) if (probe_mpu401(hw_config)) hw_config->always_detect = 1; hw_config->name = "SoundScape"; @@ -736,7 +732,6 @@ void attach_sscape(struct address_info *hw_config) sscape_mididev = hw_config->slots[1]; midi_devs[hw_config->slots[1]]->coproc = &sscape_coproc_operations; } -#endif sscape_write(devc, GA_INTENA_REG, 0x80); /* Master IRQ enable */ devc->ok = 1; devc->failed = 0; @@ -1421,9 +1416,7 @@ void attach_ss_ms_sound(struct address_info *hw_config) void unload_sscape(struct address_info *hw_config) { release_region(devc->base + 2, 6); -#if defined(CONFIG_MPU_EMU) && defined(CONFIG_MIDI) unload_mpu401(hw_config); -#endif } void unload_ss_ms_sound(struct address_info *hw_config) @@ -1516,5 +1509,4 @@ void cleanup_module(void) unload_sscape(&mpu_config); } -#endif -#endif +#endif /* MODULE */ diff --git a/drivers/sound/sys_timer.c b/drivers/sound/sys_timer.c index e7ca0c84b..5a8a7787a 100644 --- a/drivers/sound/sys_timer.c +++ b/drivers/sound/sys_timer.c @@ -20,8 +20,6 @@ #include "sound_config.h" -#ifdef CONFIG_SEQUENCER - static volatile int opened = 0, tmr_running = 0; static volatile time_t tmr_offs, tmr_ctr; static volatile unsigned long ticks_offs; @@ -289,5 +287,3 @@ struct sound_timer_operations default_sound_timer = def_tmr_ioctl, def_tmr_arm }; - -#endif diff --git a/drivers/sound/trident.c b/drivers/sound/trident.c index bbe991eb2..de01c6cbe 100644 --- a/drivers/sound/trident.c +++ b/drivers/sound/trident.c @@ -79,11 +79,11 @@ #include #include #include +#include #include #include #include "trident.h" -#include "ac97_codec.h" #undef DEBUG @@ -1131,7 +1131,7 @@ static void trident_interrupt(int irq, void *dev_id, struct pt_regs *regs) /* Midi - TODO */ } - /* manually clear interrupt status, bad hardware design, balme T^2 */ + /* manually clear interrupt status, bad hardware design, blame T^2 */ outl((ST_TARGET_REACHED | MIXER_OVERFLOW | MIXER_UNDERFLOW), TRID_REG(card, T4D_MISCINT)); spin_unlock(&card->lock); diff --git a/drivers/sound/trix.c b/drivers/sound/trix.c index b54d00992..107c6ca9e 100644 --- a/drivers/sound/trix.c +++ b/drivers/sound/trix.c @@ -23,15 +23,8 @@ #include "sb.h" #include "sound_firmware.h" -#ifdef CONFIG_TRIX - -#ifdef INCLUDE_TRIX_BOOT #include #include "trix_boot.h" -#else -static unsigned char *trix_boot = NULL; -static int trix_boot_len = 0; -#endif static int kilroy_was_here = 0; /* Don't detect twice */ @@ -327,11 +320,7 @@ int probe_trix_sb(struct address_info *hw_config) sb_initialized = 1; hw_config->name = "AudioTrix SB"; -#ifdef CONFIG_SBDSP return sb_dsp_detect(hw_config, 0, 0); -#else - return 0; -#endif } void attach_trix_sb(struct address_info *hw_config) @@ -339,7 +328,6 @@ void attach_trix_sb(struct address_info *hw_config) extern int sb_be_quiet; int old_quiet; -#ifdef CONFIG_SBDSP hw_config->driver_use_1 = SB_NO_MIDI | SB_NO_MIXER | SB_NO_RECORDING; /* Prevent false alarms */ @@ -349,20 +337,16 @@ void attach_trix_sb(struct address_info *hw_config) sb_dsp_init(hw_config); sb_be_quiet = old_quiet; -#endif } void attach_trix_mpu(struct address_info *hw_config) { -#if defined(CONFIG_UART401) && defined(CONFIG_MIDI) hw_config->name = "AudioTrix Pro"; attach_uart401(hw_config); -#endif } int probe_trix_mpu(struct address_info *hw_config) { -#if defined(CONFIG_UART401) && defined(CONFIG_MIDI) unsigned char conf; static char irq_bits[] = { -1, -1, -1, 1, 2, 3, -1, 4, -1, 5 @@ -420,9 +404,6 @@ int probe_trix_mpu(struct address_info *hw_config) trix_write(0x19, (trix_read(0x19) & 0x83) | conf); mpu_initialized = 1; return probe_uart401(hw_config); -#else - return 0; -#endif } void unload_trix_wss(struct address_info *hw_config) @@ -445,16 +426,12 @@ void unload_trix_wss(struct address_info *hw_config) void unload_trix_mpu(struct address_info *hw_config) { -#if defined(CONFIG_UART401) && defined(CONFIG_MIDI) unload_uart401(hw_config); -#endif } void unload_trix_sb(struct address_info *hw_config) { -#ifdef CONFIG_SBDSP sb_dsp_unload(hw_config, mpu); -#endif } #ifdef MODULE @@ -566,5 +543,4 @@ void cleanup_module(void) SOUND_LOCK_END; } -#endif -#endif +#endif /* MODULE */ diff --git a/drivers/sound/uart401.c b/drivers/sound/uart401.c index 7ccc65a4f..a59fa7c99 100644 --- a/drivers/sound/uart401.c +++ b/drivers/sound/uart401.c @@ -25,9 +25,6 @@ #include "sound_config.h" #include "soundmodule.h" -#ifdef CONFIG_UART401 -#ifdef CONFIG_MIDI - typedef struct uart401_devc { int base; @@ -482,12 +479,9 @@ void cleanup_module(void) SOUND_LOCK_END; } -#endif +#endif /* MODULE */ EXPORT_SYMBOL(attach_uart401); EXPORT_SYMBOL(probe_uart401); EXPORT_SYMBOL(unload_uart401); EXPORT_SYMBOL(uart401intr); - -#endif -#endif diff --git a/drivers/sound/uart6850.c b/drivers/sound/uart6850.c index 13dcb5fc2..dfa6ed417 100644 --- a/drivers/sound/uart6850.c +++ b/drivers/sound/uart6850.c @@ -24,9 +24,6 @@ */ #include "sound_config.h" - -#ifdef CONFIG_SOUND_UART6850 -#ifdef CONFIG_MIDI #include "soundmodule.h" static int uart6850_base = 0x330; @@ -353,6 +350,4 @@ void cleanup_module(void) unload_uart6850(&cfg); SOUND_LOCK_END; } -#endif -#endif -#endif +#endif /* MODULE */ diff --git a/drivers/sound/v_midi.c b/drivers/sound/v_midi.c index c1d695c99..caeda1e41 100644 --- a/drivers/sound/v_midi.c +++ b/drivers/sound/v_midi.c @@ -24,8 +24,6 @@ #include "sound_config.h" #include "soundmodule.h" -#ifdef CONFIG_VMIDI - #include "v_midi.h" static vmidi_devc *v_devc[2] = { NULL, NULL}; @@ -52,7 +50,7 @@ void cleanup_module(void) SOUND_LOCK_END; } -#endif +#endif /* MODULE */ /* * The DSP channel can be used either for input or output. Variable @@ -297,5 +295,3 @@ void unload_v_midi(struct address_info *hw_config) sound_unload_mididev(midi2); kfree(midi_mem); } - -#endif diff --git a/drivers/sound/vidc.c b/drivers/sound/vidc.c index 04fcd3413..4fed93e06 100644 --- a/drivers/sound/vidc.c +++ b/drivers/sound/vidc.c @@ -1,128 +1,534 @@ /* - * drivers/sound/vidc.c + * drivers/sound/vidc.c * - * Detection routine for the VIDC. + * VIDC20 audio driver. * - * Copyright (C) 1997 by Russell King + * Copyright (C) 1997-2000 by Russell King + * + * The VIDC20 sound hardware consists of the VIDC20 itself, a DAC and a DMA + * engine. The DMA transfers fixed-format (16-bit little-endian linear) + * samples to the VIDC20, which then transfers this data serially to the + * DACs. The samplerate is controlled by the VIDC. + * + * We currently support a mixer device, but it is currently non-functional. */ #include #include -#include +#include #include +#include +#include +#include + #include "sound_config.h" #include "soundmodule.h" #include "vidc.h" -int vidc_busy; +#ifndef _SIOC_TYPE +#define _SIOC_TYPE(x) _IOC_TYPE(x) +#endif +#ifndef _SIOC_NR +#define _SIOC_NR(x) _IOC_NR(x) +#endif -void vidc_update_filler(int format, int channels) +#define VIDC_SOUND_CLOCK (250000) + +/* + * When using SERIAL SOUND mode (external DAC), the number of physical + * channels is fixed at 2. + */ +static int vidc_busy; +static int vidc_adev; +static int vidc_audio_rate; +static char vidc_audio_format; +static char vidc_audio_channels; + +static unsigned char vidc_level_l[SOUND_MIXER_NRDEVICES] = { + 85, /* master */ + 50, /* bass */ + 50, /* treble */ + 0, /* synth */ + 75, /* pcm */ + 0, /* speaker */ + 100, /* ext line */ + 0, /* mic */ + 100, /* CD */ + 0, +}; + +static unsigned char vidc_level_r[SOUND_MIXER_NRDEVICES] = { + 85, /* master */ + 50, /* bass */ + 50, /* treble */ + 0, /* synth */ + 75, /* pcm */ + 0, /* speaker */ + 100, /* ext line */ + 0, /* mic */ + 100, /* CD */ + 0, +}; + +static unsigned int vidc_audio_volume_l; /* left PCM vol, 0 - 65536 */ +static unsigned int vidc_audio_volume_r; /* right PCM vol, 0 - 65536 */ + +static void (*old_mksound)(unsigned int hz, unsigned int ticks); +extern void (*kd_mksound)(unsigned int hz, unsigned int ticks); +extern void vidc_update_filler(int bits, int channels); +extern int softoss_dev; + +static void +vidc_mksound(unsigned int hz, unsigned int ticks) { - int fillertype; + printk("BEEP - %d %d!\n", hz, ticks); +} -#define TYPE(fmt,ch) (((fmt)<<2) | ((ch)&3)) +static void +vidc_mixer_set(int mdev, unsigned int level) +{ + unsigned int lev_l = level & 0x007f; + unsigned int lev_r = (level & 0x7f00) >> 8; + unsigned int mlev_l, mlev_r; + + if (lev_l > 100) + lev_l = 100; + if (lev_r > 100) + lev_r = 100; + +#define SCALE(lev,master) ((lev) * (master) * 65536 / 10000) + + mlev_l = vidc_level_l[SOUND_MIXER_VOLUME]; + mlev_r = vidc_level_r[SOUND_MIXER_VOLUME]; + + switch (mdev) { + case SOUND_MIXER_VOLUME: + case SOUND_MIXER_PCM: + vidc_level_l[mdev] = lev_l; + vidc_level_r[mdev] = lev_r; + + vidc_audio_volume_l = SCALE(lev_l, mlev_l); + vidc_audio_volume_r = SCALE(lev_r, mlev_r); +/*printk("VIDC: PCM vol %05X %05X\n", vidc_audio_volume_l, vidc_audio_volume_r);*/ + break; + } +#undef SCALE +} + +static int vidc_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg) +{ + unsigned int val; + unsigned int mdev; + + if (_SIOC_TYPE(cmd) != 'M') + return -EINVAL; + + mdev = _SIOC_NR(cmd); + + if (_SIOC_DIR(cmd) & _SIOC_WRITE) { + if (get_user(val, (unsigned int *)arg)) + return -EFAULT; + + if (mdev < SOUND_MIXER_NRDEVICES) + vidc_mixer_set(mdev, val); + else + return -EINVAL; + } + + /* + * Return parameters + */ + switch (mdev) { + case SOUND_MIXER_RECSRC: + val = 0; + break; + + case SOUND_MIXER_DEVMASK: + val = SOUND_MASK_VOLUME | SOUND_MASK_PCM | SOUND_MASK_SYNTH; + break; - fillertype = TYPE(format, channels); + case SOUND_MIXER_STEREODEVS: + val = SOUND_MASK_VOLUME | SOUND_MASK_PCM | SOUND_MASK_SYNTH; + break; - switch (fillertype) - { - default: - case TYPE(AFMT_U8, 1): - vidc_filler = vidc_fill_1x8_u; - break; + case SOUND_MIXER_RECMASK: + val = 0; + break; - case TYPE(AFMT_U8, 2): - vidc_filler = vidc_fill_2x8_u; - break; + case SOUND_MIXER_CAPS: + val = 0; + break; - case TYPE(AFMT_S8, 1): - vidc_filler = vidc_fill_1x8_s; - break; + default: + if (mdev < SOUND_MIXER_NRDEVICES) + val = vidc_level_l[mdev] | vidc_level_r[mdev] << 8; + else + return -EINVAL; + } + + return put_user(val, (unsigned int *)arg) ? -EFAULT : 0; +} + +static unsigned int vidc_audio_set_format(int dev, unsigned int fmt) +{ + switch (fmt) { + default: + fmt = AFMT_S16_LE; + case AFMT_U8: + case AFMT_S8: + case AFMT_S16_LE: + vidc_audio_format = fmt; + vidc_update_filler(vidc_audio_format, vidc_audio_channels); + case AFMT_QUERY: + break; + } + return vidc_audio_format; +} + +static int vidc_audio_set_speed(int dev, int rate) +{ + if (rate) { + unsigned int hwctrl, hwrate; + unsigned int newsize, new2size; - case TYPE(AFMT_S8, 2): - vidc_filler = vidc_fill_2x8_s; - break; + /* + * If we have selected 44.1kHz, use the DAC clock. + */ + if (0 && rate == 44100) { + hwctrl = 0x00000002; + hwrate = 3; + } else { + hwctrl = 0x00000003; - case TYPE(AFMT_S16_LE, 1): - vidc_filler = vidc_fill_1x16_s; - break; + hwrate = (((VIDC_SOUND_CLOCK * 2) / rate) + 1) >> 1; + if (hwrate < 3) + hwrate = 3; + if (hwrate > 255) + hwrate = 255; - case TYPE(AFMT_S16_LE, 2): - vidc_filler = vidc_fill_2x16_s; - break; + rate = VIDC_SOUND_CLOCK / hwrate; + } + + outl(0xb0000000 | (hwrate - 2), IO_VIDC_BASE); + outl(0xb1000000 | hwctrl, IO_VIDC_BASE); + + newsize = (10000 / hwrate) & ~3; + if (newsize < 208) + newsize = 208; + if (newsize > 4096) + newsize = 4096; + for (new2size = 128; new2size < newsize; new2size <<= 1); + if (new2size - newsize > newsize - (new2size >> 1)) + new2size >>= 1; + if (new2size > 4096) { + printk(KERN_ERR "VIDC: error: dma buffer (%d) %d > 4K\n", + newsize, new2size); + new2size = 4096; + } + dma_bufsize = new2size; + vidc_audio_rate = rate; + } + return vidc_audio_rate; +} + +static short vidc_audio_set_channels(int dev, short channels) +{ + switch (channels) { + default: + channels = 2; + case 1: + case 2: + vidc_audio_channels = channels; + vidc_update_filler(vidc_audio_format, vidc_audio_channels); + case 0: + break; + } + return vidc_audio_channels; +} + +/* + * Open the device + */ +static int vidc_audio_open(int dev, int mode) +{ + /* This audio device does not have recording capability */ + if (mode == OPEN_READ) + return -EPERM; + + if (vidc_busy) + return -EBUSY; + + vidc_busy = 1; + return 0; +} + +/* + * Close the device + */ +static void vidc_audio_close(int dev) +{ + vidc_busy = 0; +} + +/* + * Output a block via DMA to sound device. + * + * We just set the DMA start and count; the DMA interrupt routine + * will take care of formatting the samples (via the appropriate + * vidc_filler routine), and flag via vidc_audio_dma_interrupt when + * more data is required. + */ +static void +vidc_audio_output_block(int dev, unsigned long buf, int total_count, int one) +{ + struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; + unsigned long flags; + + save_flags_cli(flags); + dma_start = buf - (unsigned long)dmap->raw_buf_phys + (unsigned long)dmap->raw_buf; + dma_count = total_count; + restore_flags(flags); +} + +static void +vidc_audio_start_input(int dev, unsigned long buf, int count, int intrflag) +{ +} + +static int vidc_audio_prepare_for_input(int dev, int bsize, int bcount) +{ + return -EINVAL; +} + +static void vidc_audio_dma_interrupt(void) +{ + DMAbuf_outputintr(vidc_adev, 1); +} + +/* + * Prepare for outputting samples. + * + * Each buffer that will be passed will be `bsize' bytes long, + * with a total of `bcount' buffers. + */ +static int vidc_audio_prepare_for_output(int dev, int bsize, int bcount) +{ + struct audio_operations *adev = audio_devs[dev]; + + dma_interrupt = NULL; + adev->dmap_out->flags |= DMA_NODMA; + + return 0; +} + +/* + * Stop our current operation. + */ +static void vidc_audio_reset(int dev) +{ + dma_interrupt = NULL; +} + +static int vidc_audio_local_qlen(int dev) +{ + return /*dma_count !=*/ 0; +} + +static void vidc_audio_trigger(int dev, int enable_bits) +{ + struct audio_operations *adev = audio_devs[dev]; + + if (enable_bits & PCM_ENABLE_OUTPUT) { + if (!(adev->flags & DMA_ACTIVE)) { + unsigned long flags; + + save_flags_cli(flags); + + /* prevent recusion */ + adev->flags |= DMA_ACTIVE; + + dma_interrupt = vidc_audio_dma_interrupt; + vidc_sound_dma_irq(0, NULL, NULL); + outb(DMA_CR_E | 0x10, IOMD_SD0CR); + + restore_flags(flags); + } + } +} + +static struct audio_driver vidc_audio_driver = +{ + open: vidc_audio_open, + close: vidc_audio_close, + output_block: vidc_audio_output_block, + start_input: vidc_audio_start_input, + prepare_for_input: vidc_audio_prepare_for_input, + prepare_for_output: vidc_audio_prepare_for_output, + halt_io: vidc_audio_reset, + local_qlen: vidc_audio_local_qlen, + trigger: vidc_audio_trigger, + set_speed: vidc_audio_set_speed, + set_bits: vidc_audio_set_format, + set_channels: vidc_audio_set_channels +}; + +static struct mixer_operations vidc_mixer_operations = { + id: "VIDC", + name: "VIDCsound", + ioctl: vidc_mixer_ioctl +}; + +void vidc_update_filler(int format, int channels) +{ +#define TYPE(fmt,ch) (((fmt)<<2) | ((ch)&3)) + + switch (TYPE(format, channels)) { + default: + case TYPE(AFMT_U8, 1): + vidc_filler = vidc_fill_1x8_u; + break; + + case TYPE(AFMT_U8, 2): + vidc_filler = vidc_fill_2x8_u; + break; + + case TYPE(AFMT_S8, 1): + vidc_filler = vidc_fill_1x8_s; + break; + + case TYPE(AFMT_S8, 2): + vidc_filler = vidc_fill_2x8_s; + break; + + case TYPE(AFMT_S16_LE, 1): + vidc_filler = vidc_fill_1x16_s; + break; + + case TYPE(AFMT_S16_LE, 2): + vidc_filler = vidc_fill_2x16_s; + break; } } void attach_vidc(struct address_info *hw_config) { char name[32]; - int i; + int i, adev; sprintf(name, "VIDC %d-bit sound", hw_config->card_subtype); conf_printf(name, hw_config); memset(dma_buf, 0, sizeof(dma_buf)); - for (i = 0; i < 2; i++) - { + adev = sound_install_audiodrv(AUDIO_DRIVER_VERSION, name, + &vidc_audio_driver, sizeof(vidc_audio_driver), + DMA_AUTOMODE, AFMT_U8 | AFMT_S8 | AFMT_S16_LE, + NULL, hw_config->dma, hw_config->dma2); + + if (adev < 0) + goto audio_failed; + + /* + * 1024 bytes => 64 buffers + */ + audio_devs[adev]->min_fragment = 10; + audio_devs[adev]->mixer_dev = num_mixers; + + audio_devs[adev]->mixer_dev = + sound_install_mixer(MIXER_DRIVER_VERSION, + name, &vidc_mixer_operations, + sizeof(vidc_mixer_operations), NULL); + + if (audio_devs[adev]->mixer_dev < 0) + goto mixer_failed; + + for (i = 0; i < 2; i++) { dma_buf[i] = get_free_page(GFP_KERNEL); - if (!dma_buf[i]) - goto nomem; - dma_pbuf[i] = virt_to_phys(dma_buf[i]); + if (!dma_buf[i]) { + printk(KERN_ERR "%s: can't allocate required buffers\n", + name); + goto mem_failed; + } + dma_pbuf[i] = virt_to_phys((void *)dma_buf[i]); } - if (sound_alloc_dma(hw_config->dma, "VIDCsound")) - { - printk(KERN_ERR "VIDCsound: can't allocate virtual DMA channel\n"); - return; + if (sound_alloc_dma(hw_config->dma, hw_config->name)) { + printk(KERN_ERR "%s: DMA %d is in use\n", name, hw_config->dma); + goto dma_failed; } - if (request_irq(hw_config->irq, vidc_sound_dma_irq, 0, "VIDCsound", &dma_start)) - { - printk(KERN_ERR "VIDCsound: can't allocate DMA interrupt\n"); - return; + + if (request_irq(hw_config->irq, vidc_sound_dma_irq, 0, + hw_config->name, &dma_start)) { + printk(KERN_ERR "%s: IRQ %d is in use\n", name, hw_config->irq); + goto irq_failed; } + old_mksound = kd_mksound; + kd_mksound = vidc_mksound; + vidc_adev = adev; + vidc_mixer_set(SOUND_MIXER_VOLUME, (85 | 85 << 8)); -// vidc_synth_init(hw_config); - vidc_audio_init(hw_config); - vidc_mixer_init(hw_config); +#if defined(CONFIG_SOUND_SOFTOSS) || defined(CONFIG_SOUND_SOFTOSS_MODULE) + softoss_dev = adev; +#endif return; -nomem: +irq_failed: + sound_free_dma(hw_config->dma); +dma_failed: +mem_failed: for (i = 0; i < 2; i++) free_page(dma_buf[i]); - printk(KERN_ERR "VIDCsound: can't allocate required buffers\n"); + sound_unload_mixerdev(audio_devs[adev]->mixer_dev); +mixer_failed: + sound_unload_audiodev(adev); +audio_failed: + return; } int probe_vidc(struct address_info *hw_config) { - hw_config->irq = IRQ_DMAS0; - hw_config->dma = DMA_VIRTUAL_SOUND; - hw_config->dma2 = -1; - hw_config->card_subtype = 16; + hw_config->irq = IRQ_DMAS0; + hw_config->dma = DMA_VIRTUAL_SOUND; + hw_config->dma2 = -1; + hw_config->card_subtype = 16; + hw_config->name = "VIDC20"; return 1; } void unload_vidc(struct address_info *hw_config) { - int i; + int i, adev = vidc_adev; + + vidc_adev = -1; - free_irq(hw_config->irq, NULL); + if (old_mksound) + kd_mksound = old_mksound; + + free_irq(hw_config->irq, &dma_start); sound_free_dma(hw_config->dma); - for (i = 0; i < 2; i++) - free_page(dma_buf[i]); + if (adev >= 0) { + sound_unload_mixerdev(audio_devs[adev]->mixer_dev); + sound_unload_audiodev(adev); + for (i = 0; i < 2; i++) + free_page(dma_buf[i]); + } } #ifdef MODULE static struct address_info config; +/* + * Note! Module use count is handled by SOUNDLOCK/SOUND_LOCK_END + */ int init_module(void) { if (probe_vidc(&config) == 0) return -ENODEV; - printk("VIDC 16-bit serial sound\n"); + SOUND_LOCK; attach_vidc(&config); + return 0; } diff --git a/drivers/sound/vidc.h b/drivers/sound/vidc.h index a79bdc85d..0b56e8b7a 100644 --- a/drivers/sound/vidc.h +++ b/drivers/sound/vidc.h @@ -55,18 +55,9 @@ extern void (*dma_interrupt) (void); extern unsigned long dma_start, dma_count, dma_bufsize; extern unsigned long dma_buf[2], dma_pbuf[2]; -/* vidc_audio.c */ - -extern void vidc_audio_init(struct address_info *hw_config); -extern int vidc_audio_get_volume(void); -extern int vidc_audio_set_volume(int vol); - -/* vidc_mixer.c */ - -extern void vidc_mixer_init(struct address_info *hw_config); - /* vidc_synth.c */ extern void vidc_synth_init(struct address_info *hw_config); +extern void vidc_synth_exit(struct address_info *hw_config); extern int vidc_synth_get_volume(void); extern int vidc_synth_set_volume(int vol); diff --git a/drivers/sound/vidc_audio.c b/drivers/sound/vidc_audio.c deleted file mode 100644 index 3a1f162fb..000000000 --- a/drivers/sound/vidc_audio.c +++ /dev/null @@ -1,314 +0,0 @@ -/* - * drivers/sound/vidc_audio.c - * - * Audio routines for the VIDC - * - * Copyright (C) 1997 Russell King - */ - -#include -#include -#include -#include - -#include "sound_config.h" -#include "vidc.h" - -/* - * VIDC sound - * - * When using SERIAL SOUND mode (external DAC), the number of physical - * channels is fixed at 2. Therefore, the sample rate = vidc sample rate. - */ - -static int vidc_adev; - -static int vidc_audio_volume; -static int vidc_audio_rate; -static char vidc_audio_format; -static char vidc_audio_channels; - -extern void vidc_update_filler(int bits, int channels); - -int vidc_audio_get_volume(void) -{ - return vidc_audio_volume; -} - -int vidc_audio_set_volume(int newvol) -{ - vidc_audio_volume = newvol; - return vidc_audio_volume; -} - -static int vidc_audio_set_bits(int fmt) -{ - switch (fmt) - { - case AFMT_QUERY: - break; - case AFMT_U8: - case AFMT_S8: - case AFMT_S16_LE: - vidc_audio_format = fmt; - vidc_update_filler(vidc_audio_format, vidc_audio_channels); - break; - default: - vidc_audio_format = AFMT_S16_LE; - vidc_update_filler(vidc_audio_format, vidc_audio_channels); - break; - } - return vidc_audio_format; -} - -static int vidc_audio_set_rate(int rate) -{ - if (rate) - { - int newsize, new2size; - - vidc_audio_rate = ((500000 / rate) + 1) >> 1; - if (vidc_audio_rate < 3) - vidc_audio_rate = 3; - if (vidc_audio_rate > 255) - vidc_audio_rate = 255; - outl((vidc_audio_rate - 2) | 0xb0000000, IO_VIDC_BASE); - outl(0xb1000003, IO_VIDC_BASE); - newsize = (10000 / vidc_audio_rate) & ~3; - if (newsize < 208) - newsize = 208; - if (newsize > 4096) - newsize = 4096; - for (new2size = 128; new2size < newsize; new2size <<= 1); - if (new2size - newsize > newsize - (new2size >> 1)) - new2size >>= 1; - dma_bufsize = new2size; - } - return 250000 / vidc_audio_rate; -} - -static int vidc_audio_set_channels(int channels) -{ - switch (channels) - { - case 0: - break; - case 1: - case 2: - vidc_audio_channels = channels; - vidc_update_filler(vidc_audio_format, vidc_audio_channels); - break; - default: - vidc_audio_channels = 2; - vidc_update_filler(vidc_audio_format, vidc_audio_channels); - break; - } - return vidc_audio_channels; -} - -/* - * Open the device - * - * dev - device - * mode - mode to open device (logical OR of OPEN_READ and OPEN_WRITE) - * - * Called when opening the DMAbuf (dmabuf.c:259) - */ -static int vidc_audio_open(int dev, int mode) -{ - if (vidc_busy) - return -EBUSY; - - if ((mode & OPEN_READ) && (!mode & OPEN_WRITE)) - { - /* This audio device doesn't have recording capability */ - return -EIO; - } - vidc_busy = 1; - return 0; -} - -/* - * Close the device - * - * dev - device - * - * Called when closing the DMAbuf (dmabuf.c:477) - * after halt_xfer - */ -static void vidc_audio_close(int dev) -{ - vidc_busy = 0; -} - -static int vidc_audio_ioctl(int dev, unsigned int cmd, caddr_t arg) -{ - int ret; - - switch (cmd) - { - case SOUND_PCM_WRITE_RATE: - if (get_user(ret, (int *) arg)) - return -EFAULT; - ret = vidc_audio_set_rate(ret); - break; - - case SOUND_PCM_READ_RATE: - ret = vidc_audio_set_rate(0); - break; - - case SNDCTL_DSP_STEREO: - if (get_user(ret, (int *) arg)) - return -EFAULT; - ret = vidc_audio_set_channels(ret + 1) - 1; - break; - - case SOUND_PCM_WRITE_CHANNELS: - if (get_user(ret, (int *) arg)) - return -EFAULT; - ret = vidc_audio_set_channels(ret); - break; - - case SOUND_PCM_READ_CHANNELS: - ret = vidc_audio_set_channels(0); - break; - - case SNDCTL_DSP_SETFMT: - if (get_user(ret, (int *) arg)) - return -EFAULT; - ret = vidc_audio_set_bits(ret); - break; - - case SOUND_PCM_READ_BITS: - ret = vidc_audio_set_bits(0); - break; - - case SOUND_PCM_WRITE_FILTER: - case SOUND_PCM_READ_FILTER: - return -EINVAL; - - default: - return -EINVAL; - } - return put_user(ret, (int *) arg); -} - -/* - * Output a block via DMA to sound device - * - * dev - device number - * buf - physical address of buffer - * total_count - total byte count in buffer - * intrflag - set if this has been called from an interrupt (via DMAbuf_outputintr) - * restart_dma - set if DMA needs to be re-initialised - * - * Called when: - * 1. Starting output (dmabuf.c:1327) - * 2. (dmabuf.c:1504) - * 3. A new buffer needs to be sent to the device (dmabuf.c:1579) - */ -static void vidc_audio_output_block(int dev, unsigned long buf, int total_count, - int intrflag) -{ - struct audio_operations *adev = audio_devs[dev]; - struct dma_buffparms *dmap = adev->dmap_out; - - dma_start = buf - (unsigned long)dmap->raw_buf_phys + (unsigned long)dmap->raw_buf; - dma_count = total_count; - - if (!(adev->flags & DMA_ACTIVE)) - { - unsigned long flags; - save_flags_cli(flags); - - vidc_sound_dma_irq(0, NULL, NULL); - outb(DMA_CR_E | 0x10, IOMD_SD0CR); - - restore_flags(flags); - } -} - -static void vidc_audio_start_input(int dev, unsigned long buf, int count, - int intrflag) -{ -} - -static int vidc_audio_prepare_for_input(int dev, int bsize, int bcount) -{ - return -EINVAL; -} - -static void vidc_audio_dma_interrupt(void) -{ - DMAbuf_outputintr(vidc_adev, 1); -} - -/* - * Prepare for outputting samples to `dev' - * - * Each buffer that will be passed will be `bsize' bytes long, - * with a total of `bcount' buffers. - * - * Called when: - * 1. A trigger enables audio output (dmabuf.c:978) - * 2. We get a write buffer without dma_mode setup (dmabuf.c:1152) - * 3. We restart a transfer (dmabuf.c:1324) - */ -static int vidc_audio_prepare_for_output(int dev, int bsize, int bcount) -{ - audio_devs[dev]->dmap_out->flags |= DMA_NODMA; - dma_interrupt = vidc_audio_dma_interrupt; - return 0; -} - -/* - * Stop our current operation. - */ -static void vidc_audio_reset(int dev) -{ - /* stop interrupts. Our real interrupt routine - * will close DMA down for us - */ - dma_interrupt = NULL; -} - -static int vidc_audio_local_qlen(int dev) -{ - return /*dma_count !=*/ 0; -} - -static struct audio_driver vidc_audio_driver = -{ - vidc_audio_open, /* open */ - vidc_audio_close, /* close */ - vidc_audio_output_block, /* output_block */ - vidc_audio_start_input, /* start_input */ - vidc_audio_ioctl, /* ioctl */ - vidc_audio_prepare_for_input, /* prepare_for_input */ - vidc_audio_prepare_for_output, /* prepare_for_output */ - vidc_audio_reset, /* reset */ - vidc_audio_local_qlen, /*+local_qlen */ - NULL, /*+copy_from_user */ - NULL, /*+halt_input */ - NULL, /* halt_output */ - NULL, /*+trigger */ - NULL, /*+set_speed */ - NULL, /*+set_bits */ - NULL, /*+set_channels */ -}; - -void vidc_audio_init(struct address_info *hw_config) -{ - vidc_audio_volume = 100 | (100 << 8); - - if ((vidc_adev = sound_install_audiodrv(AUDIO_DRIVER_VERSION, - "VIDCsound", &vidc_audio_driver, - sizeof(struct audio_driver), - DMA_AUTOMODE, AFMT_U8 | AFMT_S8 | AFMT_S16_LE, - NULL, hw_config->dma, hw_config->dma2)) >= 0) - { - audio_devs[vidc_adev]->min_fragment = 10; /* 1024 bytes => 64 buffers */ - audio_devs[vidc_adev]->mixer_dev = num_mixers; - } - else printk(KERN_ERR "VIDCsound: Too many PCM devices available\n"); -} diff --git a/drivers/sound/vidc_fill.S b/drivers/sound/vidc_fill.S index 53fc2ed01..c198b72c6 100644 --- a/drivers/sound/vidc_fill.S +++ b/drivers/sound/vidc_fill.S @@ -191,24 +191,24 @@ ENTRY(vidc_sound_dma_irq) .data .globl SYMBOL_NAME(dma_interrupt) SYMBOL_NAME(dma_interrupt): - .long 0 + .long 0 @ r3 .globl SYMBOL_NAME(dma_pbuf) SYMBOL_NAME(dma_pbuf): - .long 0 - .long 0 + .long 0 @ r4 + .long 0 @ r5 .globl SYMBOL_NAME(dma_start) SYMBOL_NAME(dma_start): - .long 0 + .long 0 @ r0 .globl SYMBOL_NAME(dma_count) SYMBOL_NAME(dma_count): - .long 0 + .long 0 @ r1 .globl SYMBOL_NAME(dma_buf) SYMBOL_NAME(dma_buf): - .long 0 - .long 0 + .long 0 @ r2 + .long 0 @ r3 .globl SYMBOL_NAME(vidc_filler) SYMBOL_NAME(vidc_filler): - .long SYMBOL_NAME(vidc_fill_noaudio) + .long SYMBOL_NAME(vidc_fill_noaudio) @ r4 .globl SYMBOL_NAME(dma_bufsize) SYMBOL_NAME(dma_bufsize): - .long 0x1000 + .long 0x1000 @ r5 diff --git a/drivers/sound/vidc_mixer.c b/drivers/sound/vidc_mixer.c deleted file mode 100644 index 01be4925c..000000000 --- a/drivers/sound/vidc_mixer.c +++ /dev/null @@ -1,151 +0,0 @@ -/* - * drivers/sound/vidc_mixer.c - * - * Mixer routines for VIDC - * - * Copyright (C) 1997 Russell King - */ - -#include "sound_config.h" -#include "vidc.h" - -int vidc_volume; - -static int vidc_get_volume(void) -{ - return vidc_volume; -} - -static int vidc_set_volume(int newvol) -{ - vidc_volume = newvol; -/* printk ("vidc_set_volume: %X\n", newvol); */ - return newvol; -} - -static int vidc_default_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg) -{ - int ret; - - switch (cmd) - { - case SOUND_MIXER_READ_VOLUME: - ret = vidc_get_volume(); - break; - - case SOUND_MIXER_WRITE_VOLUME: - if (get_user(ret, (int *) arg)) - return -EINVAL; - ret = vidc_set_volume(ret); - break; - - case SOUND_MIXER_READ_BASS: - case SOUND_MIXER_WRITE_BASS: - case SOUND_MIXER_READ_TREBLE: - case SOUND_MIXER_WRITE_TREBLE: - ret = 50; - break; - - case SOUND_MIXER_READ_SYNTH: -// ret = vidc_synth_get_volume(); - ret = 0; - break; - - case SOUND_MIXER_WRITE_SYNTH: - if (get_user(ret, (int *) arg)) - return -EINVAL; -// ret = vidc_synth_set_volume(ret); - ret = 0; - break; - - case SOUND_MIXER_READ_PCM: - ret = vidc_audio_get_volume(); - break; - - case SOUND_MIXER_WRITE_PCM: - if (get_user(ret, (int *) arg)) - return -EINVAL; - ret = vidc_audio_set_volume(ret); - break; - - case SOUND_MIXER_READ_SPEAKER: - ret = 100; - break; - - case SOUND_MIXER_WRITE_SPEAKER: - ret = 100; - break; - - case SOUND_MIXER_READ_LINE: - case SOUND_MIXER_WRITE_LINE: - case SOUND_MIXER_READ_MIC: - case SOUND_MIXER_WRITE_MIC: - ret = 0; - break; - - case SOUND_MIXER_READ_CD: - case SOUND_MIXER_WRITE_CD: - ret = 100 | (100 << 8); - break; - - case SOUND_MIXER_READ_IMIX: - case SOUND_MIXER_WRITE_IMIX: - case SOUND_MIXER_READ_ALTPCM: - case SOUND_MIXER_WRITE_ALTPCM: - case SOUND_MIXER_READ_LINE1: - case SOUND_MIXER_WRITE_LINE1: - case SOUND_MIXER_READ_LINE2: - case SOUND_MIXER_WRITE_LINE2: - case SOUND_MIXER_READ_LINE3: - case SOUND_MIXER_WRITE_LINE3: - ret = 0; - break; - - case SOUND_MIXER_READ_RECSRC: - ret = 0; - break; - - case SOUND_MIXER_WRITE_RECSRC: - return -EINVAL; - break; - - case SOUND_MIXER_READ_DEVMASK: - ret = SOUND_MASK_VOLUME | SOUND_MASK_PCM | SOUND_MASK_SYNTH; - break; - - case SOUND_MIXER_READ_RECMASK: - ret = 0; - break; - - case SOUND_MIXER_READ_STEREODEVS: - ret = SOUND_MASK_VOLUME | SOUND_MASK_PCM | SOUND_MASK_SYNTH; - break; - - case SOUND_MIXER_READ_CAPS: - ret = 0; - break; - - case SOUND_MIXER_READ_MUTE: - return -EINVAL; - break; - - default: - return -EINVAL; - break; - } - return put_user(ret, (int *) arg); -} - -static struct mixer_operations vidc_mixer_operations = { - "VIDC", - "VIDCsound", - vidc_default_mixer_ioctl /* ioctl */ -}; - -void vidc_mixer_init(struct address_info *hw_config) -{ - int vidc_mixer = sound_alloc_mixerdev(); - vidc_volume = 100 | (100 << 8); - if (num_mixers < MAX_MIXER_DEV) - mixer_devs[vidc_mixer] = &vidc_mixer_operations; -} diff --git a/drivers/sound/vidc_synth.c b/drivers/sound/vidc_synth.c deleted file mode 100644 index ba94f0bc6..000000000 --- a/drivers/sound/vidc_synth.c +++ /dev/null @@ -1,91 +0,0 @@ -/* - * drivers/sound/vidc_synth.c - * - * Synthesizer routines for the VIDC - * - * Copyright (C) 1997 Russell King - */ - -#include "sound_config.h" -#include "vidc.h" -#if 0 -static struct synth_info vidc_info = -{ - "VIDCsound", /* name */ - 0, /* device */ - SYNTH_TYPE_SAMPLE, /* synth_type */ - 0, /* synth_subtype */ - 0, /* perc_mode */ - 16, /* nr_voices */ - 0, /* nr_drums */ - 0, /* instr_bank_size */ - 0, /* capabilities */ -}; - -int vidc_sdev; -int vidc_synth_volume; - -static int vidc_synth_open(int dev, int mode) -{ - if (vidc_busy) - return -EBUSY; - - vidc_busy = 1; - return 0; -} - -static void vidc_synth_close(int dev) -{ - vidc_busy = 0; -} - - -static struct synth_operations vidc_synth_operations = -{ - "VIDC Synth", /* name */ - &vidc_info, /* info */ - 0, /* midi_dev */ - SYNTH_TYPE_SAMPLE, /* synth_type */ - /*SAMPLE_TYPE_XXX */ 0, /* synth_subtype */ - vidc_synth_open, /* open */ - vidc_synth_close, /* close */ - NULL, /* ioctl */ - NULL, /* kill_note */ - NULL, /* start_note */ - NULL, /* set_instr */ - NULL, /* reset */ - NULL, /* hw_control */ - NULL, /* load_patch */ - NULL, /* aftertouch */ - NULL, /* controller */ - NULL, /* panning */ - NULL, /* volume_method */ - NULL, /* bender */ - NULL, /* alloc_voice */ - NULL, /* setup_voice */ - NULL, /* send_sysex */ - /* alloc */ - /* chn_info[16] */ - /* syex_buf */ - /* syex_ptr */ -}; - -int vidc_synth_get_volume(void) -{ - return vidc_synth_volume; -} - -int vidc_synth_set_volume(int newvol) -{ - return vidc_synth_volume = newvol; -} - -void vidc_synth_init(struct address_info *hw_config) -{ - vidc_synth_volume = 100 | (100 << 8); - if ((vidc_sdev=sound_alloc_synthdev())!=-1) - synth_devs[vidc_sdev] = &vidc_synth_operations; - else - printk(KERN_ERR "VIDCsound: Too many synthesizers\n"); -} -#endif diff --git a/drivers/sound/waveartist.c b/drivers/sound/waveartist.c index 143512ea4..905b9cff6 100644 --- a/drivers/sound/waveartist.c +++ b/drivers/sound/waveartist.c @@ -838,7 +838,6 @@ waveartist_intr(int irq, void *dev_id, struct pt_regs *regs) else printk(KERN_WARNING "waveartist: unexpected interrupt\n"); -#ifdef CONFIG_AUDIO if (irqstatus & 0x01) { int temp = 1; @@ -855,7 +854,6 @@ waveartist_intr(int irq, void *dev_id, struct pt_regs *regs) if (temp) //default: printk(KERN_WARNING "waveartist: Unknown interrupt\n"); } -#endif if (irqstatus & 0x2) // We do not use SB mode natively... printk(KERN_WARNING "waveartist: Unexpected SB interrupt...\n"); diff --git a/drivers/sound/wavfront.c b/drivers/sound/wavfront.c index d7df1790b..2967fdf18 100644 --- a/drivers/sound/wavfront.c +++ b/drivers/sound/wavfront.c @@ -86,7 +86,7 @@ */ #if defined(__alpha__) -#ifdef __SMP__ +#ifdef CONFIG_SMP #define LOOPS_PER_SEC cpu_data[smp_processor_id()].loops_per_sec #else #define LOOPS_PER_SEC loops_per_sec @@ -1686,13 +1686,11 @@ wavefront_load_gus_patch (int devno, int format, const char *addr, master otherwise. */ -#ifdef CONFIG_MIDI if (dev.mididev > 0) { midi_synth_controller (dev.mididev, guspatch.instr_no, 10, ((guspatch.panning << 4) > 127) ? 127 : (guspatch.panning << 4)); } -#endif CONFIG_MIDI return(0); } diff --git a/drivers/usb/acm.c b/drivers/usb/acm.c index cc03acb09..d93391340 100644 --- a/drivers/usb/acm.c +++ b/drivers/usb/acm.c @@ -643,16 +643,10 @@ static struct tty_driver acm_tty_driver = { }; /* - * Init / cleanup. + * Init / exit. */ -static void __exit usb_acm_cleanup(void) -{ - usb_deregister(&acm_driver); - tty_unregister_driver(&acm_tty_driver); -} - -static int __init usb_acm_init(void) +static int __init acm_init(void) { acm_tty_driver.init_termios = tty_std_termios; acm_tty_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; @@ -668,5 +662,11 @@ static int __init usb_acm_init(void) return 0; } -module_init(usb_acm_init); -module_exit(usb_acm_cleanup); +static void __exit acm_exit(void) +{ + usb_deregister(&acm_driver); + tty_unregister_driver(&acm_tty_driver); +} + +module_init(acm_init); +module_exit(acm_exit); diff --git a/drivers/usb/devio.c b/drivers/usb/devio.c index 82a55ec8e..c4ae62d4c 100644 --- a/drivers/usb/devio.c +++ b/drivers/usb/devio.c @@ -1002,7 +1002,7 @@ static unsigned int usbdev_poll(struct file *file, struct poll_table_struct *wai return mask; } -static struct file_operations usbdevfs_device_file_operations = { +struct file_operations usbdevfs_device_file_operations = { llseek: usbdev_lseek, read: usbdev_read, poll: usbdev_poll, @@ -1010,7 +1010,3 @@ static struct file_operations usbdevfs_device_file_operations = { open: usbdev_open, release: usbdev_release, }; - -struct inode_operations usbdevfs_device_inode_operations = { - &usbdevfs_device_file_operations, /* file-ops */ -}; diff --git a/drivers/usb/evdev.c b/drivers/usb/evdev.c index 44d7cfec4..9cca9fdf6 100644 --- a/drivers/usb/evdev.c +++ b/drivers/usb/evdev.c @@ -256,20 +256,16 @@ static struct input_handler evdev_handler = { disconnect: evdev_disconnect, }; -#ifdef MODULE -int init_module(void) -#else -int __init evdev_init(void) -#endif +static int __init evdev_init(void) { input_register_handler(&evdev_handler); - return 0; } -#ifdef MODULE -void cleanup_module(void) +static void __exit evdev_exit(void) { input_unregister_handler(&evdev_handler); } -#endif + +module_init(evdev_init); +module_exit(evdev_exit); diff --git a/drivers/usb/ftdi_sio.h b/drivers/usb/ftdi_sio.h new file mode 100644 index 000000000..36fa7bb3e --- /dev/null +++ b/drivers/usb/ftdi_sio.h @@ -0,0 +1,380 @@ +/* Bill Ryder - bryder@sgi.com - wrote the FTDI_SIO implementation */ +/* The device is based on the FTDI FT8U100AX chip, DB25 on one side, USB on the other */ +/* Thanx to FTDI for so kindly providing details of the protocol required */ +/* http://www.ftdi.co.uk */ + +/* The implementation of the device I have is called a USC-1000 */ +/* which is available from http://www.dse.co.nz - cat no XH4214 */ +/* It looks similar to this: http://www.dansdata.com/usbser.htm but I can't be sure */ +/* There are other USC-1000s which don't look like my device though so beware */ + +/* Definitions for the FTDI USB Single Port Serial Converter */ +/* known as FTDI_SIO (Serial Input/Output application of the chipset) */ + +#define FTDI_VID 0x0403 /* Vendor Id */ +#define FTDI_SIO_PID 0x8372 /* Product Id */ + +/* Vendor Request Interface */ +#define FTDI_SIO_RESET 0 /* Reset the port */ +#define FTDI_SIO_MODEM_CTRL 1 /* Set the modem control register */ +#define FTDI_SIO_SET_FLOW_CTRL 2 /* Set flow control register */ +#define FTDI_SIO_SET_BAUD_RATE 3 /* Set baud rate */ +#define FTDI_SIO_SET_DATA 4 /* Set the data characteristics of the port */ +#define FTDI_SIO_GET_MODEM_STATUS 5 /* Retrieve current value of modern status register */ +#define FTDI_SIO_SET_EVENT_CHAR 6 /* Set the event character */ +#define FTDI_SIO_SET_ERROR_CHAR 7 /* Set the error character */ + +/* Port Identifier Table */ +#define PIT_DEFAULT 0 /* SIOA */ +#define PIT_SIOA 1 /* SIOA */ +/* The device this is tested with one has one port */ +#define PIT_SIOB 2 /* SIOB */ +#define PIT_PARALLEL 3 /* Parallel */ + +/* FTDI_SIO_RESET */ +#define FTDI_SIO_RESET_REQUEST FTDI_SIO_RESET +#define FTDI_SIO_RESET_REQUEST_TYPE 0x40 +#define FTDI_SIO_RESET_SIO 0 +#define FTDI_SIO_RESET_PURGE_RX 1 +#define FTDI_SIO_RESET_PURGE_TX 2 +/* + BmRequestType: 0100 0000B + bRequest: FTDI_SIO_RESET + wValue: Control Value + 0 = Reset SIO + 1 = Purge RX buffer + 2 = Purge TX buffer + wIndex: Port + wLength: 0 + Data: None + + */ + +/* FTDI_SIO_SET_BAUDRATE */ +#define FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE 0x40 +#define FTDI_SIO_SET_BAUDRATE_REQUEST 3 + +/* + BmRequestType: 0100 0000B + bRequest: FTDI_SIO_SET_BAUDRATE + wValue: BaudRate value - see below + wIndex: Port + wLength: 0 + Data: None +*/ + +typedef enum { + ftdi_sio_b300 = 0, + ftdi_sio_b600 = 1, + ftdi_sio_b1200 = 2, + ftdi_sio_b2400 = 3, + ftdi_sio_b4800 = 4, + ftdi_sio_b9600 = 5, + ftdi_sio_b19200 = 6, + ftdi_sio_b38400 = 7, + ftdi_sio_b57600 = 8, + ftdi_sio_b115200 = 9 +} FTDI_SIO_baudrate_t ; + +#define FTDI_SIO_SET_DATA_REQUEST FTDI_SIO_SET_DATA +#define FTDI_SIO_SET_DATA_REQUEST_TYPE 0x40 +#define FTDI_SIO_SET_DATA_PARITY_NONE (0x0 << 8 ) +#define FTDI_SIO_SET_DATA_PARITY_ODD (0x1 << 8 ) +#define FTDI_SIO_SET_DATA_PARITY_EVEN (0x2 << 8 ) +#define FTDI_SIO_SET_DATA_PARITY_MARK (0x3 << 8 ) +#define FTDI_SIO_SET_DATA_PARITY_SPACE (0x4 << 8 ) +#define FTDI_SIO_SET_DATA_STOP_BITS_1 (0x0 << 11 ) +#define FTDI_SIO_SET_DATA_STOP_BITS_15 (0x1 << 11 ) +#define FTDI_SIO_SET_DATA_STOP_BITS_2 (0x2 << 11 ) + +/* FTDI_SIO_SET_DATA */ + +/* BmRequestType: 0100 0000B */ +/* bRequest: FTDI_SIO_SET_DATA */ +/* wValue: Data characteristics (see below) */ +/* wIndex: Port */ +/* wLength: 0 */ +/* Data: None */ +/* + Data characteristics + +B0..7 Number of data bits +B8..10 Parity + 0 = None + 1 = Odd + 2 = Even + 3 = Mark + 4 = Space + B11..13 Stop Bits + 0 = 1 + 1 = 1.5 + 2 = 2 + B14..15 Reserved +*/ + + + +/* FTDI_SIO_MODEM_CTRL */ +#define FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE 0x40 +#define FTDI_SIO_SET_MODEM_CTRL_REQUEST FTDI_SIO_MODEM_CTRL + +/* + BmRequestType: 0100 0000B + bRequest: FTDI_SIO_MODEM_CTRL + wValue: ControlValue (see below) + wIndex: Port + wLength: 0 + Data: None + + NOTE: If the device is in RTS/CTS flow control, the RTS set by this + command will be IGNORED without an error being returned +*/ + +#define FTDI_SIO_SET_DTR_MASK 0x1 +#define FTDI_SIO_SET_DTR_HIGH ( 1 | ( FTDI_SIO_SET_DTR_MASK << 8)) +#define FTDI_SIO_SET_DTR_LOW ( 0 | ( FTDI_SIO_SET_DTR_MASK << 8)) +#define FTDI_SIO_SET_RTS_MASK 0x2 +#define FTDI_SIO_SET_RTS_HIGH ( 2 | ( FTDI_SIO_SET_RTS_MASK << 8 )) +#define FTDI_SIO_SET_RTS_LOW ( 0 | ( FTDI_SIO_SET_RTS_MASK << 8 )) + +/* ControlValue + B0 DTR state + 0 = reset + 1 = set + B1 RTS state + 0 = reset + 1 = set + B2..7 Reserved + B8 DTR state enable + 0 = ignore + 1 = use DTR state + B9 RTS state enable + 0 = ignore + 1 = use RTS state + B10..15 Reserved +*/ + +/* FTDI_SIO_SET_FLOW_CTRL */ +#define FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE 0x40 +#define FTDI_SIO_SET_FLOW_CTRL_REQUEST FTDI_SIO_SET_FLOW_CTRL +#define FTDI_SIO_DISABLE_FLOW_CTRL 0x0 +#define FTDI_SIO_RTS_CTS_HS 0x1 +#define FTDI_SIO_DTR_DSR_HS 0x2 +#define FTDI_SIO_XON_XOFF_HS 0x4 +/* + BmRequestType: 0100 0000b + bRequest: FTDI_SIO_SET_FLOW_CTRL + wValue: Xoff/Xon + wIndex: Protocol/Port - hIndex is protocl / lIndex is port + wLength: 0 + Data: None + +hIndex - protocol has + B0 Output handshaking using RTS/CTS + 0 = disabled + 1 = enabled + B1 Output handshaking using DTR/DSR + 0 = disabled + 1 = enabled + B2 Xon/Xoff handshaking + 0 = disabled + 1 = enabled + +A value of zero in the hIndex field selects no handshaking + +If Xon/Xoff handshaking is specified, the hValue field contains the Xoff character +and the lValue field contains the Xon character. + +*/ + +/* FTDI_SIO_SET_EVENT_CHAR */ +/* Set the special event character for the specified communications port */ +/* If the device sees this character it will immediately return the */ +/* data read so far - rather than wait 40ms or until 62 bytes is read */ +#define FTDI_SIO_SET_EVENT_CHAR_REQUEST FTDI_SIO_SET_EVENT_CHAR +#define FTDI_SIO_SET_EVENT_CHAR_REQUEST_TYPE 0x40 + + +/* + BmRequestType: 0100 0000b + bRequest: FTDI_SIO_SET_EVENT_CHAR + wValue: EventChar + wIndex: Port + wLength: 0 + Data: None + +wValue: + B0..7 Event Character + B8 Event Character Processing + 0 = disabled + 1 = enabled + B9..15 Reserved + +*/ + +/* FTDI_SIO_SET_ERROR_CHAR */ +/* Set the parity error replacement character for the specified communications port */ + +/* + BmRequestType: 0100 0000b + bRequest: FTDI_SIO_SET_EVENT_CHAR + wValue: Error Char + wIndex: Port + wLength: 0 + Data: None + +Error Char + B0..7 Error Character + B8 Error Character Processing + 0 = disabled + 1 = enabled + B9..15 Reserved + +*/ + +/* FTDI_SIO_GET_MODEM_STATUS */ +/* Retreive the current value of the modem status register */ + +#define FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE 0xc0 +#define FTDI_SIO_GET_MODEM_STATUS_REQUEST FTDI_SIO_GET_MODEM_STATUS +#define FTDI_SIO_CTS_MASK 0x10 +#define FTDI_SIO_DSR_MASK 0x20 +#define FTDI_SIO_RI_MASK 0x40 +#define FTDI_SIO_RLSD_MASK 0x80 +/* + BmRequestType: 1100 0000b + bRequest: FTDI_SIO_GET_MODEM_STATUS + wValue: zero + wIndex: Port + wLength: 1 + Data: Status + +One byte of data is returned +B0..3 0 +B4 CTS + 0 = inactive + 1 = active +B5 DSR + 0 = inactive + 1 = active +B6 Ring Indicator (RI) + 0 = inactive + 1 = active +B7 Receive Line Signal Detect (RLSD) + 0 = inactive + 1 = active +*/ + + + +/* Descriptors returned by the device + + Device Descriptor + +Offset Field Size Value Description +0 bLength 1 0x12 Size of descriptor in bytes +1 bDescriptorType 1 0x01 DEVICE Descriptor Type +2 bcdUSB 2 0x0110 USB Spec Release Number +4 bDeviceClass 1 0x00 Class Code +5 bDeviceSubClass 1 0x00 SubClass Code +6 bDeviceProtocol 1 0x00 Protocol Code +7 bMaxPacketSize0 1 0x08 Maximum packet size for endpoint 0 +8 idVendor 2 0x0403 Vendor ID +10 idProduct 2 0x8372 Product ID (FTDI_SIO_PID) +12 bcdDevice 2 0x0001 Device release number +14 iManufacturer 1 0x01 Index of man. string desc +15 iProduct 1 0x02 Index of prod string desc +16 iSerialNumber 1 0x02 Index of serial nmr string desc +17 bNumConfigurations 1 0x01 Number of possible configurations + +Configuration Descriptor + +Offset Field Size Value +0 bLength 1 0x09 Size of descriptor in bytes +1 bDescriptorType 1 0x02 CONFIGURATION Descriptor Type +2 wTotalLength 2 0x0020 Total length of data +4 bNumInterfaces 1 0x01 Number of interfaces supported +5 bConfigurationValue 1 0x01 Argument for SetCOnfiguration() req +6 iConfiguration 1 0x02 Index of config string descriptor +7 bmAttributes 1 0x20 Config characteristics Remote Wakeup +8 MaxPower 1 0x1E Max power consumption + +Interface Descriptor + +Offset Field Size Value +0 bLength 1 0x09 Size of descriptor in bytes +1 bDescriptorType 1 0x04 INTERFACE Descriptor Type +2 bInterfaceNumber 1 0x00 Number of interface +3 bAlternateSetting 1 0x00 Value used to select alternate +4 bNumEndpoints 1 0x02 Number of endpoints +5 bInterfaceClass 1 0xFF Class Code +6 bInterfaceSubClass 1 0xFF Subclass Code +7 bInterfaceProtocol 1 0xFF Protocol Code +8 iInterface 1 0x02 Index of interface string description + +IN Endpoint Descriptor + +Offset Field Size Value +0 bLength 1 0x07 Size of descriptor in bytes +1 bDescriptorType 1 0x05 ENDPOINT descriptor type +2 bEndpointAddress 1 0x82 Address of endpoint +3 bmAttributes 1 0x02 Endpoint attributes - Bulk +4 bNumEndpoints 2 0x0040 maximum packet size +5 bInterval 1 0x00 Interval for polling endpoint + +OUT Endpoint Descriptor + +Offset Field Size Value +0 bLength 1 0x07 Size of descriptor in bytes +1 bDescriptorType 1 0x05 ENDPOINT descriptor type +2 bEndpointAddress 1 0x02 Address of endpoint +3 bmAttributes 1 0x02 Endpoint attributes - Bulk +4 bNumEndpoints 2 0x0040 maximum packet size +5 bInterval 1 0x00 Interval for polling endpoint + +DATA FORMAT + +IN Endpoint + +The device reserves the first two bytes of data on this endpoint to contain the current +values of the modem and line status registers. In the absence of data, the device +generates a message consisting of these two status bytes every 40 ms + +Byte 0: Modem Status + +Offset Description +B0 Reserved - must be 1 +B1 Reserved - must be 0 +B2 Reserved - must be 0 +B3 Reserved - must be 0 +B4 Clear to Send (CTS) +B5 Data Set Ready (DSR) +B6 Ring Indicator (RI) +B7 Receive Line Signal Detect (RLSD) + +Byte 1: Line Status + +Offset Description +B0 Data Ready (DR) +B1 Overrun Error (OE) +B2 Parity Error (PE) +B3 Framing Error (FE) +B4 Break Interrupt (BI) +B5 Transmitter Holding Register (THRE) +B6 Transmitter Empty (TEMT) +B7 Error in RCVR FIFO + +OUT Endpoint + +This device reserves the first bytes of data on this endpoint contain the length +and port identifier of the message. For the FTDI USB Serial converter the port +identifier is always 1. + +Byte 0: Line Status + +Offset Description +B0 Reserved - must be 1 +B1 Reserved - must be 0 +B2..7 Length of message - (not including Byte 0) + +*/ diff --git a/drivers/usb/graphire.c b/drivers/usb/graphire.c index 8921c7db8..3537c8607 100644 --- a/drivers/usb/graphire.c +++ b/drivers/usb/graphire.c @@ -37,6 +37,7 @@ #include #include #include +#include #include "usb.h" MODULE_AUTHOR("Vojtech Pavlik "); @@ -179,17 +180,16 @@ static struct usb_driver graphire_driver = { disconnect: graphire_disconnect, }; -#ifdef MODULE -void cleanup_module(void) +static int __init graphire_init(void) { - usb_deregister(&graphire_driver); + usb_register(&graphire_driver); + return 0; } -int init_module(void) -#else -int graphire_init(void) -#endif +static void __exit graphire_exit(void) { - usb_register(&graphire_driver); - return 0; + usb_deregister(&graphire_driver); } + +module_init(graphire_init); +module_exit(graphire_exit); diff --git a/drivers/usb/hid.c b/drivers/usb/hid.c index 85b44010c..778bb3532 100644 --- a/drivers/usb/hid.c +++ b/drivers/usb/hid.c @@ -40,6 +40,8 @@ #include #include +#include + #undef DEBUG #undef DEBUG_DATA @@ -573,14 +575,14 @@ static __u8 *fetch_item(__u8 *start, __u8 *end, struct hid_item *item) case 2: if ((end - start) >= 2) { - item->data.u16 = le16_to_cpu( *((__u16*)start)++); + item->data.u16 = le16_to_cpu( get_unaligned(((__u16*)start)++)); return start; } case 3: item->size++; if ((end - start) >= 4) { - item->data.u32 = le32_to_cpu( *((__u32*)start)++); + item->data.u32 = le32_to_cpu( get_unaligned(((__u32*)start)++)); return start; } } @@ -706,7 +708,7 @@ static __inline__ __u32 s32ton(__s32 value, unsigned n) static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n) { report += (offset >> 5) << 2; offset &= 31; - return (le64_to_cpu(*(__u64*)report) >> offset) & ((1 << n) - 1); + return (le64_to_cpu(get_unaligned((__u64*)report)) >> offset) & ((1 << n) - 1); } static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u32 value) @@ -1408,19 +1410,16 @@ static struct usb_driver hid_driver = { disconnect: hid_disconnect }; -#ifdef MODULE -void cleanup_module(void) +static int __init hid_init(void) { - usb_deregister(&hid_driver); + usb_register(&hid_driver); + return 0; } -int init_module(void) -#else -int hid_init(void) -#endif +static void __exit hid_exit(void) { - usb_register(&hid_driver); - return 0; + usb_deregister(&hid_driver); } -__initcall(hid_init); +module_init(hid_init); +module_exit(hid_exit); diff --git a/drivers/usb/inode.c b/drivers/usb/inode.c index 3c80bb8be..2306615f0 100644 --- a/drivers/usb/inode.c +++ b/drivers/usb/inode.c @@ -46,24 +46,17 @@ static LIST_HEAD(superlist); extern struct inode_operations usbdevfs_bus_inode_operations; - -static struct inode_operations devices_inode_operations = { - &usbdevfs_devices_fops -}; - -static struct inode_operations drivers_inode_operations = { - &usbdevfs_drivers_fops -}; +extern struct file_operations usbdevfs_bus_file_operations; struct special { const char *name; - struct inode_operations *iops; + struct file_operations *fops; struct list_head inodes; }; static struct special special[] = { - { "devices", &devices_inode_operations, }, - { "drivers", &drivers_inode_operations, } + { "devices", &usbdevfs_devices_fops, }, + { "drivers", &usbdevfs_drivers_fops, } }; #define NRSPECIAL (sizeof(special)/sizeof(special[0])) @@ -110,7 +103,7 @@ static void new_dev_inode(struct usb_device *dev, struct super_block *sb) inode->i_uid = sb->u.usbdevfs_sb.devuid; inode->i_gid = sb->u.usbdevfs_sb.devgid; inode->i_mode = sb->u.usbdevfs_sb.devmode | S_IFREG; - inode->i_op = &usbdevfs_device_inode_operations; + inode->i_fop = &usbdevfs_device_file_operations; inode->i_size = sizeof(struct usb_device_descriptor); inode->u.usbdev_i.p.dev = dev; list_add_tail(&inode->u.usbdev_i.slist, &sb->u.usbdevfs_sb.ilist); @@ -148,6 +141,7 @@ static void new_bus_inode(struct usb_bus *bus, struct super_block *sb) inode->i_gid = sb->u.usbdevfs_sb.busgid; inode->i_mode = sb->u.usbdevfs_sb.busmode | S_IFDIR; inode->i_op = &usbdevfs_bus_inode_operations; + inode->i_fop = &usbdevfs_bus_file_operations; inode->u.usbdev_i.p.bus = bus; list_add_tail(&inode->u.usbdev_i.slist, &sb->u.usbdevfs_sb.ilist); list_add_tail(&inode->u.usbdev_i.dlist, &bus->inodes); @@ -159,7 +153,6 @@ static void free_inode(struct inode *inode) inode->u.usbdev_i.p.dev = NULL; inode->i_mode &= ~S_IRWXUGO; inode->i_uid = inode->i_gid = 0; - inode->i_op = NULL; inode->i_size = 0; list_del(&inode->u.usbdev_i.slist); INIT_LIST_HEAD(&inode->u.usbdev_i.slist); @@ -405,7 +398,6 @@ static struct file_operations usbdevfs_root_file_operations = { }; static struct inode_operations usbdevfs_root_inode_operations = { - default_file_ops: &usbdevfs_root_file_operations, lookup: usbdevfs_root_lookup, }; @@ -414,7 +406,6 @@ static struct file_operations usbdevfs_bus_file_operations = { }; static struct inode_operations usbdevfs_bus_inode_operations = { - default_file_ops: &usbdevfs_bus_file_operations, lookup: usbdevfs_bus_lookup, }; @@ -433,13 +424,14 @@ static void usbdevfs_read_inode(struct inode *inode) case ISPECIAL: if (inode->i_ino == IROOT) { inode->i_op = &usbdevfs_root_inode_operations; + inode->i_fop = &usbdevfs_root_file_operations; inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; return; } if (inode->i_ino <= IROOT || inode->i_ino > IROOT+NRSPECIAL) return; spec = &special[inode->i_ino-(IROOT+1)]; - inode->i_op = spec->iops; + inode->i_fop = spec->fops; return; case IDEVICE: @@ -453,10 +445,6 @@ static void usbdevfs_read_inode(struct inode *inode) } } -static void usbdevfs_put_inode(struct inode *inode) -{ -} - static void usbdevfs_put_super(struct super_block *sb) { list_del(&sb->u.usbdevfs_sb.slist); @@ -482,15 +470,9 @@ static int usbdevfs_statfs(struct super_block *sb, struct statfs *buf, int bufsi } static struct super_operations usbdevfs_sops = { - usbdevfs_read_inode, - NULL, - usbdevfs_put_inode, - NULL, - NULL, - usbdevfs_put_super, - NULL, - usbdevfs_statfs, - NULL + read_inode: usbdevfs_read_inode, + put_super: usbdevfs_put_super, + statfs: usbdevfs_statfs, }; struct super_block *usbdevfs_read_super(struct super_block *s, void *data, int silent) diff --git a/drivers/usb/input.c b/drivers/usb/input.c index d613976f5..e370927b3 100644 --- a/drivers/usb/input.c +++ b/drivers/usb/input.c @@ -31,7 +31,6 @@ #include #include #include -#include #include MODULE_AUTHOR("Vojtech Pavlik "); @@ -303,35 +302,3 @@ void input_close_device(struct input_handle *handle) handleptr = &((*handleptr)->hnext); *handleptr = (*handleptr)->hnext; } - - -#ifdef MODULE -int init_module(void) -#else -int __init input_init(void) -#endif -{ -#ifndef MODULE -#ifdef CONFIG_INPUT_KEYBDEV - keybdev_init(); -#endif -#ifdef CONFIG_INPUT_MOUSEDEV - mousedev_init(); -#endif -#ifdef CONFIG_INPUT_JOYDEV - joydev_init(); -#endif -#ifdef CONFIG_INPUT_EVDEV - evdev_init(); -#endif -#endif - return 0; -} - -#ifdef MODULE -void cleanup_module(void) -{ -} -#endif - -__initcall(input_init); diff --git a/drivers/usb/joydev.c b/drivers/usb/joydev.c index 9f1c94fc0..e2e1d2961 100644 --- a/drivers/usb/joydev.c +++ b/drivers/usb/joydev.c @@ -82,7 +82,7 @@ static struct joydev *joydev_base[BITS_PER_LONG]; MODULE_AUTHOR("Vojtech Pavlik "); MODULE_SUPPORTED_DEVICE("js"); -static int js_correct(int value, struct js_corr *corr) +static int joydev_correct(int value, struct js_corr *corr) { switch (corr->type) { case JS_CORR_NONE: @@ -102,7 +102,7 @@ static int js_correct(int value, struct js_corr *corr) return value; } -static void js_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) +static void joydev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) { struct joydev *joydev = handle->private; struct joydev_list *list = joydev->list; @@ -120,7 +120,7 @@ static void js_event(struct input_handle *handle, unsigned int type, unsigned in case EV_ABS: event.type = JS_EVENT_AXIS; event.number = joydev->absmap[code]; - event.value = js_correct(value, &joydev->corr[event.number]); + event.value = joydev_correct(value, &joydev->corr[event.number]); break; default: @@ -226,8 +226,8 @@ static ssize_t joydev_read(struct file *file, char *buf, size_t count, loff_t *p data.buttons = (joydev->nkey > 0 && test_bit(joydev->keypam[0], input->key)) ? 1 : 0 | (joydev->nkey > 1 && test_bit(joydev->keypam[1], input->key)) ? 2 : 0; - data.x = ((js_correct(input->abs[ABS_X], &joydev->corr[0]) / 256) + 128) >> joydev->glue.JS_CORR.x; - data.y = ((js_correct(input->abs[ABS_Y], &joydev->corr[1]) / 256) + 128) >> joydev->glue.JS_CORR.y; + data.x = ((joydev_correct(input->abs[ABS_X], &joydev->corr[0]) / 256) + 128) >> joydev->glue.JS_CORR.x; + data.y = ((joydev_correct(input->abs[ABS_Y], &joydev->corr[1]) / 256) + 128) >> joydev->glue.JS_CORR.y; if (copy_to_user(buf, &data, sizeof(struct JS_DATA_TYPE))) return -EFAULT; @@ -276,7 +276,7 @@ static ssize_t joydev_read(struct file *file, char *buf, size_t count, loff_t *p event.number = list->startup; } else { event.type = JS_EVENT_AXIS | JS_EVENT_INIT; - event.value = js_correct(input->abs[joydev->abspam[list->startup - joydev->nkey]], + event.value = joydev_correct(input->abs[joydev->abspam[list->startup - joydev->nkey]], &joydev->corr[list->startup - joydev->nkey]); event.number = list->startup - joydev->nkey; } @@ -459,29 +459,27 @@ static void joydev_disconnect(struct input_handle *handle) } static struct input_handler joydev_handler = { - event: js_event, + event: joydev_event, connect: joydev_connect, disconnect: joydev_disconnect, }; -#ifdef MODULE -void cleanup_module(void) -{ - input_unregister_handler(&joydev_handler); - if (unregister_chrdev(JOYSTICK_MAJOR, "js")) - printk(KERN_ERR "js: can't unregister device\n"); -} - -int init_module(void) -#else -int __init joydev_init(void) -#endif +static int joydev_init(void) { if (register_chrdev(JOYDEV_MAJOR, "js", &joydev_fops)) { printk(KERN_ERR "joydev: unable to get major %d for joystick\n", JOYDEV_MAJOR); return -EBUSY; } input_register_handler(&joydev_handler); - return 0; } + +static void joydev_exit(void) +{ + input_unregister_handler(&joydev_handler); + if (unregister_chrdev(JOYSTICK_MAJOR, "js")) + printk(KERN_ERR "js: can't unregister device\n"); +} + +module_init(joydev_init); +module_exit(joydev_exit); diff --git a/drivers/usb/keybdev.c b/drivers/usb/keybdev.c index 1e00b7e49..2aef212cb 100644 --- a/drivers/usb/keybdev.c +++ b/drivers/usb/keybdev.c @@ -158,18 +158,18 @@ struct input_handler keybdev_handler = { disconnect: keybdev_disconnect, }; -#ifdef MODULE -void cleanup_module(void) -{ - kbd_ledfunc = NULL; - input_unregister_handler(&keybdev_handler); -} -int init_module(void) -#else -int __init keybdev_init(void) -#endif +static int __init keybdev_init(void) { input_register_handler(&keybdev_handler); kbd_ledfunc = keybdev_ledfunc; return 0; } + +static void __exit keybdev_exit(void) +{ + kbd_ledfunc = NULL; + input_unregister_handler(&keybdev_handler); +} + +module_init(keybdev_init); +module_exit(keybdev_exit); diff --git a/drivers/usb/mousedev.c b/drivers/usb/mousedev.c index 95623c986..0984e48fd 100644 --- a/drivers/usb/mousedev.c +++ b/drivers/usb/mousedev.c @@ -447,12 +447,7 @@ static struct input_handler mousedev_handler = { disconnect: mousedev_disconnect, }; - -#ifdef MODULE -int init_module(void) -#else -int __init mousedev_init(void) -#endif +static int __init mousedev_init(void) { input_register_handler(&mousedev_handler); @@ -472,13 +467,13 @@ int __init mousedev_init(void) return 0; } -#ifdef MODULE -void cleanup_module(void) +static void __exit mousedev_exit(void) { #ifdef CONFIG_INPUT_MOUSEDEV_MIX misc_deregister(&mousedev_single.misc); #endif - input_unregister_handler(&mousedev_handler); } -#endif + +module_init(mousedev_init); +module_exit(mousedev_exit); diff --git a/drivers/usb/printer.c b/drivers/usb/printer.c index 07220ad9b..182915a19 100644 --- a/drivers/usb/printer.c +++ b/drivers/usb/printer.c @@ -432,18 +432,17 @@ static struct usb_driver usblp_driver = { minor: USBLP_MINOR_BASE }; -static void __exit usb_printer_cleanup(void) -{ - usb_deregister(&usblp_driver); -} - -static int __init usb_printer_init(void) +static int __init usblp_init(void) { if (usb_register(&usblp_driver)) return -1; - return 0; } -module_init(usb_printer_init); -module_exit(usb_printer_cleanup); +static void __exit usblp_exit(void) +{ + usb_deregister(&usblp_driver); +} + +module_init(usblp_init); +module_exit(usblp_exit); diff --git a/drivers/usb/scanner.c b/drivers/usb/scanner.c index d55e54206..aa0531a89 100644 --- a/drivers/usb/scanner.c +++ b/drivers/usb/scanner.c @@ -817,15 +817,12 @@ usb_driver scanner_driver = { SCN_BASE_MNR }; -#ifdef MODULE -void cleanup_module(void) +void __exit usb_scanner_exit(void) { usb_deregister(&scanner_driver); } -int init_module(void) -#else -int usb_scanner_init(void) -#endif + +int __init usb_scanner_init(void) { if (usb_register(&scanner_driver) < 0) return -1; @@ -834,4 +831,5 @@ int usb_scanner_init(void) return 0; } -__initcall(usb_scanner_init); +module_init(usb_scanner_init); +module_exit(usb_scanner_exit); diff --git a/drivers/usb/usb-core.c b/drivers/usb/usb-core.c index 60b411761..0d6457965 100644 --- a/drivers/usb/usb-core.c +++ b/drivers/usb/usb-core.c @@ -33,12 +33,8 @@ int usb_audio_init(void); int usb_cpia_init(void); int usb_ibmcam_init(void); int usb_ov511_init(void); -int usb_stor_init(void); int dabusb_init(void); int plusb_init(void); -int usb_mouse_init(void); -int usb_kbd_init(void); -int graphire_init(void); /* * HCI drivers @@ -86,24 +82,12 @@ int usb_init(void) #ifdef CONFIG_USB_OV511 usb_ov511_init(); #endif -#ifdef CONFIG_USB_STORAGE - usb_stor_init(); -#endif #ifdef CONFIG_USB_DABUSB dabusb_init(); #endif #ifdef CONFIG_USB_PLUSB plusb_init(); #endif -#ifdef CONFIG_USB_MOUSE - usb_mouse_init(); -#endif -#ifdef CONFIG_USB_KBD - usb_kbd_init(); -#endif -#ifdef CONFIG_USB_GRAPHIRE - graphire_init(); -#endif #ifdef CONFIG_USB_UHCI uhci_init(); #endif diff --git a/drivers/usb/usb-ohci.c b/drivers/usb/usb-ohci.c index 7ca3b5b59..bb017e60c 100644 --- a/drivers/usb/usb-ohci.c +++ b/drivers/usb/usb-ohci.c @@ -45,6 +45,7 @@ #include #include #include +#include #undef DEBUG #define OHCI_USE_NPS @@ -62,7 +63,7 @@ static int handle_pm_event (struct pm_dev *dev, pm_request_t rqst, void *data); static DECLARE_WAIT_QUEUE_HEAD (op_wakeup); static LIST_HEAD (ohci_hcd_list); -spinlock_t usb_ed_lock = SPIN_LOCK_UNLOCKED; +static spinlock_t usb_ed_lock = SPIN_LOCK_UNLOCKED; /*-------------------------------------------------------------------------* * URB support functions @@ -319,6 +320,7 @@ static int sohci_submit_urb (urb_t * urb) if (ed->state == ED_NEW || (ed->state & ED_DEL)) { urb_rm_priv(urb); usb_dec_dev_use (urb->dev); + spin_unlock_irqrestore(&usb_ed_lock, flags); return -EINVAL; } @@ -1261,7 +1263,7 @@ static int rh_submit_urb (urb_t * urb) int len = 0; int status = TD_CC_NOERROR; - __u8 datab[16]; + __u32 datab[4]; __u8 * data_buf = datab; __u16 bmRType_bReq; @@ -1371,7 +1373,8 @@ static int rh_submit_urb (urb_t * urb) case RH_GET_DESCRIPTOR | RH_CLASS: *(__u8 *) (data_buf+1) = 0x29; - *(__u32 *) (data_buf+2) = cpu_to_le32 (readl (&ohci->regs->roothub.a)); + put_unaligned(cpu_to_le32 (readl (&ohci->regs->roothub.a)), + (__u32 *) (data_buf + 2)); *(__u8 *) data_buf = (*(__u8 *) (data_buf + 2) / 8) * 2 + 9; /* length of descriptor */ len = min (leni, min(*(__u8 *) data_buf, wLength)); @@ -1380,7 +1383,8 @@ static int rh_submit_urb (urb_t * urb) *(__u8 *) (data_buf+7) = readl (&ohci->regs->roothub.b) & 0xff; *(__u8 *) (data_buf+8) = (readl (&ohci->regs->roothub.b) & 0xff0000) >> 16; } else { - *(__u32 *) (data_buf+7) = cpu_to_le32 (readl(&ohci->regs->roothub.b)); + put_unaligned(cpu_to_le32 (readl(&ohci->regs->roothub.b)), + (__u32 *) (data_buf + 7)); } OK (len); diff --git a/drivers/usb/usb-serial.c b/drivers/usb/usb-serial.c index f87600e83..6b9615e72 100644 --- a/drivers/usb/usb-serial.c +++ b/drivers/usb/usb-serial.c @@ -14,6 +14,17 @@ * * See Documentation/usb/usb-serial.txt for more information on using this driver * + * (02/21/2000) gkh + * Made it so that any serial devices only have to specify which functions + * they want to overload from the generic function calls (great, + * inheritance in C, in a driver, just what I wanted...) + * Added support for set_termios and ioctl function calls. No drivers take + * advantage of this yet. + * Removed the #ifdef MODULE, now there is no module specific code. + * Cleaned up a few comments in usb-serial.h that were wrong (thanks again + * to Miles Lott). + * Small fix to get_free_serial. + * * (02/14/2000) gkh * Removed the Belkin and Peracom functionality from the driver due to * the lack of support from the vendor, and me not wanting people to @@ -169,6 +180,19 @@ #include "usb-serial.h" +/* parity check flag */ +#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) + +/* local function prototypes */ +static int serial_open (struct tty_struct *tty, struct file * filp); +static void serial_close (struct tty_struct *tty, struct file * filp); +static int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count); +static int serial_write_room (struct tty_struct *tty); +static int serial_chars_in_buffer (struct tty_struct *tty); +static void serial_throttle (struct tty_struct * tty); +static void serial_unthrottle (struct tty_struct * tty); +static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg); +static void serial_set_termios (struct tty_struct *tty, struct termios * old); static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum); static void usb_serial_disconnect(struct usb_device *dev, void *ptr); @@ -224,7 +248,7 @@ static struct usb_serial *get_free_serial (int num_ports, int *minor) continue; good_spot = 1; - for (j = 0; j < num_ports-1; ++j) + for (j = 1; j <= num_ports-1; ++j) if (serial_table[i+j]) good_spot = 0; if (good_spot == 0) @@ -328,12 +352,12 @@ static int serial_open (struct tty_struct *tty, struct file * filp) tty->driver_data = serial; serial->tty = tty; - /* pass on to the driver specific version of this function */ + /* pass on to the driver specific version of this function if it is available */ if (serial->type->open) { return (serial->type->open(tty, filp)); + } else { + return (generic_serial_open(tty, filp)); } - - return (0); } @@ -363,9 +387,11 @@ static void serial_close(struct tty_struct *tty, struct file * filp) return; } - /* pass on to the driver specific version of this function */ + /* pass on to the driver specific version of this function if it is available */ if (serial->type->close) { serial->type->close(tty, filp); + } else { + generic_serial_close(tty, filp); } } @@ -391,13 +417,12 @@ static int serial_write (struct tty_struct * tty, int from_user, const unsigned return (-EINVAL); } - /* pass on to the driver specific version of this function */ + /* pass on to the driver specific version of this function if it is available */ if (serial->type->write) { return (serial->type->write(tty, from_user, buf, count)); + } else { + return (generic_serial_write(tty, from_user, buf, count)); } - - /* no specific driver, so return that we didn't write anything */ - return (0); } @@ -422,12 +447,12 @@ static int serial_write_room (struct tty_struct *tty) return (-EINVAL); } - /* pass on to the driver specific version of this function */ + /* pass on to the driver specific version of this function if it is available */ if (serial->type->write_room) { return (serial->type->write_room(tty)); + } else { + return (generic_write_room(tty)); } - - return (0); } @@ -452,12 +477,12 @@ static int serial_chars_in_buffer (struct tty_struct *tty) return (-EINVAL); } - /* pass on to the driver specific version of this function */ + /* pass on to the driver specific version of this function if it is available */ if (serial->type->chars_in_buffer) { return (serial->type->chars_in_buffer(tty)); + } else { + return (generic_chars_in_buffer(tty)); } - - return (0); } @@ -485,6 +510,8 @@ static void serial_throttle (struct tty_struct * tty) /* pass on to the driver specific version of this function */ if (serial->type->throttle) { serial->type->throttle(tty); + } else { + generic_throttle(tty); } return; @@ -515,12 +542,86 @@ static void serial_unthrottle (struct tty_struct * tty) /* pass on to the driver specific version of this function */ if (serial->type->unthrottle) { serial->type->unthrottle(tty); + } else { + generic_unthrottle(tty); } return; } +static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg) +{ + struct usb_serial *serial = (struct usb_serial *) tty->driver_data; + int port; + + dbg("serial_ioctl"); + + if (!serial) { + dbg("serial == NULL!"); + return -ENODEV; + } + + port = MINOR(tty->device) - serial->minor; + + dbg("serial_ioctl port %d", port); + + /* do some sanity checking that we really have a device present */ + if (!serial->type) { + dbg("serial->type == NULL!"); + return -ENODEV; + } + if (!serial->active[port]) { + dbg ("device not open"); + return -ENODEV; + } + + /* pass on to the driver specific version of this function if it is available */ + if (serial->type->ioctl) { + return (serial->type->ioctl(tty, file, cmd, arg)); + } else { + return (generic_ioctl (tty, file, cmd, arg)); + } +} + + +static void serial_set_termios (struct tty_struct *tty, struct termios * old) +{ + struct usb_serial *serial = (struct usb_serial *) tty->driver_data; + int port; + + dbg("serial_set_termios"); + + if (!serial) { + dbg("serial == NULL!"); + return; + } + + port = MINOR(tty->device) - serial->minor; + + dbg("serial_set_termios port %d", port); + + /* do some sanity checking that we really have a device present */ + if (!serial->type) { + dbg("serial->type == NULL!"); + return; + } + if (!serial->active[port]) { + dbg ("device not open"); + return; + } + + /* pass on to the driver specific version of this function if it is available */ + if (serial->type->set_termios) { + serial->type->set_termios(tty, old); + } else { + generic_set_termios (tty, old); + } + + return; +} + + #ifdef CONFIG_USB_SERIAL_WHITEHEAT /***************************************************************************** * Connect Tech's White Heat specific driver functions @@ -566,6 +667,29 @@ static void whiteheat_serial_close(struct tty_struct *tty, struct file * filp) } +static void whiteheat_set_termios (struct tty_struct *tty, struct termios *old_termios) +{ + struct usb_serial *serial = (struct usb_serial *) tty->driver_data; + int port = MINOR(tty->device) - serial->minor; + unsigned int cflag = tty->termios->c_cflag; + + dbg("whiteheat_set_termios port %d", port); + + /* check that they really want us to change something */ + if (old_termios) { + if ((cflag == old_termios->c_cflag) && + (RELEVANT_IFLAG(tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) { + dbg("nothing to change..."); + return; + } + } + + /* do the parsing of the cflag to see what to set the line to */ + /* FIXME!! */ + + return; +} + static void whiteheat_throttle (struct tty_struct * tty) { struct usb_serial *serial = (struct usb_serial *) tty->driver_data; @@ -813,25 +937,96 @@ static int visor_startup (struct usb_serial *serial) /****************************************************************************** * FTDI SIO Serial Converter specific driver functions ******************************************************************************/ + +/* Bill Ryder - bryder@sgi.com - wrote the FTDI_SIO implementation */ +/* Thanx to FTDI for so kindly providing details of the protocol required */ +/* to talk to the device */ + +#include "ftdi_sio.h" + static int ftdi_sio_serial_open (struct tty_struct *tty, struct file *filp) { struct usb_serial *serial = (struct usb_serial *) tty->driver_data; + char buf[1]; /* Needed for the usb_control_msg I think */ int port = MINOR(tty->device) - serial->minor; - dbg("ftdi_serial_open port %d", port); + dbg("ftdi_sio_serial_open port %d", port); if (serial->active[port]) { dbg ("device already open"); return -EINVAL; } serial->active[port] = 1; - + + usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE, + FTDI_SIO_RESET_SIO, + 0, buf, 0, HZ * 5); + + /* FIXME - Should I really purge the buffers? */ + usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE, + FTDI_SIO_RESET_PURGE_RX, + 0, buf, 0, HZ * 5); + + usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE, + FTDI_SIO_RESET_PURGE_TX, + 0, buf, 0, HZ * 5); + + + /* As per usb_serial_init s/be CS8, B9600, 1 STOP BIT */ + if ( usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + FTDI_SIO_SET_BAUDRATE_REQUEST, + FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE, + ftdi_sio_b9600, 0, + buf, 0, HZ * 5) < 0){ + dbg("Error from baudrate urb"); + return(-EINVAL); + } + + if ( usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + FTDI_SIO_SET_DATA_REQUEST, + FTDI_SIO_SET_DATA_REQUEST_TYPE, + 8 | FTDI_SIO_SET_DATA_PARITY_NONE | + FTDI_SIO_SET_DATA_STOP_BITS_1, 0, + buf, 0, HZ * 5) < 0){ + dbg("Error from cs8/noparity/1 stopbit urb"); + return(-EINVAL); + } + + /* Disable flow control */ + if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + FTDI_SIO_SET_FLOW_CTRL_REQUEST, + FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, + 0, 0, + buf, 0, HZ * 5) < 0) { + dbg("error from flowcontrol urb"); + return(-EINVAL); + } + + /* Turn on RTS and DTR since we are not flow controlling*/ + /* FIXME - check for correct behaviour clocal vs non clocal */ + /* FIXME - might be able to do both simultaneously */ + if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + FTDI_SIO_SET_MODEM_CTRL_REQUEST, + FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, + (unsigned)FTDI_SIO_SET_DTR_HIGH, 0, + buf, 0, HZ * 5) < 0) { + dbg("Error from DTR HIGH urb"); + } + if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + FTDI_SIO_SET_MODEM_CTRL_REQUEST, + FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, + (unsigned)FTDI_SIO_SET_RTS_HIGH, 0, + buf, 0, HZ * 5) < 0) { + dbg("Error from RTS HIGH urb"); + } + /*Start reading from the device*/ if (usb_submit_urb(&serial->read_urb[port])) dbg("usb_submit_urb(read bulk) failed"); - /* Need to do device specific setup here (control lines, baud rate, etc.) */ - /* FIXME!!! */ return (0); } @@ -840,13 +1035,29 @@ static int ftdi_sio_serial_open (struct tty_struct *tty, struct file *filp) static void ftdi_sio_serial_close (struct tty_struct *tty, struct file *filp) { struct usb_serial *serial = (struct usb_serial *) tty->driver_data; + char buf[1]; int port = MINOR(tty->device) - serial->minor; - dbg("ftdi_serial_close port %d", port); - - /* Need to change the control lines here */ - /* FIXME */ + dbg("ftdi_sio_serial_close port %d", port); + /* FIXME - might be able to do both simultaneously */ + if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + FTDI_SIO_SET_MODEM_CTRL_REQUEST, + FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, + (unsigned)FTDI_SIO_SET_DTR_LOW, 0, + buf, 0, HZ * 5) < 0) { + dbg("Error from DTR LOW urb"); + } + if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + FTDI_SIO_SET_MODEM_CTRL_REQUEST, + FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, + (unsigned)FTDI_SIO_SET_RTS_LOW, 0, + buf, 0, HZ * 5) < 0) { + dbg("Error from RTS LOW urb"); + } + + /* FIXME Should I flush the device here? - not doing it for now */ + /* shutdown our bulk reads and writes */ usb_unlink_urb (&serial->write_urb[port]); usb_unlink_urb (&serial->read_urb[port]); @@ -854,6 +1065,290 @@ static void ftdi_sio_serial_close (struct tty_struct *tty, struct file *filp) } + +/* The ftdi_sio requires the first byte to have: + B0 1 + B1 0 + B2..7 length of message excluding byte 0 +*/ +static int ftdi_sio_serial_write (struct tty_struct * tty, int from_user, + const unsigned char *buf, int count) +{ + struct usb_serial *serial = (struct usb_serial *) tty->driver_data; + int port = MINOR(tty->device) - serial->minor; + const int data_offset = 1; + + dbg("ftdi_sio_serial_write port %d, %d bytes", port, count); + + if (count == 0) { + dbg("write request of 0 bytes"); + return (0); + } + + /* only do something if we have a bulk out endpoint */ + if (serial->num_bulk_out) { + unsigned char *first_byte = serial->write_urb[port].transfer_buffer; + + if (serial->write_urb[port].status == -EINPROGRESS) { + dbg ("already writing"); + return (0); + } + + count += data_offset; + count = (count > serial->bulk_out_size[port]) ? + serial->bulk_out_size[port] : count; + + + /* Copy in the data to send */ + if (from_user) { + copy_from_user(serial->write_urb[port].transfer_buffer + data_offset , + buf, count - data_offset ); + } + else { + memcpy(serial->write_urb[port].transfer_buffer + data_offset, + buf, count - data_offset ); + } + + /* Write the control byte at the front of the packet*/ + first_byte = serial->write_urb[port].transfer_buffer; + *first_byte = 1 | ((count-data_offset) << 2) ; + +#ifdef DEBUG + dbg("Bytes: %d, Control Byte: 0o%03o",count, first_byte[0]); + + if (count) { + int i; + printk (KERN_DEBUG __FILE__ ": data written - length = %d, data = ", count); + for (i = 0; i < count; ++i) { + printk ("0x%02x ", first_byte[i]); + if (first_byte[i] > ' ' && first_byte[i] < '~') { + printk("%c ", first_byte[i]); + } else { + printk(" "); + } + } + + + printk ("\n"); + } + +#endif + + + /* send the data out the bulk port */ + serial->write_urb[port].transfer_buffer_length = count; + + if (usb_submit_urb(&serial->write_urb[port])) + dbg("usb_submit_urb(write bulk) failed"); + + dbg("write returning: %d",count - data_offset); + return (count - data_offset); + } + + /* no bulk out, so return 0 bytes written */ + return (0); +} + + +static void ftdi_sio_read_bulk_callback (struct urb *urb) +{ /* ftdi_sio_serial_buld_callback */ + struct usb_serial *serial = (struct usb_serial *)urb->context; + struct tty_struct *tty = serial->tty; + unsigned char *data = urb->transfer_buffer; + const int data_offset = 2; + int i; + + dbg("ftdi_sio_read_bulk_callback"); + + if (urb->status) { + dbg("nonzero read bulk status received: %d", urb->status); + return; + } + +#ifdef DEBUG + if (urb->actual_length > 2) { + printk (KERN_DEBUG __FILE__ ": data read - length = %d, data = ", urb->actual_length); + for (i = 0; i < urb->actual_length; ++i) { + printk ("0x%.2x ", data[i]); + if (data[i] > ' ' && data[i] < '~') { + printk("%c ", data[i]); + } else { + printk(" "); + } + } + printk ("\n"); + } +#endif + + + if (urb->actual_length > data_offset) { + for (i = data_offset ; i < urb->actual_length ; ++i) { + tty_insert_flip_char(tty, data[i], 0); + } + tty_flip_buffer_push(tty); + } + + /* Continue trying to always read */ + if (usb_submit_urb(urb)) + dbg("failed resubmitting read urb"); + + return; +} /* ftdi_sio_serial_read_bulk_callback */ + +static void ftdi_sio_set_termios (struct tty_struct *tty, struct termios *old_termios) +{ + struct usb_serial *serial = (struct usb_serial *) tty->driver_data; + int port = MINOR(tty->device) - serial->minor; + unsigned int cflag = tty->termios->c_cflag; + __u16 urb_value; /* Will hold the new flags */ + char buf[1]; /* Perhaps I should dynamically alloc this? */ + dbg("ftdi_sio_set_termios port %d", port); + + /* FIXME - we should keep the old termios really */ + /* FIXME -For this cut I don't care if the line is really changing or + not - so just do the change regardless */ + + /* Set number of data bits, parity, stop bits */ + + urb_value = 0; + urb_value |= (cflag & CSTOPB ? FTDI_SIO_SET_DATA_STOP_BITS_2 : + FTDI_SIO_SET_DATA_STOP_BITS_1); + urb_value |= (cflag & PARENB ? + (cflag & PARODD ? FTDI_SIO_SET_DATA_PARITY_ODD : + FTDI_SIO_SET_DATA_PARITY_EVEN) : + FTDI_SIO_SET_DATA_PARITY_NONE); + if (cflag & CSIZE) { + switch (cflag & CSIZE) { + case CS5: urb_value |= 5; dbg("Setting CS5"); break; + case CS6: urb_value |= 6; dbg("Setting CS6"); break; + case CS7: urb_value |= 7; dbg("Setting CS7"); break; + case CS8: urb_value |= 8; dbg("Setting CS8"); break; + default: + dbg("CSIZE was set but not CS5-CS8"); + } + } + if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + FTDI_SIO_SET_DATA_REQUEST, + FTDI_SIO_SET_DATA_REQUEST_TYPE, + urb_value , 0, + buf, 0, 100) < 0) { + dbg("FAILED to set databits/stopbits/parity"); + } + + /* Now do the baudrate */ + /* FIXME - should drop lines on B0 */ + /* FIXME Should also handle CLOCAL here */ + + switch(cflag & CBAUD){ + case B300: urb_value = ftdi_sio_b300; dbg("Set to 300"); break; + case B600: urb_value = ftdi_sio_b600; dbg("Set to 600") ; break; + case B1200: urb_value = ftdi_sio_b1200; dbg("Set to 1200") ; break; + case B2400: urb_value = ftdi_sio_b2400; dbg("Set to 2400") ; break; + case B4800: urb_value = ftdi_sio_b4800; dbg("Set to 4800") ; break; + case B9600: urb_value = ftdi_sio_b9600; dbg("Set to 9600") ; break; + case B19200: urb_value = ftdi_sio_b19200; dbg("Set to 19200") ; break; + case B38400: urb_value = ftdi_sio_b38400; dbg("Set to 38400") ; break; + case B57600: urb_value = ftdi_sio_b57600; dbg("Set to 57600") ; break; + case B115200: urb_value = ftdi_sio_b115200; dbg("Set to 115200") ; break; + default: dbg("FTDI_SIO does not support the baudrate requested"); + /* FIXME - how to return an error for this? */ break; + } + /* Send the URB */ + if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + FTDI_SIO_SET_BAUDRATE_REQUEST, + FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE, + urb_value, 0, + buf, 0, 100) < 0) { + dbg("urb failed to set baurdrate"); + } + return; +} + +/*FIXME - the beginnings of this implementation - not even hooked into the driver yet */ +static int ftdi_sio_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg) +{ + struct usb_serial *serial = (struct usb_serial *) tty->driver_data; + int port = MINOR(tty->device) - serial->minor; + __u16 urb_value=0; /* Will hold the new flags */ + char buf[1]; + int ret, mask; + dbg("ftdi_sio_ioctl port %d", port); + + /* Based on code from acm.c */ + switch (cmd) { + + case TIOCMGET: + /* Request the status from the device */ + if ((ret = usb_control_msg(serial->dev, + usb_sndctrlpipe(serial->dev, 0), + FTDI_SIO_GET_MODEM_STATUS_REQUEST, + FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE, + 0, 0, + buf, 1, HZ * 5)) < 0 ) { + dbg("Get not get modem status of device"); + return(ret); + } + + return put_user((buf[0] & FTDI_SIO_DSR_MASK ? TIOCM_DSR : 0) | + (buf[0] & FTDI_SIO_CTS_MASK ? TIOCM_CTS : 0) | + (buf[0] & FTDI_SIO_RI_MASK ? TIOCM_RI : 0) | + (buf[0] & FTDI_SIO_RLSD_MASK ? TIOCM_CD : 0), + (unsigned long *) arg); + break; + + case TIOCMSET: + case TIOCMBIS: + case TIOCMBIC: + if ((ret = get_user(mask, (unsigned long *) arg))) return ret; + + /* FIXME Need to remember if we have set DTR or RTS since we + can't ask the device */ + /* FIXME - also need to find the meaning of TIOCMBIS/BIC/SET */ + if (mask & TIOCM_DTR) { + switch(cmd) { + case TIOCMSET: + urb_value = FTDI_SIO_SET_DTR_HIGH | FTDI_SIO_SET_RTS_LOW; + break; + + case TIOCMBIS: + /* Will leave RTS alone and set DTR */ + urb_value = FTDI_SIO_SET_DTR_HIGH; + break; + + case TIOCMBIC: + urb_value = FTDI_SIO_SET_DTR_LOW; + break; + } + } + + if (mask & TIOCM_RTS) { + switch(cmd) { + case TIOCMSET: + urb_value = FTDI_SIO_SET_DTR_LOW | FTDI_SIO_SET_RTS_HIGH; + break; + + case TIOCMBIS: + /* Will leave DTR and set RTS */ + urb_value = FTDI_SIO_SET_RTS_HIGH; + break; + + case TIOCMBIC: + /* Will unset RTS */ + urb_value = FTDI_SIO_SET_RTS_LOW; + break; + } + } + + + return(usb_control_msg(serial->dev, + usb_sndctrlpipe(serial->dev, 0), + FTDI_SIO_SET_MODEM_CTRL_REQUEST, + FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, + urb_value , 0, + buf, 0, HZ * 5)); + } +} + #endif /* CONFIG_USB_SERIAL_FTDI_SIO */ @@ -1041,6 +1536,34 @@ static int generic_chars_in_buffer (struct tty_struct *tty) } +static void generic_throttle (struct tty_struct *tty) +{ + /* do nothing for the generic device */ + return; +} + + +static void generic_unthrottle (struct tty_struct *tty) +{ + /* do nothing for the generic device */ + return; +} + + +static int generic_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg) +{ + /* generic driver doesn't support any ioctls yet */ + return -ENOIOCTLCMD; +} + + +static void generic_set_termios (struct tty_struct *tty, struct termios * old) +{ + /* generic driver doesn't really care about setting any line settings */ + return; +} + + static void generic_read_bulk_callback (struct urb *urb) { struct usb_serial *serial = (struct usb_serial *)urb->context; @@ -1059,7 +1582,7 @@ static void generic_read_bulk_callback (struct urb *urb) if (urb->actual_length) { printk (KERN_DEBUG __FILE__ ": data read - length = %d, data = ", urb->actual_length); for (i = 0; i < urb->actual_length; ++i) { - printk ("0x%.2x ", data[i]); + printk ("%.2x ", data[i]); } printk ("\n"); } @@ -1352,8 +1875,8 @@ static struct tty_driver serial_tty_driver = { put_char: NULL, flush_chars: NULL, write_room: serial_write_room, - ioctl: NULL, - set_termios: NULL, + ioctl: serial_ioctl, + set_termios: serial_set_termios, set_ldisc: NULL, throttle: serial_throttle, unthrottle: serial_unthrottle, @@ -1397,19 +1920,14 @@ int usb_serial_init(void) } -#ifdef MODULE -int init_module(void) -{ - return usb_serial_init(); -} - -void cleanup_module(void) +void usb_serial_exit(void) { tty_unregister_driver(&serial_tty_driver); usb_deregister(&usb_serial_driver); } -#else -__initcall(usb_serial_init); -#endif + +module_init(usb_serial_init); +module_exit(usb_serial_exit); + diff --git a/drivers/usb/usb-serial.h b/drivers/usb/usb-serial.h index 6d8e978b5..c62bae569 100644 --- a/drivers/usb/usb-serial.h +++ b/drivers/usb/usb-serial.h @@ -87,15 +87,6 @@ struct usb_serial { #define NUM_DONT_CARE (-1) -/* local function prototypes */ -static int serial_open (struct tty_struct *tty, struct file * filp); -static void serial_close (struct tty_struct *tty, struct file * filp); -static int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count); -static int serial_write_room (struct tty_struct *tty); -static int serial_chars_in_buffer (struct tty_struct *tty); -static void serial_throttle (struct tty_struct * tty); -static void serial_unthrottle (struct tty_struct * tty); - /* This structure defines the individual serial converter. */ struct usb_serial_device_type { @@ -110,6 +101,8 @@ struct usb_serial_device_type { char num_bulk_out; char num_ports; /* number of serial ports this device has */ + void *private; /* data private to the specific driver */ + /* function call to make before accepting driver */ int (*startup) (struct usb_serial *serial); /* return 0 to continue initialization, anything else to abort */ @@ -118,21 +111,30 @@ struct usb_serial_device_type { void (*close)(struct tty_struct * tty, struct file * filp); int (*write)(struct tty_struct * tty, int from_user,const unsigned char *buf, int count); int (*write_room)(struct tty_struct *tty); + int (*ioctl)(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg); + void (*set_termios)(struct tty_struct *tty, struct termios * old); int (*chars_in_buffer)(struct tty_struct *tty); void (*throttle)(struct tty_struct * tty); void (*unthrottle)(struct tty_struct * tty); + void (*read_bulk_callback)(struct urb *urb); void (*write_bulk_callback)(struct urb *urb); + }; /* function prototypes for a "generic" type serial converter (no flow control, not all endpoints needed) */ /* need to always compile these in, as some of the other devices use these functions as their own. */ +/* if a driver does not provide a function pointer, the generic function will be called. */ static int generic_serial_open (struct tty_struct *tty, struct file *filp); static void generic_serial_close (struct tty_struct *tty, struct file *filp); static int generic_serial_write (struct tty_struct *tty, int from_user, const unsigned char *buf, int count); static int generic_write_room (struct tty_struct *tty); +static int generic_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg); +static void generic_set_termios (struct tty_struct *tty, struct termios * old); static int generic_chars_in_buffer (struct tty_struct *tty); +static void generic_throttle (struct tty_struct *tty); +static void generic_unthrottle (struct tty_struct *tty); static void generic_read_bulk_callback (struct urb *urb); static void generic_write_bulk_callback (struct urb *urb); @@ -150,13 +152,6 @@ static struct usb_serial_device_type generic_device = { num_bulk_in: NUM_DONT_CARE, num_bulk_out: NUM_DONT_CARE, num_ports: 1, - open: generic_serial_open, - close: generic_serial_close, - write: generic_serial_write, - write_room: generic_write_room, - chars_in_buffer: generic_chars_in_buffer, - read_bulk_callback: generic_read_bulk_callback, - write_bulk_callback: generic_write_bulk_callback }; #endif @@ -165,6 +160,7 @@ static struct usb_serial_device_type generic_device = { /* function prototypes for the Connect Tech WhiteHEAT serial converter */ static int whiteheat_serial_open (struct tty_struct *tty, struct file *filp); static void whiteheat_serial_close (struct tty_struct *tty, struct file *filp); +static void whiteheat_set_termios (struct tty_struct *tty, struct termios * old); static void whiteheat_throttle (struct tty_struct *tty); static void whiteheat_unthrottle (struct tty_struct *tty); static int whiteheat_startup (struct usb_serial *serial); @@ -198,11 +194,9 @@ static struct usb_serial_device_type whiteheat_device = { num_ports: 4, open: whiteheat_serial_open, close: whiteheat_serial_close, - write: generic_serial_write, - write_room: generic_write_room, - chars_in_buffer: generic_chars_in_buffer, throttle: whiteheat_throttle, - unthrottle: whiteheat_unthrottle + unthrottle: whiteheat_unthrottle, + set_termios: whiteheat_set_termios, }; #endif @@ -283,14 +277,9 @@ static struct usb_serial_device_type handspring_device = { num_ports: 2, open: visor_serial_open, close: visor_serial_close, - write: generic_serial_write, - write_room: generic_write_room, - chars_in_buffer: generic_chars_in_buffer, throttle: visor_throttle, unthrottle: visor_unthrottle, startup: visor_startup, - read_bulk_callback: generic_read_bulk_callback, - write_bulk_callback: generic_write_bulk_callback }; #endif @@ -299,8 +288,12 @@ static struct usb_serial_device_type handspring_device = { /* function prototypes for a FTDI serial converter */ static int ftdi_sio_serial_open (struct tty_struct *tty, struct file *filp); static void ftdi_sio_serial_close (struct tty_struct *tty, struct file *filp); +static int ftdi_sio_serial_write (struct tty_struct *tty, int from_user, const unsigned char *buf, int count); +static void ftdi_sio_read_bulk_callback (struct urb *urb); +static void ftdi_sio_set_termios (struct tty_struct *tty, struct termios * old); +static int ftdi_sio_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg); -/* All of the device info needed for the Handspring Visor */ +/* All of the device info needed for the FTDI SIO serial converter */ static __u16 ftdi_vendor_id = FTDI_VENDOR_ID; static __u16 ftdi_sio_product_id = FTDI_SIO_SERIAL_CONVERTER_ID; static struct usb_serial_device_type ftdi_sio_device = { @@ -316,11 +309,9 @@ static struct usb_serial_device_type ftdi_sio_device = { num_ports: 1, open: ftdi_sio_serial_open, close: ftdi_sio_serial_close, - write: generic_serial_write, - write_room: generic_write_room, - chars_in_buffer: generic_chars_in_buffer, - read_bulk_callback: generic_read_bulk_callback, - write_bulk_callback: generic_write_bulk_callback + write: ftdi_sio_serial_write, + read_bulk_callback: ftdi_sio_read_bulk_callback, + set_termios: ftdi_sio_set_termios }; #endif @@ -331,7 +322,7 @@ static int keyspan_pda_serial_open (struct tty_struct *tty, struct file *filp); static void keyspan_pda_serial_close (struct tty_struct *tty, struct file *filp); static int keyspan_pda_startup (struct usb_serial *serial); -/* All of the device info needed for the Handspring Visor */ +/* All of the device info needed for the Keyspan PDA serial converter */ static __u16 keyspan_vendor_id = KEYSPAN_VENDOR_ID; static __u16 keyspan_pda_fake_product_id = KEYSPAN_PDA_FAKE_ID; static __u16 keyspan_pda_product_id = KEYSPAN_PDA_ID; @@ -360,17 +351,12 @@ static struct usb_serial_device_type keyspan_pda_device = { num_ports: 1, open: keyspan_pda_serial_open, close: keyspan_pda_serial_close, - write: generic_serial_write, - write_room: generic_write_room, - chars_in_buffer: generic_chars_in_buffer, - read_bulk_callback: generic_read_bulk_callback, - write_bulk_callback: generic_write_bulk_callback }; #endif /* To add support for another serial converter, create a usb_serial_device_type - structure for that device, and add it to this list, making sure that the last - entry is NULL. */ + structure for that device, and add it to this list, making sure that the + last entry is NULL. */ static struct usb_serial_device_type *usb_serial_devices[] = { #ifdef CONFIG_USB_SERIAL_GENERIC &generic_device, diff --git a/drivers/usb/usb-storage-debug.h b/drivers/usb/usb-storage-debug.h index 8994c06ba..1c5fcc0e2 100644 --- a/drivers/usb/usb-storage-debug.h +++ b/drivers/usb/usb-storage-debug.h @@ -1,3 +1,4 @@ +#include #ifdef CONFIG_USB_STORAGE_DEBUG /* Debug output for Driver for USB mass storage (scsi-like) devices diff --git a/drivers/usb/usbkbd.c b/drivers/usb/usbkbd.c index f3358ddfe..00fecea9d 100644 --- a/drivers/usb/usbkbd.c +++ b/drivers/usb/usbkbd.c @@ -32,6 +32,7 @@ #include #include #include +#include #include "usb.h" MODULE_AUTHOR("Vojtech Pavlik "); @@ -202,17 +203,16 @@ static struct usb_driver usb_kbd_driver = { disconnect: usb_kbd_disconnect }; -#ifdef MODULE -void cleanup_module(void) +static int __init usb_kbd_init(void) { - usb_deregister(&usb_kbd_driver); + usb_register(&usb_kbd_driver); + return 0; } -int init_module(void) -#else -int usb_kbd_init(void) -#endif +static void __exit usb_kbd_exit(void) { - usb_register(&usb_kbd_driver); - return 0; + usb_deregister(&usb_kbd_driver); } + +module_init(usb_kbd_init); +module_exit(usb_kbd_exit); diff --git a/drivers/usb/usbmouse.c b/drivers/usb/usbmouse.c index 7276ca670..75e834649 100644 --- a/drivers/usb/usbmouse.c +++ b/drivers/usb/usbmouse.c @@ -32,6 +32,7 @@ #include #include #include +#include #include "usb.h" MODULE_AUTHOR("Vojtech Pavlik "); @@ -132,18 +133,16 @@ static struct usb_driver usb_mouse_driver = { disconnect: usb_mouse_disconnect, }; -#ifdef MODULE -void cleanup_module(void) +static int __init usb_mouse_init(void) { - usb_deregister(&usb_mouse_driver); + usb_register(&usb_mouse_driver); + return 0; } -int init_module(void) -#else -int usb_mouse_init(void) -#endif +static void __exit usb_mouse_exit(void) { - usb_register(&usb_mouse_driver); - return 0; + usb_deregister(&usb_mouse_driver); } +module_init(usb_mouse_init); +module_exit(usb_mouse_exit); diff --git a/drivers/usb/wmforce.c b/drivers/usb/wmforce.c index fa2d1b465..06ddeb5b2 100644 --- a/drivers/usb/wmforce.c +++ b/drivers/usb/wmforce.c @@ -32,6 +32,7 @@ #include #include #include +#include #include "usb.h" MODULE_AUTHOR("Vojtech Pavlik "); @@ -149,17 +150,16 @@ static struct usb_driver wmforce_driver = { disconnect: wmforce_disconnect, }; -#ifdef MODULE -void cleanup_module(void) +static int __init wmforce_init(void) { - usb_deregister(&wmforce_driver); + usb_register(&wmforce_driver); + return 0; } -int init_module(void) -#else -int wmforce_init(void) -#endif +static void __exit wmforce_exit(void) { - usb_register(&wmforce_driver); - return 0; + usb_deregister(&wmforce_driver); } + +module_init(wmforce_init); +module_exit(wmforce_exit); diff --git a/drivers/video/Config.in b/drivers/video/Config.in index b7a855b77..9d12bf42a 100644 --- a/drivers/video/Config.in +++ b/drivers/video/Config.in @@ -105,6 +105,10 @@ if [ "$CONFIG_FB" = "y" ]; then bool ' Millennium I/II support' CONFIG_FB_MATROX_MILLENIUM bool ' Mystique support' CONFIG_FB_MATROX_MYSTIQUE bool ' G100/G200/G400 support' CONFIG_FB_MATROX_G100 + dep_tristate ' Matrox I2C support' CONFIG_FB_MATROX_I2C $CONFIG_FB_MATROX $CONFIG_I2C_ALGOBIT + if [ "$CONFIG_FB_MATROX_G100" = "y" ]; then + dep_tristate ' G400 second head support' CONFIG_FB_MATROX_MAVEN $CONFIG_FB_MATROX_I2C + fi bool ' Multihead support' CONFIG_FB_MATROX_MULTIHEAD fi tristate ' ATI Mach64 display support (EXPERIMENTAL)' CONFIG_FB_ATY diff --git a/drivers/video/Makefile b/drivers/video/Makefile index e52eee833..75896bbf8 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -3,9 +3,9 @@ # Rewritten to use lists instead of if-statements. SUB_DIRS := -MOD_SUB_DIRS := +MOD_SUB_DIRS := $(SUB_DIRS) MOD_IN_SUB_DIRS := -ALL_SUB_DIRS := +ALL_SUB_DIRS := $(SUB_DIRS) matrox O_TARGET := video.o O_OBJS := @@ -16,7 +16,11 @@ M_OBJS := # All of the (potential) objects that export symbols. # This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'. -export-objs := fbmem.o fbcmap.o fbcon.o fbcon-afb.o fbcon-ilbm.o fbcon-vga.o fbcon-iplan2p2.o fbcon-iplan2p4.o fbcon-iplan2p8.o fbcon-vga-planes.o fbcon-cfb16.o fbcon-cfb2.o fbcon-cfb24.o fbcon-cfb32.o fbcon-cfb4.o fbcon-cfb8.o fbcon-mac.o fbcon-mfb.o fbcon-vga.o +export-objs := fbmem.o fbcmap.o fbcon.o fbcon-afb.o fbcon-ilbm.o fbcon-vga.o \ + fbcon-iplan2p2.o fbcon-iplan2p4.o fbcon-iplan2p8.o fbcon-vga-planes.o \ + fbcon-cfb16.o fbcon-cfb2.o fbcon-cfb24.o fbcon-cfb32.o fbcon-cfb4.o fbcon-cfb8.o \ + fbcon-mac.o fbcon-mfb.o fbcon-vga8-planes.o \ + matrox/matroxfb.o # Object file lists. obj-y := @@ -81,11 +85,20 @@ obj-$(CONFIG_FB_TCX) += tcxfb.o sbusfb.o obj-$(CONFIG_FB_CGFOURTEEN) += cgfourteenfb.o sbusfb.o obj-$(CONFIG_FB_P9100) += p9100fb.o sbusfb.o obj-$(CONFIG_FB_LEO) += leofb.o sbusfb.o -obj-$(CONFIG_FB_MATROX) += matroxfb.o obj-$(CONFIG_FB_SUN3) += sun3fb.o obj-$(CONFIG_FB_BWTWO) += bwtwofb.o obj-$(CONFIG_FB_VIRTUAL) += vfb.o +ifeq ($(CONFIG_FB_MATROX),y) +SUB_DIRS += matrox +obj-y += matrox/matrox.o +MOD_SUB_DIRS += matrox +else + ifeq ($(CONFIG_FB_MATROX),m) + MOD_SUB_DIRS += matrox + endif +endif + # Generic Low Level Drivers obj-$(CONFIG_FBCON_AFB) += fbcon-afb.o diff --git a/drivers/video/aty128fb.c b/drivers/video/aty128fb.c index da084b045..388b0e1d2 100644 --- a/drivers/video/aty128fb.c +++ b/drivers/video/aty128fb.c @@ -118,20 +118,19 @@ static struct fb_videomode defaultmode __initdata = { /* chip description information */ struct aty128_chip_info { const char *name; - unsigned short vendor; unsigned short device; }; /* supported Rage128 chipsets */ -static const struct aty128_chip_info aty128_pci_probe_list[] = -{ - {"PCI_DEVICE_ID_ATI_RAGE128_RE", PCI_VENDOR_ID_ATI, 0x5245}, - {"PCI_DEVICE_ID_ATI_RAGE128_RF", PCI_VENDOR_ID_ATI, 0x5246}, - {"PCI_DEVICE_ID_ATI_RAGE128_RK", PCI_VENDOR_ID_ATI, 0x524b}, - {"PCI_DEVICE_ID_ATI_RAGE128_RL", PCI_VENDOR_ID_ATI, 0x524c}, - {"PCI_DEVICE_ID_ATI_RAGE128_PF", PCI_VENDOR_ID_ATI, 0x5046}, - {"PCI_DEVICE_ID_ATI_RAGE128_PR", PCI_VENDOR_ID_ATI, 0x5052}, - {NULL, 0, 0} +static const struct aty128_chip_info aty128_pci_probe_list[] __initdata = +{ + {"Rage128 RE (PCI)", PCI_DEVICE_ID_ATI_RAGE128_RE}, + {"Rage128 RF (AGP)", PCI_DEVICE_ID_ATI_RAGE128_RF}, + {"Rage128 RK (PCI)", PCI_DEVICE_ID_ATI_RAGE128_RK}, + {"Rage128 RL (AGP)", PCI_DEVICE_ID_ATI_RAGE128_RL}, + {"Rage128 Pro PF (AGP)", PCI_DEVICE_ID_ATI_RAGE128_PF}, + {"Rage128 Pro PR (PCI)", PCI_DEVICE_ID_ATI_RAGE128_PR}, + {NULL, 0} }; /* packed BIOS settings */ @@ -186,7 +185,8 @@ static int currcon = 0; static char *aty128fb_name = "ATY Rage128"; static char fontname[40] __initdata = { 0 }; -static char noaccel __initdata = 0; +static char noaccel __initdata = 1; +static unsigned int initdepth __initdata = 8; #ifndef MODULE static const char *mode_option __initdata = NULL; @@ -253,7 +253,9 @@ struct fb_info_aty128 { void *regbase; const struct aty128_meminfo *mem; /* onboard mem info */ u32 vram_size; /* onboard video ram */ - void *BIOS_SEG; /* BIOS segment */ +#ifndef CONFIG_PPC + void *bios_seg; /* video BIOS segment */ +#endif unsigned short card_revision; /* video card revision */ struct aty128fb_par default_par, current_par; struct display disp; @@ -362,12 +364,27 @@ static void fbcon_aty8_putcs(struct vc_data *conp, struct display *p, #endif #ifdef FBCON_HAS_CFB16 static struct display_switch fbcon_aty128_16; +static void fbcon_aty16_putc(struct vc_data *conp, struct display *p, + int c, int yy, int xx); +static void fbcon_aty16_putcs(struct vc_data *conp, struct display *p, + const unsigned short *s, int count, + int yy, int xx); #endif #ifdef FBCON_HAS_CFB24 static struct display_switch fbcon_aty128_24; +static void fbcon_aty24_putc(struct vc_data *conp, struct display *p, + int c, int yy, int xx); +static void fbcon_aty24_putcs(struct vc_data *conp, struct display *p, + const unsigned short *s, int count, + int yy, int xx); #endif #ifdef FBCON_HAS_CFB32 static struct display_switch fbcon_aty128_32; +static void fbcon_aty32_putc(struct vc_data *conp, struct display *p, + int c, int yy, int xx); +static void fbcon_aty32_putcs(struct vc_data *conp, struct display *p, + const unsigned short *s, int count, + int yy, int xx); #endif static struct fb_ops aty128fb_ops = { @@ -651,7 +668,7 @@ aty128_init_engine(const struct aty128fb_par *par, GMC_SRC_CLIP_DEFAULT | GMC_DST_CLIP_DEFAULT | GMC_BRUSH_SOLIDCOLOR | - (bpp_to_depth(par->crtc.bpp) << 8) | + (bpp_to_depth(par->crtc.bpp << 8)) | GMC_SRC_DSTCOLOR | GMC_BYTE_ORDER_MSB_TO_LSB | GMC_DP_CONVERSION_TEMP_6500 | @@ -911,6 +928,7 @@ aty128_crtc_to_var(const struct aty128_crtc *crtc, u32 v_total, v_disp, v_sync_strt, v_sync_wid, v_sync_pol, c_sync; u32 pix_width; + /* fun with masking */ h_total = crtc->h_total & 0x1ff; h_disp = (crtc->h_total>>16) & 0xff; h_sync_strt = (crtc->h_sync_strt_wid>>3) & 0x1ff; @@ -1094,7 +1112,7 @@ aty128_ddafifo(struct aty128_ddafifo *dsp, x; #ifdef DEBUG - printk(KERN_DEBUG "x %x\n", x); + printk(KERN_DEBUG "aty128fb: x %x\n", x); #endif b = 0; while (x) { @@ -1109,13 +1127,13 @@ aty128_ddafifo(struct aty128_ddafifo *dsp, x = round_div(n, d); roff = x * (fifo_depth - 4); if ((ron + m->Rloop) >= roff) { - printk(KERN_ERR "Mode out of range\n"); + printk(KERN_ERR "aty128fb: Mode out of range!\n"); return -EINVAL; } #ifdef DEBUG - printk(KERN_DEBUG "p: %x rloop: %x x: %x ron: %x roff: %x\n", p, - m->Rloop, x, ron, roff); + printk(KERN_DEBUG "aty128fb: p: %x rloop: %x x: %x ron: %x roff: %x\n", + p, m->Rloop, x, ron, roff); #endif dsp->dda_config = p << 16 | m->Rloop << 20 | x; dsp->dda_on_off = ron << 16 | roff; @@ -1203,10 +1221,10 @@ aty128_decode_var(struct fb_var_screeninfo *var, struct aty128fb_par *par, { int err; - if ((err = aty128_var_to_crtc(var, &(par->crtc), info))) + if ((err = aty128_var_to_crtc(var, &par->crtc, info))) return err; - if ((err = aty128_var_to_pll(var->pixclock, &(par->pll), info))) + if ((err = aty128_var_to_pll(var->pixclock, &par->pll, info))) return err; if ((err = aty128_ddafifo(&par->fifo_reg, &par->pll, par->crtc.bpp, info))) @@ -1587,7 +1605,25 @@ aty128fb_setup(char *options) fontname[i] = 0; } else if (!strncmp(this_opt, "noaccel", 7)) { noaccel = 1; - } + } else if (!strncmp(this_opt, "depth:", 6)) { + unsigned int depth = simple_strtoul(this_opt+6, NULL, 0); + switch (depth) { + case 0 ... 8: + initdepth = 8; + break; + case 9 ... 16: + initdepth = 16; + break; + case 17 ... 24: + initdepth = 24; + break; + case 25 ... 32: + initdepth = 32; + break; + default: + initdepth = 8; + } + } #ifdef CONFIG_MTRR else if(!strncmp(this_opt, "nomtrr", 6)) { mtrr = 0; @@ -1636,9 +1672,11 @@ aty128_init(struct fb_info_aty128 *info, const char *name) u32 dac; int j, k; u8 chip_rev; + const struct aty128_chip_info *aci = &aty128_pci_probe_list[0]; + char *video_card = NULL; if (!register_test(info)) { - printk(KERN_ERR "Can't write to video registers\n"); + printk(KERN_ERR "aty128fb: Can't write to video registers\n"); return 0; } @@ -1647,14 +1685,17 @@ aty128_init(struct fb_info_aty128 *info, const char *name) chip_rev = (aty_ld_le32(CONFIG_CNTL) >> 16) & 0x1F; - /* TODO: be more verbose */ - printk(KERN_INFO "aty128fb: Rage128 [chip rev 0x%x] [card rev %x] ", - chip_rev, info->card_revision); + /* put a name with the face */ + while (info->pdev->device != aci->device) { aci++; } + video_card = (char *)aci->name; + + printk(KERN_INFO "aty128fb: %s [chip rev 0x%x] [card rev %x] ", + video_card, chip_rev, info->card_revision); if (info->vram_size % (1024 * 1024) == 0) - printk("%dM \n", info->vram_size / (1024*1024)); + printk("%dM\n", info->vram_size / (1024*1024)); else - printk("%dk \n", info->vram_size / 1024); + printk("%dk\n", info->vram_size / 1024); /* fill in info */ strcpy(info->fb_info.modename, aty128fb_name); @@ -1678,7 +1719,7 @@ aty128_init(struct fb_info_aty128 *info, const char *name) #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,1) if (!fb_find_mode(&var, &info->fb_info, mode_option, NULL, 0, - &defaultmode, 8)) + &defaultmode, initdepth)) var = default_var; #endif @@ -1767,13 +1808,13 @@ aty128pci_probe(void) struct pci_dev *pdev = NULL; const struct aty128_chip_info *aci = &aty128_pci_probe_list[0]; - while(aci->name != NULL) { - pdev = pci_find_device(aci->vendor, aci->device, NULL); - while(pdev != NULL) { - if(aty128_pci_register(pdev, aci) > 0) + while (aci->name != NULL) { + pdev = pci_find_device(PCI_VENDOR_ID_ATI, aci->device, pdev); + while (pdev != NULL) { + if (aty128_pci_register(pdev, aci) == 0) return; - pdev = pci_find_device(aci->vendor, aci->device, pdev); - } + pdev = pci_find_device(PCI_VENDOR_ID_ATI, aci->device, pdev); + } aci++; } @@ -1797,16 +1838,16 @@ aty128_pci_register(struct pci_dev *pdev, fb_addr = rp->start; fb_addr &= PCI_BASE_ADDRESS_MEM_MASK; - request_mem_region (rp->start, rp->end - rp->start + 1, "aty128fb"); + request_mem_region(rp->start, rp->end - rp->start + 1, "aty128fb"); rp = &pdev->resource[2]; reg_addr = rp->start; reg_addr &= PCI_BASE_ADDRESS_MEM_MASK; if (!reg_addr) { - release_mem_region (pdev->resource[0].start, - pdev->resource[0].end - - pdev->resource[0].start + 1); + release_mem_region(pdev->resource[0].start, + pdev->resource[0].end - + pdev->resource[0].start + 1); return -1; } #else @@ -1874,13 +1915,13 @@ aty128_pci_register(struct pci_dev *pdev, return 0; err_out: - kfree (info); + kfree(info); unmap_out: #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,1) - release_mem_region (pdev->resource[0].start, + release_mem_region(pdev->resource[0].start, pdev->resource[0].end - pdev->resource[0].start + 1); - release_mem_region (pdev->resource[2].start, + release_mem_region(pdev->resource[2].start, pdev->resource[2].end - pdev->resource[2].start + 1); #endif @@ -1949,7 +1990,7 @@ aty128find_ROM(struct fb_info_aty128 *info) printk(KERN_INFO "aty128fb: Rage128 BIOS located at segment %4.4X\n", (u32)rom_base); - info->BIOS_SEG = rom_base; + info->bios_seg = rom_base; flag = 1; break; } @@ -1965,16 +2006,16 @@ aty128_get_pllinfo(struct fb_info_aty128 *info) u16 bios_header_offset, pll_info_offset; PLL_BLOCK pll; - bios_header = info->BIOS_SEG + 0x48L; + bios_header = info->bios_seg + 0x48L; header_ptr = bios_header; bios_header_offset = readw(header_ptr); - bios_header = info->BIOS_SEG + bios_header_offset; + bios_header = info->bios_seg + bios_header_offset; bios_header += 0x30; header_ptr = bios_header; pll_info_offset = readw(header_ptr); - header_ptr = info->BIOS_SEG + pll_info_offset; + header_ptr = info->bios_seg + pll_info_offset; memcpy_fromio(&pll, header_ptr, 50); @@ -2013,8 +2054,8 @@ aty128_get_pllinfo(struct fb_info_aty128 *info) } /* free up to-be unused resources */ - if (info->BIOS_SEG) - iounmap(info->BIOS_SEG); + if (info->bios_seg) + iounmap(info->bios_seg); return; } @@ -2346,7 +2387,6 @@ fbcon_aty128_bmove(struct display *p, int sy, int sx, int dy, int dx, } -/* TODO: Fix accel and add to these structs */ #ifdef FBCON_HAS_CFB8 static void fbcon_aty8_putc(struct vc_data *conp, struct display *p, int c, int yy, int xx) diff --git a/drivers/video/atyfb.c b/drivers/video/atyfb.c index 57ae6e15e..5b78c939c 100644 --- a/drivers/video/atyfb.c +++ b/drivers/video/atyfb.c @@ -1,4 +1,4 @@ -/* $Id: atyfb.c,v 1.139 2000/02/12 22:47:04 davem Exp $ +/* $Id: atyfb.c,v 1.140 2000/02/25 05:46:27 davem Exp $ * linux/drivers/video/atyfb.c -- Frame buffer device for ATI Mach64 * * Copyright (C) 1997-1998 Geert Uytterhoeven @@ -63,11 +63,13 @@ #ifdef __powerpc__ #include -#include #include #include #include